1 /* 2 * FILS AEAD for (Re)Association Request/Response frames 3 * Copyright 2016, Qualcomm Atheros, Inc. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9 10 #include <crypto/aes.h> 11 #include <crypto/algapi.h> 12 #include <crypto/skcipher.h> 13 14 #include "ieee80211_i.h" 15 #include "aes_cmac.h" 16 #include "fils_aead.h" 17 18 static int aes_s2v(struct crypto_cipher *tfm, 19 size_t num_elem, const u8 *addr[], size_t len[], u8 *v) 20 { 21 u8 d[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE]; 22 size_t i; 23 const u8 *data[2]; 24 size_t data_len[2], data_elems; 25 26 /* D = AES-CMAC(K, <zero>) */ 27 memset(tmp, 0, AES_BLOCK_SIZE); 28 data[0] = tmp; 29 data_len[0] = AES_BLOCK_SIZE; 30 aes_cmac_vector(tfm, 1, data, data_len, d, AES_BLOCK_SIZE); 31 32 for (i = 0; i < num_elem - 1; i++) { 33 /* D = dbl(D) xor AES_CMAC(K, Si) */ 34 gf_mulx(d); /* dbl */ 35 aes_cmac_vector(tfm, 1, &addr[i], &len[i], tmp, 36 AES_BLOCK_SIZE); 37 crypto_xor(d, tmp, AES_BLOCK_SIZE); 38 } 39 40 if (len[i] >= AES_BLOCK_SIZE) { 41 /* len(Sn) >= 128 */ 42 size_t j; 43 const u8 *pos; 44 45 /* T = Sn xorend D */ 46 47 /* Use a temporary buffer to perform xorend on Sn (addr[i]) to 48 * avoid modifying the const input argument. 49 */ 50 data[0] = addr[i]; 51 data_len[0] = len[i] - AES_BLOCK_SIZE; 52 pos = addr[i] + data_len[0]; 53 for (j = 0; j < AES_BLOCK_SIZE; j++) 54 tmp[j] = pos[j] ^ d[j]; 55 data[1] = tmp; 56 data_len[1] = AES_BLOCK_SIZE; 57 data_elems = 2; 58 } else { 59 /* len(Sn) < 128 */ 60 /* T = dbl(D) xor pad(Sn) */ 61 gf_mulx(d); /* dbl */ 62 memset(tmp, 0, AES_BLOCK_SIZE); 63 memcpy(tmp, addr[i], len[i]); 64 tmp[len[i]] = 0x80; 65 crypto_xor(d, tmp, AES_BLOCK_SIZE); 66 data[0] = d; 67 data_len[0] = sizeof(d); 68 data_elems = 1; 69 } 70 /* V = AES-CMAC(K, T) */ 71 aes_cmac_vector(tfm, data_elems, data, data_len, v, AES_BLOCK_SIZE); 72 73 return 0; 74 } 75 76 /* Note: addr[] and len[] needs to have one extra slot at the end. */ 77 static int aes_siv_encrypt(const u8 *key, size_t key_len, 78 const u8 *plain, size_t plain_len, 79 size_t num_elem, const u8 *addr[], 80 size_t len[], u8 *out) 81 { 82 u8 v[AES_BLOCK_SIZE]; 83 struct crypto_cipher *tfm; 84 struct crypto_skcipher *tfm2; 85 struct skcipher_request *req; 86 int res; 87 struct scatterlist src[1], dst[1]; 88 u8 *tmp; 89 90 key_len /= 2; /* S2V key || CTR key */ 91 92 addr[num_elem] = plain; 93 len[num_elem] = plain_len; 94 num_elem++; 95 96 /* S2V */ 97 98 tfm = crypto_alloc_cipher("aes", 0, 0); 99 if (IS_ERR(tfm)) 100 return PTR_ERR(tfm); 101 /* K1 for S2V */ 102 res = crypto_cipher_setkey(tfm, key, key_len); 103 if (!res) 104 res = aes_s2v(tfm, num_elem, addr, len, v); 105 crypto_free_cipher(tfm); 106 if (res) 107 return res; 108 109 /* Use a temporary buffer of the plaintext to handle need for 110 * overwriting this during AES-CTR. 111 */ 112 tmp = kmemdup(plain, plain_len, GFP_KERNEL); 113 if (!tmp) 114 return -ENOMEM; 115 116 /* IV for CTR before encrypted data */ 117 memcpy(out, v, AES_BLOCK_SIZE); 118 119 /* Synthetic IV to be used as the initial counter in CTR: 120 * Q = V bitand (1^64 || 0^1 || 1^31 || 0^1 || 1^31) 121 */ 122 v[8] &= 0x7f; 123 v[12] &= 0x7f; 124 125 /* CTR */ 126 127 tfm2 = crypto_alloc_skcipher("ctr(aes)", 0, 0); 128 if (IS_ERR(tfm2)) { 129 kfree(tmp); 130 return PTR_ERR(tfm2); 131 } 132 /* K2 for CTR */ 133 res = crypto_skcipher_setkey(tfm2, key + key_len, key_len); 134 if (res) 135 goto fail; 136 137 req = skcipher_request_alloc(tfm2, GFP_KERNEL); 138 if (!req) { 139 res = -ENOMEM; 140 goto fail; 141 } 142 143 sg_init_one(src, tmp, plain_len); 144 sg_init_one(dst, out + AES_BLOCK_SIZE, plain_len); 145 skcipher_request_set_crypt(req, src, dst, plain_len, v); 146 res = crypto_skcipher_encrypt(req); 147 skcipher_request_free(req); 148 fail: 149 kfree(tmp); 150 crypto_free_skcipher(tfm2); 151 return res; 152 } 153 154 /* Note: addr[] and len[] needs to have one extra slot at the end. */ 155 static int aes_siv_decrypt(const u8 *key, size_t key_len, 156 const u8 *iv_crypt, size_t iv_c_len, 157 size_t num_elem, const u8 *addr[], size_t len[], 158 u8 *out) 159 { 160 struct crypto_cipher *tfm; 161 struct crypto_skcipher *tfm2; 162 struct skcipher_request *req; 163 struct scatterlist src[1], dst[1]; 164 size_t crypt_len; 165 int res; 166 u8 frame_iv[AES_BLOCK_SIZE], iv[AES_BLOCK_SIZE]; 167 u8 check[AES_BLOCK_SIZE]; 168 169 crypt_len = iv_c_len - AES_BLOCK_SIZE; 170 key_len /= 2; /* S2V key || CTR key */ 171 addr[num_elem] = out; 172 len[num_elem] = crypt_len; 173 num_elem++; 174 175 memcpy(iv, iv_crypt, AES_BLOCK_SIZE); 176 memcpy(frame_iv, iv_crypt, AES_BLOCK_SIZE); 177 178 /* Synthetic IV to be used as the initial counter in CTR: 179 * Q = V bitand (1^64 || 0^1 || 1^31 || 0^1 || 1^31) 180 */ 181 iv[8] &= 0x7f; 182 iv[12] &= 0x7f; 183 184 /* CTR */ 185 186 tfm2 = crypto_alloc_skcipher("ctr(aes)", 0, 0); 187 if (IS_ERR(tfm2)) 188 return PTR_ERR(tfm2); 189 /* K2 for CTR */ 190 res = crypto_skcipher_setkey(tfm2, key + key_len, key_len); 191 if (res) { 192 crypto_free_skcipher(tfm2); 193 return res; 194 } 195 196 req = skcipher_request_alloc(tfm2, GFP_KERNEL); 197 if (!req) { 198 crypto_free_skcipher(tfm2); 199 return -ENOMEM; 200 } 201 202 sg_init_one(src, iv_crypt + AES_BLOCK_SIZE, crypt_len); 203 sg_init_one(dst, out, crypt_len); 204 skcipher_request_set_crypt(req, src, dst, crypt_len, iv); 205 res = crypto_skcipher_decrypt(req); 206 skcipher_request_free(req); 207 crypto_free_skcipher(tfm2); 208 if (res) 209 return res; 210 211 /* S2V */ 212 213 tfm = crypto_alloc_cipher("aes", 0, 0); 214 if (IS_ERR(tfm)) 215 return PTR_ERR(tfm); 216 /* K1 for S2V */ 217 res = crypto_cipher_setkey(tfm, key, key_len); 218 if (!res) 219 res = aes_s2v(tfm, num_elem, addr, len, check); 220 crypto_free_cipher(tfm); 221 if (res) 222 return res; 223 if (memcmp(check, frame_iv, AES_BLOCK_SIZE) != 0) 224 return -EINVAL; 225 return 0; 226 } 227 228 int fils_encrypt_assoc_req(struct sk_buff *skb, 229 struct ieee80211_mgd_assoc_data *assoc_data) 230 { 231 struct ieee80211_mgmt *mgmt = (void *)skb->data; 232 u8 *capab, *ies, *encr; 233 const u8 *addr[5 + 1], *session; 234 size_t len[5 + 1]; 235 size_t crypt_len; 236 237 if (ieee80211_is_reassoc_req(mgmt->frame_control)) { 238 capab = (u8 *)&mgmt->u.reassoc_req.capab_info; 239 ies = mgmt->u.reassoc_req.variable; 240 } else { 241 capab = (u8 *)&mgmt->u.assoc_req.capab_info; 242 ies = mgmt->u.assoc_req.variable; 243 } 244 245 session = cfg80211_find_ext_ie(WLAN_EID_EXT_FILS_SESSION, 246 ies, skb->data + skb->len - ies); 247 if (!session || session[1] != 1 + 8) 248 return -EINVAL; 249 /* encrypt after FILS Session element */ 250 encr = (u8 *)session + 2 + 1 + 8; 251 252 /* AES-SIV AAD vectors */ 253 254 /* The STA's MAC address */ 255 addr[0] = mgmt->sa; 256 len[0] = ETH_ALEN; 257 /* The AP's BSSID */ 258 addr[1] = mgmt->da; 259 len[1] = ETH_ALEN; 260 /* The STA's nonce */ 261 addr[2] = assoc_data->fils_nonces; 262 len[2] = FILS_NONCE_LEN; 263 /* The AP's nonce */ 264 addr[3] = &assoc_data->fils_nonces[FILS_NONCE_LEN]; 265 len[3] = FILS_NONCE_LEN; 266 /* The (Re)Association Request frame from the Capability Information 267 * field to the FILS Session element (both inclusive). 268 */ 269 addr[4] = capab; 270 len[4] = encr - capab; 271 272 crypt_len = skb->data + skb->len - encr; 273 skb_put(skb, AES_BLOCK_SIZE); 274 return aes_siv_encrypt(assoc_data->fils_kek, assoc_data->fils_kek_len, 275 encr, crypt_len, 1, addr, len, encr); 276 } 277 278 int fils_decrypt_assoc_resp(struct ieee80211_sub_if_data *sdata, 279 u8 *frame, size_t *frame_len, 280 struct ieee80211_mgd_assoc_data *assoc_data) 281 { 282 struct ieee80211_mgmt *mgmt = (void *)frame; 283 u8 *capab, *ies, *encr; 284 const u8 *addr[5 + 1], *session; 285 size_t len[5 + 1]; 286 int res; 287 size_t crypt_len; 288 289 if (*frame_len < 24 + 6) 290 return -EINVAL; 291 292 capab = (u8 *)&mgmt->u.assoc_resp.capab_info; 293 ies = mgmt->u.assoc_resp.variable; 294 session = cfg80211_find_ext_ie(WLAN_EID_EXT_FILS_SESSION, 295 ies, frame + *frame_len - ies); 296 if (!session || session[1] != 1 + 8) { 297 mlme_dbg(sdata, 298 "No (valid) FILS Session element in (Re)Association Response frame from %pM", 299 mgmt->sa); 300 return -EINVAL; 301 } 302 /* decrypt after FILS Session element */ 303 encr = (u8 *)session + 2 + 1 + 8; 304 305 /* AES-SIV AAD vectors */ 306 307 /* The AP's BSSID */ 308 addr[0] = mgmt->sa; 309 len[0] = ETH_ALEN; 310 /* The STA's MAC address */ 311 addr[1] = mgmt->da; 312 len[1] = ETH_ALEN; 313 /* The AP's nonce */ 314 addr[2] = &assoc_data->fils_nonces[FILS_NONCE_LEN]; 315 len[2] = FILS_NONCE_LEN; 316 /* The STA's nonce */ 317 addr[3] = assoc_data->fils_nonces; 318 len[3] = FILS_NONCE_LEN; 319 /* The (Re)Association Response frame from the Capability Information 320 * field to the FILS Session element (both inclusive). 321 */ 322 addr[4] = capab; 323 len[4] = encr - capab; 324 325 crypt_len = frame + *frame_len - encr; 326 if (crypt_len < AES_BLOCK_SIZE) { 327 mlme_dbg(sdata, 328 "Not enough room for AES-SIV data after FILS Session element in (Re)Association Response frame from %pM", 329 mgmt->sa); 330 return -EINVAL; 331 } 332 res = aes_siv_decrypt(assoc_data->fils_kek, assoc_data->fils_kek_len, 333 encr, crypt_len, 5, addr, len, encr); 334 if (res != 0) { 335 mlme_dbg(sdata, 336 "AES-SIV decryption of (Re)Association Response frame from %pM failed", 337 mgmt->sa); 338 return res; 339 } 340 *frame_len -= AES_BLOCK_SIZE; 341 return 0; 342 } 343