1 /*
2 * hostapd / IEEE 802.11 Management
3 * Copyright (c) 2002-2017, 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 "utils/includes.h"
10 #include "common/sae.h"
11 #include "common/ieee802_11_defs.h"
12 #include "esp_wifi_driver.h"
13 #include "ap/wpa_auth.h"
14 #include "ap/hostapd.h"
15 #include "ap/sta_info.h"
16 #include "crypto/sha256.h"
17 #include "ap/pmksa_cache_auth.h"
18 #include "ap/comeback_token.h"
19 #include "crypto/random.h"
20 #include "esp_wpa3_i.h"
21
22 #ifdef CONFIG_SAE
23
sae_set_state(struct sta_info * sta,enum sae_state state,const char * reason)24 static void sae_set_state(struct sta_info *sta, enum sae_state state,
25 const char *reason)
26 {
27 wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)",
28 sae_state_txt(sta->sae->state), sae_state_txt(state),
29 MAC2STR(sta->addr), reason);
30 sta->sae->state = state;
31 }
32
33
sae_get_password(struct hostapd_data * hapd,struct sta_info * sta,const char * rx_id,struct sae_pt ** s_pt)34 static const char * sae_get_password(struct hostapd_data *hapd,
35 struct sta_info *sta,
36 const char *rx_id,
37 struct sae_pt **s_pt)
38 {
39 const char *password = NULL;
40 struct sae_pt *pt = NULL;
41
42 if (!password) {
43 password = hapd->conf->ssid.wpa_passphrase;
44 pt = hapd->conf->ssid.pt;
45 }
46
47 if (s_pt) {
48 *s_pt = pt;
49 }
50
51 return password;
52 }
53
54
auth_build_sae_commit(struct hostapd_data * hapd,struct sta_info * sta,int update,int status_code)55 static struct wpabuf *auth_build_sae_commit(struct hostapd_data *hapd,
56 struct sta_info *sta, int update, int status_code)
57 {
58 struct wpabuf *buf;
59 const char *password = NULL;
60 const char *rx_id = NULL;
61 int use_pt = 0;
62 struct sae_pt *pt = NULL;
63
64 if (sta->sae->tmp) {
65 rx_id = sta->sae->tmp->pw_id;
66 use_pt = sta->sae->h2e;
67 }
68
69 if (rx_id && hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
70 use_pt = 1;
71 else if (status_code == WLAN_STATUS_SUCCESS)
72 use_pt = 0;
73 else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
74 use_pt = 1;
75
76 password = sae_get_password(hapd, sta, rx_id, &pt);
77 if (!password || (use_pt && !pt)) {
78 wpa_printf(MSG_DEBUG, "SAE: No password available");
79 return NULL;
80 }
81
82 if (update && use_pt &&
83 sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
84 NULL, NULL) < 0) {
85 return NULL;
86 }
87
88 if (update && !use_pt &&
89 sae_prepare_commit(hapd->own_addr, sta->addr,
90 (u8 *) password, os_strlen((const char *)password),
91 sta->sae) < 0) {
92 wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
93 return NULL;
94 }
95
96 buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
97 (rx_id ? 3 + os_strlen(rx_id) : 0));
98
99 if (buf &&
100 sae_write_commit(sta->sae, buf, sta->sae->tmp ?
101 sta->sae->tmp->anti_clogging_token : NULL,
102 rx_id) < 0) {
103 wpabuf_free(buf);
104 buf = NULL;
105 }
106
107 return buf;
108 }
109
110
auth_build_sae_confirm(struct hostapd_data * hapd,struct sta_info * sta)111 static struct wpabuf *auth_build_sae_confirm(struct hostapd_data *hapd,
112 struct sta_info *sta)
113 {
114 struct wpabuf *buf;
115
116 buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
117 if (buf == NULL) {
118 return NULL;
119 }
120
121 if (sae_write_confirm(sta->sae, buf) < 0) {
122 wpabuf_free(buf);
123 return NULL;
124 }
125
126 return buf;
127 }
128
129
auth_sae_send_commit(struct hostapd_data * hapd,struct sta_info * sta,const u8 * bssid,int update,int status_code)130 static int auth_sae_send_commit(struct hostapd_data *hapd,
131 struct sta_info *sta,
132 const u8 *bssid, int update, int status_code)
133 {
134 struct wpabuf *data;
135 int reply_res;
136 u16 status;
137
138 data = auth_build_sae_commit(hapd, sta, update, status_code);
139 if (!data && sta->sae->tmp && sta->sae->tmp->pw_id) {
140 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
141 }
142 if (data == NULL) {
143 return WLAN_STATUS_UNSPECIFIED_FAILURE;
144 }
145
146 if (sta->sae->tmp && sta->sae->h2e) {
147 status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
148 } else {
149 status = WLAN_STATUS_SUCCESS;
150 }
151
152 #ifdef ESP_SUPPLICANT
153 if (sta->remove_pending) {
154 reply_res = -1;
155 } else {
156 reply_res = esp_send_sae_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
157 status, wpabuf_head(data),
158 wpabuf_len(data));
159 }
160 #endif /* ESP_SUPPLICANT */
161
162 wpabuf_free(data);
163 return reply_res;
164 }
165
auth_sae_send_confirm(struct hostapd_data * hapd,struct sta_info * sta,const u8 * bssid)166 static int auth_sae_send_confirm(struct hostapd_data *hapd,
167 struct sta_info *sta,
168 const u8 *bssid)
169 {
170 struct wpabuf *data;
171 int reply_res;
172
173 data = auth_build_sae_confirm(hapd, sta);
174 if (data == NULL) {
175 return WLAN_STATUS_UNSPECIFIED_FAILURE;
176 }
177
178 #ifdef ESP_SUPPLICANT
179 if (sta->remove_pending) {
180 reply_res = -1;
181 } else {
182 reply_res = esp_send_sae_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
183 WLAN_STATUS_SUCCESS, wpabuf_head(data),
184 wpabuf_len(data));
185 }
186 #endif /* ESP_SUPPLICANT */
187
188 wpabuf_free(data);
189 return reply_res;
190 }
191
192
use_sae_anti_clogging(struct hostapd_data * hapd)193 static int use_sae_anti_clogging(struct hostapd_data *hapd)
194 {
195 struct sta_info *sta;
196 unsigned int open = 0;
197
198 if (hapd->conf->sae_anti_clogging_threshold == 0) {
199 return 1;
200 }
201
202 for (sta = hapd->sta_list; sta; sta = sta->next) {
203 if (sta->sae &&
204 (sta->sae->state == SAE_COMMITTED ||
205 sta->sae->state == SAE_CONFIRMED)) {
206 open++;
207 }
208 if (open >= hapd->conf->sae_anti_clogging_threshold) {
209 return 1;
210 }
211 }
212
213 /* In addition to already existing open SAE sessions, check whether
214 * there are enough pending commit messages in the processing queue to
215 * potentially result in too many open sessions. */
216 if (open + dl_list_len(&hapd->sae_commit_queue) >=
217 hapd->conf->sae_anti_clogging_threshold) {
218 return 1;
219 }
220
221 return 0;
222 }
223
224
sae_check_big_sync(struct hostapd_data * hapd,struct sta_info * sta)225 static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
226 {
227 if (sta->sae->sync > hapd->conf->sae_sync) {
228 sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
229 sta->sae->sync = 0;
230 return -1;
231 }
232 return 0;
233 }
234
235
sae_accept_sta(struct hostapd_data * hapd,struct sta_info * sta)236 void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
237 {
238 sta->flags |= WLAN_STA_AUTH;
239
240 #ifdef ESP_SUPPLICANT
241 sta->sae_commit_processing = false;
242 #endif /* ESP_SUPPLICANT */
243
244 sta->auth_alg = WLAN_AUTH_SAE;
245 sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
246 wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
247 sta->sae->pmk, sta->sae->pmkid, false);
248 }
249
250
sae_sm_step(struct hostapd_data * hapd,struct sta_info * sta,const u8 * bssid,u8 auth_transaction,u16 status_code,int allow_reuse,int * sta_removed)251 static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
252 const u8 *bssid, u8 auth_transaction, u16 status_code,
253 int allow_reuse, int *sta_removed)
254 {
255 int ret = WLAN_STATUS_SUCCESS;
256 *sta_removed = 0;
257
258 if (auth_transaction != 1 && auth_transaction != 2) {
259 return WLAN_STATUS_UNSPECIFIED_FAILURE;
260 }
261
262 wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
263 MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
264 auth_transaction);
265 switch (sta->sae->state) {
266 case SAE_NOTHING:
267 if (auth_transaction == 1) {
268 if (sta->sae->tmp) {
269 sta->sae->h2e =
270 (status_code ==
271 WLAN_STATUS_SAE_HASH_TO_ELEMENT);
272 }
273 ret = auth_sae_send_commit(hapd, sta, bssid,
274 !allow_reuse, status_code);
275
276 if (ret) {
277 return ret;
278 }
279
280 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
281
282 if (sae_process_commit(sta->sae) < 0) {
283 return WLAN_STATUS_UNSPECIFIED_FAILURE;
284 }
285
286 sta->sae->sync = 0;
287 } else {
288 wpa_printf(MSG_DEBUG, "SAE confirm before commit");
289 }
290 break;
291 case SAE_COMMITTED:
292 if (auth_transaction == 1) {
293 if (sae_process_commit(sta->sae) < 0) {
294 return WLAN_STATUS_UNSPECIFIED_FAILURE;
295 }
296
297 ret = auth_sae_send_confirm(hapd, sta, bssid);
298 if (ret) {
299 return ret;
300 }
301 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
302 sta->sae->sync = 0;
303 } else {
304 /*
305 * For instructure BSS, send the postponed Confirm from
306 * Nothing -> Confirmed transition that was reduced to
307 * Nothing -> Committed above.
308 */
309 ret = auth_sae_send_confirm(hapd, sta, bssid);
310 if (ret) {
311 return ret;
312 }
313
314 sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
315
316 /*
317 * Since this was triggered on Confirm RX, run another
318 * step to get to Accepted without waiting for
319 * additional events.
320 */
321 return sae_sm_step(hapd, sta, bssid, auth_transaction,
322 WLAN_STATUS_SUCCESS, 0, sta_removed);
323 }
324 break;
325 case SAE_CONFIRMED:
326 if (auth_transaction == 1) {
327 if (sae_check_big_sync(hapd, sta)) {
328 return WLAN_STATUS_SUCCESS;
329 }
330 sta->sae->sync++;
331
332 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
333 status_code);
334
335 if (ret) {
336 return ret;
337 }
338
339 if (sae_process_commit(sta->sae) < 0) {
340 return WLAN_STATUS_UNSPECIFIED_FAILURE;
341 }
342
343 ret = auth_sae_send_confirm(hapd, sta, bssid);
344 if (ret) {
345 return ret;
346 }
347
348 } else {
349 sta->sae->send_confirm = 0xffff;
350 sae_accept_sta(hapd, sta);
351 }
352 break;
353 case SAE_ACCEPTED:
354 if (auth_transaction == 1) {
355 wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
356 ret = auth_sae_send_commit(hapd, sta, bssid, 1,
357 status_code);
358 if (ret) {
359 return ret;
360 }
361 sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
362
363 if (sae_process_commit(sta->sae) < 0) {
364 return WLAN_STATUS_UNSPECIFIED_FAILURE;
365 }
366
367 sta->sae->sync = 0;
368 } else {
369 if (sae_check_big_sync(hapd, sta)) {
370 return WLAN_STATUS_SUCCESS;
371 }
372 sta->sae->sync++;
373
374 ret = auth_sae_send_confirm(hapd, sta, bssid);
375 sae_clear_temp_data(sta->sae);
376 if (ret) {
377 return ret;
378 }
379 }
380 break;
381 default:
382 wpa_printf(MSG_ERROR, "SAE: invalid state %d",
383 sta->sae->state);
384 return WLAN_STATUS_UNSPECIFIED_FAILURE;
385 }
386 return WLAN_STATUS_SUCCESS;
387 }
388
389
sae_status_success(struct hostapd_data * hapd,u16 status_code)390 static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
391 {
392 enum sae_pwe sae_pwe = hapd->conf->sae_pwe;
393
394 return ((sae_pwe == SAE_PWE_HUNT_AND_PECK ||
395 sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) &&
396 status_code == WLAN_STATUS_SUCCESS) ||
397 (sae_pwe == SAE_PWE_HASH_TO_ELEMENT &&
398 (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)) ||
399 (sae_pwe == SAE_PWE_BOTH &&
400 (status_code == WLAN_STATUS_SUCCESS ||
401 status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT));
402 }
403
404
sae_is_group_enabled(struct hostapd_data * hapd,int group)405 static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
406 {
407 int *groups = NULL;
408 int default_groups[] = { 19, 0 };
409 int i;
410
411 if (!groups) {
412 groups = default_groups;
413 }
414
415 for (i = 0; groups[i] > 0; i++) {
416 if (groups[i] == group)
417 return 1;
418 }
419
420 return 0;
421 }
422
423
check_sae_rejected_groups(struct hostapd_data * hapd,struct sae_data * sae)424 static int check_sae_rejected_groups(struct hostapd_data *hapd,
425 struct sae_data *sae)
426 {
427 const struct wpabuf *groups;
428 size_t i, count, len;
429 const u8 *pos;
430
431 if (!sae->tmp)
432 return 0;
433 groups = sae->tmp->peer_rejected_groups;
434 if (!groups)
435 return 0;
436
437 pos = wpabuf_head(groups);
438 len = wpabuf_len(groups);
439 if (len & 1) {
440 wpa_printf(MSG_DEBUG,
441 "SAE: Invalid length of the Rejected Groups element payload: %zu",
442 len);
443 return 1;
444 }
445
446 count = len / 2;
447 for (i = 0; i < count; i++) {
448 int enabled;
449 u16 group;
450
451 group = WPA_GET_LE16(pos);
452 pos += 2;
453 enabled = sae_is_group_enabled(hapd, group);
454 wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
455 group, enabled ? "enabled" : "disabled");
456 if (enabled)
457 return 1;
458 }
459
460 return 0;
461 }
462
463
handle_auth_sae(struct hostapd_data * hapd,struct sta_info * sta,u8 * buf,size_t len,u8 * bssid,u16 auth_transaction,u16 status)464 int handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
465 u8 *buf, size_t len, u8 *bssid,
466 u16 auth_transaction, u16 status)
467 {
468 int resp = WLAN_STATUS_SUCCESS;
469 struct wpabuf *data = NULL;
470 int *groups = hapd->conf->sae_groups;
471 int default_group[] = { IANA_SECP256R1, 0};
472 const u8 *pos, *end;
473 int sta_removed = 0;
474
475 if (!groups) {
476 groups = default_group;
477 }
478
479 if (!sta->sae) {
480 if (auth_transaction != 1 ||
481 !sae_status_success(hapd, status)) {
482 wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
483 status);
484 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
485 goto reply;
486 }
487 sta->sae = os_zalloc(sizeof(*sta->sae));
488 if (!sta->sae) {
489 resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
490 goto remove_sta;
491 }
492 sae_set_state(sta, SAE_NOTHING, "Init");
493 sta->sae->sync = 0;
494 }
495 if (auth_transaction == 1) {
496 const u8 *token = NULL;
497 size_t token_len = 0;
498 int allow_reuse = 0;
499
500 if (!sae_status_success(hapd, status)) {
501 goto remove_sta;
502 }
503
504 if (sta->sae->state == SAE_COMMITTED) {
505 /* This is needed in the infrastructure BSS case to
506 * address a sequence where a STA entry may remain in
507 * hostapd across two attempts to do SAE authentication
508 * by the same STA. The second attempt may end up trying
509 * to use a different group and that would not be
510 * allowed if we remain in Committed state with the
511 * previously set parameters. */
512 pos = buf;
513 end = buf + len;
514 if (end - pos >= (int) sizeof(le16) &&
515 sae_group_allowed(sta->sae, groups,
516 WPA_GET_LE16(pos)) ==
517 WLAN_STATUS_SUCCESS) {
518 /* Do not waste resources deriving the same PWE
519 * again since the same group is reused. */
520 sae_set_state(sta, SAE_NOTHING,
521 "Allow previous PWE to be reused");
522 allow_reuse = 1;
523 } else {
524 sae_set_state(sta, SAE_NOTHING,
525 "Clear existing state to allow restart");
526 sae_clear_data(sta->sae);
527 }
528 }
529
530 resp = sae_parse_commit(sta->sae, buf, len, &token, &token_len, default_group,
531 status == WLAN_STATUS_SAE_HASH_TO_ELEMENT);
532 if (resp == SAE_SILENTLY_DISCARD) {
533 wpa_printf(MSG_DEBUG,
534 "SAE: Drop commit message from " MACSTR " due to reflection attack",
535 MAC2STR(sta->addr));
536 resp = WLAN_STATUS_SUCCESS;
537 goto remove_sta;
538 }
539
540 if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
541 sae_set_state(sta, SAE_NOTHING,
542 "Unknown Password Identifier");
543 goto remove_sta;
544 }
545
546 if (token &&
547 check_comeback_token(hapd->comeback_key,
548 hapd->comeback_pending_idx, sta->addr,
549 token, token_len) < 0) {
550 wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
551 "incorrect token from " MACSTR,
552 MAC2STR(sta->addr));
553 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
554 goto remove_sta;
555 }
556
557 if (check_sae_rejected_groups(hapd, sta->sae)) {
558 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
559 goto reply;
560 }
561
562 if (resp != WLAN_STATUS_SUCCESS) {
563 goto reply;
564 }
565
566 if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
567 int h2e = 0;
568
569 wpa_printf(MSG_DEBUG,
570 "SAE: Request anti-clogging token from "
571 MACSTR, MAC2STR(sta->addr));
572 if (sta->sae->tmp)
573 h2e = sta->sae->h2e;
574 if (status == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
575 h2e = 1;
576 data = auth_build_token_req(
577 &hapd->last_comeback_key_update,
578 hapd->comeback_key,
579 hapd->comeback_idx,
580 hapd->comeback_pending_idx,
581 sizeof(hapd->comeback_pending_idx),
582 sta->sae->group,
583 sta->addr, h2e);
584 resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
585
586 #ifdef ESP_SUPPLICANT
587 sta->sae_commit_processing = false;
588 #endif /* ESP_SUPPLICANT */
589
590 goto reply;
591 }
592
593 resp = sae_sm_step(hapd, sta, bssid, auth_transaction,
594 status, allow_reuse, &sta_removed);
595 } else if (auth_transaction == 2) {
596 if (status != WLAN_STATUS_SUCCESS) {
597 goto remove_sta;
598 }
599
600 const u8 *var;
601 size_t var_len;
602 u16 peer_send_confirm;
603
604 var = buf;
605 var_len = len;
606 if (var_len < 2) {
607 resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
608 goto reply;
609 }
610
611 peer_send_confirm = WPA_GET_LE16(var);
612
613 if (sta->sae->state == SAE_ACCEPTED &&
614 (peer_send_confirm <= sta->sae->rc ||
615 peer_send_confirm == 0xffff)) {
616 wpa_printf(MSG_DEBUG,
617 "SAE: Silently ignore unexpected Confirm from peer "
618 MACSTR
619 " (peer-send-confirm=%u Rc=%u)",
620 MAC2STR(sta->addr),
621 peer_send_confirm, sta->sae->rc);
622 return 0;
623 }
624
625 if (sae_check_confirm(sta->sae, buf, len) < 0) {
626 resp = WLAN_STATUS_CHALLENGE_FAIL;
627 goto reply;
628 }
629 sta->sae->rc = peer_send_confirm;
630
631 resp = sae_sm_step(hapd, sta, bssid, auth_transaction,
632 status, 0, &sta_removed);
633 } else {
634 wpa_printf(MSG_ERROR, "unexpected SAE authentication transaction %u (status=%u )", auth_transaction, status);
635 if (status != WLAN_STATUS_SUCCESS) {
636 goto remove_sta;
637 }
638 resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
639 }
640 reply:
641 if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
642 pos = buf;
643 end = buf + len;
644
645 /* Copy the Finite Cyclic Group field from the request if we
646 * rejected it as unsupported group. */
647 if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
648 !data && end - pos >= 2) {
649 data = wpabuf_alloc_copy(pos, 2);
650 }
651 #ifdef ESP_SUPPLICANT
652 if (!sta->remove_pending) {
653 esp_send_sae_auth_reply(hapd, bssid, bssid, WLAN_AUTH_SAE,
654 auth_transaction, resp,
655 data ? wpabuf_head(data) : (u8 *) "",
656 data ? wpabuf_len(data) : 0);
657 }
658 #endif /* ESP_SUPPLICANT */
659
660 }
661 remove_sta:
662 wpabuf_free(data);
663 return resp;
664 }
665
666
auth_sae_queue(struct hostapd_data * hapd,u8 * buf,size_t len,u8 * bssid,u16 status,u32 auth_transaction)667 int auth_sae_queue(struct hostapd_data *hapd,
668 u8 *buf, size_t len, u8 *bssid, u16 status, u32 auth_transaction)
669 {
670 struct hostapd_sae_commit_queue *q, *q2;
671 unsigned int queue_len;
672
673 queue_len = dl_list_len(&hapd->sae_commit_queue);
674 if (queue_len >= 5) {
675 wpa_printf(MSG_DEBUG,
676 "SAE: No more room in message queue - drop the new frame from "
677 MACSTR, MAC2STR(bssid));
678 return 0;
679 }
680
681 wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
682 MACSTR " for processing (queue_len %u)", MAC2STR(bssid),
683 queue_len);
684 q = os_zalloc(sizeof(*q) + len);
685 if (!q) {
686 return -1;
687 }
688
689 q->len = len;
690 os_memcpy(q->msg, buf, len);
691 os_memcpy(q->bssid, bssid, ETH_ALEN);
692 q->auth_transaction = auth_transaction;
693 q->status = status;
694 /* Check whether there is already a queued Authentication frame from the
695 * same station with the same transaction number and if so, replace that
696 * queue entry with the new one. This avoids issues with a peer that
697 * sends multiple times (e.g., due to frequent SAE retries). There is no
698 * point in us trying to process the old attempts after a new one has
699 * obsoleted them. */
700 dl_list_for_each(q2, &hapd->sae_commit_queue,
701 struct hostapd_sae_commit_queue, list) {
702 if (os_memcmp(bssid, q2->bssid, ETH_ALEN) == 0 &&
703 auth_transaction == q2->auth_transaction) {
704 wpa_printf(MSG_DEBUG,
705 "SAE: Replace queued message from same STA with same transaction number");
706 dl_list_add(&q2->list, &q->list);
707 dl_list_del(&q2->list);
708 os_free(q2);
709 goto queued;
710 }
711 }
712
713 /* No pending identical entry, so add to the end of the queue */
714 dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
715
716 queued:
717
718 #ifdef ESP_SUPPLICANT
719 /* posting event to the task to handle commit */
720 if (wpa3_hostap_post_evt(SIG_WPA3_RX_COMMIT, 0) != 0) {
721 wpa_printf(MSG_ERROR, "failed to queue commit build event");
722 return -1;
723 }
724 return 0;
725 #endif /* ESP_SUPPLICANT */
726
727 }
728
729 #endif /* CONFIG_SAE */
730
wpa_res_to_status_code(enum wpa_validate_result res)731 u16 wpa_res_to_status_code(enum wpa_validate_result res)
732 {
733 switch (res) {
734 case WPA_IE_OK:
735 return WLAN_STATUS_SUCCESS;
736 case WPA_INVALID_IE:
737 return WLAN_STATUS_INVALID_IE;
738 case WPA_INVALID_GROUP:
739 return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
740 case WPA_INVALID_PAIRWISE:
741 return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
742 case WPA_INVALID_AKMP:
743 return WLAN_STATUS_AKMP_NOT_VALID;
744 case WPA_NOT_ENABLED:
745 return WLAN_STATUS_INVALID_IE;
746 case WPA_ALLOC_FAIL:
747 return WLAN_STATUS_UNSPECIFIED_FAILURE;
748 case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
749 return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
750 case WPA_INVALID_MGMT_GROUP_CIPHER:
751 return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
752 case WPA_INVALID_MDIE:
753 return WLAN_STATUS_INVALID_MDIE;
754 case WPA_INVALID_PROTO:
755 return WLAN_STATUS_INVALID_IE;
756 case WPA_INVALID_PMKID:
757 return WLAN_STATUS_INVALID_PMKID;
758 case WPA_DENIED_OTHER_REASON:
759 return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
760 }
761 return WLAN_STATUS_INVALID_IE;
762 }
763