diff options
author | Jouni Malinen <jouni@qca.qualcomm.com> | 2015-01-24 12:52:08 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2015-01-27 05:09:13 -0500 |
commit | 56c52da2d554f081e8fce58ecbcf6a40c605b95b (patch) | |
tree | 9c28bdf5c73f2f2a3a6d87880a9422e6d16f9d30 | |
parent | 2b2ba0db1c820d04d5143452d70012cd44d7b578 (diff) |
mac80111: Add BIP-CMAC-256 cipher
This allows mac80211 to configure BIP-CMAC-256 to the driver and also
use software-implementation within mac80211 when the driver does not
support this with hardware accelaration.
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/linux/ieee80211.h | 9 | ||||
-rw-r--r-- | net/mac80211/aes_cmac.c | 34 | ||||
-rw-r--r-- | net/mac80211/aes_cmac.h | 5 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 2 | ||||
-rw-r--r-- | net/mac80211/debugfs_key.c | 4 | ||||
-rw-r--r-- | net/mac80211/key.c | 14 | ||||
-rw-r--r-- | net/mac80211/main.c | 13 | ||||
-rw-r--r-- | net/mac80211/rx.c | 21 | ||||
-rw-r--r-- | net/mac80211/tx.c | 3 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 92 | ||||
-rw-r--r-- | net/mac80211/wpa.h | 4 |
11 files changed, 180 insertions, 21 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index dbf417bf25bf..b9c7897dc566 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -1017,6 +1017,15 @@ struct ieee80211_mmie { | |||
1017 | u8 mic[8]; | 1017 | u8 mic[8]; |
1018 | } __packed; | 1018 | } __packed; |
1019 | 1019 | ||
1020 | /* Management MIC information element (IEEE 802.11w) for GMAC and CMAC-256 */ | ||
1021 | struct ieee80211_mmie_16 { | ||
1022 | u8 element_id; | ||
1023 | u8 length; | ||
1024 | __le16 key_id; | ||
1025 | u8 sequence_number[6]; | ||
1026 | u8 mic[16]; | ||
1027 | } __packed; | ||
1028 | |||
1020 | struct ieee80211_vendor_ie { | 1029 | struct ieee80211_vendor_ie { |
1021 | u8 element_id; | 1030 | u8 element_id; |
1022 | u8 len; | 1031 | u8 len; |
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c index 9b9009f99551..4192806be3d3 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c | |||
@@ -18,8 +18,8 @@ | |||
18 | #include "key.h" | 18 | #include "key.h" |
19 | #include "aes_cmac.h" | 19 | #include "aes_cmac.h" |
20 | 20 | ||
21 | #define AES_CMAC_KEY_LEN 16 | ||
22 | #define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */ | 21 | #define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */ |
22 | #define CMAC_TLEN_256 16 /* CMAC TLen = 128 bits (16 octets) */ | ||
23 | #define AAD_LEN 20 | 23 | #define AAD_LEN 20 |
24 | 24 | ||
25 | 25 | ||
@@ -35,9 +35,9 @@ static void gf_mulx(u8 *pad) | |||
35 | pad[AES_BLOCK_SIZE - 1] ^= 0x87; | 35 | pad[AES_BLOCK_SIZE - 1] ^= 0x87; |
36 | } | 36 | } |
37 | 37 | ||
38 | 38 | static void aes_cmac_vector(struct crypto_cipher *tfm, size_t num_elem, | |
39 | static void aes_128_cmac_vector(struct crypto_cipher *tfm, size_t num_elem, | 39 | const u8 *addr[], const size_t *len, u8 *mac, |
40 | const u8 *addr[], const size_t *len, u8 *mac) | 40 | size_t mac_len) |
41 | { | 41 | { |
42 | u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; | 42 | u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; |
43 | const u8 *pos, *end; | 43 | const u8 *pos, *end; |
@@ -88,7 +88,7 @@ static void aes_128_cmac_vector(struct crypto_cipher *tfm, size_t num_elem, | |||
88 | for (i = 0; i < AES_BLOCK_SIZE; i++) | 88 | for (i = 0; i < AES_BLOCK_SIZE; i++) |
89 | pad[i] ^= cbc[i]; | 89 | pad[i] ^= cbc[i]; |
90 | crypto_cipher_encrypt_one(tfm, pad, pad); | 90 | crypto_cipher_encrypt_one(tfm, pad, pad); |
91 | memcpy(mac, pad, CMAC_TLEN); | 91 | memcpy(mac, pad, mac_len); |
92 | } | 92 | } |
93 | 93 | ||
94 | 94 | ||
@@ -107,17 +107,35 @@ void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, | |||
107 | addr[2] = zero; | 107 | addr[2] = zero; |
108 | len[2] = CMAC_TLEN; | 108 | len[2] = CMAC_TLEN; |
109 | 109 | ||
110 | aes_128_cmac_vector(tfm, 3, addr, len, mic); | 110 | aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN); |
111 | } | 111 | } |
112 | 112 | ||
113 | void ieee80211_aes_cmac_256(struct crypto_cipher *tfm, const u8 *aad, | ||
114 | const u8 *data, size_t data_len, u8 *mic) | ||
115 | { | ||
116 | const u8 *addr[3]; | ||
117 | size_t len[3]; | ||
118 | u8 zero[CMAC_TLEN_256]; | ||
119 | |||
120 | memset(zero, 0, CMAC_TLEN_256); | ||
121 | addr[0] = aad; | ||
122 | len[0] = AAD_LEN; | ||
123 | addr[1] = data; | ||
124 | len[1] = data_len - CMAC_TLEN_256; | ||
125 | addr[2] = zero; | ||
126 | len[2] = CMAC_TLEN_256; | ||
127 | |||
128 | aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN_256); | ||
129 | } | ||
113 | 130 | ||
114 | struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[]) | 131 | struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[], |
132 | size_t key_len) | ||
115 | { | 133 | { |
116 | struct crypto_cipher *tfm; | 134 | struct crypto_cipher *tfm; |
117 | 135 | ||
118 | tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); | 136 | tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); |
119 | if (!IS_ERR(tfm)) | 137 | if (!IS_ERR(tfm)) |
120 | crypto_cipher_setkey(tfm, key, AES_CMAC_KEY_LEN); | 138 | crypto_cipher_setkey(tfm, key, key_len); |
121 | 139 | ||
122 | return tfm; | 140 | return tfm; |
123 | } | 141 | } |
diff --git a/net/mac80211/aes_cmac.h b/net/mac80211/aes_cmac.h index 0ce6487af795..3702041f44fd 100644 --- a/net/mac80211/aes_cmac.h +++ b/net/mac80211/aes_cmac.h | |||
@@ -11,9 +11,12 @@ | |||
11 | 11 | ||
12 | #include <linux/crypto.h> | 12 | #include <linux/crypto.h> |
13 | 13 | ||
14 | struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[]); | 14 | struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[], |
15 | size_t key_len); | ||
15 | void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, | 16 | void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, |
16 | const u8 *data, size_t data_len, u8 *mic); | 17 | const u8 *data, size_t data_len, u8 *mic); |
18 | void ieee80211_aes_cmac_256(struct crypto_cipher *tfm, const u8 *aad, | ||
19 | const u8 *data, size_t data_len, u8 *mic); | ||
17 | void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm); | 20 | void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm); |
18 | 21 | ||
19 | #endif /* AES_CMAC_H */ | 22 | #endif /* AES_CMAC_H */ |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ef84441c119c..b7e528bbecce 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -164,6 +164,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
164 | case WLAN_CIPHER_SUITE_CCMP: | 164 | case WLAN_CIPHER_SUITE_CCMP: |
165 | case WLAN_CIPHER_SUITE_CCMP_256: | 165 | case WLAN_CIPHER_SUITE_CCMP_256: |
166 | case WLAN_CIPHER_SUITE_AES_CMAC: | 166 | case WLAN_CIPHER_SUITE_AES_CMAC: |
167 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
167 | case WLAN_CIPHER_SUITE_GCMP: | 168 | case WLAN_CIPHER_SUITE_GCMP: |
168 | case WLAN_CIPHER_SUITE_GCMP_256: | 169 | case WLAN_CIPHER_SUITE_GCMP_256: |
169 | break; | 170 | break; |
@@ -362,6 +363,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
362 | params.seq_len = 6; | 363 | params.seq_len = 6; |
363 | break; | 364 | break; |
364 | case WLAN_CIPHER_SUITE_AES_CMAC: | 365 | case WLAN_CIPHER_SUITE_AES_CMAC: |
366 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
365 | pn64 = atomic64_read(&key->u.aes_cmac.tx_pn); | 367 | pn64 = atomic64_read(&key->u.aes_cmac.tx_pn); |
366 | seq[0] = pn64; | 368 | seq[0] = pn64; |
367 | seq[1] = pn64 >> 8; | 369 | seq[1] = pn64 >> 8; |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 64de07b16092..d1b60eb014a8 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -101,6 +101,7 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, | |||
101 | (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); | 101 | (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); |
102 | break; | 102 | break; |
103 | case WLAN_CIPHER_SUITE_AES_CMAC: | 103 | case WLAN_CIPHER_SUITE_AES_CMAC: |
104 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
104 | pn = atomic64_read(&key->u.aes_cmac.tx_pn); | 105 | pn = atomic64_read(&key->u.aes_cmac.tx_pn); |
105 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", | 106 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", |
106 | (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), | 107 | (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), |
@@ -153,6 +154,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
153 | len = p - buf; | 154 | len = p - buf; |
154 | break; | 155 | break; |
155 | case WLAN_CIPHER_SUITE_AES_CMAC: | 156 | case WLAN_CIPHER_SUITE_AES_CMAC: |
157 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
156 | rpn = key->u.aes_cmac.rx_pn; | 158 | rpn = key->u.aes_cmac.rx_pn; |
157 | p += scnprintf(p, sizeof(buf)+buf-p, | 159 | p += scnprintf(p, sizeof(buf)+buf-p, |
158 | "%02x%02x%02x%02x%02x%02x\n", | 160 | "%02x%02x%02x%02x%02x%02x\n", |
@@ -191,6 +193,7 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf, | |||
191 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); | 193 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); |
192 | break; | 194 | break; |
193 | case WLAN_CIPHER_SUITE_AES_CMAC: | 195 | case WLAN_CIPHER_SUITE_AES_CMAC: |
196 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
194 | len = scnprintf(buf, sizeof(buf), "%u\n", | 197 | len = scnprintf(buf, sizeof(buf), "%u\n", |
195 | key->u.aes_cmac.replays); | 198 | key->u.aes_cmac.replays); |
196 | break; | 199 | break; |
@@ -214,6 +217,7 @@ static ssize_t key_icverrors_read(struct file *file, char __user *userbuf, | |||
214 | 217 | ||
215 | switch (key->conf.cipher) { | 218 | switch (key->conf.cipher) { |
216 | case WLAN_CIPHER_SUITE_AES_CMAC: | 219 | case WLAN_CIPHER_SUITE_AES_CMAC: |
220 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
217 | len = scnprintf(buf, sizeof(buf), "%u\n", | 221 | len = scnprintf(buf, sizeof(buf), "%u\n", |
218 | key->u.aes_cmac.icverrors); | 222 | key->u.aes_cmac.icverrors); |
219 | break; | 223 | break; |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 83c61085c3f0..7ceea9d9fcd2 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -165,6 +165,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
165 | case WLAN_CIPHER_SUITE_CCMP: | 165 | case WLAN_CIPHER_SUITE_CCMP: |
166 | case WLAN_CIPHER_SUITE_CCMP_256: | 166 | case WLAN_CIPHER_SUITE_CCMP_256: |
167 | case WLAN_CIPHER_SUITE_AES_CMAC: | 167 | case WLAN_CIPHER_SUITE_AES_CMAC: |
168 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
168 | case WLAN_CIPHER_SUITE_GCMP: | 169 | case WLAN_CIPHER_SUITE_GCMP: |
169 | case WLAN_CIPHER_SUITE_GCMP_256: | 170 | case WLAN_CIPHER_SUITE_GCMP_256: |
170 | /* all of these we can do in software - if driver can */ | 171 | /* all of these we can do in software - if driver can */ |
@@ -417,8 +418,12 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
417 | } | 418 | } |
418 | break; | 419 | break; |
419 | case WLAN_CIPHER_SUITE_AES_CMAC: | 420 | case WLAN_CIPHER_SUITE_AES_CMAC: |
421 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
420 | key->conf.iv_len = 0; | 422 | key->conf.iv_len = 0; |
421 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | 423 | if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) |
424 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | ||
425 | else | ||
426 | key->conf.icv_len = sizeof(struct ieee80211_mmie_16); | ||
422 | if (seq) | 427 | if (seq) |
423 | for (j = 0; j < IEEE80211_CMAC_PN_LEN; j++) | 428 | for (j = 0; j < IEEE80211_CMAC_PN_LEN; j++) |
424 | key->u.aes_cmac.rx_pn[j] = | 429 | key->u.aes_cmac.rx_pn[j] = |
@@ -428,7 +433,7 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
428 | * it does not need to be initialized for every packet. | 433 | * it does not need to be initialized for every packet. |
429 | */ | 434 | */ |
430 | key->u.aes_cmac.tfm = | 435 | key->u.aes_cmac.tfm = |
431 | ieee80211_aes_cmac_key_setup(key_data); | 436 | ieee80211_aes_cmac_key_setup(key_data, key_len); |
432 | if (IS_ERR(key->u.aes_cmac.tfm)) { | 437 | if (IS_ERR(key->u.aes_cmac.tfm)) { |
433 | err = PTR_ERR(key->u.aes_cmac.tfm); | 438 | err = PTR_ERR(key->u.aes_cmac.tfm); |
434 | kfree(key); | 439 | kfree(key); |
@@ -481,6 +486,7 @@ static void ieee80211_key_free_common(struct ieee80211_key *key) | |||
481 | ieee80211_aes_key_free(key->u.ccmp.tfm); | 486 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
482 | break; | 487 | break; |
483 | case WLAN_CIPHER_SUITE_AES_CMAC: | 488 | case WLAN_CIPHER_SUITE_AES_CMAC: |
489 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
484 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | 490 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); |
485 | break; | 491 | break; |
486 | case WLAN_CIPHER_SUITE_GCMP: | 492 | case WLAN_CIPHER_SUITE_GCMP: |
@@ -804,6 +810,7 @@ void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf, | |||
804 | seq->ccmp.pn[0] = pn64 >> 40; | 810 | seq->ccmp.pn[0] = pn64 >> 40; |
805 | break; | 811 | break; |
806 | case WLAN_CIPHER_SUITE_AES_CMAC: | 812 | case WLAN_CIPHER_SUITE_AES_CMAC: |
813 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
807 | pn64 = atomic64_read(&key->u.aes_cmac.tx_pn); | 814 | pn64 = atomic64_read(&key->u.aes_cmac.tx_pn); |
808 | seq->ccmp.pn[5] = pn64; | 815 | seq->ccmp.pn[5] = pn64; |
809 | seq->ccmp.pn[4] = pn64 >> 8; | 816 | seq->ccmp.pn[4] = pn64 >> 8; |
@@ -854,6 +861,7 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
854 | memcpy(seq->ccmp.pn, pn, IEEE80211_CCMP_PN_LEN); | 861 | memcpy(seq->ccmp.pn, pn, IEEE80211_CCMP_PN_LEN); |
855 | break; | 862 | break; |
856 | case WLAN_CIPHER_SUITE_AES_CMAC: | 863 | case WLAN_CIPHER_SUITE_AES_CMAC: |
864 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
857 | if (WARN_ON(tid != 0)) | 865 | if (WARN_ON(tid != 0)) |
858 | return; | 866 | return; |
859 | pn = key->u.aes_cmac.rx_pn; | 867 | pn = key->u.aes_cmac.rx_pn; |
@@ -897,6 +905,7 @@ void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf, | |||
897 | atomic64_set(&key->u.ccmp.tx_pn, pn64); | 905 | atomic64_set(&key->u.ccmp.tx_pn, pn64); |
898 | break; | 906 | break; |
899 | case WLAN_CIPHER_SUITE_AES_CMAC: | 907 | case WLAN_CIPHER_SUITE_AES_CMAC: |
908 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
900 | pn64 = (u64)seq->aes_cmac.pn[5] | | 909 | pn64 = (u64)seq->aes_cmac.pn[5] | |
901 | ((u64)seq->aes_cmac.pn[4] << 8) | | 910 | ((u64)seq->aes_cmac.pn[4] << 8) | |
902 | ((u64)seq->aes_cmac.pn[3] << 16) | | 911 | ((u64)seq->aes_cmac.pn[3] << 16) | |
@@ -948,6 +957,7 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
948 | memcpy(pn, seq->ccmp.pn, IEEE80211_CCMP_PN_LEN); | 957 | memcpy(pn, seq->ccmp.pn, IEEE80211_CCMP_PN_LEN); |
949 | break; | 958 | break; |
950 | case WLAN_CIPHER_SUITE_AES_CMAC: | 959 | case WLAN_CIPHER_SUITE_AES_CMAC: |
960 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
951 | if (WARN_ON(tid != 0)) | 961 | if (WARN_ON(tid != 0)) |
952 | return; | 962 | return; |
953 | pn = key->u.aes_cmac.rx_pn; | 963 | pn = key->u.aes_cmac.rx_pn; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index a5ad2d5bb29b..053a17c5023a 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -671,7 +671,8 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
671 | WLAN_CIPHER_SUITE_GCMP_256, | 671 | WLAN_CIPHER_SUITE_GCMP_256, |
672 | 672 | ||
673 | /* keep last -- depends on hw flags! */ | 673 | /* keep last -- depends on hw flags! */ |
674 | WLAN_CIPHER_SUITE_AES_CMAC | 674 | WLAN_CIPHER_SUITE_AES_CMAC, |
675 | WLAN_CIPHER_SUITE_BIP_CMAC_256, | ||
675 | }; | 676 | }; |
676 | 677 | ||
677 | if (local->hw.flags & IEEE80211_HW_SW_CRYPTO_CONTROL || | 678 | if (local->hw.flags & IEEE80211_HW_SW_CRYPTO_CONTROL || |
@@ -710,7 +711,7 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
710 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | 711 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); |
711 | 712 | ||
712 | if (!have_mfp) | 713 | if (!have_mfp) |
713 | local->hw.wiphy->n_cipher_suites--; | 714 | local->hw.wiphy->n_cipher_suites -= 2; |
714 | 715 | ||
715 | if (!have_wep) { | 716 | if (!have_wep) { |
716 | local->hw.wiphy->cipher_suites += 2; | 717 | local->hw.wiphy->cipher_suites += 2; |
@@ -736,9 +737,9 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
736 | if (have_wep) | 737 | if (have_wep) |
737 | n_suites += 2; | 738 | n_suites += 2; |
738 | 739 | ||
739 | /* check if we have AES_CMAC */ | 740 | /* check if we have AES_CMAC, BIP-CMAC-256 */ |
740 | if (have_mfp) | 741 | if (have_mfp) |
741 | n_suites++; | 742 | n_suites += 2; |
742 | 743 | ||
743 | suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL); | 744 | suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL); |
744 | if (!suites) | 745 | if (!suites) |
@@ -755,8 +756,10 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
755 | suites[w++] = WLAN_CIPHER_SUITE_WEP104; | 756 | suites[w++] = WLAN_CIPHER_SUITE_WEP104; |
756 | } | 757 | } |
757 | 758 | ||
758 | if (have_mfp) | 759 | if (have_mfp) { |
759 | suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; | 760 | suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; |
761 | suites[w++] = WLAN_CIPHER_SUITE_BIP_CMAC_256; | ||
762 | } | ||
760 | 763 | ||
761 | for (r = 0; r < local->hw.n_cipher_schemes; r++) | 764 | for (r = 0; r < local->hw.n_cipher_schemes; r++) |
762 | suites[w++] = cs[r].cipher; | 765 | suites[w++] = cs[r].cipher; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e8c6ba5ce70b..93ebc9525478 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -647,6 +647,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
647 | { | 647 | { |
648 | struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; | 648 | struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; |
649 | struct ieee80211_mmie *mmie; | 649 | struct ieee80211_mmie *mmie; |
650 | struct ieee80211_mmie_16 *mmie16; | ||
650 | 651 | ||
651 | if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) | 652 | if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) |
652 | return -1; | 653 | return -1; |
@@ -656,11 +657,18 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
656 | 657 | ||
657 | mmie = (struct ieee80211_mmie *) | 658 | mmie = (struct ieee80211_mmie *) |
658 | (skb->data + skb->len - sizeof(*mmie)); | 659 | (skb->data + skb->len - sizeof(*mmie)); |
659 | if (mmie->element_id != WLAN_EID_MMIE || | 660 | if (mmie->element_id == WLAN_EID_MMIE && |
660 | mmie->length != sizeof(*mmie) - 2) | 661 | mmie->length == sizeof(*mmie) - 2) |
661 | return -1; | 662 | return le16_to_cpu(mmie->key_id); |
662 | 663 | ||
663 | return le16_to_cpu(mmie->key_id); | 664 | mmie16 = (struct ieee80211_mmie_16 *) |
665 | (skb->data + skb->len - sizeof(*mmie16)); | ||
666 | if (skb->len >= 24 + sizeof(*mmie16) && | ||
667 | mmie16->element_id == WLAN_EID_MMIE && | ||
668 | mmie16->length == sizeof(*mmie16) - 2) | ||
669 | return le16_to_cpu(mmie16->key_id); | ||
670 | |||
671 | return -1; | ||
664 | } | 672 | } |
665 | 673 | ||
666 | static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs, | 674 | static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs, |
@@ -1660,6 +1668,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1660 | case WLAN_CIPHER_SUITE_AES_CMAC: | 1668 | case WLAN_CIPHER_SUITE_AES_CMAC: |
1661 | result = ieee80211_crypto_aes_cmac_decrypt(rx); | 1669 | result = ieee80211_crypto_aes_cmac_decrypt(rx); |
1662 | break; | 1670 | break; |
1671 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
1672 | result = ieee80211_crypto_aes_cmac_256_decrypt(rx); | ||
1673 | break; | ||
1663 | case WLAN_CIPHER_SUITE_GCMP: | 1674 | case WLAN_CIPHER_SUITE_GCMP: |
1664 | case WLAN_CIPHER_SUITE_GCMP_256: | 1675 | case WLAN_CIPHER_SUITE_GCMP_256: |
1665 | result = ieee80211_crypto_gcmp_decrypt(rx); | 1676 | result = ieee80211_crypto_gcmp_decrypt(rx); |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index be57e0afd019..909c27be1fdc 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -639,6 +639,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
639 | ieee80211_is_mgmt(hdr->frame_control); | 639 | ieee80211_is_mgmt(hdr->frame_control); |
640 | break; | 640 | break; |
641 | case WLAN_CIPHER_SUITE_AES_CMAC: | 641 | case WLAN_CIPHER_SUITE_AES_CMAC: |
642 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
642 | if (!ieee80211_is_mgmt(hdr->frame_control)) | 643 | if (!ieee80211_is_mgmt(hdr->frame_control)) |
643 | tx->key = NULL; | 644 | tx->key = NULL; |
644 | break; | 645 | break; |
@@ -1021,6 +1022,8 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | |||
1021 | tx, IEEE80211_CCMP_256_MIC_LEN); | 1022 | tx, IEEE80211_CCMP_256_MIC_LEN); |
1022 | case WLAN_CIPHER_SUITE_AES_CMAC: | 1023 | case WLAN_CIPHER_SUITE_AES_CMAC: |
1023 | return ieee80211_crypto_aes_cmac_encrypt(tx); | 1024 | return ieee80211_crypto_aes_cmac_encrypt(tx); |
1025 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
1026 | return ieee80211_crypto_aes_cmac_256_encrypt(tx); | ||
1024 | case WLAN_CIPHER_SUITE_GCMP: | 1027 | case WLAN_CIPHER_SUITE_GCMP: |
1025 | case WLAN_CIPHER_SUITE_GCMP_256: | 1028 | case WLAN_CIPHER_SUITE_GCMP_256: |
1026 | return ieee80211_crypto_gcmp_encrypt(tx); | 1029 | return ieee80211_crypto_gcmp_encrypt(tx); |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index ae654de9782a..549af118de9f 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -955,6 +955,48 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) | |||
955 | return TX_CONTINUE; | 955 | return TX_CONTINUE; |
956 | } | 956 | } |
957 | 957 | ||
958 | ieee80211_tx_result | ||
959 | ieee80211_crypto_aes_cmac_256_encrypt(struct ieee80211_tx_data *tx) | ||
960 | { | ||
961 | struct sk_buff *skb; | ||
962 | struct ieee80211_tx_info *info; | ||
963 | struct ieee80211_key *key = tx->key; | ||
964 | struct ieee80211_mmie_16 *mmie; | ||
965 | u8 aad[20]; | ||
966 | u64 pn64; | ||
967 | |||
968 | if (WARN_ON(skb_queue_len(&tx->skbs) != 1)) | ||
969 | return TX_DROP; | ||
970 | |||
971 | skb = skb_peek(&tx->skbs); | ||
972 | |||
973 | info = IEEE80211_SKB_CB(skb); | ||
974 | |||
975 | if (info->control.hw_key) | ||
976 | return TX_CONTINUE; | ||
977 | |||
978 | if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) | ||
979 | return TX_DROP; | ||
980 | |||
981 | mmie = (struct ieee80211_mmie_16 *)skb_put(skb, sizeof(*mmie)); | ||
982 | mmie->element_id = WLAN_EID_MMIE; | ||
983 | mmie->length = sizeof(*mmie) - 2; | ||
984 | mmie->key_id = cpu_to_le16(key->conf.keyidx); | ||
985 | |||
986 | /* PN = PN + 1 */ | ||
987 | pn64 = atomic64_inc_return(&key->u.aes_cmac.tx_pn); | ||
988 | |||
989 | bip_ipn_set64(mmie->sequence_number, pn64); | ||
990 | |||
991 | bip_aad(skb, aad); | ||
992 | |||
993 | /* MIC = AES-256-CMAC(IGTK, AAD || Management Frame Body || MMIE, 128) | ||
994 | */ | ||
995 | ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad, | ||
996 | skb->data + 24, skb->len - 24, mmie->mic); | ||
997 | |||
998 | return TX_CONTINUE; | ||
999 | } | ||
958 | 1000 | ||
959 | ieee80211_rx_result | 1001 | ieee80211_rx_result |
960 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) | 1002 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) |
@@ -1006,6 +1048,56 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) | |||
1006 | return RX_CONTINUE; | 1048 | return RX_CONTINUE; |
1007 | } | 1049 | } |
1008 | 1050 | ||
1051 | ieee80211_rx_result | ||
1052 | ieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx) | ||
1053 | { | ||
1054 | struct sk_buff *skb = rx->skb; | ||
1055 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
1056 | struct ieee80211_key *key = rx->key; | ||
1057 | struct ieee80211_mmie_16 *mmie; | ||
1058 | u8 aad[20], mic[16], ipn[6]; | ||
1059 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
1060 | |||
1061 | if (!ieee80211_is_mgmt(hdr->frame_control)) | ||
1062 | return RX_CONTINUE; | ||
1063 | |||
1064 | /* management frames are already linear */ | ||
1065 | |||
1066 | if (skb->len < 24 + sizeof(*mmie)) | ||
1067 | return RX_DROP_UNUSABLE; | ||
1068 | |||
1069 | mmie = (struct ieee80211_mmie_16 *) | ||
1070 | (skb->data + skb->len - sizeof(*mmie)); | ||
1071 | if (mmie->element_id != WLAN_EID_MMIE || | ||
1072 | mmie->length != sizeof(*mmie) - 2) | ||
1073 | return RX_DROP_UNUSABLE; /* Invalid MMIE */ | ||
1074 | |||
1075 | bip_ipn_swap(ipn, mmie->sequence_number); | ||
1076 | |||
1077 | if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) { | ||
1078 | key->u.aes_cmac.replays++; | ||
1079 | return RX_DROP_UNUSABLE; | ||
1080 | } | ||
1081 | |||
1082 | if (!(status->flag & RX_FLAG_DECRYPTED)) { | ||
1083 | /* hardware didn't decrypt/verify MIC */ | ||
1084 | bip_aad(skb, aad); | ||
1085 | ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad, | ||
1086 | skb->data + 24, skb->len - 24, mic); | ||
1087 | if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) { | ||
1088 | key->u.aes_cmac.icverrors++; | ||
1089 | return RX_DROP_UNUSABLE; | ||
1090 | } | ||
1091 | } | ||
1092 | |||
1093 | memcpy(key->u.aes_cmac.rx_pn, ipn, 6); | ||
1094 | |||
1095 | /* Remove MMIE */ | ||
1096 | skb_trim(skb, skb->len - sizeof(*mmie)); | ||
1097 | |||
1098 | return RX_CONTINUE; | ||
1099 | } | ||
1100 | |||
1009 | ieee80211_tx_result | 1101 | ieee80211_tx_result |
1010 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | 1102 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) |
1011 | { | 1103 | { |
diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index 43e109f27a89..06b7f167a176 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h | |||
@@ -32,8 +32,12 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx, | |||
32 | 32 | ||
33 | ieee80211_tx_result | 33 | ieee80211_tx_result |
34 | ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx); | 34 | ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx); |
35 | ieee80211_tx_result | ||
36 | ieee80211_crypto_aes_cmac_256_encrypt(struct ieee80211_tx_data *tx); | ||
35 | ieee80211_rx_result | 37 | ieee80211_rx_result |
36 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); | 38 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); |
39 | ieee80211_rx_result | ||
40 | ieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx); | ||
37 | ieee80211_tx_result | 41 | ieee80211_tx_result |
38 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); | 42 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); |
39 | ieee80211_rx_result | 43 | ieee80211_rx_result |