/src/hostap/src/common/wpa_common.c
Line | Count | Source |
1 | | /* |
2 | | * WPA/RSN - Shared functions for supplicant and authenticator |
3 | | * Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> |
4 | | * |
5 | | * This software may be distributed under the terms of the BSD license. |
6 | | * See README for more details. |
7 | | */ |
8 | | |
9 | | #include "includes.h" |
10 | | |
11 | | #include "common.h" |
12 | | #include "crypto/md5.h" |
13 | | #include "crypto/sha1.h" |
14 | | #include "crypto/sha256.h" |
15 | | #include "crypto/sha384.h" |
16 | | #include "crypto/sha512.h" |
17 | | #include "crypto/aes_wrap.h" |
18 | | #include "crypto/crypto.h" |
19 | | #include "crypto/random.h" |
20 | | #include "ieee802_11_defs.h" |
21 | | #include "ieee802_11_common.h" |
22 | | #include "defs.h" |
23 | | #include "common/nan_defs.h" |
24 | | #include "wpa_common.h" |
25 | | |
26 | | |
27 | | static unsigned int wpa_kck_len(int akmp, size_t pmk_len) |
28 | 1.22k | { |
29 | 1.22k | switch (akmp) { |
30 | 0 | case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: |
31 | 0 | case WPA_KEY_MGMT_IEEE8021X_SHA384: |
32 | 0 | case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: |
33 | 0 | return 24; |
34 | 0 | case WPA_KEY_MGMT_FILS_SHA256: |
35 | 0 | case WPA_KEY_MGMT_FT_FILS_SHA256: |
36 | 0 | case WPA_KEY_MGMT_FILS_SHA384: |
37 | 0 | case WPA_KEY_MGMT_FT_FILS_SHA384: |
38 | 0 | return 0; |
39 | 0 | case WPA_KEY_MGMT_DPP: |
40 | 0 | return pmk_len / 2; |
41 | 0 | case WPA_KEY_MGMT_OWE: |
42 | 0 | return pmk_len / 2; |
43 | 0 | case WPA_KEY_MGMT_SAE_EXT_KEY: |
44 | 0 | case WPA_KEY_MGMT_FT_SAE_EXT_KEY: |
45 | 0 | return pmk_len / 2; |
46 | | #ifdef CONFIG_ENC_ASSOC |
47 | | case WPA_KEY_MGMT_EPPKE: |
48 | | return 32; |
49 | | #endif /* CONFIG_ENC_ASSOC */ |
50 | 1.22k | default: |
51 | 1.22k | return 16; |
52 | 1.22k | } |
53 | 1.22k | } |
54 | | |
55 | | |
56 | | #ifdef CONFIG_IEEE80211R |
57 | | static unsigned int wpa_kck2_len(int akmp) |
58 | 0 | { |
59 | 0 | switch (akmp) { |
60 | 0 | case WPA_KEY_MGMT_FT_FILS_SHA256: |
61 | 0 | return 16; |
62 | 0 | case WPA_KEY_MGMT_FT_FILS_SHA384: |
63 | 0 | return 24; |
64 | 0 | default: |
65 | 0 | return 0; |
66 | 0 | } |
67 | 0 | } |
68 | | #endif /* CONFIG_IEEE80211R */ |
69 | | |
70 | | |
71 | | unsigned int wpa_kek_len(int akmp, size_t pmk_len, u16 pasn_group) |
72 | 1.22k | { |
73 | 1.22k | switch (akmp) { |
74 | 0 | case WPA_KEY_MGMT_FILS_SHA384: |
75 | 0 | case WPA_KEY_MGMT_FT_FILS_SHA384: |
76 | 0 | return 64; |
77 | 0 | case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: |
78 | 0 | case WPA_KEY_MGMT_FILS_SHA256: |
79 | 0 | case WPA_KEY_MGMT_FT_FILS_SHA256: |
80 | 0 | case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: |
81 | 0 | case WPA_KEY_MGMT_IEEE8021X_SHA384: |
82 | 0 | return 32; |
83 | 0 | case WPA_KEY_MGMT_DPP: |
84 | 0 | return pmk_len <= 32 ? 16 : 32; |
85 | 0 | case WPA_KEY_MGMT_OWE: |
86 | 0 | return pmk_len <= 32 ? 16 : 32; |
87 | 0 | case WPA_KEY_MGMT_SAE_EXT_KEY: |
88 | 0 | case WPA_KEY_MGMT_FT_SAE_EXT_KEY: |
89 | 0 | return pmk_len <= 32 ? 16 : 32; |
90 | | #ifdef CONFIG_ENC_ASSOC |
91 | | case WPA_KEY_MGMT_EPPKE: |
92 | | if (pasn_group == 21 || pasn_group == 20) |
93 | | return 32; |
94 | | return 16; |
95 | | #endif /* CONFIG_ENC_ASSOC */ |
96 | 1.22k | default: |
97 | 1.22k | return 16; |
98 | 1.22k | } |
99 | 1.22k | } |
100 | | |
101 | | |
102 | | #ifdef CONFIG_IEEE80211R |
103 | | static unsigned int wpa_kek2_len(int akmp) |
104 | 0 | { |
105 | 0 | switch (akmp) { |
106 | 0 | case WPA_KEY_MGMT_FT_FILS_SHA256: |
107 | 0 | return 16; |
108 | 0 | case WPA_KEY_MGMT_FT_FILS_SHA384: |
109 | 0 | return 32; |
110 | 0 | default: |
111 | 0 | return 0; |
112 | 0 | } |
113 | 0 | } |
114 | | #endif /* CONFIG_IEEE80211R */ |
115 | | |
116 | | |
117 | | #ifdef CONFIG_ENC_ASSOC |
118 | | static int rsn_eppke_mic_len(u16 pasn_group) |
119 | | { |
120 | | /* MIC length is half of the output length of the hash algorithm */ |
121 | | switch (pasn_group) { |
122 | | case 21: |
123 | | return 32; |
124 | | case 20: |
125 | | return 24; |
126 | | default: |
127 | | return 16; |
128 | | } |
129 | | } |
130 | | #endif /* CONFIG_ENC_ASSOC */ |
131 | | |
132 | | |
133 | | static int rsn_mic_len_hash(size_t pmk_len, enum rsn_hash_alg hash) |
134 | 0 | { |
135 | 0 | switch (hash) { |
136 | 0 | case RSN_HASH_SHA256: |
137 | 0 | return 16; |
138 | 0 | case RSN_HASH_SHA384: |
139 | 0 | return 24; |
140 | 0 | case RSN_HASH_SHA512: |
141 | 0 | return 32; |
142 | 0 | default: |
143 | 0 | return pmk_len / 2; |
144 | 0 | } |
145 | 0 | } |
146 | | |
147 | | unsigned int wpa_mic_len(int akmp, size_t pmk_len, enum rsn_hash_alg hash, |
148 | | u16 pasn_group) |
149 | 4.20k | { |
150 | 4.20k | switch (akmp) { |
151 | 0 | case WPA_KEY_MGMT_PQC_8021X: |
152 | 0 | case WPA_KEY_MGMT_FT_PQC_8021X: |
153 | 0 | return rsn_mic_len_hash(pmk_len, hash); |
154 | 0 | case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: |
155 | 0 | case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: |
156 | 0 | case WPA_KEY_MGMT_IEEE8021X_SHA384: |
157 | 0 | return 24; |
158 | 0 | case WPA_KEY_MGMT_FILS_SHA256: |
159 | 0 | case WPA_KEY_MGMT_FILS_SHA384: |
160 | 0 | case WPA_KEY_MGMT_FT_FILS_SHA256: |
161 | 0 | case WPA_KEY_MGMT_FT_FILS_SHA384: |
162 | 0 | return 0; |
163 | 0 | case WPA_KEY_MGMT_DPP: |
164 | 0 | return rsn_mic_len_hash(pmk_len, hash); |
165 | 0 | case WPA_KEY_MGMT_OWE: |
166 | 0 | return rsn_mic_len_hash(pmk_len, hash); |
167 | 0 | case WPA_KEY_MGMT_SAE_EXT_KEY: |
168 | 0 | case WPA_KEY_MGMT_FT_SAE_EXT_KEY: |
169 | 0 | return rsn_mic_len_hash(pmk_len, hash); |
170 | | #ifdef CONFIG_ENC_ASSOC |
171 | | case WPA_KEY_MGMT_EPPKE: |
172 | | return rsn_eppke_mic_len(pasn_group); |
173 | | #endif /* CONFIG_ENC_ASSOC */ |
174 | 4.20k | default: |
175 | 4.20k | return 16; |
176 | 4.20k | } |
177 | 4.20k | } |
178 | | |
179 | | |
180 | | int rsn_cipher_suite_to_wpa_cipher(u32 cipher) |
181 | 0 | { |
182 | 0 | switch (cipher) { |
183 | 0 | case RSN_CIPHER_SUITE_NONE: |
184 | 0 | return WPA_CIPHER_NONE; |
185 | 0 | case RSN_CIPHER_SUITE_TKIP: |
186 | 0 | return WPA_CIPHER_TKIP; |
187 | 0 | case RSN_CIPHER_SUITE_CCMP: |
188 | 0 | return WPA_CIPHER_CCMP; |
189 | 0 | case RSN_CIPHER_SUITE_AES_128_CMAC: |
190 | 0 | return WPA_CIPHER_AES_128_CMAC; |
191 | 0 | case RSN_CIPHER_SUITE_GCMP: |
192 | 0 | return WPA_CIPHER_GCMP; |
193 | 0 | case RSN_CIPHER_SUITE_CCMP_256: |
194 | 0 | return WPA_CIPHER_CCMP_256; |
195 | 0 | case RSN_CIPHER_SUITE_GCMP_256: |
196 | 0 | return WPA_CIPHER_GCMP_256; |
197 | 0 | case RSN_CIPHER_SUITE_BIP_GMAC_128: |
198 | 0 | return WPA_CIPHER_BIP_GMAC_128; |
199 | 0 | case RSN_CIPHER_SUITE_BIP_GMAC_256: |
200 | 0 | return WPA_CIPHER_BIP_GMAC_256; |
201 | 0 | case RSN_CIPHER_SUITE_BIP_CMAC_256: |
202 | 0 | return WPA_CIPHER_BIP_CMAC_256; |
203 | 0 | case RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED: |
204 | 0 | return WPA_CIPHER_GTK_NOT_USED; |
205 | 0 | default: |
206 | 0 | return 0; |
207 | 0 | } |
208 | 0 | } |
209 | | |
210 | | |
211 | | int rsn_key_mgmt_to_wpa_akm(u32 akm_suite) |
212 | 0 | { |
213 | 0 | switch (akm_suite) { |
214 | 0 | case RSN_AUTH_KEY_MGMT_UNSPEC_802_1X: |
215 | 0 | return WPA_KEY_MGMT_IEEE8021X; |
216 | 0 | case RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X: |
217 | 0 | return WPA_KEY_MGMT_PSK; |
218 | 0 | #ifdef CONFIG_IEEE80211R |
219 | 0 | case RSN_AUTH_KEY_MGMT_FT_802_1X: |
220 | 0 | return WPA_KEY_MGMT_FT_IEEE8021X; |
221 | 0 | case RSN_AUTH_KEY_MGMT_FT_PSK: |
222 | 0 | return WPA_KEY_MGMT_FT_PSK; |
223 | | #ifdef CONFIG_SHA384 |
224 | | case RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384: |
225 | | return WPA_KEY_MGMT_FT_IEEE8021X_SHA384; |
226 | | #endif /* CONFIG_SHA384 */ |
227 | 0 | #endif /* CONFIG_IEEE80211R */ |
228 | | #ifdef CONFIG_SHA384 |
229 | | case RSN_AUTH_KEY_MGMT_802_1X_SHA384: |
230 | | return WPA_KEY_MGMT_IEEE8021X_SHA384; |
231 | | #endif /* CONFIG_SHA384 */ |
232 | 0 | case RSN_AUTH_KEY_MGMT_802_1X_SHA256: |
233 | 0 | return WPA_KEY_MGMT_IEEE8021X_SHA256; |
234 | 0 | case RSN_AUTH_KEY_MGMT_PSK_SHA256: |
235 | 0 | return WPA_KEY_MGMT_PSK_SHA256; |
236 | 0 | #ifdef CONFIG_SAE |
237 | 0 | case RSN_AUTH_KEY_MGMT_SAE: |
238 | 0 | return WPA_KEY_MGMT_SAE; |
239 | 0 | case RSN_AUTH_KEY_MGMT_SAE_EXT_KEY: |
240 | 0 | return WPA_KEY_MGMT_SAE_EXT_KEY; |
241 | 0 | case RSN_AUTH_KEY_MGMT_FT_SAE: |
242 | 0 | return WPA_KEY_MGMT_FT_SAE; |
243 | 0 | case RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY: |
244 | 0 | return WPA_KEY_MGMT_FT_SAE_EXT_KEY; |
245 | 0 | #endif /* CONFIG_SAE */ |
246 | 0 | case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B: |
247 | 0 | return WPA_KEY_MGMT_IEEE8021X_SUITE_B; |
248 | 0 | case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192: |
249 | 0 | return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; |
250 | 0 | case RSN_AUTH_KEY_MGMT_FILS_SHA256: |
251 | 0 | return WPA_KEY_MGMT_FILS_SHA256; |
252 | 0 | case RSN_AUTH_KEY_MGMT_FILS_SHA384: |
253 | 0 | return WPA_KEY_MGMT_FILS_SHA384; |
254 | 0 | case RSN_AUTH_KEY_MGMT_FT_FILS_SHA256: |
255 | 0 | return WPA_KEY_MGMT_FT_FILS_SHA256; |
256 | 0 | case RSN_AUTH_KEY_MGMT_FT_FILS_SHA384: |
257 | 0 | return WPA_KEY_MGMT_FT_FILS_SHA384; |
258 | | #ifdef CONFIG_OWE |
259 | | case RSN_AUTH_KEY_MGMT_OWE: |
260 | | return WPA_KEY_MGMT_OWE; |
261 | | #endif /* CONFIG_OWE */ |
262 | | #ifdef CONFIG_DPP |
263 | | case RSN_AUTH_KEY_MGMT_DPP: |
264 | | return WPA_KEY_MGMT_DPP; |
265 | | #endif /* CONFIG_DPP */ |
266 | | #ifdef CONFIG_PASN |
267 | | case RSN_AUTH_KEY_MGMT_PASN: |
268 | | return WPA_KEY_MGMT_PASN; |
269 | | #endif /* CONFIG_PASN */ |
270 | 0 | case RSN_AUTH_KEY_MGMT_EPPKE: |
271 | 0 | return WPA_KEY_MGMT_EPPKE; |
272 | | #ifdef CONFIG_PQC |
273 | | case RSN_AUTH_KEY_MGMT_802_1X_PQC: |
274 | | return WPA_KEY_MGMT_PQC_8021X; |
275 | | case RSN_AUTH_KEY_MGMT_FT_802_1X_PQC: |
276 | | return WPA_KEY_MGMT_FT_PQC_8021X; |
277 | | #endif /* CONFIG_PQC */ |
278 | 0 | default: |
279 | 0 | return 0; |
280 | 0 | } |
281 | 0 | } |
282 | | |
283 | | |
284 | | /** |
285 | | * wpa_use_akm_defined - Is AKM-defined Key Descriptor Version used |
286 | | * @akmp: WPA_KEY_MGMT_* used in key derivation |
287 | | * Returns: 1 if AKM-defined Key Descriptor Version is used; 0 otherwise |
288 | | */ |
289 | | int wpa_use_akm_defined(int akmp) |
290 | 3.22k | { |
291 | 3.22k | return akmp == WPA_KEY_MGMT_OWE || |
292 | 3.22k | akmp == WPA_KEY_MGMT_DPP || |
293 | 3.22k | akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 || |
294 | 3.22k | akmp == WPA_KEY_MGMT_IEEE8021X_SHA384 || |
295 | 3.22k | akmp == WPA_KEY_MGMT_EPPKE || |
296 | 3.22k | wpa_key_mgmt_sae(akmp) || |
297 | 3.22k | wpa_key_mgmt_pqc(akmp) || |
298 | 3.22k | wpa_key_mgmt_suite_b(akmp) || |
299 | 3.22k | wpa_key_mgmt_fils(akmp); |
300 | 3.22k | } |
301 | | |
302 | | |
303 | | /** |
304 | | * wpa_use_cmac - Is CMAC integrity algorithm used for EAPOL-Key MIC |
305 | | * @akmp: WPA_KEY_MGMT_* used in key derivation |
306 | | * Returns: 1 if CMAC is used; 0 otherwise |
307 | | */ |
308 | | int wpa_use_cmac(int akmp) |
309 | 0 | { |
310 | 0 | return akmp == WPA_KEY_MGMT_OWE || |
311 | 0 | akmp == WPA_KEY_MGMT_DPP || |
312 | 0 | wpa_key_mgmt_ft(akmp) || |
313 | 0 | wpa_key_mgmt_sha256(akmp) || |
314 | 0 | (wpa_key_mgmt_sae(akmp) && |
315 | 0 | !wpa_key_mgmt_sae_ext_key(akmp)) || |
316 | 0 | wpa_key_mgmt_suite_b(akmp); |
317 | 0 | } |
318 | | |
319 | | |
320 | | /** |
321 | | * wpa_use_aes_key_wrap - Is AES Keywrap algorithm used for EAPOL-Key Key Data |
322 | | * @akmp: WPA_KEY_MGMT_* used in key derivation |
323 | | * Returns: 1 if AES Keywrap is used; 0 otherwise |
324 | | * |
325 | | * Note: AKM 00-0F-AC:1 and 00-0F-AC:2 have special rules for selecting whether |
326 | | * to use AES Keywrap based on the negotiated pairwise cipher. This function |
327 | | * does not cover those special cases. |
328 | | */ |
329 | | int wpa_use_aes_key_wrap(int akmp) |
330 | 0 | { |
331 | 0 | return akmp == WPA_KEY_MGMT_OWE || |
332 | 0 | akmp == WPA_KEY_MGMT_DPP || |
333 | 0 | akmp == WPA_KEY_MGMT_IEEE8021X_SHA384 || |
334 | 0 | akmp == WPA_KEY_MGMT_EPPKE || |
335 | 0 | wpa_key_mgmt_ft(akmp) || |
336 | 0 | wpa_key_mgmt_sha256(akmp) || |
337 | 0 | wpa_key_mgmt_sae(akmp) || |
338 | 0 | wpa_key_mgmt_pqc(akmp) || |
339 | 0 | wpa_key_mgmt_suite_b(akmp); |
340 | 0 | } |
341 | | |
342 | | |
343 | | #ifdef CONFIG_ENC_ASSOC |
344 | | static int rsn_eapol_key_eppke_mic(const u8 *key, size_t key_len, |
345 | | u16 pasn_group, const u8 *buf, |
346 | | size_t len, u8 *mic) |
347 | | { |
348 | | u8 hash[SHA512_MAC_LEN]; |
349 | | size_t mic_len; |
350 | | |
351 | | switch (pasn_group) { |
352 | | case 19: |
353 | | wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key MIC using HMAC-SHA256"); |
354 | | if (hmac_sha256(key, key_len, buf, len, hash)) |
355 | | return -1; |
356 | | mic_len = 16; |
357 | | break; |
358 | | #ifdef CONFIG_SHA384 |
359 | | case 20: |
360 | | wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key MIC using HMAC-SHA384"); |
361 | | if (hmac_sha384(key, key_len, buf, len, hash)) |
362 | | return -1; |
363 | | mic_len = 24; |
364 | | break; |
365 | | #endif /* CONFIG_SHA384 */ |
366 | | #ifdef CONFIG_SHA512 |
367 | | case 21: |
368 | | wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key MIC using HMAC-SHA512"); |
369 | | if (hmac_sha512(key, key_len, buf, len, hash)) |
370 | | return -1; |
371 | | mic_len = 32; |
372 | | break; |
373 | | #endif /* CONFIG_SHA512 */ |
374 | | default: |
375 | | wpa_printf(MSG_INFO, "EPPKE: Unsupported group: %u", |
376 | | pasn_group); |
377 | | return -1; |
378 | | } |
379 | | os_memcpy(mic, hash, mic_len); |
380 | | wpa_hexdump(MSG_DEBUG, "RSN: EAPOL-Key MIC", mic, mic_len); |
381 | | return 0; |
382 | | } |
383 | | #endif /* CONFIG_ENC_ASSOC */ |
384 | | |
385 | | |
386 | | #if defined(CONFIG_SAE) || defined(CONFIG_OWE) || defined(CONFIG_DPP) |
387 | | static int rsn_eapol_key_mic_hash(const u8 *key, size_t key_len, int akmp, |
388 | | enum rsn_hash_alg hash_alg, int ver, |
389 | | const u8 *buf, size_t len, u8 *mic) |
390 | 0 | { |
391 | 0 | u8 hash[SHA512_MAC_LEN]; |
392 | 0 | size_t mic_len; |
393 | |
|
394 | 0 | if (hash_alg == RSN_HASH_NOT_SPECIFIED) { |
395 | 0 | if (key_len == 128 / 8) |
396 | 0 | hash_alg = RSN_HASH_SHA256; |
397 | 0 | else if (key_len == 192 / 8) |
398 | 0 | hash_alg = RSN_HASH_SHA384; |
399 | 0 | else if (key_len == 256 / 8) |
400 | 0 | hash_alg = RSN_HASH_SHA512; |
401 | 0 | else |
402 | 0 | return -1; |
403 | 0 | } |
404 | | |
405 | 0 | wpa_printf(MSG_DEBUG, |
406 | 0 | "RSN: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - %s)", |
407 | 0 | hash_alg == RSN_HASH_SHA512 ? 512 : |
408 | 0 | hash_alg == RSN_HASH_SHA384 ? 384 : 256, |
409 | 0 | wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN)); |
410 | 0 | wpa_hexdump(MSG_DEBUG, "RSN: KCK", key, key_len); |
411 | |
|
412 | 0 | if (hash_alg == RSN_HASH_SHA256) { |
413 | 0 | if (hmac_sha256(key, key_len, buf, len, hash)) |
414 | 0 | return -1; |
415 | 0 | mic_len = 16; |
416 | | #ifdef CONFIG_SHA384 |
417 | | } else if (hash_alg == RSN_HASH_SHA384) { |
418 | | if (hmac_sha384(key, key_len, buf, len, hash)) |
419 | | return -1; |
420 | | mic_len = 24; |
421 | | #endif /* CONFIG_SHA384 */ |
422 | | #ifdef CONFIG_SHA512 |
423 | | } else if (hash_alg == RSN_HASH_SHA512) { |
424 | | if (hmac_sha512(key, key_len, buf, len, hash)) |
425 | | return -1; |
426 | | mic_len = 32; |
427 | | #endif /* CONFIG_SHA512 */ |
428 | 0 | } else { |
429 | 0 | wpa_printf(MSG_INFO, |
430 | 0 | "RSN: Unsupported KCK length: %u (hash_alg=%d)", |
431 | 0 | (unsigned int) key_len, hash_alg); |
432 | 0 | return -1; |
433 | 0 | } |
434 | | |
435 | 0 | os_memcpy(mic, hash, mic_len); |
436 | 0 | wpa_hexdump(MSG_DEBUG, "RSN: EAPOL-Key MIC", mic, mic_len); |
437 | 0 | return 0; |
438 | 0 | } |
439 | | #endif /* CONFIG_SAE || CONFIG_OWE || CONFIG_DPP */ |
440 | | |
441 | | |
442 | | /** |
443 | | * wpa_eapol_key_mic - Calculate EAPOL-Key MIC |
444 | | * @key: EAPOL-Key Key Confirmation Key (KCK) |
445 | | * @key_len: KCK length in octets |
446 | | * @akmp: WPA_KEY_MGMT_* used in key derivation |
447 | | * @hash_alg: Hash algorithm |
448 | | * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) |
449 | | * @buf: Pointer to the beginning of the EAPOL header (version field) |
450 | | * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) |
451 | | * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written |
452 | | * Returns: 0 on success, -1 on failure |
453 | | * |
454 | | * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has |
455 | | * to be cleared (all zeroes) when calling this function. |
456 | | * |
457 | | * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the |
458 | | * description of the Key MIC calculation. It includes packet data from the |
459 | | * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change |
460 | | * happened during final editing of the standard and the correct behavior is |
461 | | * defined in the last draft (IEEE 802.11i/D10). |
462 | | */ |
463 | | int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, |
464 | | enum rsn_hash_alg hash_alg, int ver, |
465 | | const u8 *buf, size_t len, u8 *mic, u16 pasn_group) |
466 | 1.22k | { |
467 | 1.22k | u8 hash[SHA512_MAC_LEN]; |
468 | | |
469 | 1.22k | if (key_len == 0) { |
470 | 0 | wpa_printf(MSG_DEBUG, |
471 | 0 | "WPA: KCK not set - cannot calculate MIC"); |
472 | 0 | return -1; |
473 | 0 | } |
474 | | |
475 | 1.22k | switch (ver) { |
476 | 0 | #ifndef CONFIG_FIPS |
477 | 0 | case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: |
478 | 0 | wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using HMAC-MD5"); |
479 | 0 | return hmac_md5(key, key_len, buf, len, mic); |
480 | 0 | #endif /* CONFIG_FIPS */ |
481 | 522 | case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: |
482 | 522 | wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using HMAC-SHA1"); |
483 | 522 | if (hmac_sha1(key, key_len, buf, len, hash)) |
484 | 0 | return -1; |
485 | 522 | os_memcpy(mic, hash, MD5_MAC_LEN); |
486 | 522 | break; |
487 | 703 | case WPA_KEY_INFO_TYPE_AES_128_CMAC: |
488 | 703 | wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using AES-CMAC"); |
489 | 703 | return omac1_aes_128(key, buf, len, mic); |
490 | 0 | case WPA_KEY_INFO_TYPE_AKM_DEFINED: |
491 | 0 | switch (akmp) { |
492 | 0 | #ifdef CONFIG_SAE |
493 | 0 | case WPA_KEY_MGMT_SAE: |
494 | 0 | case WPA_KEY_MGMT_FT_SAE: |
495 | 0 | wpa_printf(MSG_DEBUG, |
496 | 0 | "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - SAE)"); |
497 | 0 | return omac1_aes_128(key, buf, len, mic); |
498 | 0 | case WPA_KEY_MGMT_SAE_EXT_KEY: |
499 | 0 | case WPA_KEY_MGMT_FT_SAE_EXT_KEY: |
500 | 0 | if (rsn_eapol_key_mic_hash(key, key_len, akmp, hash_alg, |
501 | 0 | ver, buf, len, mic) < 0) |
502 | 0 | return -1; |
503 | 0 | break; |
504 | 0 | #endif /* CONFIG_SAE */ |
505 | | #ifdef CONFIG_ENC_ASSOC |
506 | | case WPA_KEY_MGMT_EPPKE: |
507 | | if (rsn_eapol_key_eppke_mic(key, key_len, pasn_group, |
508 | | buf, len, mic) < 0) |
509 | | return -1; |
510 | | break; |
511 | | #endif /* CONFIG_ENC_ASSOC */ |
512 | 0 | #ifdef CONFIG_SUITEB |
513 | 0 | case WPA_KEY_MGMT_IEEE8021X_SUITE_B: |
514 | 0 | wpa_printf(MSG_DEBUG, |
515 | 0 | "WPA: EAPOL-Key MIC using HMAC-SHA256 (AKM-defined - Suite B)"); |
516 | 0 | if (hmac_sha256(key, key_len, buf, len, hash)) |
517 | 0 | return -1; |
518 | 0 | os_memcpy(mic, hash, MD5_MAC_LEN); |
519 | 0 | break; |
520 | 0 | #endif /* CONFIG_SUITEB */ |
521 | | #ifdef CONFIG_SUITEB192 |
522 | | case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: |
523 | | wpa_printf(MSG_DEBUG, |
524 | | "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - Suite B 192-bit)"); |
525 | | if (hmac_sha384(key, key_len, buf, len, hash)) |
526 | | return -1; |
527 | | os_memcpy(mic, hash, 24); |
528 | | break; |
529 | | #endif /* CONFIG_SUITEB192 */ |
530 | | #ifdef CONFIG_OWE |
531 | | case WPA_KEY_MGMT_OWE: |
532 | | if (rsn_eapol_key_mic_hash(key, key_len, akmp, hash_alg, |
533 | | ver, buf, len, mic) < 0) |
534 | | return -1; |
535 | | break; |
536 | | #endif /* CONFIG_OWE */ |
537 | | #ifdef CONFIG_DPP |
538 | | case WPA_KEY_MGMT_DPP: |
539 | | if (rsn_eapol_key_mic_hash(key, key_len, akmp, hash_alg, |
540 | | ver, buf, len, mic) < 0) |
541 | | return -1; |
542 | | break; |
543 | | #endif /* CONFIG_DPP */ |
544 | | #ifdef CONFIG_PQC |
545 | | case WPA_KEY_MGMT_PQC_8021X: |
546 | | #ifdef CONFIG_IEEE80211R |
547 | | case WPA_KEY_MGMT_FT_PQC_8021X: |
548 | | #endif /* CONFIG_IEEE80211R */ |
549 | | if (rsn_eapol_key_mic_hash(key, key_len, akmp, hash_alg, |
550 | | ver, buf, len, mic) < 0) |
551 | | return -1; |
552 | | break; |
553 | | #endif /* CONFIG_PQC */ |
554 | | #ifdef CONFIG_SHA384 |
555 | | case WPA_KEY_MGMT_IEEE8021X_SHA384: |
556 | | #ifdef CONFIG_IEEE80211R |
557 | | case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: |
558 | | #endif /* CONFIG_IEEE80211R */ |
559 | | wpa_printf(MSG_DEBUG, |
560 | | "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - 802.1X SHA384)"); |
561 | | if (hmac_sha384(key, key_len, buf, len, hash)) |
562 | | return -1; |
563 | | os_memcpy(mic, hash, 24); |
564 | | break; |
565 | | #endif /* CONFIG_SHA384 */ |
566 | 0 | default: |
567 | 0 | wpa_printf(MSG_DEBUG, |
568 | 0 | "WPA: EAPOL-Key MIC algorithm not known (AKM-defined - akmp=0x%x)", |
569 | 0 | akmp); |
570 | 0 | return -1; |
571 | 0 | } |
572 | 0 | break; |
573 | 0 | default: |
574 | 0 | wpa_printf(MSG_DEBUG, |
575 | 0 | "WPA: EAPOL-Key MIC algorithm not known (ver=%d)", |
576 | 0 | ver); |
577 | 0 | return -1; |
578 | 1.22k | } |
579 | | |
580 | 522 | return 0; |
581 | 1.22k | } |
582 | | |
583 | | |
584 | | /** |
585 | | * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces |
586 | | * @pmk: Pairwise master key |
587 | | * @pmk_len: Length of PMK |
588 | | * @label: Label to use in derivation |
589 | | * @addr1: AA or SA |
590 | | * @addr2: SA or AA |
591 | | * @nonce1: ANonce or SNonce |
592 | | * @nonce2: SNonce or ANonce |
593 | | * @ptk: Buffer for pairwise transient key |
594 | | * @akmp: Negotiated AKM |
595 | | * @cipher: Negotiated pairwise cipher |
596 | | * @z: Additional context data |
597 | | * @z_len: Length of additional context data |
598 | | * @kdk_len: The length in octets that should be derived for KDK |
599 | | * Returns: 0 on success, -1 on failure |
600 | | * |
601 | | * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy |
602 | | * PTK = PRF-X(PMK, "Pairwise key expansion", |
603 | | * Min(AA, SA) || Max(AA, SA) || |
604 | | * Min(ANonce, SNonce) || Max(ANonce, SNonce) |
605 | | * [ || Z.x ]) |
606 | | * |
607 | | * The optional Z.x component is used only with DPP and that part is not defined |
608 | | * in IEEE 802.11. The additional context data is also used to carry the DHss |
609 | | * (Diffie-Hellman shared secret) when IEEE 802.1X authentication in |
610 | | * Authentication frames is used. |
611 | | */ |
612 | | int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, |
613 | | const u8 *addr1, const u8 *addr2, |
614 | | const u8 *nonce1, const u8 *nonce2, |
615 | | struct wpa_ptk *ptk, int akmp, int cipher, |
616 | | const u8 *z, size_t z_len, size_t kdk_len, u16 pasn_group) |
617 | 1.22k | { |
618 | 1.22k | #define MAX_Z_LEN 66 /* with NIST P-521 */ |
619 | 1.22k | u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN]; |
620 | 1.22k | size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN; |
621 | 1.22k | u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN + |
622 | 1.22k | WPA_KDK_MAX_LEN]; |
623 | 1.22k | size_t ptk_len; |
624 | | #ifdef CONFIG_OWE |
625 | | int owe_ptk_workaround = 0; |
626 | | |
627 | | if (akmp == (WPA_KEY_MGMT_OWE | WPA_KEY_MGMT_PSK_SHA256)) { |
628 | | owe_ptk_workaround = 1; |
629 | | akmp = WPA_KEY_MGMT_OWE; |
630 | | } |
631 | | #endif /* CONFIG_OWE */ |
632 | | |
633 | 1.22k | if (pmk_len == 0) { |
634 | 0 | wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation"); |
635 | 0 | return -1; |
636 | 0 | } |
637 | | |
638 | 1.22k | if (z_len > MAX_Z_LEN) |
639 | 0 | return -1; |
640 | | |
641 | 1.22k | if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) { |
642 | 0 | os_memcpy(data, addr1, ETH_ALEN); |
643 | 0 | os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN); |
644 | 1.22k | } else { |
645 | 1.22k | os_memcpy(data, addr2, ETH_ALEN); |
646 | 1.22k | os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN); |
647 | 1.22k | } |
648 | | |
649 | 1.22k | if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) { |
650 | 772 | os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN); |
651 | 772 | os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2, |
652 | 772 | WPA_NONCE_LEN); |
653 | 772 | } else { |
654 | 453 | os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN); |
655 | 453 | os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1, |
656 | 453 | WPA_NONCE_LEN); |
657 | 453 | } |
658 | | |
659 | 1.22k | if (z && z_len) { |
660 | 0 | os_memcpy(data + 2 * ETH_ALEN + 2 * WPA_NONCE_LEN, z, z_len); |
661 | 0 | data_len += z_len; |
662 | 0 | } |
663 | | |
664 | 1.22k | if (kdk_len > WPA_KDK_MAX_LEN) { |
665 | 0 | wpa_printf(MSG_ERROR, |
666 | 0 | "WPA: KDK len=%zu exceeds max supported len", |
667 | 0 | kdk_len); |
668 | 0 | return -1; |
669 | 0 | } |
670 | | |
671 | 1.22k | ptk->kck_len = wpa_kck_len(akmp, pmk_len); |
672 | 1.22k | ptk->kek_len = wpa_kek_len(akmp, pmk_len, pasn_group); |
673 | 1.22k | ptk->tk_len = wpa_cipher_key_len(cipher); |
674 | 1.22k | ptk->kdk_len = kdk_len; |
675 | 1.22k | if (ptk->tk_len == 0) { |
676 | 0 | wpa_printf(MSG_ERROR, |
677 | 0 | "WPA: Unsupported cipher (0x%x) used in PTK derivation", |
678 | 0 | cipher); |
679 | 0 | return -1; |
680 | 0 | } |
681 | 1.22k | ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len + ptk->kdk_len; |
682 | | |
683 | 1.22k | if (wpa_key_mgmt_sha384(akmp)) { |
684 | | #ifdef CONFIG_SHA384 |
685 | | wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)"); |
686 | | if (sha384_prf(pmk, pmk_len, label, data, data_len, |
687 | | tmp, ptk_len) < 0) |
688 | | return -1; |
689 | | ptk->hash_alg = RSN_HASH_SHA384; |
690 | | #else /* CONFIG_SHA384 */ |
691 | 0 | return -1; |
692 | 0 | #endif /* CONFIG_SHA384 */ |
693 | 1.22k | } else if (wpa_key_mgmt_sha256(akmp)) { |
694 | 0 | wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)"); |
695 | 0 | if (sha256_prf(pmk, pmk_len, label, data, data_len, |
696 | 0 | tmp, ptk_len) < 0) |
697 | 0 | return -1; |
698 | 0 | ptk->hash_alg = RSN_HASH_SHA256; |
699 | | #ifdef CONFIG_OWE |
700 | | } else if (akmp == WPA_KEY_MGMT_OWE && (pmk_len == 32 || |
701 | | owe_ptk_workaround)) { |
702 | | wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)"); |
703 | | if (sha256_prf(pmk, pmk_len, label, data, data_len, |
704 | | tmp, ptk_len) < 0) |
705 | | return -1; |
706 | | if (owe_ptk_workaround && pmk_len == 64) |
707 | | ptk->hash_alg = RSN_HASH_SHA512; |
708 | | else if (owe_ptk_workaround && pmk_len == 48) |
709 | | ptk->hash_alg = RSN_HASH_SHA384; |
710 | | else |
711 | | ptk->hash_alg = RSN_HASH_SHA256; |
712 | | } else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 48) { |
713 | | wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)"); |
714 | | if (sha384_prf(pmk, pmk_len, label, data, data_len, |
715 | | tmp, ptk_len) < 0) |
716 | | return -1; |
717 | | ptk->hash_alg = RSN_HASH_SHA384; |
718 | | } else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 64) { |
719 | | wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)"); |
720 | | if (sha512_prf(pmk, pmk_len, label, data, data_len, |
721 | | tmp, ptk_len) < 0) |
722 | | return -1; |
723 | | ptk->hash_alg = RSN_HASH_SHA512; |
724 | | } else if (akmp == WPA_KEY_MGMT_OWE) { |
725 | | wpa_printf(MSG_INFO, "OWE: Unknown PMK length %u", |
726 | | (unsigned int) pmk_len); |
727 | | return -1; |
728 | | #endif /* CONFIG_OWE */ |
729 | | #ifdef CONFIG_DPP |
730 | | } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) { |
731 | | wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)"); |
732 | | if (sha256_prf(pmk, pmk_len, label, data, data_len, |
733 | | tmp, ptk_len) < 0) |
734 | | return -1; |
735 | | ptk->hash_alg = RSN_HASH_SHA256; |
736 | | } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 48) { |
737 | | wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)"); |
738 | | if (sha384_prf(pmk, pmk_len, label, data, data_len, |
739 | | tmp, ptk_len) < 0) |
740 | | return -1; |
741 | | ptk->hash_alg = RSN_HASH_SHA384; |
742 | | } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 64) { |
743 | | wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)"); |
744 | | if (sha512_prf(pmk, pmk_len, label, data, data_len, |
745 | | tmp, ptk_len) < 0) |
746 | | return -1; |
747 | | ptk->hash_alg = RSN_HASH_SHA512; |
748 | | } else if (akmp == WPA_KEY_MGMT_DPP) { |
749 | | wpa_printf(MSG_INFO, "DPP: Unknown PMK length %u", |
750 | | (unsigned int) pmk_len); |
751 | | return -1; |
752 | | #endif /* CONFIG_DPP */ |
753 | 0 | #ifdef CONFIG_SAE |
754 | 1.22k | } else if (wpa_key_mgmt_sae_ext_key(akmp)) { |
755 | 0 | if (pmk_len == 32) { |
756 | 0 | wpa_printf(MSG_DEBUG, |
757 | 0 | "SAE: PTK derivation using PRF(SHA256)"); |
758 | 0 | if (sha256_prf(pmk, pmk_len, label, data, data_len, |
759 | 0 | tmp, ptk_len) < 0) |
760 | 0 | return -1; |
761 | 0 | ptk->hash_alg = RSN_HASH_SHA256; |
762 | | #ifdef CONFIG_SHA384 |
763 | | } else if (pmk_len == 48) { |
764 | | wpa_printf(MSG_DEBUG, |
765 | | "SAE: PTK derivation using PRF(SHA384)"); |
766 | | if (sha384_prf(pmk, pmk_len, label, data, data_len, |
767 | | tmp, ptk_len) < 0) |
768 | | return -1; |
769 | | ptk->hash_alg = RSN_HASH_SHA384; |
770 | | #endif /* CONFIG_SHA384 */ |
771 | | #ifdef CONFIG_SHA512 |
772 | | } else if (pmk_len == 64) { |
773 | | wpa_printf(MSG_DEBUG, |
774 | | "SAE: PTK derivation using PRF(SHA512)"); |
775 | | if (sha512_prf(pmk, pmk_len, label, data, data_len, |
776 | | tmp, ptk_len) < 0) |
777 | | return -1; |
778 | | ptk->hash_alg = RSN_HASH_SHA512; |
779 | | #endif /* CONFIG_SHA512 */ |
780 | 0 | } else { |
781 | 0 | wpa_printf(MSG_INFO, "SAE: Unknown PMK length %u", |
782 | 0 | (unsigned int) pmk_len); |
783 | 0 | return -1; |
784 | 0 | } |
785 | 0 | #endif /* CONFIG_SAE */ |
786 | 1.22k | } else { |
787 | 1.22k | wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA1)"); |
788 | 1.22k | if (sha1_prf(pmk, pmk_len, label, data, data_len, tmp, |
789 | 1.22k | ptk_len) < 0) |
790 | 0 | return -1; |
791 | 1.22k | ptk->hash_alg = RSN_HASH_SHA1; |
792 | 1.22k | } |
793 | | |
794 | 1.22k | wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR, |
795 | 1.22k | MAC2STR(addr1), MAC2STR(addr2)); |
796 | 1.22k | wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN); |
797 | 1.22k | wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN); |
798 | 1.22k | if (z && z_len) |
799 | 0 | wpa_hexdump_key(MSG_DEBUG, "WPA: Z.x", z, z_len); |
800 | 1.22k | wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len); |
801 | 1.22k | wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len); |
802 | | |
803 | 1.22k | os_memcpy(ptk->kck, tmp, ptk->kck_len); |
804 | 1.22k | wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len); |
805 | | |
806 | 1.22k | os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len); |
807 | 1.22k | wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len); |
808 | | |
809 | 1.22k | os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len); |
810 | 1.22k | wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len); |
811 | | |
812 | 1.22k | if (kdk_len) { |
813 | 0 | os_memcpy(ptk->kdk, tmp + ptk->kck_len + ptk->kek_len + |
814 | 0 | ptk->tk_len, ptk->kdk_len); |
815 | 0 | wpa_hexdump_key(MSG_DEBUG, "WPA: KDK", ptk->kdk, ptk->kdk_len); |
816 | 0 | } |
817 | | |
818 | 1.22k | ptk->kek2_len = 0; |
819 | 1.22k | ptk->kck2_len = 0; |
820 | | |
821 | 1.22k | ptk->ptk_len = ptk_len; |
822 | 1.22k | os_memset(tmp, 0, sizeof(tmp)); |
823 | 1.22k | os_memset(data, 0, data_len); |
824 | 1.22k | return 0; |
825 | 1.22k | } |
826 | | |
827 | | #ifdef CONFIG_FILS |
828 | | |
829 | | int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len, |
830 | | const u8 *snonce, const u8 *anonce, const u8 *dh_ss, |
831 | | size_t dh_ss_len, u8 *pmk, size_t *pmk_len) |
832 | | { |
833 | | u8 nonces[2 * NONCE_LEN]; |
834 | | const u8 *addr[2]; |
835 | | size_t len[2]; |
836 | | size_t num_elem; |
837 | | int res; |
838 | | |
839 | | /* PMK = HMAC-Hash(SNonce || ANonce, rMSK [ || DHss ]) */ |
840 | | wpa_printf(MSG_DEBUG, "FILS: rMSK to PMK derivation"); |
841 | | |
842 | | if (wpa_key_mgmt_sha384(akmp)) |
843 | | *pmk_len = SHA384_MAC_LEN; |
844 | | else if (wpa_key_mgmt_sha256(akmp)) |
845 | | *pmk_len = SHA256_MAC_LEN; |
846 | | else |
847 | | return -1; |
848 | | |
849 | | wpa_hexdump_key(MSG_DEBUG, "FILS: rMSK", rmsk, rmsk_len); |
850 | | wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, NONCE_LEN); |
851 | | wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, NONCE_LEN); |
852 | | wpa_hexdump(MSG_DEBUG, "FILS: DHss", dh_ss, dh_ss_len); |
853 | | |
854 | | os_memcpy(nonces, snonce, NONCE_LEN); |
855 | | os_memcpy(&nonces[NONCE_LEN], anonce, NONCE_LEN); |
856 | | addr[0] = rmsk; |
857 | | len[0] = rmsk_len; |
858 | | num_elem = 1; |
859 | | if (dh_ss) { |
860 | | addr[1] = dh_ss; |
861 | | len[1] = dh_ss_len; |
862 | | num_elem++; |
863 | | } |
864 | | if (wpa_key_mgmt_sha384(akmp)) |
865 | | res = hmac_sha384_vector(nonces, 2 * NONCE_LEN, num_elem, |
866 | | addr, len, pmk); |
867 | | else |
868 | | res = hmac_sha256_vector(nonces, 2 * NONCE_LEN, num_elem, |
869 | | addr, len, pmk); |
870 | | if (res == 0) |
871 | | wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, *pmk_len); |
872 | | else |
873 | | *pmk_len = 0; |
874 | | return res; |
875 | | } |
876 | | |
877 | | |
878 | | int fils_pmkid_erp(int akmp, const u8 *reauth, size_t reauth_len, |
879 | | u8 *pmkid) |
880 | | { |
881 | | const u8 *addr[1]; |
882 | | size_t len[1]; |
883 | | u8 hash[SHA384_MAC_LEN]; |
884 | | int res; |
885 | | |
886 | | /* PMKID = Truncate-128(Hash(EAP-Initiate/Reauth)) */ |
887 | | addr[0] = reauth; |
888 | | len[0] = reauth_len; |
889 | | if (wpa_key_mgmt_sha384(akmp)) |
890 | | res = sha384_vector(1, addr, len, hash); |
891 | | else if (wpa_key_mgmt_sha256(akmp)) |
892 | | res = sha256_vector(1, addr, len, hash); |
893 | | else |
894 | | return -1; |
895 | | if (res) |
896 | | return res; |
897 | | os_memcpy(pmkid, hash, PMKID_LEN); |
898 | | wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN); |
899 | | return 0; |
900 | | } |
901 | | |
902 | | |
903 | | int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa, |
904 | | const u8 *snonce, const u8 *anonce, const u8 *dhss, |
905 | | size_t dhss_len, struct wpa_ptk *ptk, |
906 | | u8 *ick, size_t *ick_len, int akmp, int cipher, |
907 | | u8 *fils_ft, size_t *fils_ft_len, size_t kdk_len) |
908 | | { |
909 | | u8 *data, *pos; |
910 | | size_t data_len; |
911 | | u8 tmp[FILS_ICK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN + |
912 | | FILS_FT_MAX_LEN + WPA_KDK_MAX_LEN]; |
913 | | size_t key_data_len; |
914 | | const char *label = "FILS PTK Derivation"; |
915 | | int ret = -1; |
916 | | size_t offset; |
917 | | |
918 | | /* |
919 | | * FILS-Key-Data = PRF-X(PMK, "FILS PTK Derivation", |
920 | | * SPA || AA || SNonce || ANonce [ || DHss ]) |
921 | | * ICK = L(FILS-Key-Data, 0, ICK_bits) |
922 | | * KEK = L(FILS-Key-Data, ICK_bits, KEK_bits) |
923 | | * TK = L(FILS-Key-Data, ICK_bits + KEK_bits, TK_bits) |
924 | | * If doing FT initial mobility domain association: |
925 | | * FILS-FT = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits, |
926 | | * FILS-FT_bits) |
927 | | * When a KDK is derived: |
928 | | * KDK = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits + FILS-FT_bits, |
929 | | * KDK_bits) |
930 | | */ |
931 | | data_len = 2 * ETH_ALEN + 2 * NONCE_LEN + dhss_len; |
932 | | data = os_malloc(data_len); |
933 | | if (!data) |
934 | | goto err; |
935 | | pos = data; |
936 | | os_memcpy(pos, spa, ETH_ALEN); |
937 | | pos += ETH_ALEN; |
938 | | os_memcpy(pos, aa, ETH_ALEN); |
939 | | pos += ETH_ALEN; |
940 | | os_memcpy(pos, snonce, NONCE_LEN); |
941 | | pos += NONCE_LEN; |
942 | | os_memcpy(pos, anonce, NONCE_LEN); |
943 | | pos += NONCE_LEN; |
944 | | if (dhss) |
945 | | os_memcpy(pos, dhss, dhss_len); |
946 | | |
947 | | ptk->kck_len = 0; |
948 | | ptk->kek_len = wpa_kek_len(akmp, pmk_len, PASN_GROUP_NOT_SPECIFIED); |
949 | | ptk->tk_len = wpa_cipher_key_len(cipher); |
950 | | if (wpa_key_mgmt_sha384(akmp)) |
951 | | *ick_len = 48; |
952 | | else if (wpa_key_mgmt_sha256(akmp)) |
953 | | *ick_len = 32; |
954 | | else |
955 | | goto err; |
956 | | key_data_len = *ick_len + ptk->kek_len + ptk->tk_len; |
957 | | |
958 | | if (kdk_len) { |
959 | | if (kdk_len > WPA_KDK_MAX_LEN) { |
960 | | wpa_printf(MSG_ERROR, "FILS: KDK len=%zu too big", |
961 | | kdk_len); |
962 | | goto err; |
963 | | } |
964 | | |
965 | | ptk->kdk_len = kdk_len; |
966 | | key_data_len += kdk_len; |
967 | | } else { |
968 | | ptk->kdk_len = 0; |
969 | | } |
970 | | |
971 | | if (fils_ft && fils_ft_len) { |
972 | | if (akmp == WPA_KEY_MGMT_FT_FILS_SHA256) { |
973 | | *fils_ft_len = 32; |
974 | | } else if (akmp == WPA_KEY_MGMT_FT_FILS_SHA384) { |
975 | | *fils_ft_len = 48; |
976 | | } else { |
977 | | *fils_ft_len = 0; |
978 | | fils_ft = NULL; |
979 | | } |
980 | | key_data_len += *fils_ft_len; |
981 | | } |
982 | | |
983 | | if (wpa_key_mgmt_sha384(akmp)) { |
984 | | wpa_printf(MSG_DEBUG, "FILS: PTK derivation using PRF(SHA384)"); |
985 | | if (sha384_prf(pmk, pmk_len, label, data, data_len, |
986 | | tmp, key_data_len) < 0) |
987 | | goto err; |
988 | | } else { |
989 | | wpa_printf(MSG_DEBUG, "FILS: PTK derivation using PRF(SHA256)"); |
990 | | if (sha256_prf(pmk, pmk_len, label, data, data_len, |
991 | | tmp, key_data_len) < 0) |
992 | | goto err; |
993 | | } |
994 | | |
995 | | wpa_printf(MSG_DEBUG, "FILS: PTK derivation - SPA=" MACSTR |
996 | | " AA=" MACSTR, MAC2STR(spa), MAC2STR(aa)); |
997 | | wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, NONCE_LEN); |
998 | | wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, NONCE_LEN); |
999 | | if (dhss) |
1000 | | wpa_hexdump_key(MSG_DEBUG, "FILS: DHss", dhss, dhss_len); |
1001 | | wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, pmk_len); |
1002 | | wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-Key-Data", tmp, key_data_len); |
1003 | | |
1004 | | os_memcpy(ick, tmp, *ick_len); |
1005 | | offset = *ick_len; |
1006 | | wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, *ick_len); |
1007 | | |
1008 | | os_memcpy(ptk->kek, tmp + offset, ptk->kek_len); |
1009 | | wpa_hexdump_key(MSG_DEBUG, "FILS: KEK", ptk->kek, ptk->kek_len); |
1010 | | offset += ptk->kek_len; |
1011 | | |
1012 | | os_memcpy(ptk->tk, tmp + offset, ptk->tk_len); |
1013 | | wpa_hexdump_key(MSG_DEBUG, "FILS: TK", ptk->tk, ptk->tk_len); |
1014 | | offset += ptk->tk_len; |
1015 | | |
1016 | | if (fils_ft && fils_ft_len) { |
1017 | | os_memcpy(fils_ft, tmp + offset, *fils_ft_len); |
1018 | | wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-FT", |
1019 | | fils_ft, *fils_ft_len); |
1020 | | offset += *fils_ft_len; |
1021 | | } |
1022 | | |
1023 | | if (ptk->kdk_len) { |
1024 | | os_memcpy(ptk->kdk, tmp + offset, ptk->kdk_len); |
1025 | | wpa_hexdump_key(MSG_DEBUG, "FILS: KDK", ptk->kdk, ptk->kdk_len); |
1026 | | } |
1027 | | |
1028 | | ptk->kek2_len = 0; |
1029 | | ptk->kck2_len = 0; |
1030 | | |
1031 | | os_memset(tmp, 0, sizeof(tmp)); |
1032 | | ret = 0; |
1033 | | err: |
1034 | | bin_clear_free(data, data_len); |
1035 | | return ret; |
1036 | | } |
1037 | | |
1038 | | |
1039 | | int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce, |
1040 | | const u8 *anonce, const u8 *sta_addr, const u8 *bssid, |
1041 | | const u8 *g_sta, size_t g_sta_len, |
1042 | | const u8 *g_ap, size_t g_ap_len, |
1043 | | int akmp, u8 *key_auth_sta, u8 *key_auth_ap, |
1044 | | size_t *key_auth_len) |
1045 | | { |
1046 | | const u8 *addr[6]; |
1047 | | size_t len[6]; |
1048 | | size_t num_elem = 4; |
1049 | | int res; |
1050 | | |
1051 | | wpa_printf(MSG_DEBUG, "FILS: Key-Auth derivation: STA-MAC=" MACSTR |
1052 | | " AP-BSSID=" MACSTR, MAC2STR(sta_addr), MAC2STR(bssid)); |
1053 | | wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, ick_len); |
1054 | | wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, NONCE_LEN); |
1055 | | wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, NONCE_LEN); |
1056 | | wpa_hexdump(MSG_DEBUG, "FILS: gSTA", g_sta, g_sta_len); |
1057 | | wpa_hexdump(MSG_DEBUG, "FILS: gAP", g_ap, g_ap_len); |
1058 | | |
1059 | | /* |
1060 | | * For (Re)Association Request frame (STA->AP): |
1061 | | * Key-Auth = HMAC-Hash(ICK, SNonce || ANonce || STA-MAC || AP-BSSID |
1062 | | * [ || gSTA || gAP ]) |
1063 | | */ |
1064 | | addr[0] = snonce; |
1065 | | len[0] = NONCE_LEN; |
1066 | | addr[1] = anonce; |
1067 | | len[1] = NONCE_LEN; |
1068 | | addr[2] = sta_addr; |
1069 | | len[2] = ETH_ALEN; |
1070 | | addr[3] = bssid; |
1071 | | len[3] = ETH_ALEN; |
1072 | | if (g_sta && g_sta_len && g_ap && g_ap_len) { |
1073 | | addr[4] = g_sta; |
1074 | | len[4] = g_sta_len; |
1075 | | addr[5] = g_ap; |
1076 | | len[5] = g_ap_len; |
1077 | | num_elem = 6; |
1078 | | } |
1079 | | |
1080 | | if (wpa_key_mgmt_sha384(akmp)) { |
1081 | | *key_auth_len = 48; |
1082 | | res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len, |
1083 | | key_auth_sta); |
1084 | | } else if (wpa_key_mgmt_sha256(akmp)) { |
1085 | | *key_auth_len = 32; |
1086 | | res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len, |
1087 | | key_auth_sta); |
1088 | | } else { |
1089 | | return -1; |
1090 | | } |
1091 | | if (res < 0) |
1092 | | return res; |
1093 | | |
1094 | | /* |
1095 | | * For (Re)Association Response frame (AP->STA): |
1096 | | * Key-Auth = HMAC-Hash(ICK, ANonce || SNonce || AP-BSSID || STA-MAC |
1097 | | * [ || gAP || gSTA ]) |
1098 | | */ |
1099 | | addr[0] = anonce; |
1100 | | addr[1] = snonce; |
1101 | | addr[2] = bssid; |
1102 | | addr[3] = sta_addr; |
1103 | | if (g_sta && g_sta_len && g_ap && g_ap_len) { |
1104 | | addr[4] = g_ap; |
1105 | | len[4] = g_ap_len; |
1106 | | addr[5] = g_sta; |
1107 | | len[5] = g_sta_len; |
1108 | | } |
1109 | | |
1110 | | if (wpa_key_mgmt_sha384(akmp)) |
1111 | | res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len, |
1112 | | key_auth_ap); |
1113 | | else if (wpa_key_mgmt_sha256(akmp)) |
1114 | | res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len, |
1115 | | key_auth_ap); |
1116 | | if (res < 0) |
1117 | | return res; |
1118 | | |
1119 | | wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (STA)", |
1120 | | key_auth_sta, *key_auth_len); |
1121 | | wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (AP)", |
1122 | | key_auth_ap, *key_auth_len); |
1123 | | |
1124 | | return 0; |
1125 | | } |
1126 | | |
1127 | | #endif /* CONFIG_FILS */ |
1128 | | |
1129 | | |
1130 | | #ifdef CONFIG_IEEE80211R |
1131 | | int wpa_ft_mic(int key_mgmt, const u8 *kck, size_t kck_len, const u8 *sta_addr, |
1132 | | const u8 *ap_addr, u8 transaction_seqnum, |
1133 | | const u8 *mdie, size_t mdie_len, |
1134 | | const u8 *ftie, size_t ftie_len, |
1135 | | const u8 *rsnie, size_t rsnie_len, |
1136 | | const u8 *ric, size_t ric_len, |
1137 | | const u8 *rsnxe, size_t rsnxe_len, |
1138 | | const struct wpabuf *extra, |
1139 | | u8 *mic) |
1140 | 0 | { |
1141 | 0 | const u8 *addr[11]; |
1142 | 0 | size_t len[11]; |
1143 | 0 | size_t i, num_elem = 0; |
1144 | 0 | u8 zero_mic[32]; |
1145 | 0 | size_t mic_len, fte_fixed_len; |
1146 | 0 | int res; |
1147 | |
|
1148 | 0 | if (kck_len == 16) { |
1149 | 0 | mic_len = 16; |
1150 | | #ifdef CONFIG_SHA384 |
1151 | | } else if (kck_len == 24) { |
1152 | | mic_len = 24; |
1153 | | #endif /* CONFIG_SHA384 */ |
1154 | | #ifdef CONFIG_SHA512 |
1155 | | } else if (kck_len == 32) { |
1156 | | mic_len = 32; |
1157 | | #endif /* CONFIG_SHA512 */ |
1158 | 0 | } else { |
1159 | 0 | wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u", |
1160 | 0 | (unsigned int) kck_len); |
1161 | 0 | return -1; |
1162 | 0 | } |
1163 | | |
1164 | 0 | fte_fixed_len = sizeof(struct rsn_ftie) - 16 + mic_len; |
1165 | |
|
1166 | 0 | addr[num_elem] = sta_addr; |
1167 | 0 | len[num_elem] = ETH_ALEN; |
1168 | 0 | num_elem++; |
1169 | |
|
1170 | 0 | addr[num_elem] = ap_addr; |
1171 | 0 | len[num_elem] = ETH_ALEN; |
1172 | 0 | num_elem++; |
1173 | |
|
1174 | 0 | addr[num_elem] = &transaction_seqnum; |
1175 | 0 | len[num_elem] = 1; |
1176 | 0 | num_elem++; |
1177 | |
|
1178 | 0 | if (rsnie) { |
1179 | 0 | addr[num_elem] = rsnie; |
1180 | 0 | len[num_elem] = rsnie_len; |
1181 | 0 | num_elem++; |
1182 | 0 | } |
1183 | 0 | if (mdie) { |
1184 | 0 | addr[num_elem] = mdie; |
1185 | 0 | len[num_elem] = mdie_len; |
1186 | 0 | num_elem++; |
1187 | 0 | } |
1188 | 0 | if (ftie) { |
1189 | 0 | if (ftie_len < 2 + fte_fixed_len) |
1190 | 0 | return -1; |
1191 | | |
1192 | | /* IE hdr and mic_control */ |
1193 | 0 | addr[num_elem] = ftie; |
1194 | 0 | len[num_elem] = 2 + 2; |
1195 | 0 | num_elem++; |
1196 | | |
1197 | | /* MIC field with all zeros */ |
1198 | 0 | os_memset(zero_mic, 0, mic_len); |
1199 | 0 | addr[num_elem] = zero_mic; |
1200 | 0 | len[num_elem] = mic_len; |
1201 | 0 | num_elem++; |
1202 | | |
1203 | | /* Rest of FTIE */ |
1204 | 0 | addr[num_elem] = ftie + 2 + 2 + mic_len; |
1205 | 0 | len[num_elem] = ftie_len - (2 + 2 + mic_len); |
1206 | 0 | num_elem++; |
1207 | 0 | } |
1208 | 0 | if (ric) { |
1209 | 0 | addr[num_elem] = ric; |
1210 | 0 | len[num_elem] = ric_len; |
1211 | 0 | num_elem++; |
1212 | 0 | } |
1213 | |
|
1214 | 0 | if (rsnxe) { |
1215 | 0 | addr[num_elem] = rsnxe; |
1216 | 0 | len[num_elem] = rsnxe_len; |
1217 | 0 | num_elem++; |
1218 | 0 | } |
1219 | |
|
1220 | 0 | if (extra) { |
1221 | 0 | addr[num_elem] = wpabuf_head(extra); |
1222 | 0 | len[num_elem] = wpabuf_len(extra); |
1223 | 0 | num_elem++; |
1224 | 0 | } |
1225 | |
|
1226 | 0 | for (i = 0; i < num_elem; i++) |
1227 | 0 | wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]); |
1228 | 0 | res = -1; |
1229 | | #ifdef CONFIG_SHA512 |
1230 | | if (kck_len == 32) { |
1231 | | u8 hash[SHA512_MAC_LEN]; |
1232 | | |
1233 | | if (hmac_sha512_vector(kck, kck_len, num_elem, addr, len, hash)) |
1234 | | return -1; |
1235 | | os_memcpy(mic, hash, 32); |
1236 | | res = 0; |
1237 | | } |
1238 | | #endif /* CONFIG_SHA384 */ |
1239 | | #ifdef CONFIG_SHA384 |
1240 | | if (kck_len == 24) { |
1241 | | u8 hash[SHA384_MAC_LEN]; |
1242 | | |
1243 | | if (hmac_sha384_vector(kck, kck_len, num_elem, addr, len, hash)) |
1244 | | return -1; |
1245 | | os_memcpy(mic, hash, 24); |
1246 | | res = 0; |
1247 | | } |
1248 | | #endif /* CONFIG_SHA384 */ |
1249 | 0 | if (kck_len == 16 && key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) { |
1250 | 0 | u8 hash[SHA256_MAC_LEN]; |
1251 | |
|
1252 | 0 | if (hmac_sha256_vector(kck, kck_len, num_elem, addr, len, hash)) |
1253 | 0 | return -1; |
1254 | 0 | os_memcpy(mic, hash, 16); |
1255 | 0 | res = 0; |
1256 | 0 | } |
1257 | 0 | if (kck_len == 16 && key_mgmt != WPA_KEY_MGMT_FT_SAE_EXT_KEY && |
1258 | 0 | omac1_aes_128_vector(kck, num_elem, addr, len, mic) == 0) |
1259 | 0 | res = 0; |
1260 | |
|
1261 | 0 | return res; |
1262 | 0 | } |
1263 | | |
1264 | | |
1265 | | static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, |
1266 | | struct wpa_ft_ies *parse, const u8 *opt) |
1267 | 0 | { |
1268 | 0 | const u8 *end, *pos; |
1269 | 0 | u8 link_id; |
1270 | |
|
1271 | 0 | pos = opt; |
1272 | 0 | end = ie + ie_len; |
1273 | 0 | wpa_hexdump(MSG_DEBUG, "FT: Parse FTE subelements", pos, end - pos); |
1274 | |
|
1275 | 0 | while (end - pos >= 2) { |
1276 | 0 | u8 id, len; |
1277 | |
|
1278 | 0 | id = *pos++; |
1279 | 0 | len = *pos++; |
1280 | 0 | if (len > end - pos) { |
1281 | 0 | wpa_printf(MSG_DEBUG, "FT: Truncated subelement"); |
1282 | 0 | return -1; |
1283 | 0 | } |
1284 | | |
1285 | 0 | switch (id) { |
1286 | 0 | case FTIE_SUBELEM_R1KH_ID: |
1287 | 0 | if (len != FT_R1KH_ID_LEN) { |
1288 | 0 | wpa_printf(MSG_DEBUG, |
1289 | 0 | "FT: Invalid R1KH-ID length in FTIE: %d", |
1290 | 0 | len); |
1291 | 0 | return -1; |
1292 | 0 | } |
1293 | 0 | parse->r1kh_id = pos; |
1294 | 0 | wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", |
1295 | 0 | parse->r1kh_id, FT_R1KH_ID_LEN); |
1296 | 0 | break; |
1297 | 0 | case FTIE_SUBELEM_GTK: |
1298 | 0 | wpa_printf(MSG_DEBUG, "FT: GTK"); |
1299 | 0 | parse->gtk = pos; |
1300 | 0 | parse->gtk_len = len; |
1301 | 0 | break; |
1302 | 0 | case FTIE_SUBELEM_R0KH_ID: |
1303 | 0 | if (len < 1 || len > FT_R0KH_ID_MAX_LEN) { |
1304 | 0 | wpa_printf(MSG_DEBUG, |
1305 | 0 | "FT: Invalid R0KH-ID length in FTIE: %d", |
1306 | 0 | len); |
1307 | 0 | return -1; |
1308 | 0 | } |
1309 | 0 | parse->r0kh_id = pos; |
1310 | 0 | parse->r0kh_id_len = len; |
1311 | 0 | wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", |
1312 | 0 | parse->r0kh_id, parse->r0kh_id_len); |
1313 | 0 | break; |
1314 | 0 | case FTIE_SUBELEM_IGTK: |
1315 | 0 | wpa_printf(MSG_DEBUG, "FT: IGTK"); |
1316 | 0 | parse->igtk = pos; |
1317 | 0 | parse->igtk_len = len; |
1318 | 0 | break; |
1319 | | #ifdef CONFIG_OCV |
1320 | | case FTIE_SUBELEM_OCI: |
1321 | | parse->oci = pos; |
1322 | | parse->oci_len = len; |
1323 | | wpa_hexdump(MSG_DEBUG, "FT: OCI", |
1324 | | parse->oci, parse->oci_len); |
1325 | | break; |
1326 | | #endif /* CONFIG_OCV */ |
1327 | 0 | case FTIE_SUBELEM_BIGTK: |
1328 | 0 | wpa_printf(MSG_DEBUG, "FT: BIGTK"); |
1329 | 0 | parse->bigtk = pos; |
1330 | 0 | parse->bigtk_len = len; |
1331 | 0 | break; |
1332 | 0 | case FTIE_SUBELEM_MLO_GTK: |
1333 | 0 | if (len < 2 + 1 + 1 + 8) { |
1334 | 0 | wpa_printf(MSG_DEBUG, |
1335 | 0 | "FT: Too short MLO GTK in FTE"); |
1336 | 0 | return -1; |
1337 | 0 | } |
1338 | 0 | link_id = pos[2] & 0x0f; |
1339 | 0 | wpa_printf(MSG_DEBUG, "FT: MLO GTK (Link ID %u)", |
1340 | 0 | link_id); |
1341 | 0 | if (link_id >= MAX_NUM_MLD_LINKS) |
1342 | 0 | break; |
1343 | 0 | parse->valid_mlo_gtks |= BIT(link_id); |
1344 | 0 | parse->mlo_gtk[link_id] = pos; |
1345 | 0 | parse->mlo_gtk_len[link_id] = len; |
1346 | 0 | break; |
1347 | 0 | case FTIE_SUBELEM_MLO_IGTK: |
1348 | 0 | if (len < 2 + 6 + 1 + 1) { |
1349 | 0 | wpa_printf(MSG_DEBUG, |
1350 | 0 | "FT: Too short MLO IGTK in FTE"); |
1351 | 0 | return -1; |
1352 | 0 | } |
1353 | 0 | link_id = pos[2 + 6] & 0x0f; |
1354 | 0 | wpa_printf(MSG_DEBUG, "FT: MLO IGTK (Link ID %u)", |
1355 | 0 | link_id); |
1356 | 0 | if (link_id >= MAX_NUM_MLD_LINKS) |
1357 | 0 | break; |
1358 | 0 | parse->valid_mlo_igtks |= BIT(link_id); |
1359 | 0 | parse->mlo_igtk[link_id] = pos; |
1360 | 0 | parse->mlo_igtk_len[link_id] = len; |
1361 | 0 | break; |
1362 | 0 | case FTIE_SUBELEM_MLO_BIGTK: |
1363 | 0 | if (len < 2 + 6 + 1 + 1) { |
1364 | 0 | wpa_printf(MSG_DEBUG, |
1365 | 0 | "FT: Too short MLO BIGTK in FTE"); |
1366 | 0 | return -1; |
1367 | 0 | } |
1368 | 0 | link_id = pos[2 + 6] & 0x0f; |
1369 | 0 | wpa_printf(MSG_DEBUG, "FT: MLO BIGTK (Link ID %u)", |
1370 | 0 | link_id); |
1371 | 0 | if (link_id >= MAX_NUM_MLD_LINKS) |
1372 | 0 | break; |
1373 | 0 | parse->valid_mlo_bigtks |= BIT(link_id); |
1374 | 0 | parse->mlo_bigtk[link_id] = pos; |
1375 | 0 | parse->mlo_bigtk_len[link_id] = len; |
1376 | 0 | break; |
1377 | 0 | default: |
1378 | 0 | wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id); |
1379 | 0 | break; |
1380 | 0 | } |
1381 | | |
1382 | 0 | pos += len; |
1383 | 0 | } |
1384 | | |
1385 | 0 | return 0; |
1386 | 0 | } |
1387 | | |
1388 | | |
1389 | | static int wpa_ft_parse_fte(int key_mgmt, const u8 *ie, size_t len, |
1390 | | struct wpa_ft_ies *parse) |
1391 | 0 | { |
1392 | 0 | size_t mic_len; |
1393 | 0 | u8 mic_len_info; |
1394 | 0 | const u8 *pos = ie; |
1395 | 0 | const u8 *end = pos + len; |
1396 | |
|
1397 | 0 | wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control", pos, 2); |
1398 | 0 | parse->fte_rsnxe_used = pos[0] & FTE_MIC_CTRL_RSNXE_USED; |
1399 | 0 | mic_len_info = (pos[0] & FTE_MIC_CTRL_MIC_LEN_MASK) >> |
1400 | 0 | FTE_MIC_CTRL_MIC_LEN_SHIFT; |
1401 | 0 | parse->fte_elem_count = pos[1]; |
1402 | 0 | pos += 2; |
1403 | |
|
1404 | 0 | if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) { |
1405 | 0 | switch (mic_len_info) { |
1406 | 0 | case FTE_MIC_LEN_16: |
1407 | 0 | mic_len = 16; |
1408 | 0 | break; |
1409 | 0 | case FTE_MIC_LEN_24: |
1410 | 0 | mic_len = 24; |
1411 | 0 | break; |
1412 | 0 | case FTE_MIC_LEN_32: |
1413 | 0 | mic_len = 32; |
1414 | 0 | break; |
1415 | 0 | default: |
1416 | 0 | wpa_printf(MSG_DEBUG, |
1417 | 0 | "FT: Unknown MIC Length subfield value %u", |
1418 | 0 | mic_len_info); |
1419 | 0 | return -1; |
1420 | 0 | } |
1421 | 0 | } else { |
1422 | 0 | mic_len = wpa_key_mgmt_sha384(key_mgmt) ? 24 : 16; |
1423 | 0 | } |
1424 | 0 | if (mic_len > (size_t) (end - pos)) { |
1425 | 0 | wpa_printf(MSG_DEBUG, "FT: No room for %zu octet MIC in FTE", |
1426 | 0 | mic_len); |
1427 | 0 | return -1; |
1428 | 0 | } |
1429 | 0 | wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC", pos, mic_len); |
1430 | 0 | parse->fte_mic = pos; |
1431 | 0 | parse->fte_mic_len = mic_len; |
1432 | 0 | pos += mic_len; |
1433 | |
|
1434 | 0 | if (2 * WPA_NONCE_LEN > end - pos) |
1435 | 0 | return -1; |
1436 | 0 | parse->fte_anonce = pos; |
1437 | 0 | wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce", |
1438 | 0 | parse->fte_anonce, WPA_NONCE_LEN); |
1439 | 0 | pos += WPA_NONCE_LEN; |
1440 | 0 | parse->fte_snonce = pos; |
1441 | 0 | wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce", |
1442 | 0 | parse->fte_snonce, WPA_NONCE_LEN); |
1443 | 0 | pos += WPA_NONCE_LEN; |
1444 | |
|
1445 | 0 | return wpa_ft_parse_ftie(ie, len, parse, pos); |
1446 | 0 | } |
1447 | | |
1448 | | |
1449 | | int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse, |
1450 | | int key_mgmt, bool reassoc_resp) |
1451 | 0 | { |
1452 | 0 | const u8 *end, *pos; |
1453 | 0 | struct wpa_ie_data data; |
1454 | 0 | int ret; |
1455 | 0 | int prot_ie_count = 0; |
1456 | 0 | const u8 *fte = NULL; |
1457 | 0 | size_t fte_len = 0; |
1458 | 0 | bool is_fte = false; |
1459 | 0 | struct ieee802_11_elems elems; |
1460 | |
|
1461 | 0 | os_memset(parse, 0, sizeof(*parse)); |
1462 | 0 | if (ies == NULL) |
1463 | 0 | return 0; |
1464 | | |
1465 | 0 | if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == ParseFailed) { |
1466 | 0 | wpa_printf(MSG_DEBUG, "FT: Failed to parse elements"); |
1467 | 0 | goto fail; |
1468 | 0 | } |
1469 | | |
1470 | 0 | pos = ies; |
1471 | 0 | end = ies + ies_len; |
1472 | 0 | while (end - pos >= 2) { |
1473 | 0 | u8 id, len; |
1474 | |
|
1475 | 0 | id = *pos++; |
1476 | 0 | len = *pos++; |
1477 | 0 | if (len > end - pos) |
1478 | 0 | break; |
1479 | | |
1480 | 0 | if (id != WLAN_EID_FAST_BSS_TRANSITION && |
1481 | 0 | id != WLAN_EID_FRAGMENT) |
1482 | 0 | is_fte = false; |
1483 | |
|
1484 | 0 | switch (id) { |
1485 | 0 | case WLAN_EID_RSN: |
1486 | 0 | wpa_hexdump(MSG_DEBUG, "FT: RSNE", pos, len); |
1487 | 0 | parse->rsn = pos; |
1488 | 0 | parse->rsn_len = len; |
1489 | 0 | ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, |
1490 | 0 | parse->rsn_len + 2, |
1491 | 0 | &data); |
1492 | 0 | if (ret < 0) { |
1493 | 0 | wpa_printf(MSG_DEBUG, "FT: Failed to parse " |
1494 | 0 | "RSN IE: %d", ret); |
1495 | 0 | goto fail; |
1496 | 0 | } |
1497 | 0 | parse->rsn_capab = data.capabilities; |
1498 | 0 | if (data.num_pmkid == 1 && data.pmkid) |
1499 | 0 | parse->rsn_pmkid = data.pmkid; |
1500 | 0 | parse->key_mgmt = data.key_mgmt; |
1501 | 0 | parse->pairwise_cipher = data.pairwise_cipher; |
1502 | 0 | if (!key_mgmt) |
1503 | 0 | key_mgmt = parse->key_mgmt; |
1504 | 0 | break; |
1505 | 0 | case WLAN_EID_RSNX: |
1506 | 0 | wpa_hexdump(MSG_DEBUG, "FT: RSNXE", pos, len); |
1507 | 0 | if (len < 1) |
1508 | 0 | break; |
1509 | 0 | parse->rsnxe = pos; |
1510 | 0 | parse->rsnxe_len = len; |
1511 | 0 | break; |
1512 | 0 | case WLAN_EID_MOBILITY_DOMAIN: |
1513 | 0 | wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len); |
1514 | 0 | if (len < sizeof(struct rsn_mdie)) |
1515 | 0 | goto fail; |
1516 | 0 | parse->mdie = pos; |
1517 | 0 | parse->mdie_len = len; |
1518 | 0 | break; |
1519 | 0 | case WLAN_EID_FAST_BSS_TRANSITION: |
1520 | 0 | wpa_hexdump(MSG_DEBUG, "FT: FTE", pos, len); |
1521 | | /* The first two octets (MIC Control field) is in the |
1522 | | * same offset for all cases, but the second field (MIC) |
1523 | | * has variable length with three different values. |
1524 | | * In particular the FT-SAE-EXT-KEY is inconvinient to |
1525 | | * parse, so try to handle this in pieces instead of |
1526 | | * using the struct rsn_ftie* definitions. */ |
1527 | |
|
1528 | 0 | if (len < 2) |
1529 | 0 | goto fail; |
1530 | 0 | prot_ie_count = pos[1]; /* Element Count field in |
1531 | | * MIC Control */ |
1532 | 0 | is_fte = true; |
1533 | 0 | fte = pos; |
1534 | 0 | fte_len = len; |
1535 | 0 | break; |
1536 | 0 | case WLAN_EID_FRAGMENT: |
1537 | 0 | if (is_fte) { |
1538 | 0 | wpa_hexdump(MSG_DEBUG, "FT: FTE fragment", |
1539 | 0 | pos, len); |
1540 | 0 | fte_len += 2 + len; |
1541 | 0 | } |
1542 | 0 | break; |
1543 | 0 | case WLAN_EID_TIMEOUT_INTERVAL: |
1544 | 0 | wpa_hexdump(MSG_DEBUG, "FT: Timeout Interval", |
1545 | 0 | pos, len); |
1546 | 0 | if (len != 5) |
1547 | 0 | break; |
1548 | 0 | parse->tie = pos; |
1549 | 0 | parse->tie_len = len; |
1550 | 0 | break; |
1551 | 0 | case WLAN_EID_RIC_DATA: |
1552 | 0 | if (parse->ric == NULL) |
1553 | 0 | parse->ric = pos - 2; |
1554 | 0 | break; |
1555 | 0 | } |
1556 | | |
1557 | 0 | pos += len; |
1558 | 0 | } |
1559 | | |
1560 | 0 | if (fte) { |
1561 | 0 | int res; |
1562 | |
|
1563 | 0 | if (fte_len < 255) { |
1564 | 0 | res = wpa_ft_parse_fte(key_mgmt, fte, fte_len, parse); |
1565 | 0 | } else { |
1566 | 0 | parse->fte_buf = ieee802_11_defrag(fte, fte_len, false); |
1567 | 0 | if (!parse->fte_buf) |
1568 | 0 | goto fail; |
1569 | 0 | res = wpa_ft_parse_fte(key_mgmt, |
1570 | 0 | wpabuf_head(parse->fte_buf), |
1571 | 0 | wpabuf_len(parse->fte_buf), |
1572 | 0 | parse); |
1573 | 0 | } |
1574 | 0 | if (res < 0) |
1575 | 0 | goto fail; |
1576 | | |
1577 | | /* FTE might be fragmented. If it is, the separate Fragment |
1578 | | * elements are included in MIC calculation as full elements. */ |
1579 | 0 | parse->ftie = fte; |
1580 | 0 | parse->ftie_len = fte_len; |
1581 | 0 | } |
1582 | | |
1583 | 0 | if (prot_ie_count == 0) |
1584 | 0 | return 0; /* no MIC */ |
1585 | | |
1586 | | /* |
1587 | | * Check that the protected IE count matches with IEs included in the |
1588 | | * frame. |
1589 | | */ |
1590 | 0 | if (reassoc_resp && elems.basic_mle) { |
1591 | 0 | unsigned int link_id; |
1592 | | |
1593 | | /* TODO: This count should be done based on all _requested_, |
1594 | | * not _accepted_ links. */ |
1595 | 0 | for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { |
1596 | 0 | if (parse->mlo_gtk[link_id]) { |
1597 | 0 | if (parse->rsn) |
1598 | 0 | prot_ie_count--; |
1599 | 0 | if (parse->rsnxe) |
1600 | 0 | prot_ie_count--; |
1601 | 0 | } |
1602 | 0 | } |
1603 | 0 | } else { |
1604 | 0 | if (parse->rsn) |
1605 | 0 | prot_ie_count--; |
1606 | 0 | if (parse->rsnxe) |
1607 | 0 | prot_ie_count--; |
1608 | 0 | } |
1609 | 0 | if (parse->mdie) |
1610 | 0 | prot_ie_count--; |
1611 | 0 | if (parse->ftie) |
1612 | 0 | prot_ie_count--; |
1613 | 0 | if (prot_ie_count < 0) { |
1614 | 0 | wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " |
1615 | 0 | "the protected IE count"); |
1616 | 0 | goto fail; |
1617 | 0 | } |
1618 | | |
1619 | 0 | if (prot_ie_count == 0 && parse->ric) { |
1620 | 0 | wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " |
1621 | 0 | "included in protected IE count"); |
1622 | 0 | goto fail; |
1623 | 0 | } |
1624 | | |
1625 | | /* Determine the end of the RIC IE(s) */ |
1626 | 0 | if (parse->ric) { |
1627 | 0 | pos = parse->ric; |
1628 | 0 | while (end - pos >= 2 && 2 + pos[1] <= end - pos && |
1629 | 0 | prot_ie_count) { |
1630 | 0 | prot_ie_count--; |
1631 | 0 | pos += 2 + pos[1]; |
1632 | 0 | } |
1633 | 0 | parse->ric_len = pos - parse->ric; |
1634 | 0 | } |
1635 | 0 | if (prot_ie_count) { |
1636 | 0 | wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " |
1637 | 0 | "frame", (int) prot_ie_count); |
1638 | 0 | goto fail; |
1639 | 0 | } |
1640 | | |
1641 | 0 | return 0; |
1642 | | |
1643 | 0 | fail: |
1644 | 0 | wpa_ft_parse_ies_free(parse); |
1645 | 0 | return -1; |
1646 | 0 | } |
1647 | | |
1648 | | |
1649 | | void wpa_ft_parse_ies_free(struct wpa_ft_ies *parse) |
1650 | 0 | { |
1651 | 0 | if (!parse) |
1652 | 0 | return; |
1653 | 0 | wpabuf_free(parse->fte_buf); |
1654 | 0 | parse->fte_buf = NULL; |
1655 | 0 | } |
1656 | | |
1657 | | #endif /* CONFIG_IEEE80211R */ |
1658 | | |
1659 | | |
1660 | | #ifdef CONFIG_PASN |
1661 | | |
1662 | | /* |
1663 | | * pasn_use_sha384 - Should SHA384 be used or SHA256 |
1664 | | * |
1665 | | * @akmp: Authentication and key management protocol |
1666 | | * @cipher: The cipher suite |
1667 | | * |
1668 | | * According to IEEE Std 802.11-2024, 12.13.8 (PTKSA derivation with PASN |
1669 | | * authentication), the hash algorithm to use is the |
1670 | | * hash algorithm defined for the Base AKM (see Table 9-190 (AKM suite |
1671 | | * selectors)). When there is no Base AKM, the hash algorithm is selected based |
1672 | | * on the pairwise cipher suite provided in the RSNE by the AP in the second |
1673 | | * PASN frame. SHA-256 is used as the hash algorithm, except for the ciphers |
1674 | | * 00-0F-AC:9 and 00-0F-AC:10 for which SHA-384 is used. |
1675 | | */ |
1676 | | static bool pasn_use_sha384(int akmp, int cipher) |
1677 | | { |
1678 | | return ((akmp == WPA_KEY_MGMT_PASN || akmp == WPA_KEY_MGMT_EPPKE) && |
1679 | | (cipher == WPA_CIPHER_CCMP_256 || |
1680 | | cipher == WPA_CIPHER_GCMP_256)) || |
1681 | | wpa_key_mgmt_sha384(akmp); |
1682 | | } |
1683 | | |
1684 | | |
1685 | | /** |
1686 | | * pasn_select_hash_alg - Select hash algorithm for PTK derivation |
1687 | | * @akmp: Authentication and key management protocol |
1688 | | * @cipher: The cipher suite |
1689 | | * @pmk_len: PMK length in octets |
1690 | | * |
1691 | | * According to IEEE Std 802.11-2024, Table 9-190 (AKM suite selectors), AKMs |
1692 | | * 00-0F-AC:24 and 00-0F-AC:25 have the length of the PMK, the length |
1693 | | * of the SAE key confirmation key, SAE-KCK, and PTK-KCK, and the length of |
1694 | | * PTK-KEK depending on the hash algorithm specified in 12.4.2 (see 12.7.1.3 |
1695 | | * and 12.7.3), i.e, the hash algorithm depends on the prime length associated |
1696 | | * with the selected group per Table 12-1 (Hash algorithm based on length of |
1697 | | * prime). |
1698 | | */ |
1699 | | static enum rsn_hash_alg pasn_select_hash_alg(int akmp, int cipher, |
1700 | | size_t pmk_len) |
1701 | | { |
1702 | | #ifdef CONFIG_SAE |
1703 | | if (wpa_key_mgmt_sae_ext_key(akmp)) { |
1704 | | if (pmk_len == 64) |
1705 | | return RSN_HASH_SHA512; |
1706 | | if (pmk_len == 48) |
1707 | | return RSN_HASH_SHA384; |
1708 | | } |
1709 | | #endif /* CONFIG_SAE */ |
1710 | | |
1711 | | if (pasn_use_sha384(akmp, cipher)) |
1712 | | return RSN_HASH_SHA384; |
1713 | | |
1714 | | return RSN_HASH_SHA256; |
1715 | | } |
1716 | | |
1717 | | |
1718 | | /** |
1719 | | * pasn_pmk_to_ptk - Calculate PASN/EPPKE PTK from PMK, addresses, etc. |
1720 | | * @pmk: Pairwise master key |
1721 | | * @pmk_len: Length of PMK |
1722 | | * @spa: For EPPKE authentication, non-AP MLD MAC address is used for MLO. For |
1723 | | * PASN authentication or EPPKE authentication for non-MLO, non-AP STA link |
1724 | | * MAC address is used. |
1725 | | * @bssid: For EPPKE authentication, AP MLD MAC address is used for MLO. For |
1726 | | * PASN authentication or EPPKE authentication for non-MLO, AP BSSID is |
1727 | | * used. |
1728 | | * @dhss: Is the shared secret (DHss) derived from the PASN ephemeral key |
1729 | | * exchange encoded as an octet string |
1730 | | * @dhss_len: The length of dhss in octets |
1731 | | * @ptk: Buffer for pairwise transient key |
1732 | | * @akmp: Negotiated AKM |
1733 | | * @cipher: Negotiated pairwise cipher |
1734 | | * @kdk_len: the length in octets that should be derived for HTLK. Can be zero. |
1735 | | * @kek_len: The length in octets that should be derived for KEK. Can be zero. |
1736 | | * @alg: Output variable for indicating the selected hash algorithm |
1737 | | * @is_eppke: EPPKE authentication |
1738 | | * Returns: 0 on success, -1 on failure |
1739 | | */ |
1740 | | int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len, |
1741 | | const u8 *spa, const u8 *bssid, |
1742 | | const u8 *dhss, size_t dhss_len, |
1743 | | struct wpa_ptk *ptk, int akmp, int cipher, |
1744 | | size_t kdk_len, size_t kek_len, enum rsn_hash_alg *alg, |
1745 | | bool is_eppke) |
1746 | | { |
1747 | | u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN + |
1748 | | WPA_KDK_MAX_LEN]; |
1749 | | const u8 *pos; |
1750 | | u8 *data; |
1751 | | size_t data_len, ptk_len; |
1752 | | int ret = -1; |
1753 | | const char *label = is_eppke ? "EPPKE PTK Derivation" : |
1754 | | "PASN PTK Derivation"; |
1755 | | |
1756 | | if (!pmk || !pmk_len) { |
1757 | | wpa_printf(MSG_ERROR, "PASN: No PMK set for PTK derivation"); |
1758 | | return -1; |
1759 | | } |
1760 | | |
1761 | | if (!dhss || !dhss_len) { |
1762 | | wpa_printf(MSG_ERROR, "PASN: No DHss set for PTK derivation"); |
1763 | | return -1; |
1764 | | } |
1765 | | |
1766 | | /* |
1767 | | * Use "EPPKE PTK Derivation" instead of “PASN PTK Derivation” for |
1768 | | * EPPKE Authentication per IEEE P802.11bi/D4.0, 12.16.9.3.4 (PTKSA |
1769 | | * derivation and MIC computation with EPPKE authentication). For EPPKE |
1770 | | * MLO, the non-AP MLD MAC address is used instead of the SPA and the |
1771 | | * AP MLD MAC address instead of the BSSID. |
1772 | | * |
1773 | | * PASN-PTK = KDF(PMK, “PASN PTK Derivation”, SPA || BSSID || DHss) |
1774 | | * |
1775 | | * KCK = L(PASN-PTK, 0, 256) |
1776 | | * TK = L(PASN-PTK, 256, TK_bits) |
1777 | | * KDK = L(PASN-PTK, 256 + TK_bits, kdk_len * 8) |
1778 | | */ |
1779 | | data_len = 2 * ETH_ALEN + dhss_len; |
1780 | | data = os_zalloc(data_len); |
1781 | | if (!data) |
1782 | | return -1; |
1783 | | |
1784 | | os_memcpy(data, spa, ETH_ALEN); |
1785 | | os_memcpy(data + ETH_ALEN, bssid, ETH_ALEN); |
1786 | | os_memcpy(data + 2 * ETH_ALEN, dhss, dhss_len); |
1787 | | |
1788 | | ptk->kck_len = WPA_PASN_KCK_LEN; |
1789 | | ptk->tk_len = wpa_cipher_key_len(cipher); |
1790 | | ptk->kdk_len = kdk_len; |
1791 | | ptk->kek_len = kek_len; |
1792 | | ptk->kek2_len = 0; |
1793 | | ptk->kck2_len = 0; |
1794 | | |
1795 | | if (ptk->tk_len == 0) { |
1796 | | wpa_printf(MSG_ERROR, |
1797 | | "PASN: Unsupported cipher (0x%x) used in PTK derivation", |
1798 | | cipher); |
1799 | | goto err; |
1800 | | } |
1801 | | |
1802 | | ptk_len = ptk->kck_len + ptk->tk_len + ptk->kdk_len + ptk->kek_len; |
1803 | | if (ptk_len > sizeof(tmp)) |
1804 | | goto err; |
1805 | | |
1806 | | *alg = pasn_select_hash_alg(akmp, cipher, pmk_len); |
1807 | | |
1808 | | switch (*alg) { |
1809 | | case RSN_HASH_SHA512: |
1810 | | #ifdef CONFIG_SHA512 |
1811 | | wpa_printf(MSG_DEBUG, "PASN: PTK derivation using SHA512"); |
1812 | | |
1813 | | if (sha512_prf(pmk, pmk_len, label, data, data_len, tmp, |
1814 | | ptk_len) < 0) |
1815 | | goto err; |
1816 | | break; |
1817 | | #endif |
1818 | | case RSN_HASH_SHA384: |
1819 | | #ifdef CONFIG_SHA384 |
1820 | | wpa_printf(MSG_DEBUG, "PASN: PTK derivation using SHA384"); |
1821 | | |
1822 | | if (sha384_prf(pmk, pmk_len, label, data, data_len, tmp, |
1823 | | ptk_len) < 0) |
1824 | | goto err; |
1825 | | break; |
1826 | | #endif |
1827 | | case RSN_HASH_SHA256: |
1828 | | wpa_printf(MSG_DEBUG, "PASN: PTK derivation using SHA256"); |
1829 | | |
1830 | | if (sha256_prf(pmk, pmk_len, label, data, data_len, tmp, |
1831 | | ptk_len) < 0) |
1832 | | goto err; |
1833 | | break; |
1834 | | default: |
1835 | | wpa_printf(MSG_DEBUG, "PASN: Unsupported hash algorithm %d", |
1836 | | *alg); |
1837 | | goto err; |
1838 | | } |
1839 | | |
1840 | | wpa_printf(MSG_DEBUG, |
1841 | | "PASN: PTK derivation: SPA=" MACSTR " BSSID=" MACSTR, |
1842 | | MAC2STR(spa), MAC2STR(bssid)); |
1843 | | |
1844 | | wpa_hexdump_key(MSG_DEBUG, "PASN: DHss", dhss, dhss_len); |
1845 | | wpa_hexdump_key(MSG_DEBUG, "PASN: PMK", pmk, pmk_len); |
1846 | | wpa_hexdump_key(MSG_DEBUG, "PASN: PASN-PTK", tmp, ptk_len); |
1847 | | |
1848 | | os_memcpy(ptk->kck, tmp, WPA_PASN_KCK_LEN); |
1849 | | wpa_hexdump_key(MSG_DEBUG, "PASN: KCK:", ptk->kck, WPA_PASN_KCK_LEN); |
1850 | | pos = &tmp[WPA_PASN_KCK_LEN]; |
1851 | | |
1852 | | if (kek_len) { |
1853 | | os_memcpy(ptk->kek, pos, kek_len); |
1854 | | wpa_hexdump_key(MSG_DEBUG, "PASN: KEK:", |
1855 | | ptk->kek, ptk->kek_len); |
1856 | | pos += kek_len; |
1857 | | } |
1858 | | |
1859 | | os_memcpy(ptk->tk, pos, ptk->tk_len); |
1860 | | wpa_hexdump_key(MSG_DEBUG, "PASN: TK:", ptk->tk, ptk->tk_len); |
1861 | | pos += ptk->tk_len; |
1862 | | |
1863 | | if (kdk_len) { |
1864 | | os_memcpy(ptk->kdk, pos, ptk->kdk_len); |
1865 | | wpa_hexdump_key(MSG_DEBUG, "PASN: KDK:", |
1866 | | ptk->kdk, ptk->kdk_len); |
1867 | | } |
1868 | | |
1869 | | ptk->ptk_len = ptk_len; |
1870 | | ptk->hash_alg = *alg; |
1871 | | forced_memzero(tmp, sizeof(tmp)); |
1872 | | ret = 0; |
1873 | | err: |
1874 | | bin_clear_free(data, data_len); |
1875 | | return ret; |
1876 | | } |
1877 | | |
1878 | | |
1879 | | size_t wpa_hash_len(enum rsn_hash_alg hash) |
1880 | | { |
1881 | | switch (hash) { |
1882 | | case RSN_HASH_SHA256: |
1883 | | return SHA256_MAC_LEN; |
1884 | | case RSN_HASH_SHA384: |
1885 | | return SHA384_MAC_LEN; |
1886 | | case RSN_HASH_SHA512: |
1887 | | return SHA512_MAC_LEN; |
1888 | | default: |
1889 | | return 0; |
1890 | | } |
1891 | | } |
1892 | | |
1893 | | |
1894 | | #ifdef CONFIG_PQC |
1895 | | /** |
1896 | | * pqc_pmk_to_ptk - Derive PTK from PMK for PQC cases |
1897 | | * @pmk: PMK buffer |
1898 | | * @pmk_len: Length of PMK in octets |
1899 | | * @spa: Supplicant address |
1900 | | * @aa: Authenticator address |
1901 | | * @hash: Selected hash algorithm |
1902 | | * @cipher: Negotiated pairwise cipher |
1903 | | * @dhss: Diffie-Hellman shared secret. NULL, if not used. |
1904 | | * @dhss_len: Length of dhss in octets. Zero, if dhss is NULL. |
1905 | | * @ml_kem_ss: ML-KEM shared secret (32 octets) |
1906 | | * @transcript: Transcript hash of the authentication exchange |
1907 | | * @transcript_len: Length of the transcript hash in octets |
1908 | | * @ptk: Buffer for PTK |
1909 | | * @kdk_len: Length in octets that should be derived for KDK. Can be zero. |
1910 | | * Returns: 0 on success, -1 on failure |
1911 | | */ |
1912 | | int pqc_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa, |
1913 | | enum rsn_hash_alg hash, int cipher, |
1914 | | const u8 *dhss, size_t dhss_len, const u8 *ml_kem_ss, |
1915 | | const u8 *transcript, size_t transcript_len, |
1916 | | struct wpa_ptk *ptk, size_t kdk_len) |
1917 | | { |
1918 | | static const char *label = "Pairwise key expansion"; |
1919 | | size_t label_len = os_strlen(label); |
1920 | | u8 data[os_strlen(label) + 2 * ETH_ALEN]; |
1921 | | u8 prk[SHA512_MAC_LEN]; |
1922 | | u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN + |
1923 | | WPA_KDK_MAX_LEN]; |
1924 | | size_t hash_len; |
1925 | | const u8 *addrs[3]; |
1926 | | size_t addrs_len[3]; |
1927 | | unsigned int idx = 0; |
1928 | | size_t ptk_len; |
1929 | | int ret = -1; |
1930 | | |
1931 | | wpa_printf(MSG_DEBUG, "PQC PMK to PTK: hash=%d", hash); |
1932 | | |
1933 | | hash_len = wpa_hash_len(hash); |
1934 | | if (!hash_len) { |
1935 | | wpa_printf(MSG_DEBUG, |
1936 | | "RSN: Unsupported hash algorithm %d for PQC PTK derivation", |
1937 | | hash); |
1938 | | return -1; |
1939 | | } |
1940 | | |
1941 | | if (!pmk || !pmk_len) { |
1942 | | wpa_printf(MSG_DEBUG, "RSN: No PMK for PTK derivation"); |
1943 | | return -1; |
1944 | | } |
1945 | | |
1946 | | /* IEEE P802.11bt/D1.0, 12.7.1.3: PMK_bits is the hash output length */ |
1947 | | if (pmk_len != hash_len) { |
1948 | | wpa_printf(MSG_DEBUG, |
1949 | | "RSN: Unexpected PMK length %zu for PQC PTK derivation (expected %zu)", |
1950 | | pmk_len, hash_len); |
1951 | | return -1; |
1952 | | } |
1953 | | |
1954 | | if (kdk_len > WPA_KDK_MAX_LEN) { |
1955 | | wpa_printf(MSG_DEBUG, |
1956 | | "RSN: KDK len=%zu exceeds max supported length", |
1957 | | kdk_len); |
1958 | | return -1; |
1959 | | } |
1960 | | |
1961 | | if (!transcript || !transcript_len) { |
1962 | | wpa_printf(MSG_DEBUG, |
1963 | | "RSN: No transcript hash for PQC PTK derivation"); |
1964 | | return -1; |
1965 | | } |
1966 | | |
1967 | | /* IEEE P802.11bt/D1.0, Table 12-13: KCK_bits is 128/192/256 */ |
1968 | | ptk->kck_len = pmk_len / 2; |
1969 | | /* IEEE P802.11bt/D1.0, Table 12-13: KEK_bits is 128/256/256 */ |
1970 | | ptk->kek_len = hash == RSN_HASH_SHA256 ? 16 : 32; |
1971 | | ptk->tk_len = wpa_cipher_key_len(cipher); |
1972 | | ptk->kdk_len = kdk_len; |
1973 | | ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len + ptk->kdk_len; |
1974 | | ptk->hash_alg = hash; |
1975 | | |
1976 | | /* |
1977 | | * PRK = HKDF-Extract(T, EPHss || IKM) |
1978 | | * Where EPHss is: |
1979 | | * - MLKEMss for PQC profile 0 |
1980 | | * - DHss || MLKEMss for PQC profile 1, 2 and 3 |
1981 | | * Where IKM is: |
1982 | | * - PMK-R1 for FT |
1983 | | * - PMK otherwise |
1984 | | */ |
1985 | | if (dhss && dhss_len) { |
1986 | | addrs[idx] = dhss; |
1987 | | addrs_len[idx] = dhss_len; |
1988 | | idx++; |
1989 | | } |
1990 | | |
1991 | | if (!ml_kem_ss) { |
1992 | | wpa_printf(MSG_DEBUG, "RSN: No MLKEMss for PQC PTK derivation"); |
1993 | | return -1; |
1994 | | } |
1995 | | addrs[idx] = ml_kem_ss; |
1996 | | addrs_len[idx] = CRYPTO_ML_KEM_SS_LEN; |
1997 | | idx++; |
1998 | | |
1999 | | addrs[idx] = pmk; |
2000 | | addrs_len[idx] = pmk_len; |
2001 | | idx++; |
2002 | | |
2003 | | if (hkdf_extract(hash_len, transcript, transcript_len, |
2004 | | idx, addrs, addrs_len, prk) < 0) { |
2005 | | wpa_printf(MSG_DEBUG, |
2006 | | "RSN: HKDF-Extract failed for PQC PMK to PTK"); |
2007 | | goto err; |
2008 | | } |
2009 | | |
2010 | | |
2011 | | /* |
2012 | | * PTK = HKDF-Expand(PRK, Pairwise key expansion" || SPA || AA, |
2013 | | * Length) |
2014 | | */ |
2015 | | os_memcpy(data, label, label_len); |
2016 | | os_memcpy(data + label_len, spa, ETH_ALEN); |
2017 | | os_memcpy(data + label_len + ETH_ALEN, aa, ETH_ALEN); |
2018 | | |
2019 | | if (hkdf_expand_bin(hash_len, prk, hash_len, data, sizeof(data), |
2020 | | tmp, ptk_len) < 0) { |
2021 | | wpa_printf(MSG_DEBUG, |
2022 | | "RSN: HKDF-Expand failed for PQC PMK to PTK"); |
2023 | | goto err; |
2024 | | } |
2025 | | |
2026 | | wpa_printf(MSG_DEBUG, |
2027 | | "RSN: PQC: PTK derivation - SPA=" MACSTR " AA=" MACSTR, |
2028 | | MAC2STR(spa), MAC2STR(aa)); |
2029 | | wpa_hexdump_key(MSG_DEBUG, "RSN: PQC: PMK", pmk, pmk_len); |
2030 | | wpa_hexdump_key(MSG_DEBUG, "RSN: PQC: T", transcript, transcript_len); |
2031 | | wpa_hexdump_key(MSG_DEBUG, "RSN: PQC: PTK", tmp, ptk_len); |
2032 | | |
2033 | | os_memcpy(ptk->kck, tmp, ptk->kck_len); |
2034 | | wpa_hexdump_key(MSG_DEBUG, "RSN: PQC: KCK", ptk->kck, ptk->kck_len); |
2035 | | |
2036 | | os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len); |
2037 | | wpa_hexdump_key(MSG_DEBUG, "RSN: PQC: KEK", ptk->kek, ptk->kek_len); |
2038 | | |
2039 | | os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len); |
2040 | | wpa_hexdump_key(MSG_DEBUG, "RSN: PQC: TK", ptk->tk, ptk->tk_len); |
2041 | | |
2042 | | if (kdk_len) { |
2043 | | os_memcpy(ptk->kdk, tmp + ptk->kck_len + ptk->kek_len + |
2044 | | ptk->tk_len, ptk->kdk_len); |
2045 | | wpa_hexdump_key(MSG_DEBUG, |
2046 | | "RSN: PQC: KDK", ptk->kdk, ptk->kdk_len); |
2047 | | } |
2048 | | |
2049 | | ptk->kek2_len = 0; |
2050 | | ptk->kck2_len = 0; |
2051 | | |
2052 | | ptk->ptk_len = ptk_len; |
2053 | | ret = 0; |
2054 | | |
2055 | | err: |
2056 | | forced_memzero(tmp, sizeof(tmp)); |
2057 | | forced_memzero(prk, sizeof(prk)); |
2058 | | |
2059 | | return ret; |
2060 | | } |
2061 | | #endif /* CONFIG_PQC */ |
2062 | | |
2063 | | /* |
2064 | | * pasn_mic_len - Returns the MIC length for PASN authentication |
2065 | | * @alg: Selected hash algorithm from pasn_pmk_to_ptk() |
2066 | | */ |
2067 | | size_t pasn_mic_len(enum rsn_hash_alg alg) |
2068 | | { |
2069 | | switch (alg) { |
2070 | | case RSN_HASH_SHA512: |
2071 | | return 32; |
2072 | | case RSN_HASH_SHA384: |
2073 | | return 24; |
2074 | | case RSN_HASH_SHA256: |
2075 | | default: |
2076 | | return 16; |
2077 | | } |
2078 | | } |
2079 | | |
2080 | | |
2081 | | /** |
2082 | | * wpa_ltf_keyseed - Compute LTF keyseed from KDK |
2083 | | * @ptk: Buffer that holds pairwise transient key |
2084 | | * @akmp: Negotiated AKM |
2085 | | * @cipher: Negotiated pairwise cipher |
2086 | | * Returns: 0 on success, -1 on failure |
2087 | | */ |
2088 | | int wpa_ltf_keyseed(struct wpa_ptk *ptk, int akmp, int cipher) |
2089 | | { |
2090 | | u8 *buf; |
2091 | | size_t buf_len; |
2092 | | u8 hash[SHA384_MAC_LEN]; |
2093 | | const u8 *kdk = ptk->kdk; |
2094 | | size_t kdk_len = ptk->kdk_len; |
2095 | | const char *label = "Secure LTF key seed"; |
2096 | | |
2097 | | if (!kdk || !kdk_len) { |
2098 | | wpa_printf(MSG_ERROR, "WPA: No KDK for LTF keyseed generation"); |
2099 | | return -1; |
2100 | | } |
2101 | | |
2102 | | buf = (u8 *)label; |
2103 | | buf_len = os_strlen(label); |
2104 | | |
2105 | | if (pasn_use_sha384(akmp, cipher)) { |
2106 | | wpa_printf(MSG_DEBUG, |
2107 | | "WPA: Secure LTF keyseed using HMAC-SHA384"); |
2108 | | |
2109 | | if (hmac_sha384(kdk, kdk_len, buf, buf_len, hash)) { |
2110 | | wpa_printf(MSG_ERROR, |
2111 | | "WPA: HMAC-SHA384 compute failed"); |
2112 | | return -1; |
2113 | | } |
2114 | | os_memcpy(ptk->ltf_keyseed, hash, SHA384_MAC_LEN); |
2115 | | ptk->ltf_keyseed_len = SHA384_MAC_LEN; |
2116 | | wpa_hexdump_key(MSG_DEBUG, "WPA: Secure LTF keyseed: ", |
2117 | | ptk->ltf_keyseed, ptk->ltf_keyseed_len); |
2118 | | |
2119 | | } else { |
2120 | | wpa_printf(MSG_DEBUG, "WPA: LTF keyseed using HMAC-SHA256"); |
2121 | | |
2122 | | if (hmac_sha256(kdk, kdk_len, buf, buf_len, hash)) { |
2123 | | wpa_printf(MSG_ERROR, |
2124 | | "WPA: HMAC-SHA256 compute failed"); |
2125 | | return -1; |
2126 | | } |
2127 | | os_memcpy(ptk->ltf_keyseed, hash, SHA256_MAC_LEN); |
2128 | | ptk->ltf_keyseed_len = SHA256_MAC_LEN; |
2129 | | wpa_hexdump_key(MSG_DEBUG, "WPA: Secure LTF keyseed: ", |
2130 | | ptk->ltf_keyseed, ptk->ltf_keyseed_len); |
2131 | | } |
2132 | | |
2133 | | return 0; |
2134 | | } |
2135 | | |
2136 | | |
2137 | | #ifdef CONFIG_IEEE8021X_AUTH |
2138 | | |
2139 | | int wpa_auth_802_1x_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, |
2140 | | const u8 *aa, const u8 *snonce, const u8 *anonce, |
2141 | | int akmp, int cipher, const u8 *dhss, |
2142 | | size_t dhss_len, struct wpa_ptk *ptk, |
2143 | | size_t kdk_len) |
2144 | | { |
2145 | | return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion", |
2146 | | spa, aa, snonce, anonce, ptk, akmp, |
2147 | | cipher, dhss, dhss_len, kdk_len, |
2148 | | PASN_GROUP_NOT_SPECIFIED); |
2149 | | } |
2150 | | |
2151 | | |
2152 | | /** |
2153 | | * wpa_auth_8021x_mic - Calculate IEEE 802.1X in Authentication frames MIC |
2154 | | * @akmp: Negotiated key management protocol |
2155 | | * @hash_alg: Hash algorithm to use for MIC calculation |
2156 | | * @kck: The key confirmation key from 802.1X exchange |
2157 | | * @kck_len: KCK length in octets |
2158 | | * @addr1: Authenticator address |
2159 | | * @addr2: Supplicant address |
2160 | | * @data: This should hold the RSNE + RSNXE. |
2161 | | * For a MIC included by the AP with EAP-Success and the second |
2162 | | * Authentication frame if a PMKSA was identified via a PMKID included in |
2163 | | * the first Authentication frame, this holds the Beacon frame RSNE+RSNXE. |
2164 | | * For a MIC included by the non-AP STA in the (Re)Association Request |
2165 | | * frame, this holds the RSNE and RSNXE sent by the non-AP STA. |
2166 | | * @data_len: The length of data |
2167 | | * @frame: For a MIC included by the AP in EAP-Success and the second |
2168 | | * Authentication frame if a PMKSA was identified via a PMKID included in |
2169 | | * the first Authentication frame, this holds the body of the |
2170 | | * Authentication frame including the MIC element with the octets in the |
2171 | | * MIC field of the MIC element set to 0, else NULL |
2172 | | * @frame_len: The length of frame |
2173 | | * @mic: Buffer to hold the MIC on success. Must be large enough to handle the |
2174 | | * maximal MIC length. |
2175 | | * Returns: 0 on success, -1 on failure |
2176 | | * |
2177 | | * HMAC-HASH (PTK-KCK, AA || SPA || RSNE || RSNXE || Frame Data) |
2178 | | */ |
2179 | | int wpa_auth_8021x_mic(int akmp, enum rsn_hash_alg hash_alg, |
2180 | | const u8 *kck, size_t kck_len, const u8 *addr1, |
2181 | | const u8 *addr2, const u8 *data, size_t data_len, |
2182 | | const u8 *frame, size_t frame_len, u8 *mic) |
2183 | | { |
2184 | | size_t mic_len; |
2185 | | u8 *buf; |
2186 | | int ret = -1; |
2187 | | size_t buf_len = 2 * ETH_ALEN + data_len + frame_len; |
2188 | | |
2189 | | if (!kck) { |
2190 | | wpa_printf(MSG_INFO, "802.1X: No KCK for MIC calculation"); |
2191 | | return -1; |
2192 | | } |
2193 | | |
2194 | | if (!data || !data_len) { |
2195 | | wpa_printf(MSG_INFO, |
2196 | | "802.1X: Invalid data for MIC calculation"); |
2197 | | return -1; |
2198 | | } |
2199 | | |
2200 | | buf = os_zalloc(buf_len); |
2201 | | if (!buf) |
2202 | | return -1; |
2203 | | |
2204 | | wpa_printf(MSG_DEBUG, "802.1X MIC calculation"); |
2205 | | wpa_printf(MSG_DEBUG, "addr1: " MACSTR, MAC2STR(addr1)); |
2206 | | wpa_printf(MSG_DEBUG, "addr2: " MACSTR, MAC2STR(addr2)); |
2207 | | |
2208 | | os_memcpy(buf, addr1, ETH_ALEN); |
2209 | | os_memcpy(buf + ETH_ALEN, addr2, ETH_ALEN); |
2210 | | |
2211 | | wpa_hexdump_key(MSG_DEBUG, "MIC: data", data, data_len); |
2212 | | os_memcpy(buf + 2 * ETH_ALEN, data, data_len); |
2213 | | |
2214 | | wpa_hexdump_key(MSG_DEBUG, "MIC: KCK", kck, kck_len); |
2215 | | |
2216 | | if (frame) { |
2217 | | wpa_hexdump_key(MSG_MSGDUMP, "802.1X: MIC: frame", |
2218 | | frame, frame_len); |
2219 | | os_memcpy(buf + 2 * ETH_ALEN + data_len, frame, frame_len); |
2220 | | } |
2221 | | |
2222 | | wpa_hexdump_key(MSG_DEBUG, "MIC: buf", buf, buf_len); |
2223 | | |
2224 | | if (hash_alg == RSN_HASH_SHA512) { |
2225 | | wpa_printf(MSG_DEBUG, "MIC: HMAC-SHA512"); |
2226 | | mic_len = 32; |
2227 | | |
2228 | | if (hmac_sha512(kck, kck_len, buf, buf_len, mic) < 0) |
2229 | | goto out; |
2230 | | } else if (hash_alg == RSN_HASH_SHA384 || |
2231 | | wpa_key_mgmt_sha384(akmp)) { |
2232 | | wpa_printf(MSG_DEBUG, "MIC: HMAC-SHA384"); |
2233 | | mic_len = 24; |
2234 | | |
2235 | | if (hmac_sha384(kck, kck_len, buf, buf_len, mic) < 0) |
2236 | | goto out; |
2237 | | } else { |
2238 | | wpa_printf(MSG_DEBUG, "MIC: HMAC-SHA256"); |
2239 | | mic_len = 16; |
2240 | | |
2241 | | if (hmac_sha256(kck, kck_len, buf, buf_len, mic) < 0) |
2242 | | goto out; |
2243 | | } |
2244 | | |
2245 | | wpa_hexdump_key(MSG_DEBUG, "802.1X: Calculated MIC", mic, mic_len); |
2246 | | ret = 0; |
2247 | | out: |
2248 | | bin_clear_free(buf, buf_len); |
2249 | | return ret; |
2250 | | } |
2251 | | |
2252 | | #endif /* CONFIG_IEEE8021X_AUTH */ |
2253 | | |
2254 | | |
2255 | | /** |
2256 | | * pasn_mic - Calculate PASN MIC |
2257 | | * @alg: Selected hash algorithm from pasn_pmk_to_ptk() |
2258 | | * @kck: The key confirmation key for the PASN PTKSA |
2259 | | * @kck_len: KCK length in octets |
2260 | | * @addr1: For the 2nd PASN/EPPKE frame supplicant address is used for non-MLO; |
2261 | | * for MLO, 2nd EPPKE authentication to use non-AP MLD MAC address. |
2262 | | * For the 3rd PASN/EPPKE frame BSSID is used for non-MLO; for MLO, 3rd |
2263 | | * EPPKE authentication to use AP MLD MAC address as per |
2264 | | * @addr2: For the 2nd PASN/EPPKE frame BSSID is used for non-MLO; for MLO, 2nd |
2265 | | * EPPKE authentication to use AP MLD MAC address. For the 3rd PASN/EPPKE |
2266 | | * frame supplicant address is used for non-MLO; for MLO, 3rd EPPKE |
2267 | | * Authentication frame to use non-AP MLD MAC address. |
2268 | | * @data: For calculating the MIC for the 2nd PASN frame, this should hold the |
2269 | | * Beacon frame RSNE + RSNXE. For calculating the MIC for the 3rd PASN |
2270 | | * frame, this should hold the hash of the body of the PASN 1st frame. |
2271 | | * @data_len: The length of data |
2272 | | * @frame: The body of the PASN frame including the MIC element with the octets |
2273 | | * in the MIC field of the MIC element set to 0. |
2274 | | * @frame_len: The length of frame |
2275 | | * @mic: Buffer to hold the MIC on success. Should be big enough to handle the |
2276 | | * maximal MIC length |
2277 | | * Returns: 0 on success, -1 on failure |
2278 | | */ |
2279 | | int pasn_mic(enum rsn_hash_alg alg, const u8 *kck, size_t kck_len, |
2280 | | const u8 *addr1, const u8 *addr2, |
2281 | | const u8 *data, size_t data_len, |
2282 | | const u8 *frame, size_t frame_len, u8 *mic) |
2283 | | { |
2284 | | u8 *buf; |
2285 | | u8 hash[SHA512_MAC_LEN]; |
2286 | | size_t buf_len = 2 * ETH_ALEN + data_len + frame_len; |
2287 | | int ret = -1; |
2288 | | size_t mic_len; |
2289 | | |
2290 | | if (!kck) { |
2291 | | wpa_printf(MSG_ERROR, "PASN: No KCK for MIC calculation"); |
2292 | | return -1; |
2293 | | } |
2294 | | |
2295 | | if (kck_len != WPA_PASN_KCK_LEN) { |
2296 | | wpa_printf(MSG_ERROR, |
2297 | | "PASN: Unexpected KCK length %zu for MIC calculation", |
2298 | | kck_len); |
2299 | | return -1; |
2300 | | } |
2301 | | |
2302 | | if (!data || !data_len) { |
2303 | | wpa_printf(MSG_ERROR, "PASN: invalid data for MIC calculation"); |
2304 | | return -1; |
2305 | | } |
2306 | | |
2307 | | if (!frame || !frame_len) { |
2308 | | wpa_printf(MSG_ERROR, "PASN: invalid data for MIC calculation"); |
2309 | | return -1; |
2310 | | } |
2311 | | |
2312 | | buf = os_zalloc(buf_len); |
2313 | | if (!buf) |
2314 | | return -1; |
2315 | | |
2316 | | os_memcpy(buf, addr1, ETH_ALEN); |
2317 | | os_memcpy(buf + ETH_ALEN, addr2, ETH_ALEN); |
2318 | | |
2319 | | wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: data", data, data_len); |
2320 | | os_memcpy(buf + 2 * ETH_ALEN, data, data_len); |
2321 | | |
2322 | | wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: frame", frame, frame_len); |
2323 | | os_memcpy(buf + 2 * ETH_ALEN + data_len, frame, frame_len); |
2324 | | |
2325 | | wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: KCK", kck, kck_len); |
2326 | | wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: buf", buf, buf_len); |
2327 | | |
2328 | | mic_len = pasn_mic_len(alg); |
2329 | | |
2330 | | switch (alg) { |
2331 | | #ifdef CONFIG_SHA512 |
2332 | | case RSN_HASH_SHA512: |
2333 | | wpa_printf(MSG_DEBUG, "PASN: MIC using HMAC-SHA512"); |
2334 | | if (hmac_sha512(kck, kck_len, buf, buf_len, hash)) |
2335 | | goto err; |
2336 | | break; |
2337 | | #endif /* CONFIG_SHA512 */ |
2338 | | #ifdef CONFIG_SHA384 |
2339 | | case RSN_HASH_SHA384: |
2340 | | wpa_printf(MSG_DEBUG, "PASN: MIC using HMAC-SHA384"); |
2341 | | if (hmac_sha384(kck, kck_len, buf, buf_len, hash)) |
2342 | | goto err; |
2343 | | break; |
2344 | | #endif /* CONFIG_SHA384 */ |
2345 | | case RSN_HASH_SHA256: |
2346 | | wpa_printf(MSG_DEBUG, "PASN: MIC using HMAC-SHA256"); |
2347 | | if (hmac_sha256(kck, kck_len, buf, buf_len, hash)) |
2348 | | goto err; |
2349 | | break; |
2350 | | default: |
2351 | | wpa_printf(MSG_ERROR, |
2352 | | "PASN: Unsupported alg=%d for MIC calculation", alg); |
2353 | | goto err; |
2354 | | } |
2355 | | |
2356 | | os_memcpy(mic, hash, mic_len); |
2357 | | wpa_hexdump_key(MSG_DEBUG, "PASN: MIC", mic, mic_len); |
2358 | | |
2359 | | ret = 0; |
2360 | | err: |
2361 | | bin_clear_free(buf, buf_len); |
2362 | | return ret; |
2363 | | } |
2364 | | |
2365 | | |
2366 | | /** |
2367 | | * pasn_auth_frame_hash - Computes a hash of an Authentication frame body |
2368 | | * @alg: Selected hash algorithm from pasn_pmk_to_ptk() |
2369 | | * @data: Pointer to the Authentication frame body |
2370 | | * @len: Length of the Authentication frame body |
2371 | | * @hash: On return would hold the computed hash. Should be big enough to handle |
2372 | | * SHA512. |
2373 | | * Returns: 0 on success, -1 on failure |
2374 | | */ |
2375 | | int pasn_auth_frame_hash(enum rsn_hash_alg alg, const u8 *data, size_t len, |
2376 | | u8 *hash) |
2377 | | { |
2378 | | switch (alg) { |
2379 | | #ifdef CONFIG_SHA512 |
2380 | | case RSN_HASH_SHA512: |
2381 | | wpa_printf(MSG_DEBUG, "PASN: Frame hash using SHA-512"); |
2382 | | return sha512_vector(1, &data, &len, hash); |
2383 | | #endif /* CONFIG_SHA512 */ |
2384 | | #ifdef CONFIG_SHA384 |
2385 | | case RSN_HASH_SHA384: |
2386 | | wpa_printf(MSG_DEBUG, "PASN: Frame hash using SHA-384"); |
2387 | | return sha384_vector(1, &data, &len, hash); |
2388 | | #endif /* CONFIG_SHA384 */ |
2389 | | case RSN_HASH_SHA256: |
2390 | | wpa_printf(MSG_DEBUG, "PASN: Frame hash using SHA-256"); |
2391 | | return sha256_vector(1, &data, &len, hash); |
2392 | | default: |
2393 | | wpa_printf(MSG_ERROR, "PASN: Unsupported alg=%d", alg); |
2394 | | return -1; |
2395 | | } |
2396 | | } |
2397 | | |
2398 | | #endif /* CONFIG_PASN */ |
2399 | | |
2400 | | |
2401 | | static int rsn_selector_to_bitfield(const u8 *s) |
2402 | 0 | { |
2403 | 0 | return rsn_cipher_suite_to_wpa_cipher(RSN_SELECTOR_GET(s)); |
2404 | 0 | } |
2405 | | |
2406 | | |
2407 | | static int rsn_key_mgmt_to_bitfield(const u8 *s) |
2408 | 0 | { |
2409 | 0 | return rsn_key_mgmt_to_wpa_akm(RSN_SELECTOR_GET(s)); |
2410 | 0 | } |
2411 | | |
2412 | | |
2413 | | int wpa_cipher_valid_group(int cipher) |
2414 | 0 | { |
2415 | 0 | return wpa_cipher_valid_pairwise(cipher) || |
2416 | 0 | cipher == WPA_CIPHER_GTK_NOT_USED; |
2417 | 0 | } |
2418 | | |
2419 | | |
2420 | | int wpa_cipher_valid_mgmt_group(int cipher) |
2421 | 1.98k | { |
2422 | 1.98k | return cipher == WPA_CIPHER_GTK_NOT_USED || |
2423 | 1.98k | cipher == WPA_CIPHER_AES_128_CMAC || |
2424 | 1.98k | cipher == WPA_CIPHER_BIP_GMAC_128 || |
2425 | 1.98k | cipher == WPA_CIPHER_BIP_GMAC_256 || |
2426 | 1.98k | cipher == WPA_CIPHER_BIP_CMAC_256; |
2427 | 1.98k | } |
2428 | | |
2429 | | |
2430 | | /** |
2431 | | * wpa_parse_wpa_ie_rsn - Parse RSN IE |
2432 | | * @rsn_ie: Buffer containing RSN IE |
2433 | | * @rsn_ie_len: RSN IE buffer length (including IE number and length octets) |
2434 | | * @data: Pointer to structure that will be filled in with parsed data |
2435 | | * Returns: 0 on success, <0 on failure |
2436 | | */ |
2437 | | int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, |
2438 | | struct wpa_ie_data *data) |
2439 | 0 | { |
2440 | 0 | const u8 *pos; |
2441 | 0 | int left; |
2442 | 0 | int i, count; |
2443 | |
|
2444 | 0 | os_memset(data, 0, sizeof(*data)); |
2445 | 0 | data->proto = WPA_PROTO_RSN; |
2446 | 0 | data->pairwise_cipher = WPA_CIPHER_CCMP; |
2447 | 0 | data->group_cipher = WPA_CIPHER_CCMP; |
2448 | 0 | data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; |
2449 | 0 | data->capabilities = 0; |
2450 | 0 | data->pmkid = NULL; |
2451 | 0 | data->num_pmkid = 0; |
2452 | 0 | data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; |
2453 | |
|
2454 | 0 | if (rsn_ie_len == 0) { |
2455 | | /* No RSN IE - fail silently */ |
2456 | 0 | return -1; |
2457 | 0 | } |
2458 | | |
2459 | 0 | if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { |
2460 | 0 | wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", |
2461 | 0 | __func__, (unsigned long) rsn_ie_len); |
2462 | 0 | return -1; |
2463 | 0 | } |
2464 | | |
2465 | 0 | if (rsn_ie_len >= 2 + 4 + 2 && rsn_ie[1] >= 4 + 2 && |
2466 | 0 | rsn_ie[1] == rsn_ie_len - 2 && |
2467 | 0 | (WPA_GET_BE32(&rsn_ie[2]) == RSNE_OVERRIDE_IE_VENDOR_TYPE || |
2468 | 0 | WPA_GET_BE32(&rsn_ie[2]) == |
2469 | 0 | RSNE_OVERRIDE_2_IE_VENDOR_TYPE) && |
2470 | 0 | WPA_GET_LE16(&rsn_ie[2 + 4]) == RSN_VERSION) { |
2471 | 0 | pos = rsn_ie + 2 + 4 + 2; |
2472 | 0 | left = rsn_ie_len - 2 - 4 - 2; |
2473 | 0 | } else { |
2474 | 0 | const struct rsn_ie_hdr *hdr; |
2475 | |
|
2476 | 0 | hdr = (const struct rsn_ie_hdr *) rsn_ie; |
2477 | |
|
2478 | 0 | if (hdr->elem_id != WLAN_EID_RSN || |
2479 | 0 | hdr->len != rsn_ie_len - 2 || |
2480 | 0 | WPA_GET_LE16(hdr->version) != RSN_VERSION) { |
2481 | 0 | wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", |
2482 | 0 | __func__); |
2483 | 0 | return -2; |
2484 | 0 | } |
2485 | | |
2486 | 0 | pos = (const u8 *) (hdr + 1); |
2487 | 0 | left = rsn_ie_len - sizeof(*hdr); |
2488 | 0 | } |
2489 | | |
2490 | 0 | if (left >= RSN_SELECTOR_LEN) { |
2491 | 0 | data->group_cipher = rsn_selector_to_bitfield(pos); |
2492 | 0 | data->has_group = 1; |
2493 | 0 | if (!wpa_cipher_valid_group(data->group_cipher)) { |
2494 | 0 | wpa_printf(MSG_DEBUG, |
2495 | 0 | "%s: invalid group cipher 0x%x (%08x)", |
2496 | 0 | __func__, data->group_cipher, |
2497 | 0 | WPA_GET_BE32(pos)); |
2498 | | #ifdef CONFIG_NO_TKIP |
2499 | | if (RSN_SELECTOR_GET(pos) == RSN_CIPHER_SUITE_TKIP) { |
2500 | | wpa_printf(MSG_DEBUG, |
2501 | | "%s: TKIP as group cipher not supported in CONFIG_NO_TKIP=y build", |
2502 | | __func__); |
2503 | | } |
2504 | | #endif /* CONFIG_NO_TKIP */ |
2505 | 0 | return -1; |
2506 | 0 | } |
2507 | 0 | pos += RSN_SELECTOR_LEN; |
2508 | 0 | left -= RSN_SELECTOR_LEN; |
2509 | 0 | } else if (left > 0) { |
2510 | 0 | wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", |
2511 | 0 | __func__, left); |
2512 | 0 | return -3; |
2513 | 0 | } |
2514 | | |
2515 | 0 | if (left >= 2) { |
2516 | 0 | data->pairwise_cipher = 0; |
2517 | 0 | count = WPA_GET_LE16(pos); |
2518 | 0 | pos += 2; |
2519 | 0 | left -= 2; |
2520 | 0 | if (count == 0 || count > left / RSN_SELECTOR_LEN) { |
2521 | 0 | wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " |
2522 | 0 | "count %u left %u", __func__, count, left); |
2523 | 0 | return -4; |
2524 | 0 | } |
2525 | 0 | if (count) |
2526 | 0 | data->has_pairwise = 1; |
2527 | 0 | for (i = 0; i < count; i++) { |
2528 | 0 | data->pairwise_cipher |= rsn_selector_to_bitfield(pos); |
2529 | 0 | pos += RSN_SELECTOR_LEN; |
2530 | 0 | left -= RSN_SELECTOR_LEN; |
2531 | 0 | } |
2532 | 0 | if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) { |
2533 | 0 | wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as " |
2534 | 0 | "pairwise cipher", __func__); |
2535 | 0 | return -1; |
2536 | 0 | } |
2537 | 0 | } else if (left == 1) { |
2538 | 0 | wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", |
2539 | 0 | __func__); |
2540 | 0 | return -5; |
2541 | 0 | } |
2542 | | |
2543 | 0 | if (left >= 2) { |
2544 | 0 | data->key_mgmt = 0; |
2545 | 0 | count = WPA_GET_LE16(pos); |
2546 | 0 | pos += 2; |
2547 | 0 | left -= 2; |
2548 | 0 | if (count > left / RSN_SELECTOR_LEN) { |
2549 | 0 | wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " |
2550 | 0 | "count %u left %u", __func__, count, left); |
2551 | 0 | return -6; |
2552 | 0 | } |
2553 | 0 | for (i = 0; i < count; i++) { |
2554 | 0 | data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); |
2555 | 0 | pos += RSN_SELECTOR_LEN; |
2556 | 0 | left -= RSN_SELECTOR_LEN; |
2557 | 0 | } |
2558 | 0 | } else if (left == 1) { |
2559 | 0 | wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", |
2560 | 0 | __func__); |
2561 | 0 | return -7; |
2562 | 0 | } |
2563 | | |
2564 | 0 | if (left >= 2) { |
2565 | 0 | data->capabilities = WPA_GET_LE16(pos); |
2566 | 0 | pos += 2; |
2567 | 0 | left -= 2; |
2568 | 0 | } |
2569 | |
|
2570 | 0 | if (left >= 2) { |
2571 | 0 | u16 num_pmkid = WPA_GET_LE16(pos); |
2572 | 0 | pos += 2; |
2573 | 0 | left -= 2; |
2574 | 0 | if (num_pmkid > (unsigned int) left / PMKID_LEN) { |
2575 | 0 | wpa_printf(MSG_DEBUG, "%s: PMKID underflow " |
2576 | 0 | "(num_pmkid=%u left=%d)", |
2577 | 0 | __func__, num_pmkid, left); |
2578 | 0 | data->num_pmkid = 0; |
2579 | 0 | return -9; |
2580 | 0 | } else { |
2581 | 0 | data->num_pmkid = num_pmkid; |
2582 | 0 | data->pmkid = pos; |
2583 | 0 | pos += data->num_pmkid * PMKID_LEN; |
2584 | 0 | left -= data->num_pmkid * PMKID_LEN; |
2585 | 0 | } |
2586 | 0 | } |
2587 | | |
2588 | 0 | if (left >= 4) { |
2589 | 0 | data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); |
2590 | 0 | if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) { |
2591 | 0 | wpa_printf(MSG_DEBUG, |
2592 | 0 | "%s: Unsupported management group cipher 0x%x (%08x)", |
2593 | 0 | __func__, data->mgmt_group_cipher, |
2594 | 0 | WPA_GET_BE32(pos)); |
2595 | 0 | return -10; |
2596 | 0 | } |
2597 | 0 | pos += RSN_SELECTOR_LEN; |
2598 | 0 | left -= RSN_SELECTOR_LEN; |
2599 | 0 | } |
2600 | | |
2601 | 0 | if (left > 0) { |
2602 | 0 | wpa_hexdump(MSG_DEBUG, |
2603 | 0 | "wpa_parse_wpa_ie_rsn: ignore trailing bytes", |
2604 | 0 | pos, left); |
2605 | 0 | } |
2606 | |
|
2607 | 0 | return 0; |
2608 | 0 | } |
2609 | | |
2610 | | |
2611 | | static int wpa_selector_to_bitfield(const u8 *s) |
2612 | 0 | { |
2613 | 0 | if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE) |
2614 | 0 | return WPA_CIPHER_NONE; |
2615 | 0 | if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP) |
2616 | 0 | return WPA_CIPHER_TKIP; |
2617 | 0 | if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP) |
2618 | 0 | return WPA_CIPHER_CCMP; |
2619 | 0 | return 0; |
2620 | 0 | } |
2621 | | |
2622 | | |
2623 | | static int wpa_key_mgmt_to_bitfield(const u8 *s) |
2624 | 0 | { |
2625 | 0 | if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X) |
2626 | 0 | return WPA_KEY_MGMT_IEEE8021X; |
2627 | 0 | if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X) |
2628 | 0 | return WPA_KEY_MGMT_PSK; |
2629 | 0 | if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE) |
2630 | 0 | return WPA_KEY_MGMT_WPA_NONE; |
2631 | 0 | return 0; |
2632 | 0 | } |
2633 | | |
2634 | | |
2635 | | int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, |
2636 | | struct wpa_ie_data *data) |
2637 | 0 | { |
2638 | 0 | const struct wpa_ie_hdr *hdr; |
2639 | 0 | const u8 *pos; |
2640 | 0 | int left; |
2641 | 0 | int i, count; |
2642 | |
|
2643 | 0 | os_memset(data, 0, sizeof(*data)); |
2644 | 0 | data->proto = WPA_PROTO_WPA; |
2645 | 0 | data->pairwise_cipher = WPA_CIPHER_TKIP; |
2646 | 0 | data->group_cipher = WPA_CIPHER_TKIP; |
2647 | 0 | data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; |
2648 | 0 | data->capabilities = 0; |
2649 | 0 | data->pmkid = NULL; |
2650 | 0 | data->num_pmkid = 0; |
2651 | 0 | data->mgmt_group_cipher = 0; |
2652 | |
|
2653 | 0 | if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { |
2654 | 0 | wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", |
2655 | 0 | __func__, (unsigned long) wpa_ie_len); |
2656 | 0 | return -1; |
2657 | 0 | } |
2658 | | |
2659 | 0 | hdr = (const struct wpa_ie_hdr *) wpa_ie; |
2660 | |
|
2661 | 0 | if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC || |
2662 | 0 | hdr->len != wpa_ie_len - 2 || |
2663 | 0 | RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE || |
2664 | 0 | WPA_GET_LE16(hdr->version) != WPA_VERSION) { |
2665 | 0 | wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", |
2666 | 0 | __func__); |
2667 | 0 | return -2; |
2668 | 0 | } |
2669 | | |
2670 | 0 | pos = (const u8 *) (hdr + 1); |
2671 | 0 | left = wpa_ie_len - sizeof(*hdr); |
2672 | |
|
2673 | 0 | if (left >= WPA_SELECTOR_LEN) { |
2674 | 0 | data->group_cipher = wpa_selector_to_bitfield(pos); |
2675 | 0 | pos += WPA_SELECTOR_LEN; |
2676 | 0 | left -= WPA_SELECTOR_LEN; |
2677 | 0 | } else if (left > 0) { |
2678 | 0 | wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", |
2679 | 0 | __func__, left); |
2680 | 0 | return -3; |
2681 | 0 | } |
2682 | | |
2683 | 0 | if (left >= 2) { |
2684 | 0 | data->pairwise_cipher = 0; |
2685 | 0 | count = WPA_GET_LE16(pos); |
2686 | 0 | pos += 2; |
2687 | 0 | left -= 2; |
2688 | 0 | if (count == 0 || count > left / WPA_SELECTOR_LEN) { |
2689 | 0 | wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " |
2690 | 0 | "count %u left %u", __func__, count, left); |
2691 | 0 | return -4; |
2692 | 0 | } |
2693 | 0 | for (i = 0; i < count; i++) { |
2694 | 0 | data->pairwise_cipher |= wpa_selector_to_bitfield(pos); |
2695 | 0 | pos += WPA_SELECTOR_LEN; |
2696 | 0 | left -= WPA_SELECTOR_LEN; |
2697 | 0 | } |
2698 | 0 | } else if (left == 1) { |
2699 | 0 | wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", |
2700 | 0 | __func__); |
2701 | 0 | return -5; |
2702 | 0 | } |
2703 | | |
2704 | 0 | if (left >= 2) { |
2705 | 0 | data->key_mgmt = 0; |
2706 | 0 | count = WPA_GET_LE16(pos); |
2707 | 0 | pos += 2; |
2708 | 0 | left -= 2; |
2709 | 0 | if (count == 0 || count > left / WPA_SELECTOR_LEN) { |
2710 | 0 | wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " |
2711 | 0 | "count %u left %u", __func__, count, left); |
2712 | 0 | return -6; |
2713 | 0 | } |
2714 | 0 | for (i = 0; i < count; i++) { |
2715 | 0 | data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); |
2716 | 0 | pos += WPA_SELECTOR_LEN; |
2717 | 0 | left -= WPA_SELECTOR_LEN; |
2718 | 0 | } |
2719 | 0 | } else if (left == 1) { |
2720 | 0 | wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", |
2721 | 0 | __func__); |
2722 | 0 | return -7; |
2723 | 0 | } |
2724 | | |
2725 | 0 | if (left >= 2) { |
2726 | 0 | data->capabilities = WPA_GET_LE16(pos); |
2727 | 0 | pos += 2; |
2728 | 0 | left -= 2; |
2729 | 0 | } |
2730 | |
|
2731 | 0 | if (left > 0) { |
2732 | 0 | wpa_hexdump(MSG_DEBUG, |
2733 | 0 | "wpa_parse_wpa_ie_wpa: ignore trailing bytes", |
2734 | 0 | pos, left); |
2735 | 0 | } |
2736 | |
|
2737 | 0 | return 0; |
2738 | 0 | } |
2739 | | |
2740 | | |
2741 | | int wpa_default_rsn_cipher(int freq) |
2742 | 0 | { |
2743 | 0 | if (freq > 56160) |
2744 | 0 | return WPA_CIPHER_GCMP; /* DMG */ |
2745 | | |
2746 | 0 | return WPA_CIPHER_CCMP; |
2747 | 0 | } |
2748 | | |
2749 | | |
2750 | | #ifdef CONFIG_IEEE80211R |
2751 | | |
2752 | | /** |
2753 | | * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name |
2754 | | * |
2755 | | * IEEE Std 802.11r-2008 - 8.5.1.5.3 |
2756 | | */ |
2757 | | int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, |
2758 | | const u8 *ssid, size_t ssid_len, |
2759 | | const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, |
2760 | | const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name, |
2761 | | int key_mgmt) |
2762 | 0 | { |
2763 | 0 | u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 + |
2764 | 0 | FT_R0KH_ID_MAX_LEN + ETH_ALEN]; |
2765 | 0 | u8 *pos, r0_key_data[64 + 16], hash[64]; |
2766 | 0 | const u8 *addr[2]; |
2767 | 0 | size_t len[2]; |
2768 | 0 | size_t q, r0_key_data_len; |
2769 | 0 | int res; |
2770 | |
|
2771 | 0 | if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && |
2772 | 0 | (xxkey_len == SHA256_MAC_LEN || xxkey_len == SHA384_MAC_LEN || |
2773 | 0 | xxkey_len == SHA512_MAC_LEN)) |
2774 | 0 | q = xxkey_len; |
2775 | 0 | else if (wpa_key_mgmt_sha384(key_mgmt)) |
2776 | 0 | q = SHA384_MAC_LEN; |
2777 | 0 | else |
2778 | 0 | q = SHA256_MAC_LEN; |
2779 | 0 | r0_key_data_len = q + 16; |
2780 | | |
2781 | | /* |
2782 | | * R0-Key-Data = KDF-Hash-Length(XXKey, "FT-R0", |
2783 | | * SSIDlength || SSID || MDID || R0KHlength || |
2784 | | * R0KH-ID || S0KH-ID) |
2785 | | * XXKey is either the second 256 bits of MSK or PSK; or the first |
2786 | | * 384 bits of MSK for FT-EAP-SHA384; or PMK from SAE. |
2787 | | * PMK-R0 = L(R0-Key-Data, 0, Q) |
2788 | | * PMK-R0Name-Salt = L(R0-Key-Data, Q, 128) |
2789 | | * Q = 384 for FT-EAP-SHA384; the length of the digest generated by H() |
2790 | | * for FT-SAE-EXT-KEY; or otherwise, 256 |
2791 | | */ |
2792 | 0 | if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN) |
2793 | 0 | return -1; |
2794 | 0 | wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-SHA%zu", q * 8); |
2795 | 0 | wpa_hexdump_key(MSG_DEBUG, "FT: XXKey", xxkey, xxkey_len); |
2796 | 0 | wpa_hexdump_ascii(MSG_DEBUG, "FT: SSID", ssid, ssid_len); |
2797 | 0 | wpa_hexdump(MSG_DEBUG, "FT: MDID", mdid, MOBILITY_DOMAIN_ID_LEN); |
2798 | 0 | wpa_hexdump_ascii(MSG_DEBUG, "FT: R0KH-ID", r0kh_id, r0kh_id_len); |
2799 | 0 | wpa_printf(MSG_DEBUG, "FT: S0KH-ID: " MACSTR, MAC2STR(s0kh_id)); |
2800 | 0 | pos = buf; |
2801 | 0 | *pos++ = ssid_len; |
2802 | 0 | os_memcpy(pos, ssid, ssid_len); |
2803 | 0 | pos += ssid_len; |
2804 | 0 | os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN); |
2805 | 0 | pos += MOBILITY_DOMAIN_ID_LEN; |
2806 | 0 | *pos++ = r0kh_id_len; |
2807 | 0 | os_memcpy(pos, r0kh_id, r0kh_id_len); |
2808 | 0 | pos += r0kh_id_len; |
2809 | 0 | os_memcpy(pos, s0kh_id, ETH_ALEN); |
2810 | 0 | pos += ETH_ALEN; |
2811 | |
|
2812 | 0 | res = -1; |
2813 | | #ifdef CONFIG_SHA512 |
2814 | | if (q == SHA512_MAC_LEN) { |
2815 | | if (xxkey_len != SHA512_MAC_LEN) { |
2816 | | wpa_printf(MSG_ERROR, |
2817 | | "FT: Unexpected XXKey length %d (expected %d)", |
2818 | | (int) xxkey_len, SHA512_MAC_LEN); |
2819 | | return -1; |
2820 | | } |
2821 | | res = sha512_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, |
2822 | | r0_key_data, r0_key_data_len); |
2823 | | } |
2824 | | #endif /* CONFIG_SHA512 */ |
2825 | | #ifdef CONFIG_SHA384 |
2826 | | if (q == SHA384_MAC_LEN) { |
2827 | | if (xxkey_len != SHA384_MAC_LEN) { |
2828 | | wpa_printf(MSG_ERROR, |
2829 | | "FT: Unexpected XXKey length %d (expected %d)", |
2830 | | (int) xxkey_len, SHA384_MAC_LEN); |
2831 | | return -1; |
2832 | | } |
2833 | | res = sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, |
2834 | | r0_key_data, r0_key_data_len); |
2835 | | } |
2836 | | #endif /* CONFIG_SHA384 */ |
2837 | 0 | if (q == SHA256_MAC_LEN) { |
2838 | 0 | if (xxkey_len != PMK_LEN) { |
2839 | 0 | wpa_printf(MSG_ERROR, |
2840 | 0 | "FT: Unexpected XXKey length %d (expected %d)", |
2841 | 0 | (int) xxkey_len, PMK_LEN); |
2842 | 0 | return -1; |
2843 | 0 | } |
2844 | 0 | res = sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, |
2845 | 0 | r0_key_data, r0_key_data_len); |
2846 | 0 | } |
2847 | 0 | if (res < 0) |
2848 | 0 | return res; |
2849 | 0 | os_memcpy(pmk_r0, r0_key_data, q); |
2850 | 0 | wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, q); |
2851 | 0 | wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0Name-Salt", &r0_key_data[q], 16); |
2852 | | |
2853 | | /* |
2854 | | * PMKR0Name = Truncate-128(Hash("FT-R0N" || PMK-R0Name-Salt) |
2855 | | */ |
2856 | 0 | addr[0] = (const u8 *) "FT-R0N"; |
2857 | 0 | len[0] = 6; |
2858 | 0 | addr[1] = &r0_key_data[q]; |
2859 | 0 | len[1] = 16; |
2860 | |
|
2861 | 0 | res = -1; |
2862 | | #ifdef CONFIG_SHA512 |
2863 | | if (q == SHA512_MAC_LEN) |
2864 | | res = sha512_vector(2, addr, len, hash); |
2865 | | #endif /* CONFIG_SHA512 */ |
2866 | | #ifdef CONFIG_SHA384 |
2867 | | if (q == SHA384_MAC_LEN) |
2868 | | res = sha384_vector(2, addr, len, hash); |
2869 | | #endif /* CONFIG_SHA384 */ |
2870 | 0 | if (q == SHA256_MAC_LEN) |
2871 | 0 | res = sha256_vector(2, addr, len, hash); |
2872 | 0 | if (res < 0) { |
2873 | 0 | wpa_printf(MSG_DEBUG, |
2874 | 0 | "FT: Failed to derive PMKR0Name (PMK-R0 len %zu)", |
2875 | 0 | q); |
2876 | 0 | return res; |
2877 | 0 | } |
2878 | 0 | os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN); |
2879 | 0 | wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN); |
2880 | 0 | forced_memzero(r0_key_data, sizeof(r0_key_data)); |
2881 | 0 | return 0; |
2882 | 0 | } |
2883 | | |
2884 | | |
2885 | | /** |
2886 | | * wpa_derive_pmk_r1_name - Derive PMKR1Name |
2887 | | * |
2888 | | * IEEE Std 802.11r-2008 - 8.5.1.5.4 |
2889 | | */ |
2890 | | int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, |
2891 | | const u8 *s1kh_id, u8 *pmk_r1_name, |
2892 | | size_t pmk_r1_len) |
2893 | 0 | { |
2894 | 0 | u8 hash[64]; |
2895 | 0 | const u8 *addr[4]; |
2896 | 0 | size_t len[4]; |
2897 | 0 | int res; |
2898 | 0 | const char *title; |
2899 | | |
2900 | | /* |
2901 | | * PMKR1Name = Truncate-128(Hash("FT-R1N" || PMKR0Name || |
2902 | | * R1KH-ID || S1KH-ID)) |
2903 | | */ |
2904 | 0 | addr[0] = (const u8 *) "FT-R1N"; |
2905 | 0 | len[0] = 6; |
2906 | 0 | addr[1] = pmk_r0_name; |
2907 | 0 | len[1] = WPA_PMK_NAME_LEN; |
2908 | 0 | addr[2] = r1kh_id; |
2909 | 0 | len[2] = FT_R1KH_ID_LEN; |
2910 | 0 | addr[3] = s1kh_id; |
2911 | 0 | len[3] = ETH_ALEN; |
2912 | |
|
2913 | 0 | res = -1; |
2914 | | #ifdef CONFIG_SHA512 |
2915 | | if (pmk_r1_len == SHA512_MAC_LEN) { |
2916 | | title = "FT: PMKR1Name (using SHA512)"; |
2917 | | res = sha512_vector(4, addr, len, hash); |
2918 | | } |
2919 | | #endif /* CONFIG_SHA512 */ |
2920 | | #ifdef CONFIG_SHA384 |
2921 | | if (pmk_r1_len == SHA384_MAC_LEN) { |
2922 | | title = "FT: PMKR1Name (using SHA384)"; |
2923 | | res = sha384_vector(4, addr, len, hash); |
2924 | | } |
2925 | | #endif /* CONFIG_SHA384 */ |
2926 | 0 | if (pmk_r1_len == SHA256_MAC_LEN) { |
2927 | 0 | title = "FT: PMKR1Name (using SHA256)"; |
2928 | 0 | res = sha256_vector(4, addr, len, hash); |
2929 | 0 | } |
2930 | 0 | if (res < 0) { |
2931 | 0 | wpa_printf(MSG_DEBUG, |
2932 | 0 | "FT: Failed to derive PMKR1Name (PMK-R1 len %zu)", |
2933 | 0 | pmk_r1_len); |
2934 | 0 | return res; |
2935 | 0 | } |
2936 | 0 | os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN); |
2937 | 0 | wpa_hexdump(MSG_DEBUG, title, pmk_r1_name, WPA_PMK_NAME_LEN); |
2938 | 0 | return 0; |
2939 | 0 | } |
2940 | | |
2941 | | |
2942 | | /** |
2943 | | * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0 |
2944 | | * |
2945 | | * IEEE Std 802.11r-2008 - 8.5.1.5.4 |
2946 | | */ |
2947 | | int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len, |
2948 | | const u8 *pmk_r0_name, |
2949 | | const u8 *r1kh_id, const u8 *s1kh_id, |
2950 | | u8 *pmk_r1, u8 *pmk_r1_name) |
2951 | 0 | { |
2952 | 0 | u8 buf[FT_R1KH_ID_LEN + ETH_ALEN]; |
2953 | 0 | u8 *pos; |
2954 | 0 | int res; |
2955 | | |
2956 | | /* PMK-R1 = KDF-Hash(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */ |
2957 | 0 | wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 using KDF-SHA%zu", |
2958 | 0 | pmk_r0_len * 8); |
2959 | 0 | wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len); |
2960 | 0 | wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", r1kh_id, FT_R1KH_ID_LEN); |
2961 | 0 | wpa_printf(MSG_DEBUG, "FT: S1KH-ID: " MACSTR, MAC2STR(s1kh_id)); |
2962 | 0 | pos = buf; |
2963 | 0 | os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN); |
2964 | 0 | pos += FT_R1KH_ID_LEN; |
2965 | 0 | os_memcpy(pos, s1kh_id, ETH_ALEN); |
2966 | 0 | pos += ETH_ALEN; |
2967 | |
|
2968 | 0 | res = -1; |
2969 | | #ifdef CONFIG_SHA512 |
2970 | | if (pmk_r0_len == SHA512_MAC_LEN) |
2971 | | res = sha512_prf(pmk_r0, pmk_r0_len, "FT-R1", |
2972 | | buf, pos - buf, pmk_r1, pmk_r0_len); |
2973 | | #endif /* CONFIG_SHA512 */ |
2974 | | #ifdef CONFIG_SHA384 |
2975 | | if (pmk_r0_len == SHA384_MAC_LEN) |
2976 | | res = sha384_prf(pmk_r0, pmk_r0_len, "FT-R1", |
2977 | | buf, pos - buf, pmk_r1, pmk_r0_len); |
2978 | | #endif /* CONFIG_SHA384 */ |
2979 | 0 | if (pmk_r0_len == SHA256_MAC_LEN) |
2980 | 0 | res = sha256_prf(pmk_r0, pmk_r0_len, "FT-R1", |
2981 | 0 | buf, pos - buf, pmk_r1, pmk_r0_len); |
2982 | 0 | if (res < 0) { |
2983 | 0 | wpa_printf(MSG_ERROR, "FT: Failed to derive PMK-R1"); |
2984 | 0 | return res; |
2985 | 0 | } |
2986 | 0 | wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r0_len); |
2987 | |
|
2988 | 0 | return wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, |
2989 | 0 | pmk_r1_name, pmk_r0_len); |
2990 | 0 | } |
2991 | | |
2992 | | |
2993 | | /** |
2994 | | * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1 |
2995 | | * |
2996 | | * IEEE Std 802.11r-2008 - 8.5.1.5.5 |
2997 | | */ |
2998 | | int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len, |
2999 | | const u8 *snonce, const u8 *anonce, |
3000 | | const u8 *sta_addr, const u8 *bssid, |
3001 | | const u8 *pmk_r1_name, |
3002 | | struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher, |
3003 | | size_t kdk_len) |
3004 | 0 | { |
3005 | 0 | u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN]; |
3006 | 0 | u8 *pos, hash[32]; |
3007 | 0 | const u8 *addr[6]; |
3008 | 0 | size_t len[6]; |
3009 | 0 | u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN + |
3010 | 0 | WPA_KDK_MAX_LEN]; |
3011 | 0 | size_t ptk_len, offset; |
3012 | 0 | size_t key_len; |
3013 | 0 | int res; |
3014 | |
|
3015 | 0 | if (kdk_len > WPA_KDK_MAX_LEN) { |
3016 | 0 | wpa_printf(MSG_ERROR, |
3017 | 0 | "FT: KDK len=%zu exceeds max supported len", |
3018 | 0 | kdk_len); |
3019 | 0 | return -1; |
3020 | 0 | } |
3021 | | |
3022 | 0 | if (akmp == WPA_KEY_MGMT_FT_SAE_EXT_KEY && |
3023 | 0 | (pmk_r1_len == SHA256_MAC_LEN || pmk_r1_len == SHA384_MAC_LEN || |
3024 | 0 | pmk_r1_len == SHA512_MAC_LEN)) |
3025 | 0 | key_len = pmk_r1_len; |
3026 | 0 | else if (wpa_key_mgmt_sha384(akmp)) |
3027 | 0 | key_len = SHA384_MAC_LEN; |
3028 | 0 | else |
3029 | 0 | key_len = SHA256_MAC_LEN; |
3030 | | |
3031 | | /* |
3032 | | * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || |
3033 | | * BSSID || STA-ADDR) |
3034 | | */ |
3035 | 0 | wpa_printf(MSG_DEBUG, "FT: Derive PTK using KDF-SHA%zu", key_len * 8); |
3036 | 0 | wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len); |
3037 | 0 | wpa_hexdump(MSG_DEBUG, "FT: SNonce", snonce, WPA_NONCE_LEN); |
3038 | 0 | wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN); |
3039 | 0 | wpa_printf(MSG_DEBUG, "FT: BSSID=" MACSTR " STA-ADDR=" MACSTR, |
3040 | 0 | MAC2STR(bssid), MAC2STR(sta_addr)); |
3041 | 0 | pos = buf; |
3042 | 0 | os_memcpy(pos, snonce, WPA_NONCE_LEN); |
3043 | 0 | pos += WPA_NONCE_LEN; |
3044 | 0 | os_memcpy(pos, anonce, WPA_NONCE_LEN); |
3045 | 0 | pos += WPA_NONCE_LEN; |
3046 | 0 | os_memcpy(pos, bssid, ETH_ALEN); |
3047 | 0 | pos += ETH_ALEN; |
3048 | 0 | os_memcpy(pos, sta_addr, ETH_ALEN); |
3049 | 0 | pos += ETH_ALEN; |
3050 | |
|
3051 | 0 | ptk->kck_len = wpa_kck_len(akmp, key_len); |
3052 | 0 | ptk->kck2_len = wpa_kck2_len(akmp); |
3053 | 0 | ptk->kek_len = wpa_kek_len(akmp, key_len, PASN_GROUP_NOT_SPECIFIED); |
3054 | 0 | ptk->kek2_len = wpa_kek2_len(akmp); |
3055 | 0 | ptk->tk_len = wpa_cipher_key_len(cipher); |
3056 | 0 | ptk->kdk_len = kdk_len; |
3057 | 0 | ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len + |
3058 | 0 | ptk->kck2_len + ptk->kek2_len + ptk->kdk_len; |
3059 | |
|
3060 | 0 | res = -1; |
3061 | | #ifdef CONFIG_SHA512 |
3062 | | if (key_len == SHA512_MAC_LEN) { |
3063 | | if (pmk_r1_len != SHA512_MAC_LEN) { |
3064 | | wpa_printf(MSG_ERROR, |
3065 | | "FT: Unexpected PMK-R1 length %d (expected %d)", |
3066 | | (int) pmk_r1_len, SHA512_MAC_LEN); |
3067 | | return -1; |
3068 | | } |
3069 | | res = sha512_prf(pmk_r1, pmk_r1_len, "FT-PTK", |
3070 | | buf, pos - buf, tmp, ptk_len); |
3071 | | } |
3072 | | #endif /* CONFIG_SHA512 */ |
3073 | | #ifdef CONFIG_SHA384 |
3074 | | if (key_len == SHA384_MAC_LEN) { |
3075 | | if (pmk_r1_len != SHA384_MAC_LEN) { |
3076 | | wpa_printf(MSG_ERROR, |
3077 | | "FT: Unexpected PMK-R1 length %d (expected %d)", |
3078 | | (int) pmk_r1_len, SHA384_MAC_LEN); |
3079 | | return -1; |
3080 | | } |
3081 | | res = sha384_prf(pmk_r1, pmk_r1_len, "FT-PTK", |
3082 | | buf, pos - buf, tmp, ptk_len); |
3083 | | } |
3084 | | #endif /* CONFIG_SHA384 */ |
3085 | 0 | if (key_len == SHA256_MAC_LEN) { |
3086 | 0 | if (pmk_r1_len != PMK_LEN) { |
3087 | 0 | wpa_printf(MSG_ERROR, |
3088 | 0 | "FT: Unexpected PMK-R1 length %d (expected %d)", |
3089 | 0 | (int) pmk_r1_len, PMK_LEN); |
3090 | 0 | return -1; |
3091 | 0 | } |
3092 | 0 | res = sha256_prf(pmk_r1, pmk_r1_len, "FT-PTK", |
3093 | 0 | buf, pos - buf, tmp, ptk_len); |
3094 | 0 | } |
3095 | 0 | if (res < 0) |
3096 | 0 | return -1; |
3097 | 0 | wpa_hexdump_key(MSG_DEBUG, "FT: PTK", tmp, ptk_len); |
3098 | | |
3099 | | /* |
3100 | | * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce || |
3101 | | * ANonce || BSSID || STA-ADDR)) |
3102 | | */ |
3103 | 0 | wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN); |
3104 | 0 | addr[0] = pmk_r1_name; |
3105 | 0 | len[0] = WPA_PMK_NAME_LEN; |
3106 | 0 | addr[1] = (const u8 *) "FT-PTKN"; |
3107 | 0 | len[1] = 7; |
3108 | 0 | addr[2] = snonce; |
3109 | 0 | len[2] = WPA_NONCE_LEN; |
3110 | 0 | addr[3] = anonce; |
3111 | 0 | len[3] = WPA_NONCE_LEN; |
3112 | 0 | addr[4] = bssid; |
3113 | 0 | len[4] = ETH_ALEN; |
3114 | 0 | addr[5] = sta_addr; |
3115 | 0 | len[5] = ETH_ALEN; |
3116 | |
|
3117 | 0 | if (sha256_vector(6, addr, len, hash) < 0) |
3118 | 0 | return -1; |
3119 | 0 | os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN); |
3120 | |
|
3121 | 0 | os_memcpy(ptk->kck, tmp, ptk->kck_len); |
3122 | 0 | offset = ptk->kck_len; |
3123 | 0 | os_memcpy(ptk->kek, tmp + offset, ptk->kek_len); |
3124 | 0 | offset += ptk->kek_len; |
3125 | 0 | os_memcpy(ptk->tk, tmp + offset, ptk->tk_len); |
3126 | 0 | offset += ptk->tk_len; |
3127 | 0 | os_memcpy(ptk->kck2, tmp + offset, ptk->kck2_len); |
3128 | 0 | offset += ptk->kck2_len; |
3129 | 0 | os_memcpy(ptk->kek2, tmp + offset, ptk->kek2_len); |
3130 | 0 | offset += ptk->kek2_len; |
3131 | 0 | os_memcpy(ptk->kdk, tmp + offset, ptk->kdk_len); |
3132 | |
|
3133 | 0 | wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len); |
3134 | 0 | wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len); |
3135 | 0 | if (ptk->kck2_len) |
3136 | 0 | wpa_hexdump_key(MSG_DEBUG, "FT: KCK2", |
3137 | 0 | ptk->kck2, ptk->kck2_len); |
3138 | 0 | if (ptk->kek2_len) |
3139 | 0 | wpa_hexdump_key(MSG_DEBUG, "FT: KEK2", |
3140 | 0 | ptk->kek2, ptk->kek2_len); |
3141 | 0 | if (ptk->kdk_len) |
3142 | 0 | wpa_hexdump_key(MSG_DEBUG, "FT: KDK", ptk->kdk, ptk->kdk_len); |
3143 | |
|
3144 | 0 | wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len); |
3145 | 0 | wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); |
3146 | |
|
3147 | 0 | forced_memzero(tmp, sizeof(tmp)); |
3148 | |
|
3149 | 0 | return 0; |
3150 | 0 | } |
3151 | | |
3152 | | #endif /* CONFIG_IEEE80211R */ |
3153 | | |
3154 | | |
3155 | | /** |
3156 | | * rsn_pmkid - Calculate PMK identifier |
3157 | | * @pmk: Pairwise master key |
3158 | | * @pmk_len: Length of pmk in bytes |
3159 | | * @aa: Authenticator address |
3160 | | * @spa: Supplicant address |
3161 | | * @pmkid: Buffer for PMKID |
3162 | | * @akmp: Negotiated key management protocol |
3163 | | * @alg: Hash algorithm |
3164 | | * |
3165 | | * IEEE Std 802.11-2016 - 12.7.1.3 Pairwise key hierarchy |
3166 | | * AKM: 00-0F-AC:3, 00-0F-AC:5, 00-0F-AC:6, 00-0F-AC:14, 00-0F-AC:16 |
3167 | | * PMKID = Truncate-128(HMAC-SHA-256(PMK, "PMK Name" || AA || SPA)) |
3168 | | * AKM: 00-0F-AC:11 |
3169 | | * See rsn_pmkid_suite_b() |
3170 | | * AKM: 00-0F-AC:12 |
3171 | | * See rsn_pmkid_suite_b_192() |
3172 | | * AKM: 00-0F-AC:13, 00-0F-AC:15, 00-0F-AC:17 |
3173 | | * PMKID = Truncate-128(HMAC-SHA-384(PMK, "PMK Name" || AA || SPA)) |
3174 | | * Otherwise: |
3175 | | * PMKID = Truncate-128(HMAC-SHA-1(PMK, "PMK Name" || AA || SPA)) |
3176 | | */ |
3177 | | void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, |
3178 | | u8 *pmkid, int akmp, enum rsn_hash_alg alg) |
3179 | 0 | { |
3180 | 0 | char *title = "PMK Name"; |
3181 | 0 | const u8 *addr[3]; |
3182 | 0 | const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; |
3183 | 0 | unsigned char hash[SHA512_MAC_LEN]; |
3184 | |
|
3185 | 0 | addr[0] = (u8 *) title; |
3186 | 0 | addr[1] = aa; |
3187 | 0 | addr[2] = spa; |
3188 | |
|
3189 | 0 | if (0) { |
3190 | | #ifdef CONFIG_SHA512 |
3191 | | } else if (alg == RSN_HASH_SHA512) { |
3192 | | wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-512"); |
3193 | | hmac_sha512_vector(pmk, pmk_len, 3, addr, len, hash); |
3194 | | #endif /* CONFIG_SHA512 */ |
3195 | | #if defined(CONFIG_FILS) || defined(CONFIG_SHA384) |
3196 | | } else if (alg == RSN_HASH_SHA384 || wpa_key_mgmt_sha384(akmp)) { |
3197 | | wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-384"); |
3198 | | hmac_sha384_vector(pmk, pmk_len, 3, addr, len, hash); |
3199 | | #endif /* CONFIG_FILS || CONFIG_SHA384 */ |
3200 | 0 | } else if (alg == RSN_HASH_SHA256 || wpa_key_mgmt_sha256(akmp)) { |
3201 | 0 | wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-256"); |
3202 | 0 | hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); |
3203 | 0 | } else { |
3204 | 0 | wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-1"); |
3205 | 0 | hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash); |
3206 | 0 | } |
3207 | 0 | wpa_hexdump(MSG_DEBUG, "RSN: Derived PMKID", hash, PMKID_LEN); |
3208 | 0 | os_memcpy(pmkid, hash, PMKID_LEN); |
3209 | 0 | } |
3210 | | |
3211 | | |
3212 | | #ifdef CONFIG_SUITEB |
3213 | | /** |
3214 | | * rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM |
3215 | | * @kck: Key confirmation key |
3216 | | * @kck_len: Length of kck in bytes |
3217 | | * @aa: Authenticator address |
3218 | | * @spa: Supplicant address |
3219 | | * @pmkid: Buffer for PMKID |
3220 | | * Returns: 0 on success, -1 on failure |
3221 | | * |
3222 | | * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy |
3223 | | * PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA)) |
3224 | | */ |
3225 | | int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa, |
3226 | | const u8 *spa, u8 *pmkid) |
3227 | 0 | { |
3228 | 0 | char *title = "PMK Name"; |
3229 | 0 | const u8 *addr[3]; |
3230 | 0 | const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; |
3231 | 0 | unsigned char hash[SHA256_MAC_LEN]; |
3232 | |
|
3233 | 0 | addr[0] = (u8 *) title; |
3234 | 0 | addr[1] = aa; |
3235 | 0 | addr[2] = spa; |
3236 | |
|
3237 | 0 | if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0) |
3238 | 0 | return -1; |
3239 | 0 | os_memcpy(pmkid, hash, PMKID_LEN); |
3240 | 0 | return 0; |
3241 | 0 | } |
3242 | | #endif /* CONFIG_SUITEB */ |
3243 | | |
3244 | | |
3245 | | #ifdef CONFIG_SUITEB192 |
3246 | | /** |
3247 | | * rsn_pmkid_suite_b_192 - Calculate PMK identifier for Suite B AKM |
3248 | | * @kck: Key confirmation key |
3249 | | * @kck_len: Length of kck in bytes |
3250 | | * @aa: Authenticator address |
3251 | | * @spa: Supplicant address |
3252 | | * @pmkid: Buffer for PMKID |
3253 | | * Returns: 0 on success, -1 on failure |
3254 | | * |
3255 | | * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy |
3256 | | * PMKID = Truncate(HMAC-SHA-384(KCK, "PMK Name" || AA || SPA)) |
3257 | | */ |
3258 | | int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa, |
3259 | | const u8 *spa, u8 *pmkid) |
3260 | | { |
3261 | | char *title = "PMK Name"; |
3262 | | const u8 *addr[3]; |
3263 | | const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; |
3264 | | unsigned char hash[SHA384_MAC_LEN]; |
3265 | | |
3266 | | addr[0] = (u8 *) title; |
3267 | | addr[1] = aa; |
3268 | | addr[2] = spa; |
3269 | | |
3270 | | if (hmac_sha384_vector(kck, kck_len, 3, addr, len, hash) < 0) |
3271 | | return -1; |
3272 | | os_memcpy(pmkid, hash, PMKID_LEN); |
3273 | | return 0; |
3274 | | } |
3275 | | #endif /* CONFIG_SUITEB192 */ |
3276 | | |
3277 | | |
3278 | | #ifdef CONFIG_PMKSA_PRIVACY |
3279 | | /** |
3280 | | * rsn_pmkid_privacy - Calculate a new PMKID for PMKSA caching privacy |
3281 | | * @pmkid_anonce: Authenticator nonce (ANonce) |
3282 | | * @pmkid_snonce: Supplicant nonce (SNonce) |
3283 | | * @akmp: Negotiated key management protocol |
3284 | | * @pmk_len: PMK length in bytes |
3285 | | * @pmkid: Buffer for returning PMKID |
3286 | | * Returns: 0 on success, -1 on failure |
3287 | | * |
3288 | | * IEEE P802.11bi/D4.0, 12.16.7.2 (PMKID privacy) |
3289 | | * PMKID = Truncate-128(Hash("PMK Name" || PMKIDANonce || PMKIDSNonce)) |
3290 | | */ |
3291 | | int rsn_pmkid_privacy(const u8 *pmkid_anonce, const u8 *pmkid_snonce, |
3292 | | int akmp, size_t pmk_len, u8 *pmkid) |
3293 | | { |
3294 | | const char *label = "PMK Name"; |
3295 | | const u8 *addr[3]; |
3296 | | const size_t len[3] = { 8, NONCE_LEN, NONCE_LEN }; |
3297 | | unsigned char hash[SHA512_MAC_LEN]; |
3298 | | |
3299 | | wpa_hexdump(MSG_DEBUG, "PMKID privacy: PMKIDANonce", |
3300 | | pmkid_anonce, NONCE_LEN); |
3301 | | wpa_hexdump(MSG_DEBUG, "PMKID privacy: PMKIDSNonce", |
3302 | | pmkid_snonce, NONCE_LEN); |
3303 | | |
3304 | | addr[0] = (const u8 *) label; |
3305 | | addr[1] = pmkid_anonce; |
3306 | | addr[2] = pmkid_snonce; |
3307 | | |
3308 | | if (0) { |
3309 | | #if defined(CONFIG_FILS) || defined(CONFIG_SHA384) |
3310 | | } else if (wpa_key_mgmt_sha384(akmp)) { |
3311 | | wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using SHA-384"); |
3312 | | if (sha384_vector(3, addr, len, hash) < 0) |
3313 | | return -1; |
3314 | | #endif /* CONFIG_FILS || CONFIG_SHA384 */ |
3315 | | #ifdef CONFIG_SAE |
3316 | | } else if (wpa_key_mgmt_sae_ext_key(akmp)) { |
3317 | | if (pmk_len == 64) { |
3318 | | if (sha512_vector(3, addr, len, hash) < 0) |
3319 | | return -1; |
3320 | | } else if (pmk_len == 48) { |
3321 | | if (sha384_vector(3, addr, len, hash) < 0) |
3322 | | return -1; |
3323 | | } else { |
3324 | | if (sha256_vector(3, addr, len, hash) < 0) |
3325 | | return -1; |
3326 | | } |
3327 | | #endif /* CONFIG_SAE */ |
3328 | | } else { |
3329 | | wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using SHA-256"); |
3330 | | if (sha256_vector(3, addr, len, hash) < 0) |
3331 | | return -1; |
3332 | | } |
3333 | | |
3334 | | wpa_hexdump(MSG_DEBUG, "PMKID privacy: new PMKID", hash, PMKID_LEN); |
3335 | | os_memcpy(pmkid, hash, PMKID_LEN); |
3336 | | |
3337 | | return 0; |
3338 | | } |
3339 | | #endif /* CONFIG_PMKSA_PRIVACY */ |
3340 | | |
3341 | | |
3342 | | /** |
3343 | | * wpa_cipher_txt - Convert cipher suite to a text string |
3344 | | * @cipher: Cipher suite (WPA_CIPHER_* enum) |
3345 | | * Returns: Pointer to a text string of the cipher suite name |
3346 | | */ |
3347 | | const char * wpa_cipher_txt(int cipher) |
3348 | 0 | { |
3349 | 0 | switch (cipher) { |
3350 | 0 | case WPA_CIPHER_NONE: |
3351 | 0 | return "NONE"; |
3352 | | #ifdef CONFIG_WEP |
3353 | | case WPA_CIPHER_WEP40: |
3354 | | return "WEP-40"; |
3355 | | case WPA_CIPHER_WEP104: |
3356 | | return "WEP-104"; |
3357 | | #endif /* CONFIG_WEP */ |
3358 | 0 | case WPA_CIPHER_TKIP: |
3359 | 0 | return "TKIP"; |
3360 | 0 | case WPA_CIPHER_CCMP: |
3361 | 0 | return "CCMP"; |
3362 | 0 | case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP: |
3363 | 0 | return "CCMP+TKIP"; |
3364 | 0 | case WPA_CIPHER_GCMP: |
3365 | 0 | return "GCMP"; |
3366 | 0 | case WPA_CIPHER_GCMP_256: |
3367 | 0 | return "GCMP-256"; |
3368 | 0 | case WPA_CIPHER_CCMP_256: |
3369 | 0 | return "CCMP-256"; |
3370 | 0 | case WPA_CIPHER_AES_128_CMAC: |
3371 | 0 | return "BIP"; |
3372 | 0 | case WPA_CIPHER_BIP_GMAC_128: |
3373 | 0 | return "BIP-GMAC-128"; |
3374 | 0 | case WPA_CIPHER_BIP_GMAC_256: |
3375 | 0 | return "BIP-GMAC-256"; |
3376 | 0 | case WPA_CIPHER_BIP_CMAC_256: |
3377 | 0 | return "BIP-CMAC-256"; |
3378 | 0 | case WPA_CIPHER_GTK_NOT_USED: |
3379 | 0 | return "GTK_NOT_USED"; |
3380 | 0 | default: |
3381 | 0 | return "UNKNOWN"; |
3382 | 0 | } |
3383 | 0 | } |
3384 | | |
3385 | | |
3386 | | /** |
3387 | | * wpa_key_mgmt_txt - Convert key management suite to a text string |
3388 | | * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum) |
3389 | | * @proto: WPA/WPA2 version (WPA_PROTO_*) |
3390 | | * Returns: Pointer to a text string of the key management suite name |
3391 | | */ |
3392 | | const char * wpa_key_mgmt_txt(int key_mgmt, int proto) |
3393 | 0 | { |
3394 | 0 | switch (key_mgmt) { |
3395 | 0 | case WPA_KEY_MGMT_IEEE8021X: |
3396 | 0 | if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) |
3397 | 0 | return "WPA2+WPA/IEEE 802.1X/EAP"; |
3398 | 0 | return proto == WPA_PROTO_RSN ? |
3399 | 0 | "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP"; |
3400 | 0 | case WPA_KEY_MGMT_PSK: |
3401 | 0 | if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) |
3402 | 0 | return "WPA2-PSK+WPA-PSK"; |
3403 | 0 | return proto == WPA_PROTO_RSN ? |
3404 | 0 | "WPA2-PSK" : "WPA-PSK"; |
3405 | 0 | case WPA_KEY_MGMT_NONE: |
3406 | 0 | return "NONE"; |
3407 | 0 | case WPA_KEY_MGMT_WPA_NONE: |
3408 | 0 | return "WPA-NONE"; |
3409 | 0 | case WPA_KEY_MGMT_IEEE8021X_NO_WPA: |
3410 | 0 | return "IEEE 802.1X (no WPA)"; |
3411 | 0 | #ifdef CONFIG_IEEE80211R |
3412 | 0 | case WPA_KEY_MGMT_FT_IEEE8021X: |
3413 | 0 | return "FT-EAP"; |
3414 | 0 | case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: |
3415 | 0 | return "FT-EAP-SHA384"; |
3416 | 0 | case WPA_KEY_MGMT_FT_PSK: |
3417 | 0 | return "FT-PSK"; |
3418 | 0 | #endif /* CONFIG_IEEE80211R */ |
3419 | 0 | case WPA_KEY_MGMT_IEEE8021X_SHA256: |
3420 | 0 | return "WPA2-EAP-SHA256"; |
3421 | 0 | case WPA_KEY_MGMT_PSK_SHA256: |
3422 | 0 | return "WPA2-PSK-SHA256"; |
3423 | 0 | case WPA_KEY_MGMT_WPS: |
3424 | 0 | return "WPS"; |
3425 | 0 | case WPA_KEY_MGMT_SAE: |
3426 | 0 | return "SAE"; |
3427 | 0 | case WPA_KEY_MGMT_SAE_EXT_KEY: |
3428 | 0 | return "SAE-EXT-KEY"; |
3429 | 0 | case WPA_KEY_MGMT_FT_SAE: |
3430 | 0 | return "FT-SAE"; |
3431 | 0 | case WPA_KEY_MGMT_FT_SAE_EXT_KEY: |
3432 | 0 | return "FT-SAE-EXT-KEY"; |
3433 | 0 | case WPA_KEY_MGMT_IEEE8021X_SUITE_B: |
3434 | 0 | return "WPA2-EAP-SUITE-B"; |
3435 | 0 | case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: |
3436 | 0 | return "WPA2-EAP-SUITE-B-192"; |
3437 | 0 | case WPA_KEY_MGMT_FILS_SHA256: |
3438 | 0 | return "FILS-SHA256"; |
3439 | 0 | case WPA_KEY_MGMT_FILS_SHA384: |
3440 | 0 | return "FILS-SHA384"; |
3441 | 0 | case WPA_KEY_MGMT_FT_FILS_SHA256: |
3442 | 0 | return "FT-FILS-SHA256"; |
3443 | 0 | case WPA_KEY_MGMT_FT_FILS_SHA384: |
3444 | 0 | return "FT-FILS-SHA384"; |
3445 | 0 | case WPA_KEY_MGMT_OWE: |
3446 | 0 | return "OWE"; |
3447 | 0 | case WPA_KEY_MGMT_DPP: |
3448 | 0 | return "DPP"; |
3449 | 0 | case WPA_KEY_MGMT_PASN: |
3450 | 0 | return "PASN"; |
3451 | 0 | case WPA_KEY_MGMT_IEEE8021X_SHA384: |
3452 | 0 | return "WPA2-EAP-SHA384"; |
3453 | 0 | case WPA_KEY_MGMT_EPPKE: |
3454 | 0 | return "EPPKE"; |
3455 | 0 | case WPA_KEY_MGMT_PQC_8021X: |
3456 | 0 | return "EAP-PQC"; |
3457 | 0 | case WPA_KEY_MGMT_FT_PQC_8021X: |
3458 | 0 | return "FT-EAP-PQC"; |
3459 | 0 | default: |
3460 | 0 | return "UNKNOWN"; |
3461 | 0 | } |
3462 | 0 | } |
3463 | | |
3464 | | |
3465 | | u32 wpa_akm_to_suite(int akm) |
3466 | 0 | { |
3467 | 0 | if (akm & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) |
3468 | 0 | return RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384; |
3469 | 0 | if (akm & WPA_KEY_MGMT_FT_IEEE8021X) |
3470 | 0 | return RSN_AUTH_KEY_MGMT_FT_802_1X; |
3471 | 0 | if (akm & WPA_KEY_MGMT_FT_PSK) |
3472 | 0 | return RSN_AUTH_KEY_MGMT_FT_PSK; |
3473 | 0 | if (akm & WPA_KEY_MGMT_IEEE8021X_SHA384) |
3474 | 0 | return RSN_AUTH_KEY_MGMT_802_1X_SHA384; |
3475 | 0 | if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256) |
3476 | 0 | return RSN_AUTH_KEY_MGMT_802_1X_SHA256; |
3477 | 0 | if (akm & WPA_KEY_MGMT_IEEE8021X) |
3478 | 0 | return RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; |
3479 | 0 | if (akm & WPA_KEY_MGMT_PSK_SHA256) |
3480 | 0 | return RSN_AUTH_KEY_MGMT_PSK_SHA256; |
3481 | 0 | if (akm & WPA_KEY_MGMT_PSK) |
3482 | 0 | return RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; |
3483 | 0 | if (akm & WPA_KEY_MGMT_CCKM) |
3484 | 0 | return RSN_AUTH_KEY_MGMT_CCKM; |
3485 | 0 | if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B) |
3486 | 0 | return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B; |
3487 | 0 | if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) |
3488 | 0 | return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192; |
3489 | 0 | if (akm & WPA_KEY_MGMT_FILS_SHA256) |
3490 | 0 | return RSN_AUTH_KEY_MGMT_FILS_SHA256; |
3491 | 0 | if (akm & WPA_KEY_MGMT_FILS_SHA384) |
3492 | 0 | return RSN_AUTH_KEY_MGMT_FILS_SHA384; |
3493 | 0 | if (akm & WPA_KEY_MGMT_FT_FILS_SHA256) |
3494 | 0 | return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256; |
3495 | 0 | if (akm & WPA_KEY_MGMT_FT_FILS_SHA384) |
3496 | 0 | return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384; |
3497 | 0 | if (akm & WPA_KEY_MGMT_SAE) |
3498 | 0 | return RSN_AUTH_KEY_MGMT_SAE; |
3499 | 0 | if (akm & WPA_KEY_MGMT_SAE_EXT_KEY) |
3500 | 0 | return RSN_AUTH_KEY_MGMT_SAE_EXT_KEY; |
3501 | 0 | if (akm & WPA_KEY_MGMT_FT_SAE) |
3502 | 0 | return RSN_AUTH_KEY_MGMT_FT_SAE; |
3503 | 0 | if (akm & WPA_KEY_MGMT_FT_SAE_EXT_KEY) |
3504 | 0 | return RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY; |
3505 | 0 | if (akm & WPA_KEY_MGMT_OWE) |
3506 | 0 | return RSN_AUTH_KEY_MGMT_OWE; |
3507 | 0 | if (akm & WPA_KEY_MGMT_DPP) |
3508 | 0 | return RSN_AUTH_KEY_MGMT_DPP; |
3509 | | #ifdef CONFIG_PASN |
3510 | | if (akm & WPA_KEY_MGMT_PASN) |
3511 | | return RSN_AUTH_KEY_MGMT_PASN; |
3512 | | #endif /* CONFIG_PASN */ |
3513 | 0 | if (akm & WPA_KEY_MGMT_EPPKE) |
3514 | 0 | return RSN_AUTH_KEY_MGMT_EPPKE; |
3515 | 0 | if (akm & WPA_KEY_MGMT_FT_PQC_8021X) |
3516 | 0 | return RSN_AUTH_KEY_MGMT_FT_802_1X_PQC; |
3517 | 0 | if (akm & WPA_KEY_MGMT_PQC_8021X) |
3518 | 0 | return RSN_AUTH_KEY_MGMT_802_1X_PQC; |
3519 | 0 | return 0; |
3520 | 0 | } |
3521 | | |
3522 | | |
3523 | | int wpa_compare_rsn_ie(int ft_initial_assoc, |
3524 | | const u8 *ie1, size_t ie1len, |
3525 | | const u8 *ie2, size_t ie2len) |
3526 | 0 | { |
3527 | 0 | if (ie1 == NULL || ie2 == NULL) |
3528 | 0 | return -1; |
3529 | | |
3530 | 0 | if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0) |
3531 | 0 | return 0; /* identical IEs */ |
3532 | | |
3533 | 0 | #ifdef CONFIG_IEEE80211R |
3534 | 0 | if (ft_initial_assoc) { |
3535 | 0 | struct wpa_ie_data ie1d, ie2d; |
3536 | | /* |
3537 | | * The PMKID-List in RSN IE is different between Beacon/Probe |
3538 | | * Response/(Re)Association Request frames and EAPOL-Key |
3539 | | * messages in FT initial mobility domain association. Allow |
3540 | | * for this, but verify that other parts of the RSN IEs are |
3541 | | * identical. |
3542 | | */ |
3543 | 0 | if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 || |
3544 | 0 | wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0) |
3545 | 0 | return -1; |
3546 | 0 | if (ie1d.proto == ie2d.proto && |
3547 | 0 | ie1d.pairwise_cipher == ie2d.pairwise_cipher && |
3548 | 0 | ie1d.group_cipher == ie2d.group_cipher && |
3549 | 0 | ie1d.key_mgmt == ie2d.key_mgmt && |
3550 | 0 | ie1d.capabilities == ie2d.capabilities && |
3551 | 0 | ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher) |
3552 | 0 | return 0; |
3553 | 0 | } |
3554 | 0 | #endif /* CONFIG_IEEE80211R */ |
3555 | | |
3556 | 0 | return -1; |
3557 | 0 | } |
3558 | | |
3559 | | |
3560 | | /** |
3561 | | * wpa_compare_rsn_ie_params - Compare RSN IE parameters |
3562 | | * @rsne1: Pointer to first RSNE (with element ID and length) |
3563 | | * @rsne1_len: Length of the first RSNE |
3564 | | * @rsnee2: Pointer to second RSNE (with element ID and length) |
3565 | | * @rsne2_len: Length of the second RSNE |
3566 | | * @pqc_sec_prof: Whether a PQC security profile is being used |
3567 | | * Returns: 0 if parameters match, -1 otherwise |
3568 | | * |
3569 | | * Compare the security parameters (proto, ciphers, key_mgmt) |
3570 | | * of two RSN IEs. |
3571 | | */ |
3572 | | int wpa_compare_rsne_params(const u8 *rsne1, size_t rsne1_len, |
3573 | | const u8 *rsne2, size_t rsne2_len, |
3574 | | bool pqc_sec_prof) |
3575 | 0 | { |
3576 | 0 | struct wpa_ie_data rsn1, rsn2; |
3577 | |
|
3578 | 0 | if (!rsne1 || !rsne2) |
3579 | 0 | return -1; |
3580 | | |
3581 | 0 | if (wpa_parse_wpa_ie_rsn(rsne1, rsne1_len, &rsn1) < 0 || |
3582 | 0 | wpa_parse_wpa_ie_rsn(rsne2, rsne2_len, &rsn2) < 0) |
3583 | 0 | return -1; |
3584 | | |
3585 | 0 | if (pqc_sec_prof) { |
3586 | | /* PQC AKMs are not required to be included in the RSNE, so mask |
3587 | | * them out from the comparison below.*/ |
3588 | 0 | rsn1.key_mgmt &= ~(WPA_KEY_MGMT_PQC_8021X | |
3589 | 0 | WPA_KEY_MGMT_FT_PQC_8021X); |
3590 | 0 | rsn2.key_mgmt &= ~(WPA_KEY_MGMT_PQC_8021X | |
3591 | 0 | WPA_KEY_MGMT_FT_PQC_8021X); |
3592 | 0 | } |
3593 | |
|
3594 | 0 | if (rsn1.proto == rsn2.proto && |
3595 | 0 | rsn1.pairwise_cipher == rsn2.pairwise_cipher && |
3596 | 0 | rsn1.key_mgmt == rsn2.key_mgmt) |
3597 | 0 | return 0; |
3598 | | |
3599 | 0 | return -1; |
3600 | 0 | } |
3601 | | |
3602 | | |
3603 | | int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid, bool replace) |
3604 | 0 | { |
3605 | 0 | u8 *start, *end, *rpos, *rend; |
3606 | 0 | int added = 0; |
3607 | |
|
3608 | 0 | start = ies; |
3609 | 0 | end = ies + *ies_len; |
3610 | |
|
3611 | 0 | while (start < end) { |
3612 | 0 | if (*start == WLAN_EID_RSN) |
3613 | 0 | break; |
3614 | 0 | start += 2 + start[1]; |
3615 | 0 | } |
3616 | 0 | if (start >= end) { |
3617 | 0 | wpa_printf(MSG_ERROR, "RSN: Could not find RSNE in IEs data"); |
3618 | 0 | return -1; |
3619 | 0 | } |
3620 | 0 | wpa_hexdump(MSG_DEBUG, "RSN: RSNE before modification", |
3621 | 0 | start, 2 + start[1]); |
3622 | | |
3623 | | /* Find start of PMKID-Count */ |
3624 | 0 | rpos = start + 2; |
3625 | 0 | rend = rpos + start[1]; |
3626 | | |
3627 | | /* Skip Version and Group Data Cipher Suite */ |
3628 | 0 | rpos += 2 + 4; |
3629 | | /* Skip Pairwise Cipher Suite Count and List */ |
3630 | 0 | rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; |
3631 | | /* Skip AKM Suite Count and List */ |
3632 | 0 | rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; |
3633 | |
|
3634 | 0 | if (rpos == rend) { |
3635 | | /* Add RSN Capabilities */ |
3636 | 0 | os_memmove(rpos + 2, rpos, end - rpos); |
3637 | 0 | *rpos++ = 0; |
3638 | 0 | *rpos++ = 0; |
3639 | 0 | added += 2; |
3640 | 0 | start[1] += 2; |
3641 | 0 | rend = rpos; |
3642 | 0 | } else { |
3643 | | /* Skip RSN Capabilities */ |
3644 | 0 | rpos += 2; |
3645 | 0 | if (rpos > rend) { |
3646 | 0 | wpa_printf(MSG_ERROR, |
3647 | 0 | "RSN: Could not parse RSNE in IEs data"); |
3648 | 0 | return -1; |
3649 | 0 | } |
3650 | 0 | } |
3651 | | |
3652 | 0 | if (rpos == rend) { |
3653 | | /* No PMKID-Count field included; add it */ |
3654 | 0 | os_memmove(rpos + 2 + PMKID_LEN, rpos, end + added - rpos); |
3655 | 0 | WPA_PUT_LE16(rpos, 1); |
3656 | 0 | rpos += 2; |
3657 | 0 | os_memcpy(rpos, pmkid, PMKID_LEN); |
3658 | 0 | added += 2 + PMKID_LEN; |
3659 | 0 | start[1] += 2 + PMKID_LEN; |
3660 | 0 | } else { |
3661 | 0 | u16 num_pmkid; |
3662 | |
|
3663 | 0 | if (rend - rpos < 2) |
3664 | 0 | return -1; |
3665 | 0 | num_pmkid = WPA_GET_LE16(rpos); |
3666 | 0 | if (num_pmkid * PMKID_LEN > rend - rpos - 2) |
3667 | 0 | return -1; |
3668 | | /* PMKID-Count was included; use it */ |
3669 | 0 | if (replace && num_pmkid != 0) { |
3670 | 0 | u8 *after; |
3671 | | |
3672 | | /* |
3673 | | * PMKID may have been included in RSN IE in |
3674 | | * (Re)Association Request frame, so remove the old |
3675 | | * PMKID(s) first before adding the new one. |
3676 | | */ |
3677 | 0 | wpa_printf(MSG_DEBUG, |
3678 | 0 | "RSN: Remove %u old PMKID(s) from RSNE", |
3679 | 0 | num_pmkid); |
3680 | 0 | after = rpos + 2 + num_pmkid * PMKID_LEN; |
3681 | 0 | os_memmove(rpos + 2, after, end - after); |
3682 | 0 | start[1] -= num_pmkid * PMKID_LEN; |
3683 | 0 | added -= num_pmkid * PMKID_LEN; |
3684 | 0 | num_pmkid = 0; |
3685 | 0 | } |
3686 | 0 | WPA_PUT_LE16(rpos, num_pmkid + 1); |
3687 | 0 | rpos += 2; |
3688 | 0 | os_memmove(rpos + PMKID_LEN, rpos, end + added - rpos); |
3689 | 0 | os_memcpy(rpos, pmkid, PMKID_LEN); |
3690 | 0 | added += PMKID_LEN; |
3691 | 0 | start[1] += PMKID_LEN; |
3692 | 0 | } |
3693 | | |
3694 | 0 | wpa_hexdump(MSG_DEBUG, "RSN: RSNE after modification (PMKID inserted)", |
3695 | 0 | start, 2 + start[1]); |
3696 | |
|
3697 | 0 | *ies_len += added; |
3698 | |
|
3699 | 0 | return 0; |
3700 | 0 | } |
3701 | | |
3702 | | |
3703 | | int wpa_cipher_key_len(int cipher) |
3704 | 1.22k | { |
3705 | 1.22k | switch (cipher) { |
3706 | 0 | case WPA_CIPHER_CCMP_256: |
3707 | 0 | case WPA_CIPHER_GCMP_256: |
3708 | 0 | case WPA_CIPHER_BIP_GMAC_256: |
3709 | 0 | case WPA_CIPHER_BIP_CMAC_256: |
3710 | 0 | return 32; |
3711 | 1.22k | case WPA_CIPHER_CCMP: |
3712 | 1.22k | case WPA_CIPHER_GCMP: |
3713 | 1.22k | case WPA_CIPHER_AES_128_CMAC: |
3714 | 1.22k | case WPA_CIPHER_BIP_GMAC_128: |
3715 | 1.22k | return 16; |
3716 | 0 | case WPA_CIPHER_TKIP: |
3717 | 0 | return 32; |
3718 | 0 | default: |
3719 | 0 | return 0; |
3720 | 1.22k | } |
3721 | 1.22k | } |
3722 | | |
3723 | | |
3724 | | int wpa_cipher_rsc_len(int cipher) |
3725 | 0 | { |
3726 | 0 | switch (cipher) { |
3727 | 0 | case WPA_CIPHER_CCMP_256: |
3728 | 0 | case WPA_CIPHER_GCMP_256: |
3729 | 0 | case WPA_CIPHER_CCMP: |
3730 | 0 | case WPA_CIPHER_GCMP: |
3731 | 0 | case WPA_CIPHER_TKIP: |
3732 | 0 | return 6; |
3733 | 0 | default: |
3734 | 0 | return 0; |
3735 | 0 | } |
3736 | 0 | } |
3737 | | |
3738 | | |
3739 | | enum wpa_alg wpa_cipher_to_alg(int cipher) |
3740 | 0 | { |
3741 | 0 | switch (cipher) { |
3742 | 0 | case WPA_CIPHER_CCMP_256: |
3743 | 0 | return WPA_ALG_CCMP_256; |
3744 | 0 | case WPA_CIPHER_GCMP_256: |
3745 | 0 | return WPA_ALG_GCMP_256; |
3746 | 0 | case WPA_CIPHER_CCMP: |
3747 | 0 | return WPA_ALG_CCMP; |
3748 | 0 | case WPA_CIPHER_GCMP: |
3749 | 0 | return WPA_ALG_GCMP; |
3750 | 0 | case WPA_CIPHER_TKIP: |
3751 | 0 | return WPA_ALG_TKIP; |
3752 | 0 | case WPA_CIPHER_AES_128_CMAC: |
3753 | 0 | return WPA_ALG_BIP_CMAC_128; |
3754 | 0 | case WPA_CIPHER_BIP_GMAC_128: |
3755 | 0 | return WPA_ALG_BIP_GMAC_128; |
3756 | 0 | case WPA_CIPHER_BIP_GMAC_256: |
3757 | 0 | return WPA_ALG_BIP_GMAC_256; |
3758 | 0 | case WPA_CIPHER_BIP_CMAC_256: |
3759 | 0 | return WPA_ALG_BIP_CMAC_256; |
3760 | 0 | default: |
3761 | 0 | return WPA_ALG_NONE; |
3762 | 0 | } |
3763 | 0 | } |
3764 | | |
3765 | | |
3766 | | int wpa_cipher_valid_pairwise(int cipher) |
3767 | 1.98k | { |
3768 | | #ifdef CONFIG_NO_TKIP |
3769 | | return cipher == WPA_CIPHER_CCMP_256 || |
3770 | | cipher == WPA_CIPHER_GCMP_256 || |
3771 | | cipher == WPA_CIPHER_CCMP || |
3772 | | cipher == WPA_CIPHER_GCMP; |
3773 | | #else /* CONFIG_NO_TKIP */ |
3774 | 1.98k | return cipher == WPA_CIPHER_CCMP_256 || |
3775 | 1.98k | cipher == WPA_CIPHER_GCMP_256 || |
3776 | 1.98k | cipher == WPA_CIPHER_CCMP || |
3777 | 1.98k | cipher == WPA_CIPHER_GCMP || |
3778 | 0 | cipher == WPA_CIPHER_TKIP; |
3779 | 1.98k | #endif /* CONFIG_NO_TKIP */ |
3780 | 1.98k | } |
3781 | | |
3782 | | |
3783 | | u32 wpa_cipher_to_suite(int proto, int cipher) |
3784 | 3.97k | { |
3785 | 3.97k | if (cipher & WPA_CIPHER_CCMP_256) |
3786 | 0 | return RSN_CIPHER_SUITE_CCMP_256; |
3787 | 3.97k | if (cipher & WPA_CIPHER_GCMP_256) |
3788 | 0 | return RSN_CIPHER_SUITE_GCMP_256; |
3789 | 3.97k | if (cipher & WPA_CIPHER_CCMP) |
3790 | 3.97k | return (proto == WPA_PROTO_RSN ? |
3791 | 3.97k | RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP); |
3792 | 0 | if (cipher & WPA_CIPHER_GCMP) |
3793 | 0 | return RSN_CIPHER_SUITE_GCMP; |
3794 | 0 | if (cipher & WPA_CIPHER_TKIP) |
3795 | 0 | return (proto == WPA_PROTO_RSN ? |
3796 | 0 | RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP); |
3797 | 0 | if (cipher & WPA_CIPHER_NONE) |
3798 | 0 | return (proto == WPA_PROTO_RSN ? |
3799 | 0 | RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); |
3800 | 0 | if (cipher & WPA_CIPHER_GTK_NOT_USED) |
3801 | 0 | return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED; |
3802 | 0 | if (cipher & WPA_CIPHER_AES_128_CMAC) |
3803 | 0 | return RSN_CIPHER_SUITE_AES_128_CMAC; |
3804 | 0 | if (cipher & WPA_CIPHER_BIP_GMAC_128) |
3805 | 0 | return RSN_CIPHER_SUITE_BIP_GMAC_128; |
3806 | 0 | if (cipher & WPA_CIPHER_BIP_GMAC_256) |
3807 | 0 | return RSN_CIPHER_SUITE_BIP_GMAC_256; |
3808 | 0 | if (cipher & WPA_CIPHER_BIP_CMAC_256) |
3809 | 0 | return RSN_CIPHER_SUITE_BIP_CMAC_256; |
3810 | 0 | return 0; |
3811 | 0 | } |
3812 | | |
3813 | | |
3814 | | int rsn_cipher_put_suites(u8 *start, int ciphers) |
3815 | 0 | { |
3816 | 0 | u8 *pos = start; |
3817 | |
|
3818 | 0 | if (ciphers & WPA_CIPHER_CCMP_256) { |
3819 | 0 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256); |
3820 | 0 | pos += RSN_SELECTOR_LEN; |
3821 | 0 | } |
3822 | 0 | if (ciphers & WPA_CIPHER_GCMP_256) { |
3823 | 0 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256); |
3824 | 0 | pos += RSN_SELECTOR_LEN; |
3825 | 0 | } |
3826 | 0 | if (ciphers & WPA_CIPHER_CCMP) { |
3827 | 0 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); |
3828 | 0 | pos += RSN_SELECTOR_LEN; |
3829 | 0 | } |
3830 | 0 | if (ciphers & WPA_CIPHER_GCMP) { |
3831 | 0 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP); |
3832 | 0 | pos += RSN_SELECTOR_LEN; |
3833 | 0 | } |
3834 | 0 | if (ciphers & WPA_CIPHER_TKIP) { |
3835 | 0 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); |
3836 | 0 | pos += RSN_SELECTOR_LEN; |
3837 | 0 | } |
3838 | 0 | if (ciphers & WPA_CIPHER_NONE) { |
3839 | 0 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); |
3840 | 0 | pos += RSN_SELECTOR_LEN; |
3841 | 0 | } |
3842 | |
|
3843 | 0 | return (pos - start) / RSN_SELECTOR_LEN; |
3844 | 0 | } |
3845 | | |
3846 | | |
3847 | | int wpa_cipher_put_suites(u8 *start, int ciphers) |
3848 | 0 | { |
3849 | 0 | u8 *pos = start; |
3850 | |
|
3851 | 0 | if (ciphers & WPA_CIPHER_CCMP) { |
3852 | 0 | RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); |
3853 | 0 | pos += WPA_SELECTOR_LEN; |
3854 | 0 | } |
3855 | 0 | if (ciphers & WPA_CIPHER_TKIP) { |
3856 | 0 | RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); |
3857 | 0 | pos += WPA_SELECTOR_LEN; |
3858 | 0 | } |
3859 | 0 | if (ciphers & WPA_CIPHER_NONE) { |
3860 | 0 | RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); |
3861 | 0 | pos += WPA_SELECTOR_LEN; |
3862 | 0 | } |
3863 | |
|
3864 | 0 | return (pos - start) / RSN_SELECTOR_LEN; |
3865 | 0 | } |
3866 | | |
3867 | | |
3868 | | int wpa_pick_pairwise_cipher(int ciphers, int none_allowed) |
3869 | 0 | { |
3870 | 0 | if (ciphers & WPA_CIPHER_GCMP_256) |
3871 | 0 | return WPA_CIPHER_GCMP_256; |
3872 | 0 | if (ciphers & WPA_CIPHER_CCMP_256) |
3873 | 0 | return WPA_CIPHER_CCMP_256; |
3874 | 0 | if (ciphers & WPA_CIPHER_CCMP) |
3875 | 0 | return WPA_CIPHER_CCMP; |
3876 | 0 | if (ciphers & WPA_CIPHER_GCMP) |
3877 | 0 | return WPA_CIPHER_GCMP; |
3878 | 0 | if (ciphers & WPA_CIPHER_TKIP) |
3879 | 0 | return WPA_CIPHER_TKIP; |
3880 | 0 | if (none_allowed && (ciphers & WPA_CIPHER_NONE)) |
3881 | 0 | return WPA_CIPHER_NONE; |
3882 | 0 | return -1; |
3883 | 0 | } |
3884 | | |
3885 | | |
3886 | | int wpa_pick_group_cipher(int ciphers) |
3887 | 0 | { |
3888 | 0 | if (ciphers & WPA_CIPHER_GCMP_256) |
3889 | 0 | return WPA_CIPHER_GCMP_256; |
3890 | 0 | if (ciphers & WPA_CIPHER_CCMP_256) |
3891 | 0 | return WPA_CIPHER_CCMP_256; |
3892 | 0 | if (ciphers & WPA_CIPHER_CCMP) |
3893 | 0 | return WPA_CIPHER_CCMP; |
3894 | 0 | if (ciphers & WPA_CIPHER_GCMP) |
3895 | 0 | return WPA_CIPHER_GCMP; |
3896 | 0 | if (ciphers & WPA_CIPHER_GTK_NOT_USED) |
3897 | 0 | return WPA_CIPHER_GTK_NOT_USED; |
3898 | 0 | if (ciphers & WPA_CIPHER_TKIP) |
3899 | 0 | return WPA_CIPHER_TKIP; |
3900 | 0 | return -1; |
3901 | 0 | } |
3902 | | |
3903 | | |
3904 | | int wpa_parse_cipher(const char *value) |
3905 | 0 | { |
3906 | 0 | int val = 0, last; |
3907 | 0 | char *start, *end, *buf; |
3908 | |
|
3909 | 0 | buf = os_strdup(value); |
3910 | 0 | if (buf == NULL) |
3911 | 0 | return -1; |
3912 | 0 | start = buf; |
3913 | |
|
3914 | 0 | while (*start != '\0') { |
3915 | 0 | while (*start == ' ' || *start == '\t') |
3916 | 0 | start++; |
3917 | 0 | if (*start == '\0') |
3918 | 0 | break; |
3919 | 0 | end = start; |
3920 | 0 | while (*end != ' ' && *end != '\t' && *end != '\0') |
3921 | 0 | end++; |
3922 | 0 | last = *end == '\0'; |
3923 | 0 | *end = '\0'; |
3924 | 0 | if (os_strcmp(start, "CCMP-256") == 0) |
3925 | 0 | val |= WPA_CIPHER_CCMP_256; |
3926 | 0 | else if (os_strcmp(start, "GCMP-256") == 0) |
3927 | 0 | val |= WPA_CIPHER_GCMP_256; |
3928 | 0 | else if (os_strcmp(start, "CCMP") == 0) |
3929 | 0 | val |= WPA_CIPHER_CCMP; |
3930 | 0 | else if (os_strcmp(start, "GCMP") == 0) |
3931 | 0 | val |= WPA_CIPHER_GCMP; |
3932 | 0 | #ifndef CONFIG_NO_TKIP |
3933 | 0 | else if (os_strcmp(start, "TKIP") == 0) |
3934 | 0 | val |= WPA_CIPHER_TKIP; |
3935 | 0 | #endif /* CONFIG_NO_TKIP */ |
3936 | | #ifdef CONFIG_WEP |
3937 | | else if (os_strcmp(start, "WEP104") == 0) |
3938 | | val |= WPA_CIPHER_WEP104; |
3939 | | else if (os_strcmp(start, "WEP40") == 0) |
3940 | | val |= WPA_CIPHER_WEP40; |
3941 | | #endif /* CONFIG_WEP */ |
3942 | 0 | else if (os_strcmp(start, "NONE") == 0) |
3943 | 0 | val |= WPA_CIPHER_NONE; |
3944 | 0 | else if (os_strcmp(start, "GTK_NOT_USED") == 0) |
3945 | 0 | val |= WPA_CIPHER_GTK_NOT_USED; |
3946 | 0 | else if (os_strcmp(start, "AES-128-CMAC") == 0) |
3947 | 0 | val |= WPA_CIPHER_AES_128_CMAC; |
3948 | 0 | else if (os_strcmp(start, "BIP-GMAC-128") == 0) |
3949 | 0 | val |= WPA_CIPHER_BIP_GMAC_128; |
3950 | 0 | else if (os_strcmp(start, "BIP-GMAC-256") == 0) |
3951 | 0 | val |= WPA_CIPHER_BIP_GMAC_256; |
3952 | 0 | else if (os_strcmp(start, "BIP-CMAC-256") == 0) |
3953 | 0 | val |= WPA_CIPHER_BIP_CMAC_256; |
3954 | 0 | else { |
3955 | 0 | os_free(buf); |
3956 | 0 | return -1; |
3957 | 0 | } |
3958 | | |
3959 | 0 | if (last) |
3960 | 0 | break; |
3961 | 0 | start = end + 1; |
3962 | 0 | } |
3963 | 0 | os_free(buf); |
3964 | |
|
3965 | 0 | return val; |
3966 | 0 | } |
3967 | | |
3968 | | |
3969 | | int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim) |
3970 | 0 | { |
3971 | 0 | char *pos = start; |
3972 | 0 | int ret; |
3973 | |
|
3974 | 0 | if (ciphers & WPA_CIPHER_CCMP_256) { |
3975 | 0 | ret = os_snprintf(pos, end - pos, "%sCCMP-256", |
3976 | 0 | pos == start ? "" : delim); |
3977 | 0 | if (os_snprintf_error(end - pos, ret)) |
3978 | 0 | return -1; |
3979 | 0 | pos += ret; |
3980 | 0 | } |
3981 | 0 | if (ciphers & WPA_CIPHER_GCMP_256) { |
3982 | 0 | ret = os_snprintf(pos, end - pos, "%sGCMP-256", |
3983 | 0 | pos == start ? "" : delim); |
3984 | 0 | if (os_snprintf_error(end - pos, ret)) |
3985 | 0 | return -1; |
3986 | 0 | pos += ret; |
3987 | 0 | } |
3988 | 0 | if (ciphers & WPA_CIPHER_CCMP) { |
3989 | 0 | ret = os_snprintf(pos, end - pos, "%sCCMP", |
3990 | 0 | pos == start ? "" : delim); |
3991 | 0 | if (os_snprintf_error(end - pos, ret)) |
3992 | 0 | return -1; |
3993 | 0 | pos += ret; |
3994 | 0 | } |
3995 | 0 | if (ciphers & WPA_CIPHER_GCMP) { |
3996 | 0 | ret = os_snprintf(pos, end - pos, "%sGCMP", |
3997 | 0 | pos == start ? "" : delim); |
3998 | 0 | if (os_snprintf_error(end - pos, ret)) |
3999 | 0 | return -1; |
4000 | 0 | pos += ret; |
4001 | 0 | } |
4002 | 0 | if (ciphers & WPA_CIPHER_TKIP) { |
4003 | 0 | ret = os_snprintf(pos, end - pos, "%sTKIP", |
4004 | 0 | pos == start ? "" : delim); |
4005 | 0 | if (os_snprintf_error(end - pos, ret)) |
4006 | 0 | return -1; |
4007 | 0 | pos += ret; |
4008 | 0 | } |
4009 | 0 | if (ciphers & WPA_CIPHER_AES_128_CMAC) { |
4010 | 0 | ret = os_snprintf(pos, end - pos, "%sAES-128-CMAC", |
4011 | 0 | pos == start ? "" : delim); |
4012 | 0 | if (os_snprintf_error(end - pos, ret)) |
4013 | 0 | return -1; |
4014 | 0 | pos += ret; |
4015 | 0 | } |
4016 | 0 | if (ciphers & WPA_CIPHER_BIP_GMAC_128) { |
4017 | 0 | ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-128", |
4018 | 0 | pos == start ? "" : delim); |
4019 | 0 | if (os_snprintf_error(end - pos, ret)) |
4020 | 0 | return -1; |
4021 | 0 | pos += ret; |
4022 | 0 | } |
4023 | 0 | if (ciphers & WPA_CIPHER_BIP_GMAC_256) { |
4024 | 0 | ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-256", |
4025 | 0 | pos == start ? "" : delim); |
4026 | 0 | if (os_snprintf_error(end - pos, ret)) |
4027 | 0 | return -1; |
4028 | 0 | pos += ret; |
4029 | 0 | } |
4030 | 0 | if (ciphers & WPA_CIPHER_BIP_CMAC_256) { |
4031 | 0 | ret = os_snprintf(pos, end - pos, "%sBIP-CMAC-256", |
4032 | 0 | pos == start ? "" : delim); |
4033 | 0 | if (os_snprintf_error(end - pos, ret)) |
4034 | 0 | return -1; |
4035 | 0 | pos += ret; |
4036 | 0 | } |
4037 | 0 | if (ciphers & WPA_CIPHER_NONE) { |
4038 | 0 | ret = os_snprintf(pos, end - pos, "%sNONE", |
4039 | 0 | pos == start ? "" : delim); |
4040 | 0 | if (os_snprintf_error(end - pos, ret)) |
4041 | 0 | return -1; |
4042 | 0 | pos += ret; |
4043 | 0 | } |
4044 | | |
4045 | 0 | return pos - start; |
4046 | 0 | } |
4047 | | |
4048 | | |
4049 | | int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise) |
4050 | 0 | { |
4051 | 0 | int pairwise = 0; |
4052 | | |
4053 | | /* Select group cipher based on the enabled pairwise cipher suites */ |
4054 | 0 | if (wpa & 1) |
4055 | 0 | pairwise |= wpa_pairwise; |
4056 | 0 | if (wpa & 2) |
4057 | 0 | pairwise |= rsn_pairwise; |
4058 | |
|
4059 | 0 | if (pairwise & WPA_CIPHER_TKIP) |
4060 | 0 | return WPA_CIPHER_TKIP; |
4061 | 0 | if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP) |
4062 | 0 | return WPA_CIPHER_GCMP; |
4063 | 0 | if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP | |
4064 | 0 | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256) |
4065 | 0 | return WPA_CIPHER_GCMP_256; |
4066 | 0 | if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP | |
4067 | 0 | WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256) |
4068 | 0 | return WPA_CIPHER_CCMP_256; |
4069 | 0 | return WPA_CIPHER_CCMP; |
4070 | 0 | } |
4071 | | |
4072 | | |
4073 | | #ifdef CONFIG_FILS |
4074 | | int fils_domain_name_hash(const char *domain, u8 *hash) |
4075 | | { |
4076 | | char buf[255], *wpos = buf; |
4077 | | const char *pos = domain; |
4078 | | size_t len; |
4079 | | const u8 *addr[1]; |
4080 | | u8 mac[SHA256_MAC_LEN]; |
4081 | | |
4082 | | for (len = 0; len < sizeof(buf) && *pos; len++) { |
4083 | | if (isalpha(*pos) && isupper(*pos)) |
4084 | | *wpos++ = tolower(*pos); |
4085 | | else |
4086 | | *wpos++ = *pos; |
4087 | | pos++; |
4088 | | } |
4089 | | |
4090 | | addr[0] = (const u8 *) buf; |
4091 | | if (sha256_vector(1, addr, &len, mac) < 0) |
4092 | | return -1; |
4093 | | os_memcpy(hash, mac, 2); |
4094 | | return 0; |
4095 | | } |
4096 | | #endif /* CONFIG_FILS */ |
4097 | | |
4098 | | |
4099 | | /** |
4100 | | * wpa_parse_vendor_specific - Parse Vendor Specific IEs |
4101 | | * @pos: Pointer to the IE header |
4102 | | * @end: Pointer to the end of the Key Data buffer |
4103 | | * @ie: Pointer to parsed IE data |
4104 | | */ |
4105 | | static void wpa_parse_vendor_specific(const u8 *pos, const u8 *end, |
4106 | | struct wpa_eapol_ie_parse *ie) |
4107 | 13.8k | { |
4108 | 13.8k | unsigned int oui; |
4109 | | |
4110 | 13.8k | if (pos[1] < 4) { |
4111 | 3.90k | wpa_printf(MSG_MSGDUMP, |
4112 | 3.90k | "Too short vendor specific IE ignored (len=%u)", |
4113 | 3.90k | pos[1]); |
4114 | 3.90k | return; |
4115 | 3.90k | } |
4116 | | |
4117 | 9.91k | oui = WPA_GET_BE24(&pos[2]); |
4118 | 9.91k | if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) { |
4119 | 823 | if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) { |
4120 | 261 | ie->wmm = &pos[2]; |
4121 | 261 | ie->wmm_len = pos[1]; |
4122 | 261 | wpa_hexdump(MSG_DEBUG, "WPA: WMM IE", |
4123 | 261 | ie->wmm, ie->wmm_len); |
4124 | 562 | } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) { |
4125 | 312 | ie->wmm = &pos[2]; |
4126 | 312 | ie->wmm_len = pos[1]; |
4127 | 312 | wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element", |
4128 | 312 | ie->wmm, ie->wmm_len); |
4129 | 312 | } |
4130 | 823 | } |
4131 | 9.91k | } |
4132 | | |
4133 | | |
4134 | | /** |
4135 | | * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs |
4136 | | * @pos: Pointer to the IE header |
4137 | | * @ie: Pointer to parsed IE data |
4138 | | * Returns: 0 on success, 1 if end mark is found, 2 if KDE is not recognized |
4139 | | */ |
4140 | | static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie) |
4141 | 23.7k | { |
4142 | 23.7k | u8 len = pos[1]; |
4143 | 23.7k | size_t dlen = 2 + len; |
4144 | 23.7k | u32 selector; |
4145 | 23.7k | const u8 *p; |
4146 | 23.7k | size_t left; |
4147 | 23.7k | u8 link_id; |
4148 | 23.7k | char title[100]; |
4149 | 23.7k | int ret; |
4150 | | |
4151 | 23.7k | if (len == 0) |
4152 | 0 | return 1; |
4153 | | |
4154 | 23.7k | if (len < RSN_SELECTOR_LEN) |
4155 | 3.90k | return 2; |
4156 | | |
4157 | 19.8k | p = pos + 2; |
4158 | 19.8k | selector = RSN_SELECTOR_GET(p); |
4159 | 19.8k | p += RSN_SELECTOR_LEN; |
4160 | 19.8k | left = len - RSN_SELECTOR_LEN; |
4161 | | |
4162 | 19.8k | if (left >= 2 && selector == WPA_OUI_TYPE && p[0] == 1 && p[1] == 0) { |
4163 | 620 | ie->wpa_ie = pos; |
4164 | 620 | ie->wpa_ie_len = dlen; |
4165 | 620 | wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", |
4166 | 620 | ie->wpa_ie, ie->wpa_ie_len); |
4167 | 620 | return 0; |
4168 | 620 | } |
4169 | | |
4170 | 19.2k | if (left >= PMKID_LEN && selector == RSN_KEY_DATA_PMKID) { |
4171 | 1.11k | ie->pmkid = p; |
4172 | 1.11k | wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", pos, dlen); |
4173 | 1.11k | return 0; |
4174 | 1.11k | } |
4175 | | |
4176 | 18.0k | if (left >= 2 && selector == RSN_KEY_DATA_KEYID) { |
4177 | 238 | ie->key_id = p; |
4178 | 238 | wpa_hexdump(MSG_DEBUG, "WPA: KeyID in EAPOL-Key", pos, dlen); |
4179 | 238 | return 0; |
4180 | 238 | } |
4181 | | |
4182 | 17.8k | if (left > 2 && selector == RSN_KEY_DATA_GROUPKEY) { |
4183 | 337 | ie->gtk = p; |
4184 | 337 | ie->gtk_len = left; |
4185 | 337 | wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", pos, dlen); |
4186 | 337 | return 0; |
4187 | 337 | } |
4188 | | |
4189 | 17.5k | if (left >= ETH_ALEN && selector == RSN_KEY_DATA_MAC_ADDR) { |
4190 | 435 | ie->mac_addr = p; |
4191 | 435 | wpa_printf(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key: " MACSTR, |
4192 | 435 | MAC2STR(ie->mac_addr)); |
4193 | 435 | return 0; |
4194 | 435 | } |
4195 | | |
4196 | 17.0k | if (left > 2 && selector == RSN_KEY_DATA_IGTK) { |
4197 | 1.02k | ie->igtk = p; |
4198 | 1.02k | ie->igtk_len = left; |
4199 | 1.02k | wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", |
4200 | 1.02k | pos, dlen); |
4201 | 1.02k | return 0; |
4202 | 1.02k | } |
4203 | | |
4204 | 16.0k | if (left > 2 && selector == RSN_KEY_DATA_BIGTK) { |
4205 | 292 | ie->bigtk = p; |
4206 | 292 | ie->bigtk_len = left; |
4207 | 292 | wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK in EAPOL-Key", |
4208 | 292 | pos, dlen); |
4209 | 292 | return 0; |
4210 | 292 | } |
4211 | | |
4212 | 15.7k | if (left > 2 && selector == RSN_KEY_DATA_SAE_PW_IDS) { |
4213 | 353 | ie->sae_pw_ids = p; |
4214 | 353 | ie->sae_pw_ids_len = left; |
4215 | 353 | wpa_hexdump_key(MSG_DEBUG, |
4216 | 353 | "RSN: SAE Password Identifiers in EAPOL-Key", |
4217 | 353 | pos, dlen); |
4218 | 353 | return 0; |
4219 | 353 | } |
4220 | | |
4221 | 15.4k | if (left >= 1 && selector == WFA_KEY_DATA_IP_ADDR_REQ) { |
4222 | 348 | ie->ip_addr_req = p; |
4223 | 348 | wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key", |
4224 | 348 | ie->ip_addr_req, left); |
4225 | 348 | return 0; |
4226 | 348 | } |
4227 | | |
4228 | 15.0k | if (left >= 3 * 4 && selector == WFA_KEY_DATA_IP_ADDR_ALLOC) { |
4229 | 232 | ie->ip_addr_alloc = p; |
4230 | 232 | wpa_hexdump(MSG_DEBUG, |
4231 | 232 | "WPA: IP Address Allocation in EAPOL-Key", |
4232 | 232 | ie->ip_addr_alloc, left); |
4233 | 232 | return 0; |
4234 | 232 | } |
4235 | | |
4236 | 14.8k | if (left > 2 && selector == RSN_KEY_DATA_OCI) { |
4237 | 356 | ie->oci = p; |
4238 | 356 | ie->oci_len = left; |
4239 | 356 | wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key", |
4240 | 356 | pos, dlen); |
4241 | 356 | return 0; |
4242 | 356 | } |
4243 | | |
4244 | 14.4k | if (left >= 1 && selector == WFA_KEY_DATA_TRANSITION_DISABLE) { |
4245 | 289 | ie->transition_disable = p; |
4246 | 289 | ie->transition_disable_len = left; |
4247 | 289 | wpa_hexdump(MSG_DEBUG, |
4248 | 289 | "WPA: Transition Disable KDE in EAPOL-Key", |
4249 | 289 | pos, dlen); |
4250 | 289 | return 0; |
4251 | 289 | } |
4252 | | |
4253 | 14.1k | if (left >= 2 && selector == WFA_KEY_DATA_DPP) { |
4254 | 387 | ie->dpp_kde = p; |
4255 | 387 | ie->dpp_kde_len = left; |
4256 | 387 | wpa_hexdump(MSG_DEBUG, "WPA: DPP KDE in EAPOL-Key", pos, dlen); |
4257 | 387 | return 0; |
4258 | 387 | } |
4259 | | |
4260 | 13.8k | if (left >= RSN_MLO_GTK_KDE_PREFIX_LENGTH && |
4261 | 5.06k | selector == RSN_KEY_DATA_MLO_GTK) { |
4262 | 641 | link_id = (p[0] & RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_MASK) >> |
4263 | 641 | RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_SHIFT; |
4264 | 641 | if (link_id >= MAX_NUM_MLD_LINKS) |
4265 | 358 | return 2; |
4266 | | |
4267 | 283 | ie->valid_mlo_gtks |= BIT(link_id); |
4268 | 283 | ie->mlo_gtk[link_id] = p; |
4269 | 283 | ie->mlo_gtk_len[link_id] = left; |
4270 | 283 | ret = os_snprintf(title, sizeof(title), |
4271 | 283 | "RSN: Link ID %u - MLO GTK KDE in EAPOL-Key", |
4272 | 283 | link_id); |
4273 | 283 | if (!os_snprintf_error(sizeof(title), ret)) |
4274 | 283 | wpa_hexdump_key(MSG_DEBUG, title, pos, dlen); |
4275 | 283 | return 0; |
4276 | 641 | } |
4277 | | |
4278 | 13.1k | if (left >= RSN_MLO_IGTK_KDE_PREFIX_LENGTH && |
4279 | 3.06k | selector == RSN_KEY_DATA_MLO_IGTK) { |
4280 | 639 | link_id = (p[8] & RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_MASK) >> |
4281 | 639 | RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_SHIFT; |
4282 | 639 | if (link_id >= MAX_NUM_MLD_LINKS) |
4283 | 335 | return 2; |
4284 | | |
4285 | 304 | ie->valid_mlo_igtks |= BIT(link_id); |
4286 | 304 | ie->mlo_igtk[link_id] = p; |
4287 | 304 | ie->mlo_igtk_len[link_id] = left; |
4288 | 304 | ret = os_snprintf(title, sizeof(title), |
4289 | 304 | "RSN: Link ID %u - MLO IGTK KDE in EAPOL-Key", |
4290 | 304 | link_id); |
4291 | 304 | if (!os_snprintf_error(sizeof(title), ret)) |
4292 | 304 | wpa_hexdump_key(MSG_DEBUG, title, pos, dlen); |
4293 | 304 | return 0; |
4294 | 639 | } |
4295 | | |
4296 | 12.5k | if (left >= RSN_MLO_BIGTK_KDE_PREFIX_LENGTH && |
4297 | 2.42k | selector == RSN_KEY_DATA_MLO_BIGTK) { |
4298 | 890 | link_id = (p[8] & RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_MASK) >> |
4299 | 890 | RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_SHIFT; |
4300 | 890 | if (link_id >= MAX_NUM_MLD_LINKS) |
4301 | 292 | return 2; |
4302 | | |
4303 | 598 | ie->valid_mlo_bigtks |= BIT(link_id); |
4304 | 598 | ie->mlo_bigtk[link_id] = p; |
4305 | 598 | ie->mlo_bigtk_len[link_id] = left; |
4306 | 598 | ret = os_snprintf(title, sizeof(title), |
4307 | 598 | "RSN: Link ID %u - MLO BIGTK KDE in EAPOL-Key", |
4308 | 598 | link_id); |
4309 | 598 | if (!os_snprintf_error(sizeof(title), ret)) |
4310 | 598 | wpa_hexdump_key(MSG_DEBUG, title, pos, dlen); |
4311 | 598 | return 0; |
4312 | 890 | } |
4313 | | |
4314 | 11.6k | if (left >= RSN_MLO_LINK_KDE_FIXED_LENGTH && |
4315 | 2.89k | selector == RSN_KEY_DATA_MLO_LINK) { |
4316 | 540 | link_id = (p[0] & RSN_MLO_LINK_KDE_LI_LINK_ID_MASK) >> |
4317 | 540 | RSN_MLO_LINK_KDE_LI_LINK_ID_SHIFT; |
4318 | 540 | if (link_id >= MAX_NUM_MLD_LINKS) |
4319 | 208 | return 2; |
4320 | | |
4321 | 332 | ie->valid_mlo_links |= BIT(link_id); |
4322 | 332 | ie->mlo_link[link_id] = p; |
4323 | 332 | ie->mlo_link_len[link_id] = left; |
4324 | 332 | ret = os_snprintf(title, sizeof(title), |
4325 | 332 | "RSN: Link ID %u - MLO Link KDE in EAPOL-Key", |
4326 | 332 | link_id); |
4327 | 332 | if (!os_snprintf_error(sizeof(title), ret)) |
4328 | 332 | wpa_hexdump(MSG_DEBUG, title, pos, dlen); |
4329 | 332 | return 0; |
4330 | 540 | } |
4331 | | |
4332 | 11.0k | if (left >= 1 && selector == WFA_KEY_DATA_RSN_OVERRIDE_LINK) { |
4333 | 861 | link_id = p[0]; |
4334 | 861 | if (link_id >= MAX_NUM_MLD_LINKS) |
4335 | 436 | return 2; |
4336 | | |
4337 | 425 | ie->rsn_override_link[link_id] = p; |
4338 | 425 | ie->rsn_override_link_len[link_id] = left; |
4339 | 425 | ret = os_snprintf(title, sizeof(title), |
4340 | 425 | "RSN: Link ID %u - RSN Override Link KDE in EAPOL-Key", |
4341 | 425 | link_id); |
4342 | 425 | if (!os_snprintf_error(sizeof(title), ret)) |
4343 | 425 | wpa_hexdump(MSG_DEBUG, title, pos, dlen); |
4344 | 425 | return 0; |
4345 | 861 | } |
4346 | | |
4347 | 10.2k | if (selector == RSNE_OVERRIDE_IE_VENDOR_TYPE) { |
4348 | 915 | ie->rsne_override = pos; |
4349 | 915 | ie->rsne_override_len = dlen; |
4350 | 915 | wpa_hexdump(MSG_DEBUG, |
4351 | 915 | "RSN: RSNE Override element in EAPOL-Key", |
4352 | 915 | ie->rsne_override, ie->rsne_override_len); |
4353 | 915 | return 0; |
4354 | 915 | } |
4355 | | |
4356 | 9.31k | if (selector == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) { |
4357 | 368 | ie->rsne_override_2 = pos; |
4358 | 368 | ie->rsne_override_2_len = dlen; |
4359 | 368 | wpa_hexdump(MSG_DEBUG, |
4360 | 368 | "RSN: RSNE Override 2 element in EAPOL-Key", |
4361 | 368 | ie->rsne_override_2, ie->rsne_override_2_len); |
4362 | 368 | return 0; |
4363 | 368 | } |
4364 | | |
4365 | 8.94k | if (selector == RSNXE_OVERRIDE_IE_VENDOR_TYPE) { |
4366 | 277 | ie->rsnxe_override = pos; |
4367 | 277 | ie->rsnxe_override_len = dlen; |
4368 | 277 | wpa_hexdump(MSG_DEBUG, |
4369 | 277 | "RSN: RSNXE Override element in EAPOL-Key", |
4370 | 277 | ie->rsnxe_override, ie->rsnxe_override_len); |
4371 | 277 | return 0; |
4372 | 277 | } |
4373 | | |
4374 | 8.67k | if (selector == RSN_SELECTION_IE_VENDOR_TYPE) { |
4375 | 385 | ie->rsn_selection = p; |
4376 | 385 | ie->rsn_selection_len = left; |
4377 | 385 | wpa_hexdump(MSG_DEBUG, |
4378 | 385 | "RSN: RSN Selection element in EAPOL-Key", |
4379 | 385 | ie->rsn_selection, ie->rsn_selection_len); |
4380 | 385 | return 0; |
4381 | 385 | } |
4382 | | |
4383 | | #if defined(CONFIG_NAN) || defined(CONFIG_PASN) |
4384 | | if (left >= sizeof(struct nan_nik_kde) && |
4385 | | selector == NAN_KEY_DATA_NIK) { |
4386 | | ie->nan_nik = p; |
4387 | | ie->nan_nik_len = left; |
4388 | | wpa_hexdump_key(MSG_DEBUG, "RSN: NAN NIK KDE in EAPOL-Key", |
4389 | | ie->nan_nik, ie->nan_nik_len); |
4390 | | return 0; |
4391 | | } |
4392 | | |
4393 | | if (left >= sizeof(struct nan_key_lifetime_kde) && |
4394 | | selector == NAN_KEY_DATA_LIFETIME) { |
4395 | | ie->nan_key_lifetime = p; |
4396 | | ie->nan_key_lifetime_len = left; |
4397 | | wpa_hexdump(MSG_DEBUG, |
4398 | | "RSN: NAN Key Lifetime KDE in EAPOL-Key", |
4399 | | ie->nan_key_lifetime, ie->nan_key_lifetime_len); |
4400 | | return 0; |
4401 | | } |
4402 | | #endif /* CONFIG_NAN || CONFIG_PASN */ |
4403 | | |
4404 | 8.28k | return 2; |
4405 | 8.67k | } |
4406 | | |
4407 | | |
4408 | | /** |
4409 | | * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs |
4410 | | * @buf: Pointer to the Key Data buffer |
4411 | | * @len: Key Data Length |
4412 | | * @ie: Pointer to parsed IE data |
4413 | | * Returns: 0 on success, -1 on failure |
4414 | | */ |
4415 | | int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) |
4416 | 1.60k | { |
4417 | 1.60k | const u8 *pos, *end; |
4418 | 1.60k | int ret = 0; |
4419 | 1.60k | size_t dlen = 0; |
4420 | | |
4421 | 1.60k | os_memset(ie, 0, sizeof(*ie)); |
4422 | 93.5k | for (pos = buf, end = pos + len; end - pos > 1; pos += dlen) { |
4423 | 92.3k | if (pos[0] == 0xdd && |
4424 | 23.7k | ((pos == buf + len - 1) || pos[1] == 0)) { |
4425 | | /* Ignore padding */ |
4426 | 17 | break; |
4427 | 17 | } |
4428 | 92.3k | dlen = 2 + pos[1]; |
4429 | 92.3k | if ((int) dlen > end - pos) { |
4430 | 376 | wpa_printf(MSG_DEBUG, |
4431 | 376 | "WPA: EAPOL-Key Key Data underflow (ie=%d len=%d pos=%d)", |
4432 | 376 | pos[0], pos[1], (int) (pos - buf)); |
4433 | 376 | wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", buf, len); |
4434 | 376 | ret = -1; |
4435 | 376 | break; |
4436 | 376 | } |
4437 | 91.9k | if (*pos == WLAN_EID_RSN) { |
4438 | 1.70k | ie->rsn_ie = pos; |
4439 | 1.70k | ie->rsn_ie_len = dlen; |
4440 | 1.70k | wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", |
4441 | 1.70k | ie->rsn_ie, ie->rsn_ie_len); |
4442 | 90.2k | } else if (*pos == WLAN_EID_RSNX) { |
4443 | 592 | ie->rsnxe = pos; |
4444 | 592 | ie->rsnxe_len = dlen; |
4445 | 592 | wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key", |
4446 | 592 | ie->rsnxe, ie->rsnxe_len); |
4447 | 89.6k | } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { |
4448 | 1.21k | ie->mdie = pos; |
4449 | 1.21k | ie->mdie_len = dlen; |
4450 | 1.21k | wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key", |
4451 | 1.21k | ie->mdie, ie->mdie_len); |
4452 | 88.4k | } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { |
4453 | 769 | ie->ftie = pos; |
4454 | 769 | ie->ftie_len = dlen; |
4455 | 769 | wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key", |
4456 | 769 | ie->ftie, ie->ftie_len); |
4457 | 87.6k | } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) { |
4458 | 1.49k | if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) { |
4459 | 236 | ie->reassoc_deadline = pos; |
4460 | 236 | wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline " |
4461 | 236 | "in EAPOL-Key", |
4462 | 236 | ie->reassoc_deadline, dlen); |
4463 | 1.26k | } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) { |
4464 | 432 | ie->key_lifetime = pos; |
4465 | 432 | wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime " |
4466 | 432 | "in EAPOL-Key", |
4467 | 432 | ie->key_lifetime, dlen); |
4468 | 831 | } else { |
4469 | 831 | wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized " |
4470 | 831 | "EAPOL-Key Key Data IE", |
4471 | 831 | pos, dlen); |
4472 | 831 | } |
4473 | 86.1k | } else if (*pos == WLAN_EID_LINK_ID) { |
4474 | 726 | if (pos[1] >= 18) { |
4475 | 224 | ie->lnkid = pos; |
4476 | 224 | ie->lnkid_len = dlen; |
4477 | 224 | } |
4478 | 85.4k | } else if (*pos == WLAN_EID_EXT_CAPAB) { |
4479 | 462 | ie->ext_capab = pos; |
4480 | 462 | ie->ext_capab_len = dlen; |
4481 | 84.9k | } else if (*pos == WLAN_EID_SUPP_RATES) { |
4482 | 2.83k | ie->supp_rates = pos; |
4483 | 2.83k | ie->supp_rates_len = dlen; |
4484 | 82.1k | } else if (*pos == WLAN_EID_EXT_SUPP_RATES) { |
4485 | 600 | ie->ext_supp_rates = pos; |
4486 | 600 | ie->ext_supp_rates_len = dlen; |
4487 | 81.5k | } else if (*pos == WLAN_EID_HT_CAP && |
4488 | 2.25k | pos[1] >= sizeof(struct ieee80211_ht_capabilities)) { |
4489 | 372 | ie->ht_capabilities = pos + 2; |
4490 | 81.1k | } else if (*pos == WLAN_EID_AID) { |
4491 | 790 | if (pos[1] >= 2) |
4492 | 298 | ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff; |
4493 | 80.3k | } else if (*pos == WLAN_EID_VHT_CAP && |
4494 | 1.20k | pos[1] >= sizeof(struct ieee80211_vht_capabilities)) |
4495 | 368 | { |
4496 | 368 | ie->vht_capabilities = pos + 2; |
4497 | 80.0k | } else if (*pos == WLAN_EID_EXTENSION && |
4498 | 5.12k | pos[1] >= 1 + IEEE80211_HE_CAPAB_MIN_LEN && |
4499 | 1.36k | pos[2] == WLAN_EID_EXT_HE_CAPABILITIES) { |
4500 | 424 | ie->he_capabilities = pos + 3; |
4501 | 424 | ie->he_capab_len = pos[1] - 1; |
4502 | 79.6k | } else if (*pos == WLAN_EID_EXTENSION && |
4503 | 4.69k | pos[1] >= 1 + |
4504 | 4.69k | sizeof(struct ieee80211_he_6ghz_band_cap) && |
4505 | 2.86k | pos[2] == WLAN_EID_EXT_HE_6GHZ_BAND_CAP) { |
4506 | 376 | ie->he_6ghz_capabilities = pos + 3; |
4507 | 79.2k | } else if (*pos == WLAN_EID_EXTENSION && |
4508 | 4.32k | pos[1] >= 1 + IEEE80211_EHT_CAPAB_MIN_LEN && |
4509 | 1.44k | pos[2] == WLAN_EID_EXT_EHT_CAPABILITIES) { |
4510 | 276 | ie->eht_capabilities = pos + 3; |
4511 | 276 | ie->eht_capab_len = pos[1] - 1; |
4512 | 78.9k | } else if (*pos == WLAN_EID_EXTENSION && |
4513 | 4.04k | pos[1] >= 3 && |
4514 | 2.20k | pos[2] == WLAN_EID_EXT_SECURITY_PROFILE) { |
4515 | 682 | ie->security_profile = pos; |
4516 | 682 | ie->security_profile_len = dlen; |
4517 | 682 | wpa_hexdump(MSG_DEBUG, |
4518 | 682 | "WPA: Security Profile element in EAPOL-Key", |
4519 | 682 | ie->security_profile, |
4520 | 682 | ie->security_profile_len); |
4521 | 78.2k | } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) { |
4522 | 582 | ie->qosinfo = pos[2]; |
4523 | 77.6k | } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) { |
4524 | 589 | ie->supp_channels = pos + 2; |
4525 | 589 | ie->supp_channels_len = pos[1]; |
4526 | 77.1k | } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) { |
4527 | | /* |
4528 | | * The value of the Length field of the Supported |
4529 | | * Operating Classes element is between 2 and 253. |
4530 | | * Silently skip invalid elements to avoid interop |
4531 | | * issues when trying to use the value. |
4532 | | */ |
4533 | 1.85k | if (pos[1] >= 2 && pos[1] <= 253) { |
4534 | 393 | ie->supp_oper_classes = pos + 2; |
4535 | 393 | ie->supp_oper_classes_len = pos[1]; |
4536 | 393 | } |
4537 | 75.2k | } else if (*pos == WLAN_EID_SSID) { |
4538 | 22.8k | ie->ssid = pos + 2; |
4539 | 22.8k | ie->ssid_len = pos[1]; |
4540 | 22.8k | wpa_hexdump_ascii(MSG_DEBUG, "RSN: SSID in EAPOL-Key", |
4541 | 22.8k | ie->ssid, ie->ssid_len); |
4542 | 52.3k | } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { |
4543 | 23.7k | ret = wpa_parse_generic(pos, ie); |
4544 | 23.7k | if (ret == 1) { |
4545 | | /* end mark found */ |
4546 | 0 | ret = 0; |
4547 | 0 | break; |
4548 | 0 | } |
4549 | | |
4550 | 23.7k | if (ret == 2) { |
4551 | | /* not a known KDE */ |
4552 | 13.8k | wpa_parse_vendor_specific(pos, end, ie); |
4553 | 13.8k | } |
4554 | | |
4555 | 23.7k | ret = 0; |
4556 | 28.6k | } else { |
4557 | 28.6k | wpa_hexdump(MSG_DEBUG, |
4558 | 28.6k | "WPA: Unrecognized EAPOL-Key Key Data IE", |
4559 | 28.6k | pos, dlen); |
4560 | 28.6k | } |
4561 | 91.9k | } |
4562 | | |
4563 | 1.60k | return ret; |
4564 | 1.60k | } |
4565 | | |
4566 | | |
4567 | | #ifdef CONFIG_TESTING_OPTIONS |
4568 | | int wpa_rsne_inject_random_pmkids(u8 **pos, unsigned int count) |
4569 | | { |
4570 | | unsigned int i; |
4571 | | |
4572 | | wpa_printf(MSG_INFO, "TESTING: Inject %u random PMKID(s) into RSNE", |
4573 | | count); |
4574 | | WPA_PUT_LE16(*pos, count); |
4575 | | *pos += 2; |
4576 | | for (i = 0; i < count; i++) { |
4577 | | if (random_get_bytes(*pos, PMKID_LEN) < 0) { |
4578 | | wpa_printf(MSG_WARNING, |
4579 | | "TESTING: Failed to generate random PMKID"); |
4580 | | return -1; |
4581 | | } |
4582 | | wpa_hexdump(MSG_DEBUG, "TESTING: Random PMKID", |
4583 | | *pos, PMKID_LEN); |
4584 | | *pos += PMKID_LEN; |
4585 | | } |
4586 | | return 0; |
4587 | | } |
4588 | | #endif /* CONFIG_TESTING_OPTIONS */ |
4589 | | |
4590 | | |
4591 | | #ifdef CONFIG_PASN |
4592 | | |
4593 | | /* |
4594 | | * wpa_pasn_build_auth_header - Add the MAC header and initialize Authentication |
4595 | | * frame for PASN/EPPKE |
4596 | | * |
4597 | | * @buf: Buffer in which the header will be added |
4598 | | * @bssid: The BSSID of the AP |
4599 | | * @src: Source address |
4600 | | * @dst: Destination address |
4601 | | * @trans_seq: Authentication transaction sequence number |
4602 | | * @status: Authentication status |
4603 | | * @is_eppke: EPPKE authentication |
4604 | | */ |
4605 | | void wpa_pasn_build_auth_header(struct wpabuf *buf, const u8 *bssid, |
4606 | | const u8 *src, const u8 *dst, |
4607 | | u8 trans_seq, u16 status, bool is_eppke) |
4608 | | { |
4609 | | struct ieee80211_mgmt *auth; |
4610 | | u16 auth_alg = is_eppke ? WLAN_AUTH_EPPKE : WLAN_AUTH_PASN; |
4611 | | |
4612 | | wpa_printf(MSG_DEBUG, "%s: Add authentication header trans_seq=%u", |
4613 | | is_eppke ? "EPPKE" : "PASN", trans_seq); |
4614 | | |
4615 | | auth = wpabuf_put(buf, offsetof(struct ieee80211_mgmt, |
4616 | | u.auth.variable)); |
4617 | | |
4618 | | auth->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) | |
4619 | | (WLAN_FC_STYPE_AUTH << 4)); |
4620 | | |
4621 | | os_memcpy(auth->da, dst, ETH_ALEN); |
4622 | | os_memcpy(auth->sa, src, ETH_ALEN); |
4623 | | os_memcpy(auth->bssid, bssid, ETH_ALEN); |
4624 | | auth->seq_ctrl = 0; |
4625 | | |
4626 | | auth->u.auth.auth_alg = host_to_le16(auth_alg); |
4627 | | auth->u.auth.auth_transaction = host_to_le16(trans_seq); |
4628 | | auth->u.auth.status_code = host_to_le16(status); |
4629 | | } |
4630 | | |
4631 | | |
4632 | | /* |
4633 | | * wpa_pasn_add_rsne - Add an RSNE for PASN authentication |
4634 | | * @buf: Buffer in which the IE will be added |
4635 | | * @pmkid: Optional PMKID. Can be NULL. |
4636 | | * @akmp: Authentication and key management protocol |
4637 | | * @cipher: The cipher suite |
4638 | | * @random_pmkid_count: Number of random PMKIDs to add; only for testing |
4639 | | * purposes |
4640 | | */ |
4641 | | int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher, |
4642 | | unsigned int random_pmkid_count) |
4643 | | { |
4644 | | struct rsn_ie_hdr *hdr; |
4645 | | u32 suite; |
4646 | | u16 capab; |
4647 | | u8 *pos; |
4648 | | u8 rsne_len; |
4649 | | |
4650 | | wpa_printf(MSG_DEBUG, "PASN: Add RSNE"); |
4651 | | |
4652 | | rsne_len = sizeof(*hdr) + RSN_SELECTOR_LEN + |
4653 | | 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + |
4654 | | 2 + RSN_SELECTOR_LEN + 2 + (pmkid ? PMKID_LEN : 0); |
4655 | | if (!pmkid && random_pmkid_count > 0) |
4656 | | rsne_len += 2 + random_pmkid_count * PMKID_LEN; |
4657 | | |
4658 | | if (wpabuf_tailroom(buf) < rsne_len) |
4659 | | return -1; |
4660 | | hdr = wpabuf_put(buf, rsne_len); |
4661 | | hdr->elem_id = WLAN_EID_RSN; |
4662 | | hdr->len = rsne_len - 2; |
4663 | | WPA_PUT_LE16(hdr->version, RSN_VERSION); |
4664 | | pos = (u8 *) (hdr + 1); |
4665 | | |
4666 | | /* Group addressed data is not allowed */ |
4667 | | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); |
4668 | | pos += RSN_SELECTOR_LEN; |
4669 | | |
4670 | | /* Add the pairwise cipher */ |
4671 | | WPA_PUT_LE16(pos, 1); |
4672 | | pos += 2; |
4673 | | suite = wpa_cipher_to_suite(WPA_PROTO_RSN, cipher); |
4674 | | RSN_SELECTOR_PUT(pos, suite); |
4675 | | pos += RSN_SELECTOR_LEN; |
4676 | | |
4677 | | /* Add the AKM suite */ |
4678 | | WPA_PUT_LE16(pos, 1); |
4679 | | pos += 2; |
4680 | | |
4681 | | switch (akmp) { |
4682 | | case WPA_KEY_MGMT_PASN: |
4683 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PASN); |
4684 | | break; |
4685 | | #ifdef CONFIG_ENC_ASSOC |
4686 | | case WPA_KEY_MGMT_EPPKE: |
4687 | | /* EPPKE without base AKM: EPPKE AKMP is used as the selected |
4688 | | * AKMP per IEEE P802.11bi/D4.0, 12.16.9.1. */ |
4689 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_EPPKE); |
4690 | | break; |
4691 | | #endif /* CONFIG_ENC_ASSOC */ |
4692 | | #ifdef CONFIG_SAE |
4693 | | case WPA_KEY_MGMT_SAE: |
4694 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); |
4695 | | break; |
4696 | | case WPA_KEY_MGMT_SAE_EXT_KEY: |
4697 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY); |
4698 | | break; |
4699 | | #endif /* CONFIG_SAE */ |
4700 | | #ifdef CONFIG_FILS |
4701 | | case WPA_KEY_MGMT_FILS_SHA256: |
4702 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256); |
4703 | | break; |
4704 | | case WPA_KEY_MGMT_FILS_SHA384: |
4705 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384); |
4706 | | break; |
4707 | | #endif /* CONFIG_FILS */ |
4708 | | #ifdef CONFIG_IEEE80211R |
4709 | | case WPA_KEY_MGMT_FT_PSK: |
4710 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); |
4711 | | break; |
4712 | | case WPA_KEY_MGMT_FT_IEEE8021X: |
4713 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); |
4714 | | break; |
4715 | | case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: |
4716 | | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384); |
4717 | | break; |
4718 | | #endif /* CONFIG_IEEE80211R */ |
4719 | | default: |
4720 | | wpa_printf(MSG_ERROR, "PASN: Invalid AKMP=0x%x", akmp); |
4721 | | return -1; |
4722 | | } |
4723 | | pos += RSN_SELECTOR_LEN; |
4724 | | |
4725 | | /* RSN Capabilities: PASN mandates both MFP capable and required */ |
4726 | | capab = WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR; |
4727 | | WPA_PUT_LE16(pos, capab); |
4728 | | pos += 2; |
4729 | | |
4730 | | #ifdef CONFIG_TESTING_OPTIONS |
4731 | | if (!pmkid && random_pmkid_count > 0) { |
4732 | | if (wpa_rsne_inject_random_pmkids(&pos, random_pmkid_count) < 0) |
4733 | | return -1; |
4734 | | } else |
4735 | | #endif /* CONFIG_TESTING_OPTIONS */ |
4736 | | if (pmkid) { |
4737 | | wpa_printf(MSG_DEBUG, "PASN: Adding PMKID"); |
4738 | | |
4739 | | WPA_PUT_LE16(pos, 1); |
4740 | | pos += 2; |
4741 | | os_memcpy(pos, pmkid, PMKID_LEN); |
4742 | | pos += PMKID_LEN; |
4743 | | } else { |
4744 | | WPA_PUT_LE16(pos, 0); |
4745 | | pos += 2; |
4746 | | } |
4747 | | |
4748 | | /* Group addressed management is not allowed */ |
4749 | | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); |
4750 | | |
4751 | | return 0; |
4752 | | } |
4753 | | |
4754 | | |
4755 | | /* |
4756 | | * wpa_pasn_add_parameter_ie - Add PASN Parameters IE for PASN authentication |
4757 | | * @buf: Buffer in which the IE will be added |
4758 | | * @pasn_group: Finite Cyclic Group ID for PASN authentication |
4759 | | * @wrapped_data_format: Format of the data in the Wrapped Data IE |
4760 | | * @pubkey: A buffer holding the local public key. Can be NULL |
4761 | | * @compressed: In case pubkey is included, indicates if the public key is |
4762 | | * compressed (only x coordinate is included) or not (both x and y |
4763 | | * coordinates are included) |
4764 | | * @comeback: A buffer holding the comeback token. Can be NULL |
4765 | | * @after: If comeback is set, defined the comeback time in seconds. -1 to not |
4766 | | * include the Comeback After field (frames from non-AP STA). |
4767 | | */ |
4768 | | void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group, |
4769 | | u8 wrapped_data_format, |
4770 | | const struct wpabuf *pubkey, bool compressed, |
4771 | | const struct wpabuf *comeback, int after) |
4772 | | { |
4773 | | struct pasn_parameter_ie *params; |
4774 | | |
4775 | | wpa_printf(MSG_DEBUG, "PASN: Add PASN Parameters element"); |
4776 | | |
4777 | | params = wpabuf_put(buf, sizeof(*params)); |
4778 | | |
4779 | | params->id = WLAN_EID_EXTENSION; |
4780 | | params->len = sizeof(*params) - 2; |
4781 | | params->id_ext = WLAN_EID_EXT_PASN_PARAMS; |
4782 | | params->control = 0; |
4783 | | params->wrapped_data_format = wrapped_data_format; |
4784 | | |
4785 | | if (comeback) { |
4786 | | wpa_printf(MSG_DEBUG, "PASN: Adding comeback data"); |
4787 | | |
4788 | | /* |
4789 | | * 2 octets for the 'after' field + 1 octet for the length + |
4790 | | * actual cookie data |
4791 | | */ |
4792 | | if (after >= 0) |
4793 | | params->len += 2; |
4794 | | params->len += 1 + wpabuf_len(comeback); |
4795 | | params->control |= WPA_PASN_CTRL_COMEBACK_INFO_PRESENT; |
4796 | | |
4797 | | if (after >= 0) |
4798 | | wpabuf_put_le16(buf, after); |
4799 | | wpabuf_put_u8(buf, wpabuf_len(comeback)); |
4800 | | wpabuf_put_buf(buf, comeback); |
4801 | | } |
4802 | | |
4803 | | if (pubkey) { |
4804 | | wpa_printf(MSG_DEBUG, |
4805 | | "PASN: Adding public key and group ID %u", |
4806 | | pasn_group); |
4807 | | |
4808 | | /* |
4809 | | * 2 octets for the finite cyclic group + 2 octets public key |
4810 | | * length + 1 octet for the compressed/uncompressed indication + |
4811 | | * the actual key. |
4812 | | */ |
4813 | | params->len += 2 + 1 + 1 + wpabuf_len(pubkey); |
4814 | | params->control |= WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT; |
4815 | | |
4816 | | wpabuf_put_le16(buf, pasn_group); |
4817 | | |
4818 | | /* |
4819 | | * The first octet indicates whether the public key is |
4820 | | * compressed, as defined in RFC 5480 section 2.2. |
4821 | | */ |
4822 | | wpabuf_put_u8(buf, wpabuf_len(pubkey) + 1); |
4823 | | wpabuf_put_u8(buf, compressed ? WPA_PASN_PUBKEY_COMPRESSED_0 : |
4824 | | WPA_PASN_PUBKEY_UNCOMPRESSED); |
4825 | | |
4826 | | wpabuf_put_buf(buf, pubkey); |
4827 | | } |
4828 | | } |
4829 | | |
4830 | | /* |
4831 | | * wpa_pasn_add_wrapped_data - Add a Wrapped Data IE to PASN Authentication |
4832 | | * frame. If needed, the Wrapped Data IE would be fragmented. |
4833 | | * |
4834 | | * @buf: Buffer in which the IE will be added |
4835 | | * @wrapped_data_buf: Buffer holding the wrapped data |
4836 | | */ |
4837 | | int wpa_pasn_add_wrapped_data(struct wpabuf *buf, |
4838 | | struct wpabuf *wrapped_data_buf) |
4839 | | { |
4840 | | const u8 *data; |
4841 | | size_t data_len; |
4842 | | u8 len; |
4843 | | |
4844 | | if (!wrapped_data_buf) |
4845 | | return 0; |
4846 | | |
4847 | | wpa_printf(MSG_DEBUG, "PASN: Add wrapped data"); |
4848 | | |
4849 | | data = wpabuf_head_u8(wrapped_data_buf); |
4850 | | data_len = wpabuf_len(wrapped_data_buf); |
4851 | | |
4852 | | /* nothing to add */ |
4853 | | if (!data_len) |
4854 | | return 0; |
4855 | | |
4856 | | if (data_len <= 254) |
4857 | | len = 1 + data_len; |
4858 | | else |
4859 | | len = 255; |
4860 | | |
4861 | | if (wpabuf_tailroom(buf) < 3 + data_len) |
4862 | | return -1; |
4863 | | |
4864 | | wpabuf_put_u8(buf, WLAN_EID_EXTENSION); |
4865 | | wpabuf_put_u8(buf, len); |
4866 | | wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA); |
4867 | | wpabuf_put_data(buf, data, len - 1); |
4868 | | |
4869 | | data += len - 1; |
4870 | | data_len -= len - 1; |
4871 | | |
4872 | | while (data_len) { |
4873 | | if (wpabuf_tailroom(buf) < 2 + data_len) |
4874 | | return -1; |
4875 | | wpabuf_put_u8(buf, WLAN_EID_FRAGMENT); |
4876 | | len = data_len > 255 ? 255 : data_len; |
4877 | | wpabuf_put_u8(buf, len); |
4878 | | wpabuf_put_data(buf, data, len); |
4879 | | data += len; |
4880 | | data_len -= len; |
4881 | | } |
4882 | | |
4883 | | return 0; |
4884 | | } |
4885 | | |
4886 | | |
4887 | | /* |
4888 | | * wpa_pasn_validate_rsne - Validate PASN/EPPKE specific data of RSNE |
4889 | | * @data: Parsed representation of an RSNE |
4890 | | * @is_eppke: EPPKE Authentication |
4891 | | * Returns -1 for invalid data; otherwise 0 |
4892 | | */ |
4893 | | int wpa_pasn_validate_rsne(const struct wpa_ie_data *data, bool is_eppke) |
4894 | | { |
4895 | | u16 capab = WPA_CAPABILITY_MFPC; |
4896 | | |
4897 | | if (!is_eppke) |
4898 | | capab |= WPA_CAPABILITY_MFPR; |
4899 | | |
4900 | | if (data->proto != WPA_PROTO_RSN) |
4901 | | return -1; |
4902 | | |
4903 | | if ((data->capabilities & capab) != capab) { |
4904 | | wpa_printf(MSG_DEBUG, "%s: Invalid RSNE capabilities", |
4905 | | is_eppke ? "EPPKE" : "PASN"); |
4906 | | return -1; |
4907 | | } |
4908 | | |
4909 | | if (!data->has_group || |
4910 | | (!is_eppke && data->group_cipher != WPA_CIPHER_GTK_NOT_USED)) { |
4911 | | wpa_printf(MSG_DEBUG, "PASN: Invalid group data cipher"); |
4912 | | return -1; |
4913 | | } |
4914 | | |
4915 | | if (!data->has_pairwise || !data->pairwise_cipher || |
4916 | | (data->pairwise_cipher & (data->pairwise_cipher - 1))) { |
4917 | | wpa_printf(MSG_DEBUG, "PASN: No valid pairwise suite"); |
4918 | | return -1; |
4919 | | } |
4920 | | |
4921 | | switch (data->key_mgmt) { |
4922 | | #ifdef CONFIG_SAE |
4923 | | case WPA_KEY_MGMT_SAE: |
4924 | | case WPA_KEY_MGMT_SAE_EXT_KEY: |
4925 | | case WPA_KEY_MGMT_FT_SAE_EXT_KEY: |
4926 | | /* fall through */ |
4927 | | #endif /* CONFIG_SAE */ |
4928 | | #ifdef CONFIG_FILS |
4929 | | case WPA_KEY_MGMT_FILS_SHA256: |
4930 | | case WPA_KEY_MGMT_FILS_SHA384: |
4931 | | /* fall through */ |
4932 | | #endif /* CONFIG_FILS */ |
4933 | | #ifdef CONFIG_IEEE80211R |
4934 | | case WPA_KEY_MGMT_FT_PSK: |
4935 | | case WPA_KEY_MGMT_FT_IEEE8021X: |
4936 | | case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: |
4937 | | /* fall through */ |
4938 | | #endif /* CONFIG_IEEE80211R */ |
4939 | | case WPA_KEY_MGMT_PASN: |
4940 | | break; |
4941 | | #ifdef CONFIG_ENC_ASSOC |
4942 | | case WPA_KEY_MGMT_EPPKE: |
4943 | | /* EPPKE AKMP is used when EPPKE is performed without a base |
4944 | | * AKM (no mutual authentication). This is only valid for EPPKE |
4945 | | * authentication per IEEE P802.11bi/D4.0, 12.16.9.1. */ |
4946 | | if (!is_eppke) { |
4947 | | wpa_printf(MSG_INFO, |
4948 | | "PASN: EPPKE AKM not allowed for PASN"); |
4949 | | return -1; |
4950 | | } |
4951 | | break; |
4952 | | #endif /* CONFIG_ENC_ASSOC */ |
4953 | | default: |
4954 | | wpa_printf(MSG_ERROR, "%s: invalid key_mgmt: 0x%0x", |
4955 | | is_eppke ? "EPPKE" : "PASN", data->key_mgmt); |
4956 | | return -1; |
4957 | | } |
4958 | | |
4959 | | if (!is_eppke && (data->mgmt_group_cipher != WPA_CIPHER_GTK_NOT_USED)) { |
4960 | | wpa_printf(MSG_DEBUG, "PASN: Invalid group mgmt cipher"); |
4961 | | return -1; |
4962 | | } |
4963 | | |
4964 | | if (data->num_pmkid > 1) { |
4965 | | wpa_printf(MSG_DEBUG, "PASN: Invalid number of PMKIDs"); |
4966 | | return -1; |
4967 | | } |
4968 | | |
4969 | | return 0; |
4970 | | } |
4971 | | |
4972 | | |
4973 | | /* |
4974 | | * wpa_pasn_parse_parameter_ie - Validates PASN Parameters IE |
4975 | | * @data: Pointer to the PASN Parameters IE (starting with the EID). |
4976 | | * @len: Length of the data in the PASN Parameters IE |
4977 | | * @from_ap: Whether this was received from an AP |
4978 | | * @pasn_params: On successful return would hold the parsed PASN parameters. |
4979 | | * Returns: -1 for invalid data; otherwise 0 |
4980 | | * |
4981 | | * Note: On successful return, the pointers in &pasn_params point to the data in |
4982 | | * the IE and are not locally allocated (so they should not be freed etc.). |
4983 | | */ |
4984 | | int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap, |
4985 | | struct wpa_pasn_params_data *pasn_params) |
4986 | | { |
4987 | | struct pasn_parameter_ie *params = (struct pasn_parameter_ie *) data; |
4988 | | const u8 *pos = (const u8 *) (params + 1); |
4989 | | |
4990 | | if (!pasn_params) { |
4991 | | wpa_printf(MSG_DEBUG, "PASN: Invalid params"); |
4992 | | return -1; |
4993 | | } |
4994 | | |
4995 | | if (!params || ((size_t) (params->len + 2) < sizeof(*params)) || |
4996 | | len < sizeof(*params) || params->len + 2 != len) { |
4997 | | wpa_printf(MSG_DEBUG, |
4998 | | "PASN: Invalid parameters IE. len=(%u, %u)", |
4999 | | params ? params->len : 0, len); |
5000 | | return -1; |
5001 | | } |
5002 | | |
5003 | | os_memset(pasn_params, 0, sizeof(*pasn_params)); |
5004 | | |
5005 | | switch (params->wrapped_data_format) { |
5006 | | case WPA_PASN_WRAPPED_DATA_NO: |
5007 | | case WPA_PASN_WRAPPED_DATA_SAE: |
5008 | | case WPA_PASN_WRAPPED_DATA_FILS_SK: |
5009 | | case WPA_PASN_WRAPPED_DATA_FT: |
5010 | | break; |
5011 | | default: |
5012 | | wpa_printf(MSG_DEBUG, "PASN: Invalid wrapped data format"); |
5013 | | return -1; |
5014 | | } |
5015 | | |
5016 | | pasn_params->wrapped_data_format = params->wrapped_data_format; |
5017 | | |
5018 | | len -= sizeof(*params); |
5019 | | |
5020 | | if (params->control & WPA_PASN_CTRL_COMEBACK_INFO_PRESENT) { |
5021 | | if (from_ap) { |
5022 | | if (len < 2) { |
5023 | | wpa_printf(MSG_DEBUG, |
5024 | | "PASN: Invalid Parameters IE: Truncated Comeback After"); |
5025 | | return -1; |
5026 | | } |
5027 | | pasn_params->after = WPA_GET_LE16(pos); |
5028 | | pos += 2; |
5029 | | len -= 2; |
5030 | | } |
5031 | | |
5032 | | if (len < 1 || len < 1 + *pos) { |
5033 | | wpa_printf(MSG_DEBUG, |
5034 | | "PASN: Invalid Parameters IE: comeback len"); |
5035 | | return -1; |
5036 | | } |
5037 | | |
5038 | | pasn_params->comeback_len = *pos++; |
5039 | | len--; |
5040 | | pasn_params->comeback = pos; |
5041 | | len -= pasn_params->comeback_len; |
5042 | | pos += pasn_params->comeback_len; |
5043 | | } |
5044 | | |
5045 | | if (params->control & WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT) { |
5046 | | if (len < 3 || len < 3 + pos[2]) { |
5047 | | wpa_printf(MSG_DEBUG, |
5048 | | "PASN: Invalid Parameters IE: group and key"); |
5049 | | return -1; |
5050 | | } |
5051 | | |
5052 | | pasn_params->group = WPA_GET_LE16(pos); |
5053 | | pos += 2; |
5054 | | len -= 2; |
5055 | | pasn_params->pubkey_len = *pos++; |
5056 | | len--; |
5057 | | pasn_params->pubkey = pos; |
5058 | | len -= pasn_params->pubkey_len; |
5059 | | pos += pasn_params->pubkey_len; |
5060 | | } |
5061 | | |
5062 | | if (len) { |
5063 | | wpa_printf(MSG_DEBUG, |
5064 | | "PASN: Invalid Parameters IE. Bytes left=%u", len); |
5065 | | return -1; |
5066 | | } |
5067 | | |
5068 | | return 0; |
5069 | | } |
5070 | | |
5071 | | |
5072 | | void wpa_pasn_add_rsnxe(struct wpabuf *buf, u64 capab) |
5073 | | { |
5074 | | size_t flen; |
5075 | | |
5076 | | if (!capab) |
5077 | | return; /* no supported extended RSN capabilities */ |
5078 | | |
5079 | | /* Determine how many octets are needed to represent capab */ |
5080 | | if (capab & 0xFF00000000000000ULL) |
5081 | | flen = 8; |
5082 | | else if (capab & 0x00FF000000000000ULL) |
5083 | | flen = 7; |
5084 | | else if (capab & 0x0000FF0000000000ULL) |
5085 | | flen = 6; |
5086 | | else if (capab & 0x000000FF00000000ULL) |
5087 | | flen = 5; |
5088 | | else if (capab & 0xFF000000) |
5089 | | flen = 4; |
5090 | | else if (capab & 0x00FF0000) |
5091 | | flen = 3; |
5092 | | else if (capab & 0x0000FF00) |
5093 | | flen = 2; |
5094 | | else |
5095 | | flen = 1; |
5096 | | |
5097 | | if (wpabuf_tailroom(buf) < 2 + flen) |
5098 | | return; |
5099 | | capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */ |
5100 | | |
5101 | | wpabuf_put_u8(buf, WLAN_EID_RSNX); |
5102 | | wpabuf_put_u8(buf, flen); |
5103 | | |
5104 | | /* Write the little endian capability field octet-by-octet */ |
5105 | | wpabuf_put_u8(buf, capab & 0x000000FF); |
5106 | | if (flen > 1) |
5107 | | wpabuf_put_u8(buf, (capab >> 8) & 0x000000FF); |
5108 | | if (flen > 2) |
5109 | | wpabuf_put_u8(buf, (capab >> 16) & 0x000000FF); |
5110 | | if (flen > 3) |
5111 | | wpabuf_put_u8(buf, (capab >> 24) & 0x000000FF); |
5112 | | if (flen > 4) |
5113 | | wpabuf_put_u8(buf, (capab >> 32) & 0x000000FF); |
5114 | | if (flen > 5) |
5115 | | wpabuf_put_u8(buf, (capab >> 40) & 0x000000FF); |
5116 | | if (flen > 6) |
5117 | | wpabuf_put_u8(buf, (capab >> 48) & 0x000000FF); |
5118 | | if (flen > 7) |
5119 | | wpabuf_put_u8(buf, (capab >> 56) & 0x000000FF); |
5120 | | } |
5121 | | |
5122 | | |
5123 | | /* |
5124 | | * wpa_pasn_add_extra_ies - Add protocol specific IEs in Authentication |
5125 | | * frame for PASN. |
5126 | | * |
5127 | | * @buf: Buffer in which the elements will be added |
5128 | | * @extra_ies: Protocol specific elements to add |
5129 | | * @len: Length of the elements |
5130 | | * Returns: 0 on success, -1 on failure |
5131 | | */ |
5132 | | |
5133 | | int wpa_pasn_add_extra_ies(struct wpabuf *buf, const u8 *extra_ies, size_t len) |
5134 | | { |
5135 | | if (!len || !extra_ies || !buf) |
5136 | | return 0; |
5137 | | |
5138 | | if (wpabuf_tailroom(buf) < len) |
5139 | | return -1; |
5140 | | |
5141 | | wpabuf_put_data(buf, extra_ies, len); |
5142 | | return 0; |
5143 | | } |
5144 | | |
5145 | | #endif /* CONFIG_PASN */ |
5146 | | |
5147 | | |
5148 | | void rsn_set_snonce_cookie(u8 *snonce) |
5149 | 0 | { |
5150 | 0 | u8 *pos; |
5151 | |
|
5152 | 0 | pos = snonce + WPA_NONCE_LEN - 6; |
5153 | 0 | WPA_PUT_BE24(pos, OUI_WFA); |
5154 | 0 | pos += 3; |
5155 | 0 | WPA_PUT_BE24(pos, 0x000029); |
5156 | 0 | } |
5157 | | |
5158 | | |
5159 | | bool rsn_is_snonce_cookie(const u8 *snonce) |
5160 | 0 | { |
5161 | 0 | const u8 *pos; |
5162 | |
|
5163 | 0 | pos = snonce + WPA_NONCE_LEN - 6; |
5164 | 0 | return WPA_GET_BE24(pos) == OUI_WFA && |
5165 | 0 | WPA_GET_BE24(pos + 3) == 0x000029; |
5166 | 0 | } |
5167 | | |
5168 | | |
5169 | | void wpa_add_supported_groups(struct wpabuf *buf, const int *groups) |
5170 | 0 | { |
5171 | 0 | unsigned int count, i; |
5172 | 0 | static const int default_groups[] = { 19, 0 }; |
5173 | |
|
5174 | 0 | if (!buf) |
5175 | 0 | return; |
5176 | | |
5177 | 0 | if (!groups) |
5178 | 0 | groups = default_groups; |
5179 | |
|
5180 | 0 | count = int_array_len(groups); |
5181 | 0 | if (wpabuf_tailroom(buf) < 2 + 1 + count * 2) |
5182 | 0 | return; |
5183 | | |
5184 | 0 | wpabuf_put_u8(buf, WLAN_EID_EXTENSION); |
5185 | 0 | wpabuf_put_u8(buf, 1 + count * 2); |
5186 | 0 | wpabuf_put_u8(buf, WLAN_EID_EXT_SUPPORTED_GROUPS); |
5187 | 0 | for (i = 0; i < count; i++) |
5188 | 0 | wpabuf_put_le16(buf, groups[i]); |
5189 | 0 | } |
5190 | | |
5191 | | |
5192 | | static const struct security_profile_entry |
5193 | | security_profile_table[] = { |
5194 | | /* number, key_mgmt, pairwise_cipher, ieee8021x_auth_frame, |
5195 | | * assoc_frame_encrypt, pmksa_caching_privacy */ |
5196 | | |
5197 | | /* 0: EPPKE (AKM 29), unauth‑EPPKE allowed */ |
5198 | | { 0, WPA_KEY_MGMT_EPPKE, WPA_CIPHER_GCMP_256, false, true, true, -1 }, |
5199 | | |
5200 | | /* 1: EPPKE + SAE (AKM 29+24) */ |
5201 | | { 1, WPA_KEY_MGMT_EPPKE | WPA_KEY_MGMT_SAE_EXT_KEY, |
5202 | | WPA_CIPHER_GCMP_256, false, true, true, -1 }, |
5203 | | |
5204 | | /* 2: EPPKE + FT‑SAE (AKM 29+25) */ |
5205 | | { 2, WPA_KEY_MGMT_EPPKE | WPA_KEY_MGMT_FT_SAE_EXT_KEY, |
5206 | | WPA_CIPHER_GCMP_256, false, true, true, -1 }, |
5207 | | |
5208 | | /* 3: EPP 802.1X (AKM 5) */ |
5209 | | { 3, WPA_KEY_MGMT_IEEE8021X_SHA256, WPA_CIPHER_GCMP_256, |
5210 | | true, true, true, -1 }, |
5211 | | |
5212 | | /* 4: EPP FT‑802.1X (AKM 3) */ |
5213 | | { 4, WPA_KEY_MGMT_FT_IEEE8021X, WPA_CIPHER_GCMP_256, true, true, true, |
5214 | | -1 }, |
5215 | | |
5216 | | /* 5: EPP 802.1X (AKM 23) */ |
5217 | | { 5, WPA_KEY_MGMT_IEEE8021X_SHA384, WPA_CIPHER_GCMP_256, |
5218 | | true, true, true, -1 }, |
5219 | | |
5220 | | /* 6: EPP FT‑802.1X (AKM 22) */ |
5221 | | { 6, WPA_KEY_MGMT_FT_IEEE8021X_SHA384, WPA_CIPHER_GCMP_256, |
5222 | | true, true, true, -1 }, |
5223 | | |
5224 | | /* 7: EPP 802.1X (AKM 12) */ |
5225 | | { 7, WPA_KEY_MGMT_IEEE8021X_SUITE_B_192, WPA_CIPHER_GCMP_256, |
5226 | | true, true, true, -1 }, |
5227 | | |
5228 | | /* 8: OWE (AKM 18) */ |
5229 | | { 8, WPA_KEY_MGMT_OWE, WPA_CIPHER_GCMP_256, false, false, false, -1 }, |
5230 | | |
5231 | | /* 9: SAE (AKM 24) */ |
5232 | | { 9, WPA_KEY_MGMT_SAE_EXT_KEY, WPA_CIPHER_GCMP_256, |
5233 | | false, false, false, -1 }, |
5234 | | |
5235 | | #ifdef CONFIG_PQC |
5236 | | /* 16: PQC 802.1X (AKM 31), no ECP, SHA-512, ML-KEM-1024 */ |
5237 | | { SEC_PROF_8021X_PQC_0, WPA_KEY_MGMT_PQC_8021X, WPA_CIPHER_GCMP_256, |
5238 | | true, true, true, PQC_PROFILE_ML_KEM_1024 }, |
5239 | | |
5240 | | /* 17: PQC 802.1X (AKM 31), P-256, SHA-256, ML-KEM-512 */ |
5241 | | { SEC_PROF_8021X_PQC_1, WPA_KEY_MGMT_PQC_8021X, WPA_CIPHER_GCMP_256, |
5242 | | true, true, true, PQC_PROFILE_ECP_19_ML_KEM_512 }, |
5243 | | |
5244 | | /* 18: PQC 802.1X (AKM 31), P-384, SHA-384, ML-KEM-768 */ |
5245 | | { SEC_PROF_8021X_PQC_2, WPA_KEY_MGMT_PQC_8021X, WPA_CIPHER_GCMP_256, |
5246 | | true, true, true, PQC_PROFILE_ECP_20_ML_KEM_768 }, |
5247 | | |
5248 | | /* 19: PQC 802.1X (AKM 31), P-521, SHA-512, ML-KEM-1024 */ |
5249 | | { SEC_PROF_8021X_PQC_3, WPA_KEY_MGMT_PQC_8021X, WPA_CIPHER_GCMP_256, |
5250 | | true, true, true, PQC_PROFILE_ECP_21_ML_KEM_1024 }, |
5251 | | |
5252 | | /* 20: FT PQC 802.1X (AKM 32), no ECP, SHA-512, ML-KEM-1024 */ |
5253 | | { SEC_PROF_8021X_FT_PQC_0, WPA_KEY_MGMT_FT_PQC_8021X, |
5254 | | WPA_CIPHER_GCMP_256, true, true, true, PQC_PROFILE_ML_KEM_1024 }, |
5255 | | |
5256 | | /* 21: FT PQC 802.1X (AKM 32), P-256, SHA-256, ML-KEM-512 */ |
5257 | | { SEC_PROF_8021X_FT_PQC_1, WPA_KEY_MGMT_FT_PQC_8021X, |
5258 | | WPA_CIPHER_GCMP_256, true, true, true, |
5259 | | PQC_PROFILE_ECP_19_ML_KEM_512 }, |
5260 | | |
5261 | | /* 22: FT PQC 802.1X (AKM 32), P-384, SHA-384, ML-KEM-768 */ |
5262 | | { SEC_PROF_8021X_FT_PQC_2, WPA_KEY_MGMT_FT_PQC_8021X, |
5263 | | WPA_CIPHER_GCMP_256, true, true, true, |
5264 | | PQC_PROFILE_ECP_20_ML_KEM_768 }, |
5265 | | |
5266 | | /* 23: FT PQC 802.1X (AKM 32), P-521, SHA-512, ML-KEM-1024 */ |
5267 | | { SEC_PROF_8021X_FT_PQC_3, WPA_KEY_MGMT_FT_PQC_8021X, |
5268 | | WPA_CIPHER_GCMP_256, true, true, true, |
5269 | | PQC_PROFILE_ECP_21_ML_KEM_1024 }, |
5270 | | #endif /* CONFIG_PQC */ |
5271 | | }; |
5272 | | |
5273 | | |
5274 | | /** |
5275 | | * sec_prof_implied_key_mgmt - Derive implied key_mgmt from security profiles |
5276 | | * @profiles: -1 terminated int array of enabled security profile numbers |
5277 | | * Returns: Union of all AKMs defined by the enabled security profiles |
5278 | | */ |
5279 | | int sec_prof_implied_key_mgmt(const int *profiles) |
5280 | 0 | { |
5281 | 0 | int i, implied = 0; |
5282 | |
|
5283 | 0 | if (!profiles) |
5284 | 0 | return 0; |
5285 | | |
5286 | 0 | for (i = 0; profiles[i] >= 0; i++) { |
5287 | 0 | const struct security_profile_entry *sp; |
5288 | |
|
5289 | 0 | sp = sec_prof_get(profiles[i]); |
5290 | 0 | if (sp) |
5291 | 0 | implied |= sp->key_mgmt; |
5292 | 0 | } |
5293 | |
|
5294 | 0 | return implied; |
5295 | 0 | } |
5296 | | |
5297 | | |
5298 | | const struct security_profile_entry * sec_prof_get(int p) |
5299 | 0 | { |
5300 | 0 | unsigned int i; |
5301 | |
|
5302 | 0 | for (i = 0; i < ARRAY_SIZE(security_profile_table); i++) { |
5303 | 0 | const struct security_profile_entry *sp; |
5304 | |
|
5305 | 0 | sp = &security_profile_table[i]; |
5306 | 0 | if (sp->number == p) |
5307 | 0 | return sp; |
5308 | 0 | } |
5309 | | |
5310 | 0 | return NULL; |
5311 | 0 | } |
5312 | | |
5313 | | |
5314 | | #ifdef CONFIG_PQC |
5315 | | |
5316 | | /* |
5317 | | * Global table of PQC profiles as defined in IEEE P802.11bt/D1.0, |
5318 | | * Table 12-aa1 (PQC profiles). |
5319 | | */ |
5320 | | static const struct ieee80211_pqc_profile g_pqc_profiles[] = { |
5321 | | { PQC_PROFILE_ML_KEM_1024, 0, RSN_HASH_SHA512, CRYPTO_ML_KEM_1024 }, |
5322 | | { PQC_PROFILE_ECP_19_ML_KEM_512, 19, RSN_HASH_SHA256, |
5323 | | CRYPTO_ML_KEM_512 }, |
5324 | | { PQC_PROFILE_ECP_20_ML_KEM_768, 20, RSN_HASH_SHA384, |
5325 | | CRYPTO_ML_KEM_768 }, |
5326 | | { PQC_PROFILE_ECP_21_ML_KEM_1024, 21, RSN_HASH_SHA512, |
5327 | | CRYPTO_ML_KEM_1024 }, |
5328 | | { PQC_PROFILE_NONE, 0, 0, 0 } |
5329 | | }; |
5330 | | |
5331 | | |
5332 | | const struct ieee80211_pqc_profile * |
5333 | | pqc_profile_get(int security_profile_num) |
5334 | | { |
5335 | | const struct security_profile_entry *sp = |
5336 | | sec_prof_get(security_profile_num); |
5337 | | int i; |
5338 | | |
5339 | | if (!sp || sp->pqc_profile < 0) { |
5340 | | wpa_printf(MSG_ERROR, |
5341 | | "Invalid PQC security profile number: %u", |
5342 | | security_profile_num); |
5343 | | return NULL; |
5344 | | } |
5345 | | |
5346 | | for (i = 0; g_pqc_profiles[i].number != PQC_PROFILE_NONE; i++) { |
5347 | | if (g_pqc_profiles[i].number == sp->pqc_profile) |
5348 | | return &g_pqc_profiles[i]; |
5349 | | } |
5350 | | |
5351 | | return NULL; |
5352 | | } |
5353 | | |
5354 | | #endif /* CONFIG_PQC */ |
5355 | | |
5356 | | |
5357 | | #if defined(CONFIG_SAE) || defined(CONFIG_PQC) |
5358 | | |
5359 | | int hkdf_extract(size_t hash_len, const u8 *salt, size_t salt_len, |
5360 | | size_t num_elem, const u8 *addr[], const size_t len[], |
5361 | | u8 *prk) |
5362 | 0 | { |
5363 | | #ifdef CONFIG_SHA256 |
5364 | | if (hash_len == 32) |
5365 | | return hmac_sha256_vector(salt, salt_len, num_elem, addr, len, |
5366 | | prk); |
5367 | | #endif /* CONFIG_SHA256 */ |
5368 | | #ifdef CONFIG_SHA384 |
5369 | | if (hash_len == 48) |
5370 | | return hmac_sha384_vector(salt, salt_len, num_elem, addr, len, |
5371 | | prk); |
5372 | | #endif /* CONFIG_SHA384 */ |
5373 | | #ifdef CONFIG_SHA512 |
5374 | | if (hash_len == 64) |
5375 | | return hmac_sha512_vector(salt, salt_len, num_elem, addr, len, |
5376 | | prk); |
5377 | | #endif /* CONFIG_SHA512 */ |
5378 | 0 | return -1; |
5379 | 0 | } |
5380 | | |
5381 | | |
5382 | | int hkdf_expand_bin(size_t hash_len, const u8 *prk, size_t prk_len, |
5383 | | const u8 *info, size_t info_len, u8 *okm, size_t okm_len) |
5384 | 0 | { |
5385 | | #ifdef CONFIG_SHA256 |
5386 | | if (hash_len == 32) |
5387 | | return hmac_sha256_kdf(prk, prk_len, NULL, |
5388 | | (const u8 *) info, info_len, |
5389 | | okm, okm_len); |
5390 | | #endif /* CONFIG_SHA256 */ |
5391 | | #ifdef CONFIG_SHA384 |
5392 | | if (hash_len == 48) |
5393 | | return hmac_sha384_kdf(prk, prk_len, NULL, |
5394 | | (const u8 *) info, info_len, |
5395 | | okm, okm_len); |
5396 | | #endif /* CONFIG_SHA384 */ |
5397 | | #ifdef CONFIG_SHA512 |
5398 | | if (hash_len == 64) |
5399 | | return hmac_sha512_kdf(prk, prk_len, NULL, |
5400 | | (const u8 *) info, info_len, |
5401 | | okm, okm_len); |
5402 | | #endif /* CONFIG_SHA512 */ |
5403 | 0 | return -1; |
5404 | 0 | } |
5405 | | |
5406 | | |
5407 | | int hkdf_expand(size_t hash_len, const u8 *prk, size_t prk_len, |
5408 | | const char *info, u8 *okm, size_t okm_len) |
5409 | 0 | { |
5410 | 0 | return hkdf_expand_bin(hash_len, prk, prk_len, (const u8 *) info, |
5411 | 0 | os_strlen(info), okm, okm_len); |
5412 | 0 | } |
5413 | | |
5414 | | #endif /* CONFIG_SAE || CONFIG_PQC */ |