blob: 7501e7a56a027f65025a0b5357befcf29b5091ad [file] [log] [blame]
Sunil Ravi77d572f2023-01-17 23:58:31 +00001/*
2 * PASN responder processing
3 *
4 * Copyright (C) 2019, Intel Corporation
5 * Copyright (C) 2022, Qualcomm Innovation Center, Inc.
6 *
7 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
9 */
10
11#include "utils/includes.h"
12
13#include "utils/common.h"
14#include "common/wpa_common.h"
15#include "common/sae.h"
16#include "common/ieee802_11_common.h"
17#include "common/ieee802_11_defs.h"
18#include "crypto/sha384.h"
19#include "crypto/sha256.h"
20#include "crypto/random.h"
21#include "crypto/crypto.h"
22#include "ap/hostapd.h"
23#include "ap/comeback_token.h"
24#include "ap/ieee802_1x.h"
25#include "ap/pmksa_cache_auth.h"
26#include "pasn_common.h"
27
28#ifdef CONFIG_PASN
29#ifdef CONFIG_SAE
30
31static int pasn_wd_handle_sae_commit(struct pasn_data *pasn,
32 const u8 *own_addr, const u8 *peer_addr,
33 struct wpabuf *wd)
34{
35 const u8 *data;
36 size_t buf_len;
37 u16 res, alg, seq, status;
38 int groups[] = { pasn->group, 0 };
39 int ret;
40
41 if (!wd)
42 return -1;
43
44 data = wpabuf_head_u8(wd);
45 buf_len = wpabuf_len(wd);
46
47 if (buf_len < 6) {
48 wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu",
49 buf_len);
50 return -1;
51 }
52
53 alg = WPA_GET_LE16(data);
54 seq = WPA_GET_LE16(data + 2);
55 status = WPA_GET_LE16(data + 4);
56
57 wpa_printf(MSG_DEBUG, "PASN: SAE commit: alg=%u, seq=%u, status=%u",
58 alg, seq, status);
59
60 if (alg != WLAN_AUTH_SAE || seq != 1 ||
61 status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
62 wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit");
63 return -1;
64 }
65
66 sae_clear_data(&pasn->sae);
67 pasn->sae.state = SAE_NOTHING;
68
69 ret = sae_set_group(&pasn->sae, pasn->group);
70 if (ret) {
71 wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group");
72 return -1;
73 }
74
75 if (!pasn->password || !pasn->pt) {
76 wpa_printf(MSG_DEBUG, "PASN: No SAE PT found");
77 return -1;
78 }
79
80 ret = sae_prepare_commit_pt(&pasn->sae, pasn->pt, own_addr, peer_addr,
81 NULL, NULL);
82 if (ret) {
83 wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit");
84 return -1;
85 }
86
87 res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0,
88 groups, 0, NULL);
89 if (res != WLAN_STATUS_SUCCESS) {
90 wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit");
91 return -1;
92 }
93
94 /* Process the commit message and derive the PMK */
95 ret = sae_process_commit(&pasn->sae);
96 if (ret) {
97 wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
98 return -1;
99 }
100
101 pasn->sae.state = SAE_COMMITTED;
102
103 return 0;
104}
105
106
107static int pasn_wd_handle_sae_confirm(struct pasn_data *pasn,
108 const u8 *peer_addr, struct wpabuf *wd)
109{
110 const u8 *data;
111 size_t buf_len;
112 u16 res, alg, seq, status;
113
114 if (!wd)
115 return -1;
116
117 data = wpabuf_head_u8(wd);
118 buf_len = wpabuf_len(wd);
119
120 if (buf_len < 6) {
121 wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu",
122 buf_len);
123 return -1;
124 }
125
126 alg = WPA_GET_LE16(data);
127 seq = WPA_GET_LE16(data + 2);
128 status = WPA_GET_LE16(data + 4);
129
130 wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u",
131 alg, seq, status);
132
133 if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) {
134 wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm");
135 return -1;
136 }
137
138 res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6, NULL);
139 if (res != WLAN_STATUS_SUCCESS) {
140 wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm");
141 return -1;
142 }
143
144 pasn->sae.state = SAE_ACCEPTED;
145
146 /*
147 * TODO: Based on on IEEE P802.11az/D2.6, the PMKSA derived with
148 * PASN/SAE should only be allowed with future PASN only. For now do not
149 * restrict this only for PASN.
150 */
151 if (pasn->disable_pmksa_caching)
152 return 0;
153
154 wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE",
155 pasn->sae.pmk, pasn->sae.pmk_len);
156 if (!pasn->sae.akmp)
157 pasn->sae.akmp = WPA_KEY_MGMT_SAE;
158
159 pmksa_cache_auth_add(pasn->pmksa, pasn->sae.pmk, pasn->sae.pmk_len,
160 pasn->sae.pmkid, NULL, 0, pasn->own_addr,
161 peer_addr, 0, NULL, pasn->sae.akmp);
162 return 0;
163}
164
165
166static struct wpabuf * pasn_get_sae_wd(struct pasn_data *pasn)
167{
168 struct wpabuf *buf = NULL;
169 u8 *len_ptr;
170 size_t len;
171
172 /* Need to add the entire Authentication frame body */
173 buf = wpabuf_alloc(8 + SAE_COMMIT_MAX_LEN + 8 + SAE_CONFIRM_MAX_LEN);
174 if (!buf) {
175 wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
176 return NULL;
177 }
178
179 /* Need to add the entire authentication frame body for the commit */
180 len_ptr = wpabuf_put(buf, 2);
181 wpabuf_put_le16(buf, WLAN_AUTH_SAE);
182 wpabuf_put_le16(buf, 1);
183 wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
184
185 /* Write the actual commit and update the length accordingly */
186 sae_write_commit(&pasn->sae, buf, NULL, 0);
187 len = wpabuf_len(buf);
188 WPA_PUT_LE16(len_ptr, len - 2);
189
190 /* Need to add the entire Authentication frame body for the confirm */
191 len_ptr = wpabuf_put(buf, 2);
192 wpabuf_put_le16(buf, WLAN_AUTH_SAE);
193 wpabuf_put_le16(buf, 2);
194 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
195
196 sae_write_confirm(&pasn->sae, buf);
197 WPA_PUT_LE16(len_ptr, wpabuf_len(buf) - len - 2);
198
199 pasn->sae.state = SAE_CONFIRMED;
200
201 return buf;
202}
203
204#endif /* CONFIG_SAE */
205
206
207#ifdef CONFIG_FILS
208
209static struct wpabuf * pasn_get_fils_wd(struct pasn_data *pasn)
210{
211 struct pasn_fils *fils = &pasn->fils;
212 struct wpabuf *buf = NULL;
213
214 if (!fils->erp_resp) {
215 wpa_printf(MSG_DEBUG, "PASN: FILS: Missing erp_resp");
216 return NULL;
217 }
218
219 buf = wpabuf_alloc(1500);
220 if (!buf)
221 return NULL;
222
223 /* Add the authentication algorithm */
224 wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK);
225
226 /* Authentication Transaction seq# */
227 wpabuf_put_le16(buf, 2);
228
229 /* Status Code */
230 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
231
232 /* Own RSNE */
233 wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
234
235 /* FILS Nonce */
236 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
237 wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN);
238 wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
239 wpabuf_put_data(buf, fils->anonce, FILS_NONCE_LEN);
240
241 /* FILS Session */
242 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
243 wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN);
244 wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
245 wpabuf_put_data(buf, fils->session, FILS_SESSION_LEN);
246
247 /* Wrapped Data */
248 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
249 wpabuf_put_u8(buf, 1 + wpabuf_len(fils->erp_resp));
250 wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
251 wpabuf_put_buf(buf, fils->erp_resp);
252
253 return buf;
254}
255
256#endif /* CONFIG_FILS */
257
258static struct wpabuf * pasn_get_wrapped_data(struct pasn_data *pasn)
259{
260 switch (pasn->akmp) {
261 case WPA_KEY_MGMT_PASN:
262 /* no wrapped data */
263 return NULL;
264 case WPA_KEY_MGMT_SAE:
265#ifdef CONFIG_SAE
266 return pasn_get_sae_wd(pasn);
267#else /* CONFIG_SAE */
268 wpa_printf(MSG_ERROR,
269 "PASN: SAE: Cannot derive wrapped data");
270 return NULL;
271#endif /* CONFIG_SAE */
272 case WPA_KEY_MGMT_FILS_SHA256:
273 case WPA_KEY_MGMT_FILS_SHA384:
274#ifdef CONFIG_FILS
275 return pasn_get_fils_wd(pasn);
276#endif /* CONFIG_FILS */
277 /* fall through */
278 case WPA_KEY_MGMT_FT_PSK:
279 case WPA_KEY_MGMT_FT_IEEE8021X:
280 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
281 default:
282 wpa_printf(MSG_ERROR,
283 "PASN: TODO: Wrapped data for akmp=0x%x",
284 pasn->akmp);
285 return NULL;
286 }
287}
288
289
290static int
291pasn_derive_keys(struct pasn_data *pasn,
292 const u8 *own_addr, const u8 *peer_addr,
293 const u8 *cached_pmk, size_t cached_pmk_len,
294 struct wpa_pasn_params_data *pasn_data,
295 struct wpabuf *wrapped_data,
296 struct wpabuf *secret)
297{
298 static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'};
299 u8 pmk[PMK_LEN_MAX];
300 u8 pmk_len;
301 int ret;
302
303 os_memset(pmk, 0, sizeof(pmk));
304 pmk_len = 0;
305
306 if (!cached_pmk || !cached_pmk_len)
307 wpa_printf(MSG_DEBUG, "PASN: No valid PMKSA entry");
308
309 if (pasn->akmp == WPA_KEY_MGMT_PASN) {
310 wpa_printf(MSG_DEBUG, "PASN: Using default PMK");
311
312 pmk_len = WPA_PASN_PMK_LEN;
313 os_memcpy(pmk, pasn_default_pmk, sizeof(pasn_default_pmk));
314 } else if (cached_pmk && cached_pmk_len) {
315 wpa_printf(MSG_DEBUG, "PASN: Using PMKSA entry");
316
317 pmk_len = cached_pmk_len;
318 os_memcpy(pmk, cached_pmk, cached_pmk_len);
319 } else {
320 switch (pasn->akmp) {
321#ifdef CONFIG_SAE
322 case WPA_KEY_MGMT_SAE:
323 if (pasn->sae.state == SAE_COMMITTED) {
324 pmk_len = PMK_LEN;
325 os_memcpy(pmk, pasn->sae.pmk, PMK_LEN);
326 break;
327 }
328#endif /* CONFIG_SAE */
329 /* fall through */
330 default:
331 /* TODO: Derive PMK based on wrapped data */
332 wpa_printf(MSG_DEBUG,
333 "PASN: Missing PMK derivation");
334 return -1;
335 }
336 }
337
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000338 pasn->pmk_len = pmk_len;
339 os_memcpy(pasn->pmk, pmk, pmk_len);
Sunil Ravi77d572f2023-01-17 23:58:31 +0000340 ret = pasn_pmk_to_ptk(pmk, pmk_len, peer_addr, own_addr,
341 wpabuf_head(secret), wpabuf_len(secret),
342 &pasn->ptk, pasn->akmp,
343 pasn->cipher, pasn->kdk_len);
344 if (ret) {
345 wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
346 return -1;
347 }
348
349 if (pasn->secure_ltf) {
350 ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp,
351 pasn->cipher);
352 if (ret) {
353 wpa_printf(MSG_DEBUG,
354 "PASN: Failed to derive LTF keyseed");
355 return -1;
356 }
357 }
358
359 wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
360 return 0;
361}
362
363
364static void handle_auth_pasn_comeback(struct pasn_data *pasn,
365 const u8 *own_addr, const u8 *peer_addr,
366 u16 group)
367{
368 struct wpabuf *buf, *comeback;
369 int ret;
370
371 wpa_printf(MSG_DEBUG,
372 "PASN: Building comeback frame 2. Comeback after=%u",
373 pasn->comeback_after);
374
375 buf = wpabuf_alloc(1500);
376 if (!buf)
377 return;
378
379 wpa_pasn_build_auth_header(buf, pasn->bssid, own_addr, peer_addr, 2,
380 WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY);
381
382 /*
383 * Do not include the group as a part of the token since it is not going
384 * to be used.
385 */
386 comeback = auth_build_token_req(&pasn->last_comeback_key_update,
387 pasn->comeback_key, pasn->comeback_idx,
388 pasn->comeback_pending_idx,
389 sizeof(u16) * COMEBACK_PENDING_IDX_SIZE,
390 0, peer_addr, 0);
391 if (!comeback) {
392 wpa_printf(MSG_DEBUG,
393 "PASN: Failed sending auth with comeback");
394 wpabuf_free(buf);
395 return;
396 }
397
398 wpa_pasn_add_parameter_ie(buf, group,
399 WPA_PASN_WRAPPED_DATA_NO,
400 NULL, 0, comeback,
401 pasn->comeback_after);
402 wpabuf_free(comeback);
403
404 wpa_printf(MSG_DEBUG,
405 "PASN: comeback: STA=" MACSTR, MAC2STR(peer_addr));
406
407 ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf),
408 wpabuf_len(buf), 0, 0, 0);
409 if (ret)
410 wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2");
411
412 wpabuf_free(buf);
413}
414
415
416int handle_auth_pasn_resp(struct pasn_data *pasn, const u8 *own_addr,
417 const u8 *peer_addr,
418 struct rsn_pmksa_cache_entry *pmksa, u16 status)
419{
420 struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
421 struct wpabuf *rsn_buf = NULL;
422 u8 mic[WPA_PASN_MAX_MIC_LEN];
423 u8 mic_len;
424 u8 *ptr;
425 const u8 *frame, *data, *rsn_ie, *rsnxe_ie;
426 u8 *data_buf = NULL;
427 size_t frame_len, data_len;
428 int ret;
429 const u8 *pmkid = NULL;
430
431 wpa_printf(MSG_DEBUG, "PASN: Building frame 2: status=%u", status);
432
433 buf = wpabuf_alloc(1500);
434 if (!buf)
435 goto fail;
436
437 wpa_pasn_build_auth_header(buf, pasn->bssid, own_addr, peer_addr, 2,
438 status);
439
440 if (status != WLAN_STATUS_SUCCESS)
441 goto done;
442
443 if (pmksa && pasn->custom_pmkid_valid)
444 pmkid = pasn->custom_pmkid;
445 else if (pmksa) {
446 pmkid = pmksa->pmkid;
447#ifdef CONFIG_SAE
448 } else if (pasn->akmp == WPA_KEY_MGMT_SAE) {
449 wpa_printf(MSG_DEBUG, "PASN: Use SAE PMKID");
450 pmkid = pasn->sae.pmkid;
451#endif /* CONFIG_SAE */
452#ifdef CONFIG_FILS
453 } else if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
454 pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
455 wpa_printf(MSG_DEBUG, "PASN: Use FILS ERP PMKID");
456 pmkid = pasn->fils.erp_pmkid;
457#endif /* CONFIG_FILS */
458 }
459
460 if (wpa_pasn_add_rsne(buf, pmkid,
461 pasn->akmp, pasn->cipher) < 0)
462 goto fail;
463
464 /* No need to derive PMK if PMKSA is given */
465 if (!pmksa)
466 wrapped_data_buf = pasn_get_wrapped_data(pasn);
467 else
468 pasn->wrapped_data_format = WPA_PASN_WRAPPED_DATA_NO;
469
470 /* Get public key */
471 pubkey = crypto_ecdh_get_pubkey(pasn->ecdh, 0);
472 pubkey = wpabuf_zeropad(pubkey,
473 crypto_ecdh_prime_len(pasn->ecdh));
474 if (!pubkey) {
475 wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey");
476 goto fail;
477 }
478
479 wpa_pasn_add_parameter_ie(buf, pasn->group,
480 pasn->wrapped_data_format,
481 pubkey, true, NULL, 0);
482
483 if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
484 goto fail;
485
486 wpabuf_free(wrapped_data_buf);
487 wrapped_data_buf = NULL;
488 wpabuf_free(pubkey);
489 pubkey = NULL;
490
491 /* Add RSNXE if needed */
492 rsnxe_ie = pasn->rsnxe_ie;
493 if (rsnxe_ie)
494 wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]);
495
496 wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len);
497
498 /* Add the mic */
499 mic_len = pasn_mic_len(pasn->akmp, pasn->cipher);
500 wpabuf_put_u8(buf, WLAN_EID_MIC);
501 wpabuf_put_u8(buf, mic_len);
502 ptr = wpabuf_put(buf, mic_len);
503
504 os_memset(ptr, 0, mic_len);
505
506 frame = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
507 frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
508
509 if (pasn->rsn_ie && pasn->rsn_ie_len) {
510 rsn_ie = pasn->rsn_ie;
511 } else {
512 /*
513 * Note: when pasn->rsn_ie is NULL, it is likely that Beacon
514 * frame RSNE is not initialized. This is possible in case of
515 * PASN authentication used for Wi-Fi Aware for which Beacon
516 * frame RSNE and RSNXE are same as RSNE and RSNXE in the
517 * Authentication frame.
518 */
519 rsn_buf = wpabuf_alloc(500);
520 if (!rsn_buf)
521 goto fail;
522
523 if (wpa_pasn_add_rsne(rsn_buf, pmkid,
524 pasn->akmp, pasn->cipher) < 0)
525 goto fail;
526
527 rsn_ie = wpabuf_head_u8(rsn_buf);
528 }
529
530 /*
531 * Note: wpa_auth_get_wpa_ie() might return not only the RSNE but also
532 * MDE, etc. Thus, do not use the returned length but instead use the
533 * length specified in the IE header.
534 */
535 data_len = rsn_ie[1] + 2;
536 if (rsnxe_ie) {
537 data_buf = os_zalloc(rsn_ie[1] + 2 + rsnxe_ie[1] + 2);
538 if (!data_buf)
539 goto fail;
540
541 os_memcpy(data_buf, rsn_ie, rsn_ie[1] + 2);
542 os_memcpy(data_buf + rsn_ie[1] + 2, rsnxe_ie, rsnxe_ie[1] + 2);
543 data_len += rsnxe_ie[1] + 2;
544 data = data_buf;
545 } else {
546 data = rsn_ie;
547 }
548
549 ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
550 own_addr, peer_addr, data, data_len,
551 frame, frame_len, mic);
552 os_free(data_buf);
553 if (ret) {
554 wpa_printf(MSG_DEBUG, "PASN: Frame 3: Failed MIC calculation");
555 goto fail;
556 }
557
558#ifdef CONFIG_TESTING_OPTIONS
559 if (pasn->corrupt_mic) {
560 wpa_printf(MSG_DEBUG, "PASN: frame 2: Corrupt MIC");
561 mic[0] = ~mic[0];
562 }
563#endif /* CONFIG_TESTING_OPTIONS */
564
565 os_memcpy(ptr, mic, mic_len);
566
567done:
568 wpa_printf(MSG_DEBUG,
569 "PASN: Building frame 2: success; resp STA=" MACSTR,
570 MAC2STR(peer_addr));
571
572 ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf),
573 wpabuf_len(buf), 0, 0, 0);
574 if (ret)
575 wpa_printf(MSG_INFO, "send_auth_reply: Send failed");
576
577 wpabuf_free(rsn_buf);
578 wpabuf_free(buf);
579 return ret;
580fail:
581 wpabuf_free(wrapped_data_buf);
582 wpabuf_free(pubkey);
583 wpabuf_free(rsn_buf);
584 wpabuf_free(buf);
585 return -1;
586}
587
588
589int handle_auth_pasn_1(struct pasn_data *pasn,
590 const u8 *own_addr, const u8 *peer_addr,
591 const struct ieee80211_mgmt *mgmt, size_t len)
592{
593 struct ieee802_11_elems elems;
594 struct wpa_ie_data rsn_data;
595 struct wpa_pasn_params_data pasn_params;
596 struct rsn_pmksa_cache_entry *pmksa = NULL;
597 const u8 *cached_pmk = NULL;
598 size_t cached_pmk_len = 0;
599 struct wpabuf *wrapped_data = NULL, *secret = NULL;
600 const int *groups = pasn->pasn_groups;
601 static const int default_groups[] = { 19, 0 };
602 u16 status = WLAN_STATUS_SUCCESS;
603 int ret, inc_y;
604 bool derive_keys;
605 u32 i;
606
607 if (!groups)
608 groups = default_groups;
609
610 if (ieee802_11_parse_elems(mgmt->u.auth.variable,
611 len - offsetof(struct ieee80211_mgmt,
612 u.auth.variable),
613 &elems, 0) == ParseFailed) {
614 wpa_printf(MSG_DEBUG,
615 "PASN: Failed parsing Authentication frame");
616 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
617 goto send_resp;
618 }
619
620 if (!elems.rsn_ie) {
621 wpa_printf(MSG_DEBUG, "PASN: No RSNE");
622 status = WLAN_STATUS_INVALID_RSNIE;
623 goto send_resp;
624 }
625
626 ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
627 &rsn_data);
628 if (ret) {
629 wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE");
630 status = WLAN_STATUS_INVALID_RSNIE;
631 goto send_resp;
632 }
633
634 ret = wpa_pasn_validate_rsne(&rsn_data);
635 if (ret) {
636 wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
637 status = WLAN_STATUS_INVALID_RSNIE;
638 goto send_resp;
639 }
640
641 if (!(rsn_data.key_mgmt & pasn->wpa_key_mgmt) ||
642 !(rsn_data.pairwise_cipher & pasn->rsn_pairwise)) {
643 wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
644 status = WLAN_STATUS_INVALID_RSNIE;
645 goto send_resp;
646 }
647
648 pasn->akmp = rsn_data.key_mgmt;
649 pasn->cipher = rsn_data.pairwise_cipher;
650
651 if (pasn->derive_kdk &&
652 ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
653 WLAN_RSNX_CAPAB_SECURE_LTF))
654 pasn->secure_ltf = true;
655
656 if (pasn->derive_kdk)
657 pasn->kdk_len = WPA_KDK_MAX_LEN;
658 else
659 pasn->kdk_len = 0;
660
661 wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len);
662
663 if (!elems.pasn_params || !elems.pasn_params_len) {
664 wpa_printf(MSG_DEBUG,
665 "PASN: No PASN Parameters element found");
666 status = WLAN_STATUS_INVALID_PARAMETERS;
667 goto send_resp;
668 }
669
670 ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
671 elems.pasn_params_len + 3,
672 false, &pasn_params);
673 if (ret) {
674 wpa_printf(MSG_DEBUG,
675 "PASN: Failed validation of PASN Parameters IE");
676 status = WLAN_STATUS_INVALID_PARAMETERS;
677 goto send_resp;
678 }
679
680 for (i = 0; groups[i] > 0 && groups[i] != pasn_params.group; i++)
681 ;
682
683 if (!pasn_params.group || groups[i] != pasn_params.group) {
684 wpa_printf(MSG_DEBUG, "PASN: Requested group=%hu not allowed",
685 pasn_params.group);
686 status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
687 goto send_resp;
688 }
689
690 if (!pasn_params.pubkey || !pasn_params.pubkey_len) {
691 wpa_printf(MSG_DEBUG, "PASN: Invalid public key");
692 status = WLAN_STATUS_INVALID_PARAMETERS;
693 goto send_resp;
694 }
695
696 if (pasn_params.comeback) {
697 wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token");
698
699 ret = check_comeback_token(pasn->comeback_key,
700 pasn->comeback_pending_idx,
701 peer_addr,
702 pasn_params.comeback,
703 pasn_params.comeback_len);
704
705 if (ret) {
706 wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token");
707 status = WLAN_STATUS_INVALID_PARAMETERS;
708 goto send_resp;
709 }
710 } else if (pasn->use_anti_clogging) {
711 wpa_printf(MSG_DEBUG, "PASN: Respond with comeback");
712 handle_auth_pasn_comeback(pasn, own_addr, peer_addr,
713 pasn_params.group);
714 return -1;
715 }
716
717 pasn->ecdh = crypto_ecdh_init(pasn_params.group);
718 if (!pasn->ecdh) {
719 wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
720 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
721 goto send_resp;
722 }
723
724 pasn->group = pasn_params.group;
725
726 if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) {
727 inc_y = 1;
728 } else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 ||
729 pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) {
730 inc_y = 0;
731 } else {
732 wpa_printf(MSG_DEBUG,
733 "PASN: Invalid first octet in pubkey=0x%x",
734 pasn_params.pubkey[0]);
735 status = WLAN_STATUS_INVALID_PUBLIC_KEY;
736 goto send_resp;
737 }
738
739 secret = crypto_ecdh_set_peerkey(pasn->ecdh, inc_y,
740 pasn_params.pubkey + 1,
741 pasn_params.pubkey_len - 1);
742 if (!secret) {
743 wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
744 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
745 goto send_resp;
746 }
747
Sunil Ravi640215c2023-06-28 23:08:09 +0000748 if (!pasn->noauth && pasn->akmp == WPA_KEY_MGMT_PASN) {
749 wpa_printf(MSG_DEBUG, "PASN: Refuse PASN-UNAUTH");
750 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
751 goto send_resp;
752 }
753
Sunil Ravi77d572f2023-01-17 23:58:31 +0000754 derive_keys = true;
755 if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000756 wrapped_data = ieee802_11_defrag(elems.wrapped_data,
757 elems.wrapped_data_len, true);
Sunil Ravi77d572f2023-01-17 23:58:31 +0000758 if (!wrapped_data) {
759 wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
760 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
761 goto send_resp;
762 }
763
764#ifdef CONFIG_SAE
765 if (pasn->akmp == WPA_KEY_MGMT_SAE) {
766 ret = pasn_wd_handle_sae_commit(pasn, own_addr,
767 peer_addr,
768 wrapped_data);
769 if (ret) {
770 wpa_printf(MSG_DEBUG,
771 "PASN: Failed processing SAE commit");
772 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
773 goto send_resp;
774 }
775 }
776#endif /* CONFIG_SAE */
777#ifdef CONFIG_FILS
778 if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
779 pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
780 if (!pasn->fils_wd_valid) {
781 wpa_printf(MSG_DEBUG,
782 "PASN: Invalid FILS wrapped data");
783 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
784 goto send_resp;
785 }
786
787 wpa_printf(MSG_DEBUG,
788 "PASN: FILS: Pending AS response");
789
790 /*
791 * With PASN/FILS, keys can be derived only after a
792 * response from the AS is processed.
793 */
794 derive_keys = false;
795 }
796#endif /* CONFIG_FILS */
797 }
798
799 pasn->wrapped_data_format = pasn_params.wrapped_data_format;
800
801 ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher,
802 ((const u8 *) mgmt) + IEEE80211_HDRLEN,
803 len - IEEE80211_HDRLEN, pasn->hash);
804 if (ret) {
805 wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
806 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
807 goto send_resp;
808 }
809
810 if (!derive_keys) {
811 wpa_printf(MSG_DEBUG, "PASN: Storing secret");
812 pasn->secret = secret;
813 wpabuf_free(wrapped_data);
814 return 0;
815 }
816
817 if (rsn_data.num_pmkid) {
818 if (wpa_key_mgmt_ft(pasn->akmp)) {
819#ifdef CONFIG_IEEE80211R_AP
820 wpa_printf(MSG_DEBUG, "PASN: FT: Fetch PMK-R1");
821
822 if (!pasn->pmk_r1_len) {
823 wpa_printf(MSG_DEBUG,
824 "PASN: FT: Failed getting PMK-R1");
825 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
826 goto send_resp;
827 }
828 cached_pmk = pasn->pmk_r1;
829 cached_pmk_len = pasn->pmk_r1_len;
830#else /* CONFIG_IEEE80211R_AP */
831 wpa_printf(MSG_DEBUG, "PASN: FT: Not supported");
832 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
833 goto send_resp;
834#endif /* CONFIG_IEEE80211R_AP */
835 } else {
836 wpa_printf(MSG_DEBUG, "PASN: Try to find PMKSA entry");
837
838 if (pasn->pmksa) {
839 const u8 *pmkid = NULL;
840
841 if (pasn->custom_pmkid_valid) {
842 ret = pasn->validate_custom_pmkid(
843 pasn->cb_ctx, peer_addr,
844 rsn_data.pmkid);
845 if (ret) {
846 wpa_printf(MSG_DEBUG,
847 "PASN: Failed custom PMKID validation");
848 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
849 goto send_resp;
850 }
851 } else {
852 pmkid = rsn_data.pmkid;
853 }
854
855 pmksa = pmksa_cache_auth_get(pasn->pmksa,
856 peer_addr,
857 pmkid);
858 if (pmksa) {
859 cached_pmk = pmksa->pmk;
860 cached_pmk_len = pmksa->pmk_len;
861 }
862 }
863 }
864 } else {
865 wpa_printf(MSG_DEBUG, "PASN: No PMKID specified");
866 }
867
868 ret = pasn_derive_keys(pasn, own_addr, peer_addr,
869 cached_pmk, cached_pmk_len,
870 &pasn_params, wrapped_data, secret);
871 if (ret) {
872 wpa_printf(MSG_DEBUG, "PASN: Failed to derive keys");
873 status = WLAN_STATUS_PASN_BASE_AKMP_FAILED;
874 goto send_resp;
875 }
876
877 ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher,
878 ((const u8 *) mgmt) + IEEE80211_HDRLEN,
879 len - IEEE80211_HDRLEN, pasn->hash);
880 if (ret) {
881 wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
882 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
883 }
884
885send_resp:
886 ret = handle_auth_pasn_resp(pasn, own_addr, peer_addr, pmksa, status);
887 if (ret) {
888 wpa_printf(MSG_DEBUG, "PASN: Failed to send response");
889 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
890 } else {
891 wpa_printf(MSG_DEBUG,
892 "PASN: Success handling transaction == 1");
893 }
894
895 wpabuf_free(secret);
896 wpabuf_free(wrapped_data);
897
898 if (status != WLAN_STATUS_SUCCESS)
899 return -1;
900
901 return 0;
902}
903
904
905int handle_auth_pasn_3(struct pasn_data *pasn, const u8 *own_addr,
906 const u8 *peer_addr,
907 const struct ieee80211_mgmt *mgmt, size_t len)
908{
909 struct ieee802_11_elems elems;
910 struct wpa_pasn_params_data pasn_params;
911 struct wpabuf *wrapped_data = NULL;
912 u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
913 u8 mic_len;
914 int ret;
915 u8 *copy = NULL;
916 size_t copy_len, mic_offset;
917
918 if (ieee802_11_parse_elems(mgmt->u.auth.variable,
919 len - offsetof(struct ieee80211_mgmt,
920 u.auth.variable),
921 &elems, 0) == ParseFailed) {
922 wpa_printf(MSG_DEBUG,
923 "PASN: Failed parsing Authentication frame");
924 goto fail;
925 }
926
927 /* Check that the MIC IE exists. Save it and zero out the memory. */
928 mic_len = pasn_mic_len(pasn->akmp, pasn->cipher);
929 if (!elems.mic || elems.mic_len != mic_len) {
930 wpa_printf(MSG_DEBUG,
931 "PASN: Invalid MIC. Expecting len=%u", mic_len);
932 goto fail;
933 }
934 os_memcpy(mic, elems.mic, mic_len);
935
936 if (!elems.pasn_params || !elems.pasn_params_len) {
937 wpa_printf(MSG_DEBUG,
938 "PASN: No PASN Parameters element found");
939 goto fail;
940 }
941
942 ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
943 elems.pasn_params_len + 3,
944 false, &pasn_params);
945 if (ret) {
946 wpa_printf(MSG_DEBUG,
947 "PASN: Failed validation of PASN Parameters IE");
948 goto fail;
949 }
950
951 if (pasn_params.pubkey || pasn_params.pubkey_len) {
952 wpa_printf(MSG_DEBUG,
953 "PASN: Public key should not be included");
954 goto fail;
955 }
956
957 /* Verify the MIC */
958 copy_len = len - offsetof(struct ieee80211_mgmt, u.auth);
959 mic_offset = elems.mic - (const u8 *) &mgmt->u.auth;
960 copy_len = len - offsetof(struct ieee80211_mgmt, u.auth);
961 if (mic_offset + mic_len > copy_len)
962 goto fail;
963 copy = os_memdup(&mgmt->u.auth, copy_len);
964 if (!copy)
965 goto fail;
966 os_memset(copy + mic_offset, 0, mic_len);
967 ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
968 peer_addr, own_addr,
969 pasn->hash, mic_len * 2,
970 copy, copy_len, out_mic);
971 os_free(copy);
972 copy = NULL;
973
974 wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len);
975 if (ret || os_memcmp(mic, out_mic, mic_len) != 0) {
976 wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification");
977 goto fail;
978 }
979
980 if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000981 wrapped_data = ieee802_11_defrag(elems.wrapped_data,
982 elems.wrapped_data_len,
983 true);
Sunil Ravi77d572f2023-01-17 23:58:31 +0000984
985 if (!wrapped_data) {
986 wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
987 goto fail;
988 }
989
990#ifdef CONFIG_SAE
991 if (pasn->akmp == WPA_KEY_MGMT_SAE) {
992 ret = pasn_wd_handle_sae_confirm(pasn, peer_addr,
993 wrapped_data);
994 if (ret) {
995 wpa_printf(MSG_DEBUG,
996 "PASN: Failed processing SAE confirm");
997 wpabuf_free(wrapped_data);
998 goto fail;
999 }
1000 }
1001#endif /* CONFIG_SAE */
1002#ifdef CONFIG_FILS
1003 if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
1004 pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
1005 if (wrapped_data) {
1006 wpa_printf(MSG_DEBUG,
1007 "PASN: FILS: Ignore wrapped data");
1008 }
1009 }
1010#endif /* CONFIG_FILS */
1011 wpabuf_free(wrapped_data);
1012 }
1013
1014 wpa_printf(MSG_INFO,
1015 "PASN: Success handling transaction == 3. Store PTK");
1016 return 0;
1017
1018fail:
1019 os_free(copy);
1020 return -1;
1021}
1022
1023#endif /* CONFIG_PASN */