diff options
Diffstat (limited to 'contrib/wpa/wpa_supplicant/sme.c')
-rw-r--r-- | contrib/wpa/wpa_supplicant/sme.c | 511 |
1 files changed, 440 insertions, 71 deletions
diff --git a/contrib/wpa/wpa_supplicant/sme.c b/contrib/wpa/wpa_supplicant/sme.c index dd5020179f3b..7f43216c6582 100644 --- a/contrib/wpa/wpa_supplicant/sme.c +++ b/contrib/wpa/wpa_supplicant/sme.c @@ -37,9 +37,7 @@ static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx); static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx); static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx); -#ifdef CONFIG_IEEE80211W static void sme_stop_sa_query(struct wpa_supplicant *wpa_s); -#endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_SAE @@ -86,11 +84,21 @@ static int sme_set_sae_group(struct wpa_supplicant *wpa_s) static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, const u8 *bssid, int external, - int reuse) + int reuse, int *ret_use_pt, + bool *ret_use_pk) { struct wpabuf *buf; size_t len; const char *password; + struct wpa_bss *bss; + int use_pt = 0; + bool use_pk = false; + u8 rsnxe_capa = 0; + + if (ret_use_pt) + *ret_use_pt = 0; + if (ret_use_pk) + *ret_use_pk = false; #ifdef CONFIG_TESTING_OPTIONS if (wpa_s->sae_commit_override) { @@ -119,6 +127,8 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) { wpa_printf(MSG_DEBUG, "SAE: Reuse previously generated PWE on a retry with the same AP"); + use_pt = wpa_s->sme.sae.h2e; + use_pk = wpa_s->sme.sae.pk; goto reuse_data; } if (sme_set_sae_group(wpa_s) < 0) { @@ -126,18 +136,79 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, return NULL; } - if (sae_prepare_commit(wpa_s->own_addr, bssid, + bss = wpa_bss_get_bssid_latest(wpa_s, bssid); + if (!bss) { + wpa_printf(MSG_DEBUG, + "SAE: BSS not available, update scan result to get BSS"); + wpa_supplicant_update_scan_results(wpa_s); + bss = wpa_bss_get_bssid_latest(wpa_s, bssid); + } + if (bss) { + const u8 *rsnxe; + + rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX); + if (rsnxe && rsnxe[1] >= 1) + rsnxe_capa = rsnxe[2]; + } + + if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3) + use_pt = 1; +#ifdef CONFIG_SAE_PK + if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) && + ssid->sae_pk != SAE_PK_MODE_DISABLED && + ((ssid->sae_password && + sae_pk_valid_password(ssid->sae_password)) || + (!ssid->sae_password && ssid->passphrase && + sae_pk_valid_password(ssid->passphrase)))) { + use_pt = 1; + use_pk = true; + } + + if (ssid->sae_pk == SAE_PK_MODE_ONLY && !use_pk) { + wpa_printf(MSG_DEBUG, + "SAE: Cannot use PK with the selected AP"); + return NULL; + } +#endif /* CONFIG_SAE_PK */ + + if (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) { + use_pt = !!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E)); + + if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) && + wpa_s->conf->sae_pwe != 3 && + !use_pt) { + wpa_printf(MSG_DEBUG, + "SAE: Cannot use H2E with the selected AP"); + return NULL; + } + } + + if (use_pt && + sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt, + wpa_s->own_addr, bssid, + wpa_s->sme.sae_rejected_groups, NULL) < 0) + return NULL; + if (!use_pt && + sae_prepare_commit(wpa_s->own_addr, bssid, (u8 *) password, os_strlen(password), - ssid->sae_password_id, &wpa_s->sme.sae) < 0) { wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE"); return NULL; } - if (wpa_s->sme.sae.tmp) + if (wpa_s->sme.sae.tmp) { os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN); + if (use_pt && use_pk) + wpa_s->sme.sae.pk = 1; +#ifdef CONFIG_SAE_PK + os_memcpy(wpa_s->sme.sae.tmp->own_addr, wpa_s->own_addr, + ETH_ALEN); + os_memcpy(wpa_s->sme.sae.tmp->peer_addr, bssid, ETH_ALEN); + sae_pk_set_password(&wpa_s->sme.sae, password); +#endif /* CONFIG_SAE_PK */ + } reuse_data: - len = wpa_s->sme.sae_token ? wpabuf_len(wpa_s->sme.sae_token) : 0; + len = wpa_s->sme.sae_token ? 3 + wpabuf_len(wpa_s->sme.sae_token) : 0; if (ssid->sae_password_id) len += 4 + os_strlen(ssid->sae_password_id); buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len); @@ -145,10 +216,22 @@ reuse_data: return NULL; if (!external) { wpabuf_put_le16(buf, 1); /* Transaction seq# */ - wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); + if (use_pk) + wpabuf_put_le16(buf, WLAN_STATUS_SAE_PK); + else if (use_pt) + wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT); + else + wpabuf_put_le16(buf,WLAN_STATUS_SUCCESS); + } + if (sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token, + ssid->sae_password_id) < 0) { + wpabuf_free(buf); + return NULL; } - sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token, - ssid->sae_password_id); + if (ret_use_pt) + *ret_use_pt = use_pt; + if (ret_use_pk) + *ret_use_pk = use_pk; return buf; } @@ -221,7 +304,7 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s, *pos++ = WLAN_EID_RRM_ENABLED_CAPABILITIES; *pos++ = rrm_ie_len; - /* Set supported capabilites flags */ + /* Set supported capabilities flags */ if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) *pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT; @@ -249,7 +332,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS) const u8 *md = NULL; #endif /* CONFIG_IEEE80211R || CONFIG_FILS */ - int i, bssid_changed; + int bssid_changed; struct wpabuf *resp = NULL; u8 ext_capab[18]; int ext_capab_len; @@ -259,6 +342,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #ifdef CONFIG_MBO const u8 *mbo_ie; #endif /* CONFIG_MBO */ + int omit_rsnxe = 0; if (bss == NULL) { wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for " @@ -333,18 +417,18 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_SAE */ - for (i = 0; i < NUM_WEP_KEYS; i++) { - if (ssid->wep_key_len[i]) - params.wep_key[i] = ssid->wep_key[i]; - params.wep_key_len[i] = ssid->wep_key_len[i]; - } - params.wep_tx_keyidx = ssid->wep_tx_keyidx; +#ifdef CONFIG_WEP + { + int i; - bssid_changed = !is_zero_ether_addr(wpa_s->bssid); - os_memset(wpa_s->bssid, 0, ETH_ALEN); - os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN); - if (bssid_changed) - wpas_notify_bssid_changed(wpa_s); + for (i = 0; i < NUM_WEP_KEYS; i++) { + if (ssid->wep_key_len[i]) + params.wep_key[i] = ssid->wep_key[i]; + params.wep_key_len[i] = ssid->wep_key_len[i]; + } + params.wep_tx_keyidx = ssid->wep_tx_keyidx; + } +#endif /* CONFIG_WEP */ if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) || wpa_bss_get_ie(bss, WLAN_EID_RSN)) && @@ -466,6 +550,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "SME: FT mobility domain %02x%02x", md[0], md[1]); + omit_rsnxe = !wpa_bss_get_ie(bss, WLAN_EID_RSNX); if (wpa_s->sme.assoc_req_ie_len + 5 < sizeof(wpa_s->sme.assoc_req_ie)) { struct rsn_mdie *mdie; @@ -492,7 +577,6 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W wpa_s->sme.mfp = wpas_get_ssid_pmf(wpa_s, ssid); if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) { const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); @@ -505,7 +589,6 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED; } } -#endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_P2P if (wpa_s->global->p2p) { @@ -540,7 +623,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, sme_auth_handle_rrm(wpa_s, bss); wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie( - wpa_s, ssid, bss->freq, + wpa_s, ssid, bss, wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len); @@ -562,6 +645,27 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, os_memcpy(pos, ext_capab, ext_capab_len); } +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->rsnxe_override_assoc && + wpabuf_len(wpa_s->rsnxe_override_assoc) <= + sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) { + wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override"); + os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, + wpabuf_head(wpa_s->rsnxe_override_assoc), + wpabuf_len(wpa_s->rsnxe_override_assoc)); + wpa_s->sme.assoc_req_ie_len += + wpabuf_len(wpa_s->rsnxe_override_assoc); + } else +#endif /* CONFIG_TESTING_OPTIONS */ + if (wpa_s->rsnxe_len > 0 && + wpa_s->rsnxe_len <= + sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len && + !omit_rsnxe) { + os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, + wpa_s->rsnxe, wpa_s->rsnxe_len); + wpa_s->sme.assoc_req_ie_len += wpa_s->rsnxe_len; + } + #ifdef CONFIG_HS20 if (is_hs20_network(wpa_s, ssid, bss)) { struct wpabuf *hs20; @@ -623,7 +727,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #ifdef CONFIG_MBO mbo_ie = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE); - if (mbo_ie) { + if (!wpa_s->disable_mbo_oce && mbo_ie) { int len; len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie + @@ -655,7 +759,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, if (start) resp = sme_auth_build_sae_commit(wpa_s, ssid, bss->bssid, 0, - start == 2); + start == 2, NULL, + NULL); else resp = sme_auth_build_sae_confirm(wpa_s, 0); if (resp == NULL) { @@ -668,6 +773,12 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_SAE */ + bssid_changed = !is_zero_ether_addr(wpa_s->bssid); + os_memset(wpa_s->bssid, 0, ETH_ALEN); + os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN); + if (bssid_changed) + wpas_notify_bssid_changed(wpa_s); + old_ssid = wpa_s->current_ssid; wpa_s->current_ssid = ssid; wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); @@ -761,7 +872,7 @@ no_fils: " (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid), wpa_ssid_txt(params.ssid, params.ssid_len), params.freq); - eapol_sm_notify_portValid(wpa_s->eapol, FALSE); + eapol_sm_notify_portValid(wpa_s->eapol, false); wpa_clear_keys(wpa_s, bss->bssid); wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING); if (old_ssid != wpa_s->current_ssid) @@ -834,6 +945,11 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit) struct wpa_connect_work *cwork = work->ctx; struct wpa_supplicant *wpa_s = work->wpa_s; + wpa_s->roam_in_progress = false; +#ifdef CONFIG_WNM + wpa_s->bss_trans_mgmt_in_progress = false; +#endif /* CONFIG_WNM */ + if (deinit) { if (work->started) wpa_s->connect_work = NULL; @@ -855,6 +971,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit) /* Starting new connection, so clear the possibly used WPA IE from the * previous association. */ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); + wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0); + wpa_s->rsnxe_len = 0; sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1); } @@ -872,6 +990,18 @@ void sme_authenticate(struct wpa_supplicant *wpa_s, return; } + if (wpa_s->roam_in_progress) { + wpa_dbg(wpa_s, MSG_DEBUG, + "SME: Reject sme_authenticate() in favor of explicit roam request"); + return; + } +#ifdef CONFIG_WNM + if (wpa_s->bss_trans_mgmt_in_progress) { + wpa_dbg(wpa_s, MSG_DEBUG, + "SME: Reject sme_authenticate() in favor of BSS transition management request"); + return; + } +#endif /* CONFIG_WNM */ if (radio_work_pending(wpa_s, "sme-connect")) { /* * The previous sme-connect work might no longer be valid due to @@ -909,7 +1039,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s, static int sme_external_auth_build_buf(struct wpabuf *buf, struct wpabuf *params, const u8 *sa, const u8 *da, - u16 auth_transaction, u16 seq_num) + u16 auth_transaction, u16 seq_num, + u16 status_code) { struct ieee80211_mgmt *resp; @@ -924,7 +1055,7 @@ static int sme_external_auth_build_buf(struct wpabuf *buf, resp->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE); resp->seq_ctrl = host_to_le16(seq_num << 4); resp->u.auth.auth_transaction = host_to_le16(auth_transaction); - resp->u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS); + resp->u.auth.status_code = host_to_le16(status_code); if (params) wpabuf_put_buf(buf, params); @@ -937,8 +1068,12 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct wpabuf *resp, *buf; + int use_pt; + bool use_pk; + u16 status; - resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0); + resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt, + &use_pk); if (!resp) { wpa_printf(MSG_DEBUG, "SAE: Failed to build SAE commit"); return -1; @@ -952,9 +1087,15 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s, } wpa_s->sme.seq_num++; + if (use_pk) + status = WLAN_STATUS_SAE_PK; + else if (use_pt) + status = WLAN_STATUS_SAE_HASH_TO_ELEMENT; + else + status = WLAN_STATUS_SUCCESS; sme_external_auth_build_buf(buf, resp, wpa_s->own_addr, - bssid, 1, wpa_s->sme.seq_num); - wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0); + bssid, 1, wpa_s->sme.seq_num, status); + wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0); wpabuf_free(resp); wpabuf_free(buf); @@ -972,6 +1113,8 @@ static void sme_send_external_auth_status(struct wpa_supplicant *wpa_s, params.ssid = wpa_s->sme.ext_auth_ssid; params.ssid_len = wpa_s->sme.ext_auth_ssid_len; params.bssid = wpa_s->sme.ext_auth_bssid; + if (wpa_s->conf->sae_pmkid_in_assoc && status == WLAN_STATUS_SUCCESS) + params.pmkid = wpa_s->sme.sae.pmkid; wpa_drv_send_external_auth_status(wpa_s, ¶ms); } @@ -1020,8 +1163,9 @@ static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s, } wpa_s->sme.seq_num++; sme_external_auth_build_buf(buf, resp, wpa_s->own_addr, - da, 2, wpa_s->sme.seq_num); - wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0); + da, 2, wpa_s->sme.seq_num, + WLAN_STATUS_SUCCESS); + wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0); wpabuf_free(resp); wpabuf_free(buf); } @@ -1057,6 +1201,52 @@ void sme_external_auth_trigger(struct wpa_supplicant *wpa_s, } +static int sme_sae_is_group_enabled(struct wpa_supplicant *wpa_s, int group) +{ + int *groups = wpa_s->conf->sae_groups; + int default_groups[] = { 19, 20, 21, 0 }; + int i; + + if (!groups) + groups = default_groups; + + for (i = 0; groups[i] > 0; i++) { + if (groups[i] == group) + return 1; + } + + return 0; +} + + +static int sme_check_sae_rejected_groups(struct wpa_supplicant *wpa_s, + const struct wpabuf *groups) +{ + size_t i, count; + const u8 *pos; + + if (!groups) + return 0; + + pos = wpabuf_head(groups); + count = wpabuf_len(groups) / 2; + for (i = 0; i < count; i++) { + int enabled; + u16 group; + + group = WPA_GET_LE16(pos); + pos += 2; + enabled = sme_sae_is_group_enabled(wpa_s, group); + wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s", + group, enabled ? "enabled" : "disabled"); + if (enabled) + return 1; + } + + return 0; +} + + static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, u16 status_code, const u8 *data, size_t len, int external, const u8 *sa) @@ -1072,11 +1262,16 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, (external || wpa_s->current_bss) && wpa_s->current_ssid) { int default_groups[] = { 19, 20, 21, 0 }; u16 group; + const u8 *token_pos; + size_t token_len; + int h2e = 0; groups = wpa_s->conf->sae_groups; if (!groups || groups[0] <= 0) groups = default_groups; + wpa_hexdump(MSG_DEBUG, "SME: SAE anti-clogging token request", + data, len); if (len < sizeof(le16)) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Too short SAE anti-clogging token request"); @@ -1094,8 +1289,29 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, return -1; } wpabuf_free(wpa_s->sme.sae_token); - wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16), - len - sizeof(le16)); + token_pos = data + sizeof(le16); + token_len = len - sizeof(le16); + h2e = wpa_s->sme.sae.h2e; + if (h2e) { + if (token_len < 3) { + wpa_dbg(wpa_s, MSG_DEBUG, + "SME: Too short SAE anti-clogging token container"); + return -1; + } + if (token_pos[0] != WLAN_EID_EXTENSION || + token_pos[1] == 0 || + token_pos[1] > token_len - 2 || + token_pos[2] != WLAN_EID_EXT_ANTI_CLOGGING_TOKEN) { + wpa_dbg(wpa_s, MSG_DEBUG, + "SME: Invalid SAE anti-clogging token container header"); + return -1; + } + token_len = token_pos[1] - 1; + token_pos += 3; + } + wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len); + wpa_hexdump_buf(MSG_DEBUG, "SME: Requested anti-clogging token", + wpa_s->sme.sae_token); if (!external) sme_send_authentication(wpa_s, wpa_s->current_bss, wpa_s->current_ssid, 2); @@ -1111,6 +1327,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, wpa_s->sme.sae.state == SAE_COMMITTED && (external || wpa_s->current_bss) && wpa_s->current_ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported"); + int_array_add_unique(&wpa_s->sme.sae_rejected_groups, + wpa_s->sme.sae.group); wpa_s->sme.sae_group_index++; if (sme_set_sae_group(wpa_s) < 0) return -1; /* no other groups enabled */ @@ -1135,8 +1353,17 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, return -1; } - if (status_code != WLAN_STATUS_SUCCESS) + if (status_code != WLAN_STATUS_SUCCESS && + status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT && + status_code != WLAN_STATUS_SAE_PK) { + const u8 *bssid = sa ? sa : wpa_s->pending_bssid; + + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AUTH_REJECT MACSTR + " auth_type=%u auth_transaction=%u status_code=%u", + MAC2STR(bssid), WLAN_AUTH_SAE, + auth_transaction, status_code); return -1; + } if (auth_transaction == 1) { u16 res; @@ -1147,12 +1374,35 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, if ((!external && wpa_s->current_bss == NULL) || wpa_s->current_ssid == NULL) return -1; - if (wpa_s->sme.sae.state != SAE_COMMITTED) + if (wpa_s->sme.sae.state != SAE_COMMITTED) { + wpa_printf(MSG_DEBUG, + "SAE: Ignore commit message while waiting for confirm"); + return 0; + } + if (wpa_s->sme.sae.h2e && status_code == WLAN_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, + "SAE: Unexpected use of status code 0 in SAE commit when H2E was expected"); + return -1; + } + if ((!wpa_s->sme.sae.h2e || wpa_s->sme.sae.pk) && + status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) { + wpa_printf(MSG_DEBUG, + "SAE: Unexpected use of status code for H2E in SAE commit when H2E was not expected"); return -1; + } + if (!wpa_s->sme.sae.pk && + status_code == WLAN_STATUS_SAE_PK) { + wpa_printf(MSG_DEBUG, + "SAE: Unexpected use of status code for PK in SAE commit when PK was not expected"); + return -1; + } + if (groups && groups[0] <= 0) groups = NULL; res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL, - groups); + groups, status_code == + WLAN_STATUS_SAE_HASH_TO_ELEMENT || + status_code == WLAN_STATUS_SAE_PK); if (res == SAE_SILENTLY_DISCARD) { wpa_printf(MSG_DEBUG, "SAE: Drop commit message due to reflection attack"); @@ -1161,6 +1411,12 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, if (res != WLAN_STATUS_SUCCESS) return -1; + if (wpa_s->sme.sae.tmp && + sme_check_sae_rejected_groups( + wpa_s, + wpa_s->sme.sae.tmp->peer_rejected_groups)) + return -1; + if (sae_process_commit(&wpa_s->sme.sae) < 0) { wpa_printf(MSG_DEBUG, "SAE: Failed to process peer " "commit"); @@ -1176,6 +1432,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, sme_external_auth_send_sae_confirm(wpa_s, sa); return 0; } else if (auth_transaction == 2) { + if (status_code != WLAN_STATUS_SUCCESS) + return -1; wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm"); if (wpa_s->sme.sae.state != SAE_CONFIRMED) return -1; @@ -1197,6 +1455,37 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, } +static int sme_sae_set_pmk(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + wpa_printf(MSG_DEBUG, + "SME: SAE completed - setting PMK for 4-way handshake"); + wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN, + wpa_s->sme.sae.pmkid, bssid); + if (wpa_s->conf->sae_pmkid_in_assoc) { + /* Update the own RSNE contents now that we have set the PMK + * and added a PMKSA cache entry based on the successfully + * completed SAE exchange. In practice, this will add the PMKID + * into RSNE. */ + if (wpa_s->sme.assoc_req_ie_len + 2 + PMKID_LEN > + sizeof(wpa_s->sme.assoc_req_ie)) { + wpa_msg(wpa_s, MSG_WARNING, + "RSN: Not enough room for inserting own PMKID into RSNE"); + return -1; + } + if (wpa_insert_pmkid(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + wpa_s->sme.sae.pmkid) < 0) + return -1; + wpa_hexdump(MSG_DEBUG, + "SME: Updated Association Request IEs", + wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len); + } + + return 0; +} + + void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s, const u8 *auth_frame, size_t len) { @@ -1230,10 +1519,8 @@ void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s, if (res != 1) return; - wpa_printf(MSG_DEBUG, - "SME: SAE completed - setting PMK for 4-way handshake"); - wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN, - wpa_s->sme.sae.pmkid, wpa_s->pending_bssid); + if (sme_sae_set_pmk(wpa_s, wpa_s->sme.ext_auth_bssid) < 0) + return; } } @@ -1277,7 +1564,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) int res; res = sme_sae_auth(wpa_s, data->auth.auth_transaction, data->auth.status_code, data->auth.ies, - data->auth.ies_len, 0, NULL); + data->auth.ies_len, 0, data->auth.peer); if (res < 0) { wpas_connection_failed(wpa_s, wpa_s->pending_bssid); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); @@ -1286,10 +1573,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) if (res != 1) return; - wpa_printf(MSG_DEBUG, "SME: SAE completed - setting PMK for " - "4-way handshake"); - wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN, - wpa_s->sme.sae.pmkid, wpa_s->pending_bssid); + if (sme_sae_set_pmk(wpa_s, wpa_s->pending_bssid) < 0) + return; } #endif /* CONFIG_SAE */ @@ -1442,6 +1727,7 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, { struct wpa_driver_associate_params params; struct ieee802_11_elems elems; + struct wpa_ssid *ssid = wpa_s->current_ssid; #ifdef CONFIG_FILS u8 nonces[2 * FILS_NONCE_LEN]; #endif /* CONFIG_FILS */ @@ -1551,8 +1837,8 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, struct wpabuf *owe_ie; u16 group; - if (wpa_s->current_ssid && wpa_s->current_ssid->owe_group) { - group = wpa_s->current_ssid->owe_group; + if (ssid && ssid->owe_group) { + group = ssid->owe_group; } else if (wpa_s->assoc_status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) { if (wpa_s->last_owe_group == 19) @@ -1588,9 +1874,14 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, #endif /* CONFIG_OWE */ #ifdef CONFIG_DPP2 - if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->current_ssid && - wpa_s->current_ssid->dpp_netaccesskey) { - struct wpa_ssid *ssid = wpa_s->current_ssid; + if (DPP_VERSION > 1 && wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && ssid && + ssid->dpp_netaccesskey && ssid->dpp_pfs != 2 && + !ssid->dpp_pfs_fallback) { + struct rsn_pmksa_cache_entry *pmksa; + + pmksa = pmksa_cache_get_current(wpa_s->wpa); + if (!pmksa || !pmksa->dpp_pfs) + goto pfs_fail; dpp_pfs_free(wpa_s->dpp_pfs); wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey, @@ -1617,7 +1908,41 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, pfs_fail: #endif /* CONFIG_DPP2 */ - if (wpa_s->current_ssid && wpa_s->current_ssid->multi_ap_backhaul_sta) { + wpa_s->mscs_setup_done = false; + if (wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_MSCS) && + wpa_s->robust_av.valid_config) { + struct wpabuf *mscs_ie; + size_t mscs_ie_len, buf_len, *wpa_ie_len, max_ie_len; + + buf_len = 3 + /* MSCS descriptor IE header */ + 1 + /* Request type */ + 2 + /* User priority control */ + 4 + /* Stream timeout */ + 3 + /* TCLAS Mask IE header */ + wpa_s->robust_av.frame_classifier_len; + mscs_ie = wpabuf_alloc(buf_len); + if (!mscs_ie) { + wpa_printf(MSG_INFO, + "MSCS: Failed to allocate MSCS IE"); + goto mscs_fail; + } + + wpa_ie_len = &wpa_s->sme.assoc_req_ie_len; + max_ie_len = sizeof(wpa_s->sme.assoc_req_ie); + wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie); + if ((*wpa_ie_len + wpabuf_len(mscs_ie)) <= max_ie_len) { + wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE", mscs_ie); + mscs_ie_len = wpabuf_len(mscs_ie); + os_memcpy(wpa_s->sme.assoc_req_ie + *wpa_ie_len, + wpabuf_head(mscs_ie), mscs_ie_len); + *wpa_ie_len += mscs_ie_len; + } + + wpabuf_free(mscs_ie); + } +mscs_fail: + + if (ssid && ssid->multi_ap_backhaul_sta) { size_t multi_ap_ie_len; multi_ap_ie_len = add_multi_ap_ie( @@ -1637,8 +1962,7 @@ pfs_fail: params.ssid = wpa_s->sme.ssid; params.ssid_len = wpa_s->sme.ssid_len; params.freq.freq = wpa_s->sme.freq; - params.bg_scan_period = wpa_s->current_ssid ? - wpa_s->current_ssid->bg_scan_period : -1; + params.bg_scan_period = ssid ? ssid->bg_scan_period : -1; params.wpa_ie = wpa_s->sme.assoc_req_ie_len ? wpa_s->sme.assoc_req_ie : NULL; params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len; @@ -1654,15 +1978,18 @@ pfs_fail: os_memset(&htcaps_mask, 0, sizeof(htcaps_mask)); params.htcaps = (u8 *) &htcaps; params.htcaps_mask = (u8 *) &htcaps_mask; - wpa_supplicant_apply_ht_overrides(wpa_s, wpa_s->current_ssid, ¶ms); + wpa_supplicant_apply_ht_overrides(wpa_s, ssid, ¶ms); #endif /* CONFIG_HT_OVERRIDES */ #ifdef CONFIG_VHT_OVERRIDES os_memset(&vhtcaps, 0, sizeof(vhtcaps)); os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask)); params.vhtcaps = &vhtcaps; params.vhtcaps_mask = &vhtcaps_mask; - wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, ¶ms); + wpa_supplicant_apply_vht_overrides(wpa_s, ssid, ¶ms); #endif /* CONFIG_VHT_OVERRIDES */ +#ifdef CONFIG_HE_OVERRIDES + wpa_supplicant_apply_he_overrides(wpa_s, ssid, ¶ms); +#endif /* CONFIG_HE_OVERRIDES */ #ifdef CONFIG_IEEE80211R if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies && get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len, @@ -1778,7 +2105,12 @@ pfs_fail: elems.osen_len + 2); } else wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); - if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group) + if (elems.rsnxe) + wpa_sm_set_assoc_rsnxe(wpa_s->wpa, elems.rsnxe - 2, + elems.rsnxe_len + 2); + else + wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0); + if (ssid && ssid->p2p_group) params.p2p = 1; if (wpa_s->p2pdev->set_sta_uapsd) @@ -1995,15 +2327,17 @@ void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s) if (wpa_s->sme.ft_ies || wpa_s->sme.ft_used) sme_update_ft_ies(wpa_s, NULL, NULL, 0); #endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W sme_stop_sa_query(wpa_s); -#endif /* CONFIG_IEEE80211W */ } void sme_deinit(struct wpa_supplicant *wpa_s) { sme_clear_on_disassoc(wpa_s); +#ifdef CONFIG_SAE + os_free(wpa_s->sme.sae_rejected_groups); + wpa_s->sme.sae_rejected_groups = NULL; +#endif /* CONFIG_SAE */ eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL); eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL); @@ -2139,7 +2473,7 @@ static void wpa_obss_scan_freqs_list(struct wpa_supplicant *wpa_s, int start, end; mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, - HOSTAPD_MODE_IEEE80211G); + HOSTAPD_MODE_IEEE80211G, false); if (mode == NULL) { /* No channels supported in this band - use empty list */ params->freqs = os_zalloc(sizeof(int)); @@ -2249,6 +2583,12 @@ void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable) ssid == NULL || ssid->mode != WPAS_MODE_INFRA) return; +#ifdef CONFIG_HT_OVERRIDES + /* No need for OBSS scan if HT40 is explicitly disabled */ + if (ssid->disable_ht40) + return; +#endif /* CONFIG_HT_OVERRIDES */ + if (!wpa_s->hw.modes) return; @@ -2292,8 +2632,6 @@ void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable) } -#ifdef CONFIG_IEEE80211W - static const unsigned int sa_query_max_timeout = 1000; static const unsigned int sa_query_retry_timeout = 201; static const unsigned int sa_query_ch_switch_max_delay = 5000; /* in usec */ @@ -2341,6 +2679,16 @@ static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s, return; } +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->oci_freq_override_saquery_req) { + wpa_printf(MSG_INFO, + "TEST: Override SA Query Request OCI frequency %d -> %d MHz", + ci.frequency, + wpa_s->oci_freq_override_saquery_req); + ci.frequency = wpa_s->oci_freq_override_saquery_req; + } +#endif /* CONFIG_TESTING_OPTIONS */ + if (ocv_insert_extended_oci(&ci, req + req_len) < 0) return; @@ -2434,6 +2782,10 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa, return; if (wpa_s->sme.sa_query_count > 0) return; +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->disable_sa_query) + return; +#endif /* CONFIG_TESTING_OPTIONS */ os_get_reltime(&now); if (wpa_s->sme.last_unprot_disconnect.sec && @@ -2491,6 +2843,16 @@ static void sme_process_sa_query_request(struct wpa_supplicant *wpa_s, return; } +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->oci_freq_override_saquery_resp) { + wpa_printf(MSG_INFO, + "TEST: Override SA Query Response OCI frequency %d -> %d MHz", + ci.frequency, + wpa_s->oci_freq_override_saquery_resp); + ci.frequency = wpa_s->oci_freq_override_saquery_resp; + } +#endif /* CONFIG_TESTING_OPTIONS */ + if (ocv_insert_extended_oci(&ci, resp + resp_len) < 0) return; @@ -2540,11 +2902,17 @@ static void sme_process_sa_query_response(struct wpa_supplicant *wpa_s, } -void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa, +void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *da, const u8 *sa, const u8 *data, size_t len) { if (len < 1 + WLAN_SA_QUERY_TR_ID_LEN) return; + if (is_multicast_ether_addr(da)) { + wpa_printf(MSG_DEBUG, + "IEEE 802.11: Ignore group-addressed SA Query frame (A1=" MACSTR " A2=" MACSTR ")", + MAC2STR(da), MAC2STR(sa)); + return; + } wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query frame from " MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]); @@ -2570,8 +2938,11 @@ void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa, if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci, channel_width_to_int(ci.chanwidth), - ci.seg1_idx) != 0) { - wpa_printf(MSG_WARNING, "%s", ocv_errorstr); + ci.seg1_idx) != OCI_SUCCESS) { + wpa_msg(wpa_s, MSG_INFO, OCV_FAILURE "addr=" MACSTR + " frame=saquery%s error=%s", + MAC2STR(sa), data[0] == WLAN_SA_QUERY_REQUEST ? + "req" : "resp", ocv_errorstr); return; } } @@ -2582,5 +2953,3 @@ void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa, else if (data[0] == WLAN_SA_QUERY_RESPONSE) sme_process_sa_query_response(wpa_s, sa, data, len); } - -#endif /* CONFIG_IEEE80211W */ |