Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac802154: add llsec decryption method

Signed-off-by: Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Phoebe Buckheister and committed by
David S. Miller
4c14a2fb 03556e4d

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