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