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