aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac802154
diff options
context:
space:
mode:
authorPhoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>2014-05-16 11:46:39 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-16 17:23:41 -0400
commit4c14a2fb5d143e4ed94143be2b8c1961b47df9af (patch)
tree3b10a9a07c5fb699d8797e7e9b96cb30663086e7 /net/mac802154
parent03556e4d0dbbbf4af9df76f4a3839c86f6afb015 (diff)
mac802154: add llsec decryption method
Signed-off-by: Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac802154')
-rw-r--r--net/mac802154/llsec.c247
-rw-r--r--net/mac802154/llsec.h1
2 files changed, 248 insertions, 0 deletions
diff --git a/net/mac802154/llsec.c b/net/mac802154/llsec.c
index 2a4b68e2a934..392653b1b5a3 100644
--- a/net/mac802154/llsec.c
+++ b/net/mac802154/llsec.c
@@ -18,6 +18,7 @@
18#include <linux/bug.h> 18#include <linux/bug.h>
19#include <linux/completion.h> 19#include <linux/completion.h>
20#include <net/ieee802154.h> 20#include <net/ieee802154.h>
21#include <crypto/algapi.h>
21 22
22#include "mac802154.h" 23#include "mac802154.h"
23#include "llsec.h" 24#include "llsec.h"
@@ -780,3 +781,249 @@ fail:
780 rcu_read_unlock(); 781 rcu_read_unlock();
781 return rc; 782 return rc;
782} 783}
784
785
786
787static struct mac802154_llsec_device*
788llsec_lookup_dev(struct mac802154_llsec *sec,
789 const struct ieee802154_addr *addr)
790{
791 struct ieee802154_addr devaddr = *addr;
792 struct mac802154_llsec_device *dev = NULL;
793
794 if (devaddr.mode == IEEE802154_ADDR_NONE &&
795 llsec_recover_addr(sec, &devaddr) < 0)
796 return NULL;
797
798 if (devaddr.mode == IEEE802154_ADDR_SHORT) {
799 u32 key = llsec_dev_hash_short(devaddr.short_addr,
800 devaddr.pan_id);
801
802 hash_for_each_possible_rcu(sec->devices_short, dev,
803 bucket_s, key) {
804 if (dev->dev.pan_id == devaddr.pan_id &&
805 dev->dev.short_addr == devaddr.short_addr)
806 return dev;
807 }
808 } else {
809 u64 key = llsec_dev_hash_long(devaddr.extended_addr);
810
811 hash_for_each_possible_rcu(sec->devices_hw, dev,
812 bucket_hw, key) {
813 if (dev->dev.hwaddr == devaddr.extended_addr)
814 return dev;
815 }
816 }
817
818 return NULL;
819}
820
821static int
822llsec_lookup_seclevel(const struct mac802154_llsec *sec,
823 u8 frame_type, u8 cmd_frame_id,
824 struct ieee802154_llsec_seclevel *rlevel)
825{
826 struct ieee802154_llsec_seclevel *level;
827
828 list_for_each_entry_rcu(level, &sec->table.security_levels, list) {
829 if (level->frame_type == frame_type &&
830 (frame_type != IEEE802154_FC_TYPE_MAC_CMD ||
831 level->cmd_frame_id == cmd_frame_id)) {
832 *rlevel = *level;
833 return 0;
834 }
835 }
836
837 return -EINVAL;
838}
839
840static int
841llsec_do_decrypt_unauth(struct sk_buff *skb, const struct mac802154_llsec *sec,
842 const struct ieee802154_hdr *hdr,
843 struct mac802154_llsec_key *key, __le64 dev_addr)
844{
845 u8 iv[16];
846 unsigned char *data;
847 int datalen;
848 struct scatterlist src;
849 struct blkcipher_desc req = {
850 .tfm = key->tfm0,
851 .info = iv,
852 .flags = 0,
853 };
854
855 llsec_geniv(iv, dev_addr, &hdr->sec);
856 data = skb_mac_header(skb) + skb->mac_len;
857 datalen = skb_tail_pointer(skb) - data;
858
859 sg_init_one(&src, data, datalen);
860
861 return crypto_blkcipher_decrypt_iv(&req, &src, &src, datalen);
862}
863
864static int
865llsec_do_decrypt_auth(struct sk_buff *skb, const struct mac802154_llsec *sec,
866 const struct ieee802154_hdr *hdr,
867 struct mac802154_llsec_key *key, __le64 dev_addr)
868{
869 u8 iv[16];
870 unsigned char *data;
871 int authlen, datalen, assoclen, rc;
872 struct scatterlist src, assoc[2];
873 struct aead_request *req;
874
875 authlen = ieee802154_sechdr_authtag_len(&hdr->sec);
876 llsec_geniv(iv, dev_addr, &hdr->sec);
877
878 req = aead_request_alloc(llsec_tfm_by_len(key, authlen), GFP_ATOMIC);
879 if (!req)
880 return -ENOMEM;
881
882 sg_init_table(assoc, 2);
883 sg_set_buf(&assoc[0], skb_mac_header(skb), skb->mac_len);
884 assoclen = skb->mac_len;
885
886 data = skb_mac_header(skb) + skb->mac_len;
887 datalen = skb_tail_pointer(skb) - data;
888
889 if (hdr->sec.level & IEEE802154_SCF_SECLEVEL_ENC) {
890 sg_set_buf(&assoc[1], data, 0);
891 } else {
892 sg_set_buf(&assoc[1], data, datalen - authlen);
893 assoclen += datalen - authlen;
894 data += datalen - authlen;
895 datalen = authlen;
896 }
897
898 sg_init_one(&src, data, datalen);
899
900 aead_request_set_callback(req, 0, NULL, NULL);
901 aead_request_set_assoc(req, assoc, assoclen);
902 aead_request_set_crypt(req, &src, &src, datalen, iv);
903
904 rc = crypto_aead_decrypt(req);
905
906 kfree(req);
907 skb_trim(skb, skb->len - authlen);
908
909 return rc;
910}
911
912static int
913llsec_do_decrypt(struct sk_buff *skb, const struct mac802154_llsec *sec,
914 const struct ieee802154_hdr *hdr,
915 struct mac802154_llsec_key *key, __le64 dev_addr)
916{
917 if (hdr->sec.level == IEEE802154_SCF_SECLEVEL_ENC)
918 return llsec_do_decrypt_unauth(skb, sec, hdr, key, dev_addr);
919 else
920 return llsec_do_decrypt_auth(skb, sec, hdr, key, dev_addr);
921}
922
923static int
924llsec_update_devkey_info(struct mac802154_llsec_device *dev,
925 const struct ieee802154_llsec_key_id *in_key,
926 u32 frame_counter)
927{
928 struct mac802154_llsec_device_key *devkey = NULL;
929
930 if (dev->dev.key_mode == IEEE802154_LLSEC_DEVKEY_RESTRICT) {
931 devkey = llsec_devkey_find(dev, in_key);
932 if (!devkey)
933 return -ENOENT;
934 }
935
936 spin_lock_bh(&dev->lock);
937
938 if ((!devkey && frame_counter < dev->dev.frame_counter) ||
939 (devkey && frame_counter < devkey->devkey.frame_counter)) {
940 spin_unlock_bh(&dev->lock);
941 return -EINVAL;
942 }
943
944 if (devkey)
945 devkey->devkey.frame_counter = frame_counter + 1;
946 else
947 dev->dev.frame_counter = frame_counter + 1;
948
949 spin_unlock_bh(&dev->lock);
950
951 return 0;
952}
953
954int mac802154_llsec_decrypt(struct mac802154_llsec *sec, struct sk_buff *skb)
955{
956 struct ieee802154_hdr hdr;
957 struct mac802154_llsec_key *key;
958 struct ieee802154_llsec_key_id key_id;
959 struct mac802154_llsec_device *dev;
960 struct ieee802154_llsec_seclevel seclevel;
961 int err;
962 __le64 dev_addr;
963 u32 frame_ctr;
964
965 if (ieee802154_hdr_peek(skb, &hdr) < 0)
966 return -EINVAL;
967 if (!hdr.fc.security_enabled)
968 return 0;
969 if (hdr.fc.version == 0)
970 return -EINVAL;
971
972 read_lock_bh(&sec->lock);
973 if (!sec->params.enabled) {
974 read_unlock_bh(&sec->lock);
975 return -EINVAL;
976 }
977 read_unlock_bh(&sec->lock);
978
979 rcu_read_lock();
980
981 key = llsec_lookup_key(sec, &hdr, &hdr.source, &key_id);
982 if (!key) {
983 err = -ENOKEY;
984 goto fail;
985 }
986
987 dev = llsec_lookup_dev(sec, &hdr.source);
988 if (!dev) {
989 err = -EINVAL;
990 goto fail_dev;
991 }
992
993 if (llsec_lookup_seclevel(sec, hdr.fc.type, 0, &seclevel) < 0) {
994 err = -EINVAL;
995 goto fail_dev;
996 }
997
998 if (!(seclevel.sec_levels & BIT(hdr.sec.level)) &&
999 (hdr.sec.level == 0 && seclevel.device_override &&
1000 !dev->dev.seclevel_exempt)) {
1001 err = -EINVAL;
1002 goto fail_dev;
1003 }
1004
1005 frame_ctr = le32_to_cpu(hdr.sec.frame_counter);
1006
1007 if (frame_ctr == 0xffffffff) {
1008 err = -EOVERFLOW;
1009 goto fail_dev;
1010 }
1011
1012 err = llsec_update_devkey_info(dev, &key_id, frame_ctr);
1013 if (err)
1014 goto fail_dev;
1015
1016 dev_addr = dev->dev.hwaddr;
1017
1018 rcu_read_unlock();
1019
1020 err = llsec_do_decrypt(skb, sec, &hdr, key, dev_addr);
1021 llsec_key_put(key);
1022 return err;
1023
1024fail_dev:
1025 llsec_key_put(key);
1026fail:
1027 rcu_read_unlock();
1028 return err;
1029}
diff --git a/net/mac802154/llsec.h b/net/mac802154/llsec.h
index 083055b3b795..950578e1d7be 100644
--- a/net/mac802154/llsec.h
+++ b/net/mac802154/llsec.h
@@ -103,5 +103,6 @@ int mac802154_llsec_seclevel_del(struct mac802154_llsec *sec,
103 const struct ieee802154_llsec_seclevel *sl); 103 const struct ieee802154_llsec_seclevel *sl);
104 104
105int mac802154_llsec_encrypt(struct mac802154_llsec *sec, struct sk_buff *skb); 105int mac802154_llsec_encrypt(struct mac802154_llsec *sec, struct sk_buff *skb);
106int mac802154_llsec_decrypt(struct mac802154_llsec *sec, struct sk_buff *skb);
106 107
107#endif /* MAC802154_LLSEC_H */ 108#endif /* MAC802154_LLSEC_H */