From efec8223892b3e677acb46eae84ec3534989971f Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Mon, 12 Apr 2021 16:39:23 -0700 Subject: [PATCH] wpa: Import wpa_supplicant/hostapd commit f91680c15 This is the April update to vendor/wpa committed upstream 2021/04/07. --- hostapd/config_file.c | 33 +- hostapd/ctrl_iface.c | 33 ++ hostapd/hostapd.conf | 24 +- src/ap/airtime_policy.c | 4 + src/ap/ap_config.c | 5 + src/ap/ap_config.h | 11 + src/ap/ap_drv_ops.h | 13 + src/ap/dpp_hostapd.c | 17 +- src/ap/drv_callbacks.c | 4 +- src/ap/hostapd.c | 6 +- src/ap/hostapd.h | 2 + src/ap/ieee802_11.c | 123 ++++-- src/ap/ieee802_11_shared.c | 67 +--- src/ap/sta_info.h | 1 + src/ap/wpa_auth.c | 8 +- src/ap/wpa_auth_ft.c | 3 +- src/common/common_module_tests.c | 131 +++---- src/common/ieee802_11_common.c | 29 ++ src/common/ieee802_11_common.h | 3 + src/common/qca-vendor.h | 42 ++ src/common/sae.c | 59 +-- src/common/sae.h | 2 +- src/common/wpa_common.c | 4 +- src/common/wpa_common.h | 4 +- src/crypto/crypto_openssl.c | 2 + src/drivers/driver.h | 6 + src/drivers/driver_nl80211.c | 65 ++- src/drivers/driver_nl80211_capa.c | 2 +- src/eap_common/eap_sim_common.c | 24 ++ src/rsn_supp/wpa.c | 12 +- src/rsn_supp/wpa_ft.c | 8 +- src/wps/wps_registrar.c | 40 +- tests/hwsim/example-hostapd.config | 1 + tests/hwsim/hostapd.py | 16 +- tests/hwsim/test_ap_eap.py | 1 + tests/hwsim/test_ap_ft.py | 30 +- tests/hwsim/test_ap_ht.py | 69 +++- tests/hwsim/test_ap_params.py | 61 +++ tests/hwsim/test_ap_psk.py | 16 + tests/hwsim/test_ap_track.py | 32 ++ tests/hwsim/test_ap_wps.py | 108 ++++- tests/hwsim/test_dpp.py | 524 +++++++++++++++++++++++++ tests/hwsim/test_eap_proto.py | 8 +- tests/hwsim/test_fils.py | 51 +++ tests/hwsim/test_he.py | 22 +- tests/hwsim/test_ieee8021x.py | 17 + tests/hwsim/test_mbo.py | 31 +- tests/hwsim/test_mscs.py | 231 +++++++++++ tests/hwsim/test_multi_ap.py | 12 +- tests/hwsim/test_ocv.py | 57 ++- tests/hwsim/test_p2p_discovery.py | 51 +++ tests/hwsim/test_pasn.py | 235 +++++++++-- tests/hwsim/test_pmksa_cache.py | 14 + tests/hwsim/test_rrm.py | 14 + tests/hwsim/test_wnm.py | 37 +- tests/hwsim/test_wpas_ctrl.py | 10 + tests/hwsim/vm/inside.sh | 5 + wpa_supplicant/ctrl_iface.c | 216 ++++++++-- wpa_supplicant/ctrl_iface.h | 10 +- wpa_supplicant/ctrl_iface_named_pipe.c | 5 +- wpa_supplicant/ctrl_iface_udp.c | 6 +- wpa_supplicant/ctrl_iface_unix.c | 43 +- wpa_supplicant/eapol_test.c | 6 +- wpa_supplicant/events.c | 7 +- wpa_supplicant/mesh_rsn.c | 1 - wpa_supplicant/pasn_supplicant.c | 196 +++++++-- wpa_supplicant/preauth_test.c | 6 +- wpa_supplicant/robust_av.c | 2 +- wpa_supplicant/sme.c | 1 - wpa_supplicant/wpa_supplicant.c | 10 +- wpa_supplicant/wpa_supplicant_i.h | 7 +- 71 files changed, 2510 insertions(+), 446 deletions(-) create mode 100644 tests/hwsim/test_mscs.py diff --git a/hostapd/config_file.c b/hostapd/config_file.c index fd9bc0e9fced..e05c81366d9b 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2332,6 +2332,22 @@ static int hostapd_dpp_controller_parse(struct hostapd_bss_config *bss, #endif /* CONFIG_DPP2 */ +static int get_hex_config(u8 *buf, size_t max_len, int line, + const char *field, const char *val) +{ + size_t hlen = os_strlen(val), len = hlen / 2; + u8 tmp[EXT_CAPA_MAX_LEN]; + + os_memset(tmp, 0, EXT_CAPA_MAX_LEN); + if (hlen & 1 || len > EXT_CAPA_MAX_LEN || hexstr2bin(val, tmp, len)) { + wpa_printf(MSG_ERROR, "Line %d: Invalid %s", line, field); + return -1; + } + os_memcpy(buf, tmp, EXT_CAPA_MAX_LEN); + return 0; +} + + static int hostapd_config_fill(struct hostapd_config *conf, struct hostapd_bss_config *bss, const char *buf, char *pos, int line) @@ -2458,12 +2474,13 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->ieee802_1x = atoi(pos); } else if (os_strcmp(buf, "eapol_version") == 0) { int eapol_version = atoi(pos); - #ifdef CONFIG_MACSEC - if (eapol_version < 1 || eapol_version > 3) { + int max_ver = 3; #else /* CONFIG_MACSEC */ - if (eapol_version < 1 || eapol_version > 2) { + int max_ver = 2; #endif /* CONFIG_MACSEC */ + + if (eapol_version < 1 || eapol_version > max_ver) { wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL version (%d): '%s'.", line, eapol_version, pos); @@ -4675,7 +4692,17 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, pos); return 1; } + } else if (os_strcmp(buf, "pasn_comeback_after") == 0) { + bss->pasn_comeback_after = atoi(pos); #endif /* CONFIG_PASN */ + } else if (os_strcmp(buf, "ext_capa_mask") == 0) { + if (get_hex_config(bss->ext_capa_mask, EXT_CAPA_MAX_LEN, + line, "ext_capa_mask", pos)) + return 1; + } else if (os_strcmp(buf, "ext_capa") == 0) { + if (get_hex_config(bss->ext_capa, EXT_CAPA_MAX_LEN, + line, "ext_capa", pos)) + return 1; } else { wpa_printf(MSG_ERROR, "Line %d: unknown configuration item '%s'", diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 62fa51e91c20..b39f40252f29 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1469,6 +1469,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) hapd->ext_mgmt_frame_handling = atoi(value); } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) { hapd->ext_eapol_frame_io = atoi(value); + } else if (os_strcasecmp(cmd, "force_backlog_bytes") == 0) { + hapd->force_backlog_bytes = atoi(value); #ifdef CONFIG_DPP } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) { os_free(hapd->dpp_config_obj_override); @@ -2562,6 +2564,34 @@ static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd, return wpa_snprintf_hex(buf, buflen, pmk, pmk_len); } + +static int hostapd_ctrl_register_frame(struct hostapd_data *hapd, + const char *cmd) +{ + u16 type; + char *pos, *end; + u8 match[10]; + size_t match_len; + bool multicast = false; + + type = strtol(cmd, &pos, 16); + if (*pos != ' ') + return -1; + pos++; + end = os_strchr(pos, ' '); + if (end) { + match_len = end - pos; + multicast = os_strstr(end, "multicast") != NULL; + } else { + match_len = os_strlen(pos) / 2; + } + if (hexstr2bin(pos, match, match_len)) + return -1; + + return hostapd_drv_register_frame(hapd, type, match, match_len, + multicast); +} + #endif /* CONFIG_TESTING_OPTIONS */ @@ -3646,6 +3676,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "GET_PMK ", 8) == 0) { reply_len = hostapd_ctrl_get_pmk(hapd, buf + 8, reply, reply_size); + } else if (os_strncmp(buf, "REGISTER_FRAME ", 15) == 0) { + if (hostapd_ctrl_register_frame(hapd, buf + 16) < 0) + reply_len = -1; #endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12)) diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index e3ee8b2a0c1b..7932cb862f48 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -877,18 +877,31 @@ wmm_ac_vo_acm=0 #he_mu_edca_ac_vo_timer=255 # Spatial Reuse Parameter Set +# +# SR Control field value +# B0 = PSR Disallowed +# B1 = Non-SRG OBSS PD SR Disallowed +# B2 = Non-SRG Offset Present +# B3 = SRG Information Present +# B4 = HESIGA_Spatial_reuse_value15_allowed #he_spr_sr_control +# +# Non-SRG OBSS PD Max Offset (included if he_spr_sr_control B2=1) #he_spr_non_srg_obss_pd_max_offset + +# SRG OBSS PD Min Offset (included if he_spr_sr_control B3=1) #he_spr_srg_obss_pd_min_offset +# +# SRG OBSS PD Max Offset (included if he_spr_sr_control B3=1) #he_spr_srg_obss_pd_max_offset # -# SPR SRG BSS Color +# SPR SRG BSS Color (included if he_spr_sr_control B3=1) # This config represents SRG BSS Color Bitmap field of Spatial Reuse Parameter # Set element that indicates the BSS color values used by members of the # SRG of which the transmitting STA is a member. The value is in range of 0-63. #he_spr_srg_bss_colors=1 2 10 63 # -# SPR SRG Partial BSSID +# SPR SRG Partial BSSID (included if he_spr_sr_control B3=1) # This config represents SRG Partial BSSID Bitmap field of Spatial Reuse # Parameter Set element that indicates the Partial BSSID values used by members # of the SRG of which the transmitting STA is a member. The value range @@ -2038,6 +2051,13 @@ own_ip_addr=127.0.0.1 # http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10 #pasn_groups=19 20 21 +# PASN comeback after time in TUs +# In case the AP is temporarily unable to handle a PASN authentication exchange +# due to a too large number of parallel operations, this value indicates to the +# peer after how many TUs it can try the PASN exchange again. +# (default: 10 TUs) +#pasn_comeback_after=10 + ##### IEEE 802.11r configuration ############################################## # Mobility Domain identifier (dot11FTMobilityDomainID, MDID) diff --git a/src/ap/airtime_policy.c b/src/ap/airtime_policy.c index 1e67f0d5996e..abe817c5b015 100644 --- a/src/ap/airtime_policy.c +++ b/src/ap/airtime_policy.c @@ -79,6 +79,10 @@ static void count_backlogged_sta(struct hostapd_data *hapd) for (sta = hapd->sta_list; sta; sta = sta->next) { if (hostapd_drv_read_sta_data(hapd, &data, sta->addr)) continue; +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->force_backlog_bytes) + data.backlog_bytes = 1; +#endif /* CONFIG_TESTING_OPTIONS */ if (data.backlog_bytes > 0) set_new_backlog_time(hapd, sta, &now); diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 452386b7e5de..7b6249bbe5cf 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -165,6 +165,11 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) #ifdef CONFIG_TESTING_OPTIONS bss->sae_commit_status = -1; #endif /* CONFIG_TESTING_OPTIONS */ + +#ifdef CONFIG_PASN + /* comeback after 10 TUs */ + bss->pasn_comeback_after = 10; +#endif /* CONFIG_PASN */ } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 8aeb03107af2..95bd79873a59 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -267,6 +267,8 @@ struct airtime_sta_weight { u8 addr[ETH_ALEN]; }; +#define EXT_CAPA_MAX_LEN 15 + /** * struct hostapd_bss_config - Per-BSS configuration */ @@ -880,9 +882,18 @@ struct hostapd_bss_config { #endif /* CONFIG_TESTING_OPTIONS */ int *pasn_groups; + + /* + * The time in TUs after which the non-AP STA is requested to retry the + * PASN authentication in case there are too many parallel operations. + */ + u16 pasn_comeback_after; #endif /* CONFIG_PASN */ unsigned int unsol_bcast_probe_resp_interval; + + u8 ext_capa_mask[EXT_CAPA_MAX_LEN]; + u8 ext_capa[EXT_CAPA_MAX_LEN]; }; /** diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index a42070116771..61c8f64eb471 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -403,4 +403,17 @@ static inline int hostapd_drv_driver_cmd(struct hostapd_data *hapd, } #endif /* ANDROID */ +#ifdef CONFIG_TESTING_OPTIONS +static inline int +hostapd_drv_register_frame(struct hostapd_data *hapd, u16 type, + const u8 *match, size_t match_len, + bool multicast) +{ + if (!hapd->driver || !hapd->drv_priv || !hapd->driver->register_frame) + return -1; + return hapd->driver->register_frame(hapd->drv_priv, type, match, + match_len, multicast); +} +#endif /* CONFIG_TESTING_OPTIONS */ + #endif /* AP_DRV_OPS */ diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index e1e5a3ac4bb3..aaeb94c2f53b 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -915,7 +915,8 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); return; } - if (!resp || status_code != WLAN_STATUS_SUCCESS) { + if (result != GAS_QUERY_AP_SUCCESS || + !resp || status_code != WLAN_STATUS_SUCCESS) { wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed"); goto fail; } @@ -1189,6 +1190,7 @@ static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src, wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result"); eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd, NULL); + auth->waiting_conn_status_result = 1; eloop_cancel_timeout( hostapd_dpp_conn_status_result_wait_timeout, hapd, NULL); @@ -1981,6 +1983,19 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa, wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); return NULL; } + + if (hapd->dpp_auth_ok_on_ack && auth->configurator) { + wpa_printf(MSG_DEBUG, + "DPP: Have not received ACK for Auth Confirm yet - assume it was received based on this GAS request"); + /* hostapd_dpp_auth_success() would normally have been called + * from TX status handler, but since there was no such handler + * call yet, simply send out the event message and proceed with + * exchange. */ + wpa_msg(hapd->msg_ctx, MSG_INFO, + DPP_EVENT_AUTH_SUCCESS "init=1"); + hapd->dpp_auth_ok_on_ack = 0; + } + wpa_hexdump(MSG_DEBUG, "DPP: Received Configuration Request (GAS Query Request)", query, query_len); diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 290d354a016c..ec5abf166b23 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -459,8 +459,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, if (hapd->conf->sae_pwe == 2 && sta->auth_alg == WLAN_AUTH_SAE && sta->sae && !sta->sae->h2e && - elems.rsnxe && elems.rsnxe_len >= 1 && - (elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) { + ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len, + WLAN_RSNX_CAPAB_SAE_H2E)) { wpa_printf(MSG_INFO, "SAE: " MACSTR " indicates support for SAE H2E, but did not use it", MAC2STR(sta->addr)); diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 7bb0f097669b..e9aae6dcf2f5 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -107,7 +107,8 @@ static void hostapd_reload_bss(struct hostapd_data *hapd) return; if (hapd->conf->wmm_enabled < 0) - hapd->conf->wmm_enabled = hapd->iconf->ieee80211n; + hapd->conf->wmm_enabled = hapd->iconf->ieee80211n | + hapd->iconf->ieee80211ax; #ifndef CONFIG_NO_RADIUS radius_client_reconfig(hapd->radius, hapd->conf->radius); @@ -1173,7 +1174,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) } if (conf->wmm_enabled < 0) - conf->wmm_enabled = hapd->iconf->ieee80211n; + conf->wmm_enabled = hapd->iconf->ieee80211n | + hapd->iconf->ieee80211ax; #ifdef CONFIG_IEEE80211R_AP if (is_zero_ether_addr(conf->r1_key_holder)) diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 44f566a42403..07d0aaa92100 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -354,6 +354,8 @@ struct hostapd_data { int last_bigtk_key_idx; u8 last_bigtk[WPA_BIGTK_MAX_LEN]; size_t last_bigtk_len; + + bool force_backlog_bytes; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_MBO diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 72d102f44e21..b404e84affe5 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -572,7 +572,7 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, if (update && !use_pt && sae_prepare_commit(hapd->own_addr, sta->addr, - (u8 *) password, os_strlen(password), rx_id, + (u8 *) password, os_strlen(password), sta->sae) < 0) { wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE"); return NULL; @@ -702,13 +702,15 @@ static int use_anti_clogging(struct hostapd_data *hapd) for (sta = hapd->sta_list; sta; sta = sta->next) { #ifdef CONFIG_SAE - if (!sta->sae) - continue; - if (sta->sae->state != SAE_COMMITTED && - sta->sae->state != SAE_CONFIRMED) - continue; - open++; + if (sta->sae && + (sta->sae->state == SAE_COMMITTED || + sta->sae->state == SAE_CONFIRMED)) + open++; #endif /* CONFIG_SAE */ +#ifdef CONFIG_PASN + if (sta->pasn && sta->pasn->ecdh) + open++; +#endif /* CONFIG_PASN */ if (open >= hapd->conf->anti_clogging_threshold) return 1; } @@ -806,7 +808,8 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd, if (buf == NULL) return NULL; - wpabuf_put_le16(buf, group); /* Finite Cyclic Group */ + if (group) + wpabuf_put_le16(buf, group); /* Finite Cyclic Group */ if (h2e) { /* Encapsulate Anti-clogging Token field in a container IE */ @@ -2380,11 +2383,12 @@ static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd, struct wpabuf *wd) { struct pasn_data *pasn = sta->pasn; - const char *password = NULL; + const char *password; const u8 *data; size_t buf_len; u16 res, alg, seq, status; int groups[] = { pasn->group, 0 }; + struct sae_pt *pt = NULL; int ret; if (!wd) @@ -2406,8 +2410,8 @@ static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd, wpa_printf(MSG_DEBUG, "PASN: SAE commit: alg=%u, seq=%u, status=%u", alg, seq, status); - /* TODO: SAE H2E */ - if (alg != WLAN_AUTH_SAE || seq != 1 || status != WLAN_STATUS_SUCCESS) { + if (alg != WLAN_AUTH_SAE || seq != 1 || + status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) { wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit"); return -1; } @@ -2421,15 +2425,14 @@ static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd, return -1; } - password = sae_get_password(hapd, sta, NULL, NULL, NULL, NULL); - if (!password) { - wpa_printf(MSG_DEBUG, "PASN: No SAE password found"); + password = sae_get_password(hapd, sta, NULL, NULL, &pt, NULL); + if (!password || !pt) { + wpa_printf(MSG_DEBUG, "PASN: No SAE PT found"); return -1; } - ret = sae_prepare_commit(hapd->own_addr, sta->addr, - (const u8 *) password, os_strlen(password), 0, - &pasn->sae); + ret = sae_prepare_commit_pt(&pasn->sae, pt, hapd->own_addr, sta->addr, + NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit"); return -1; @@ -2526,7 +2529,7 @@ static struct wpabuf * pasn_get_sae_wd(struct hostapd_data *hapd, len_ptr = wpabuf_put(buf, 2); wpabuf_put_le16(buf, WLAN_AUTH_SAE); wpabuf_put_le16(buf, 1); - wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); + wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT); /* Write the actual commit and update the length accordingly */ sae_write_commit(&pasn->sae, buf, NULL, 0); @@ -2643,7 +2646,7 @@ static void pasn_fils_auth_resp(struct hostapd_data *hapd, wpabuf_head(pasn->secret), wpabuf_len(pasn->secret), &sta->pasn->ptk, sta->pasn->akmp, - sta->pasn->cipher, WPA_KDK_MAX_LEN); + sta->pasn->cipher, sta->pasn->kdk_len); if (ret) { wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK"); goto fail; @@ -2880,7 +2883,7 @@ pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta, ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr, wpabuf_head(secret), wpabuf_len(secret), &sta->pasn->ptk, sta->pasn->akmp, - sta->pasn->cipher, WPA_KDK_MAX_LEN); + sta->pasn->cipher, sta->pasn->kdk_len); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK"); return -1; @@ -2891,6 +2894,54 @@ pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta, } +static void handle_auth_pasn_comeback(struct hostapd_data *hapd, + struct sta_info *sta, u16 group) +{ + struct wpabuf *buf, *comeback; + int ret; + + wpa_printf(MSG_DEBUG, + "PASN: Building comeback frame 2. Comeback after=%u", + hapd->conf->pasn_comeback_after); + + buf = wpabuf_alloc(1500); + if (!buf) + return; + + wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr, + sta->addr, 2, + WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY); + + /* + * Do not include the group as a part of the token since it is not going + * to be used. + */ + comeback = auth_build_token_req(hapd, 0, sta->addr, 0); + if (!comeback) { + wpa_printf(MSG_DEBUG, + "PASN: Failed sending auth with comeback"); + wpabuf_free(buf); + return; + } + + wpa_pasn_add_parameter_ie(buf, group, + WPA_PASN_WRAPPED_DATA_NO, + NULL, 0, comeback, + hapd->conf->pasn_comeback_after); + wpabuf_free(comeback); + + wpa_printf(MSG_DEBUG, + "PASN: comeback: STA=" MACSTR, MAC2STR(sta->addr)); + + ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0, + NULL, 0, 0); + if (ret) + wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2"); + + wpabuf_free(buf); +} + + static int handle_auth_pasn_resp(struct hostapd_data *hapd, struct sta_info *sta, struct rsn_pmksa_cache_entry *pmksa, @@ -3100,6 +3151,15 @@ static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta, sta->pasn->akmp = rsn_data.key_mgmt; sta->pasn->cipher = rsn_data.pairwise_cipher; + if (hapd->conf->force_kdk_derivation || + ((hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) && + ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len, + WLAN_RSNX_CAPAB_SECURE_LTF))) + sta->pasn->kdk_len = WPA_KDK_MAX_LEN; + else + sta->pasn->kdk_len = 0; + wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", sta->pasn->kdk_len); + if (!elems.pasn_params || !elems.pasn_params_len) { wpa_printf(MSG_DEBUG, "PASN: No PASN Parameters element found"); @@ -3133,6 +3193,25 @@ static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta, goto send_resp; } + if (pasn_params.comeback) { + wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token"); + + ret = check_comeback_token(hapd, sta->addr, + pasn_params.comeback, + pasn_params.comeback_len); + + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + } else if (use_anti_clogging(hapd)) { + wpa_printf(MSG_DEBUG, "PASN: Respond with comeback"); + handle_auth_pasn_comeback(hapd, sta, pasn_params.group); + ap_free_sta(hapd, sta); + return; + } + sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group); if (!sta->pasn->ecdh) { wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH"); @@ -4614,8 +4693,8 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, if (hapd->conf->sae_pwe == 2 && sta->auth_alg == WLAN_AUTH_SAE && sta->sae && !sta->sae->h2e && - elems.rsnxe && elems.rsnxe_len >= 1 && - (elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) { + ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len, + WLAN_RSNX_CAPAB_SAE_H2E)) { wpa_printf(MSG_INFO, "SAE: " MACSTR " indicates support for SAE H2E, but did not use it", MAC2STR(sta->addr)); diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c index d0074f6ba220..4bff9e591883 100644 --- a/src/ap/ieee802_11_shared.c +++ b/src/ap/ieee802_11_shared.c @@ -451,70 +451,10 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) { u8 *pos = eid; - u8 len = 0, i; + u8 len = EXT_CAPA_MAX_LEN, i; - if (hapd->conf->qos_map_set_len || - (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))) - len = 5; - if (len < 4 && - (hapd->conf->time_advertisement == 2 || hapd->conf->interworking)) - len = 4; - if (len < 3 && - (hapd->conf->wnm_sleep_mode || hapd->conf->bss_transition)) - len = 3; - if (len < 1 && - (hapd->iconf->obss_interval || - (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA))) - len = 1; - if (len < 2 && - (hapd->conf->proxy_arp || hapd->conf->coloc_intf_reporting)) - len = 2; - if (len < 7 && hapd->conf->ssid.utf8_ssid) - len = 7; - if (len < 9 && - (hapd->conf->ftm_initiator || hapd->conf->ftm_responder)) - len = 9; -#ifdef CONFIG_WNM_AP - if (len < 4) - len = 4; -#endif /* CONFIG_WNM_AP */ -#ifdef CONFIG_HS20 - if (hapd->conf->hs20 && len < 6) - len = 6; -#endif /* CONFIG_HS20 */ -#ifdef CONFIG_MBO - if (hapd->conf->mbo_enabled && len < 6) - len = 6; -#endif /* CONFIG_MBO */ -#ifdef CONFIG_FILS - if ((!(hapd->conf->wpa & WPA_PROTO_RSN) || - !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10) - len = 10; -#endif /* CONFIG_FILS */ -#ifdef CONFIG_IEEE80211AX - if (len < 10 && hapd->iconf->ieee80211ax && - hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP)) - len = 10; -#endif /* CONFIG_IEEE80211AX */ -#ifdef CONFIG_SAE - if (len < 11 && hapd->conf->wpa && - wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) && - hostapd_sae_pw_id_in_use(hapd->conf)) - len = 11; -#endif /* CONFIG_SAE */ - if (len < 11 && hapd->conf->beacon_prot && - (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION)) - len = 11; -#ifdef CONFIG_SAE_PK - if (len < 12 && hapd->conf->wpa && - wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) && - hostapd_sae_pk_exclusively(hapd->conf)) - len = 12; -#endif /* CONFIG_SAE_PK */ if (len < hapd->iface->extended_capa_len) len = hapd->iface->extended_capa_len; - if (len == 0) - return eid; *pos++ = WLAN_EID_EXT_CAPAB; *pos++ = len; @@ -525,6 +465,11 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) *pos &= ~hapd->iface->extended_capa_mask[i]; *pos |= hapd->iface->extended_capa[i]; } + + if (i < EXT_CAPA_MAX_LEN) { + *pos &= ~hapd->conf->ext_capa_mask[i]; + *pos |= hapd->conf->ext_capa[i]; + } } while (len > 0 && eid[1 + len] == 0) { diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index efa48e7e3d8d..27e72f9a0164 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -88,6 +88,7 @@ struct pasn_data { u16 group; u8 trans_seq; u8 wrapped_data_format; + size_t kdk_len; u8 hash[SHA384_MAC_LEN]; struct wpa_ptk ptk; diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 6c791e26b0b7..59cd46aa4601 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -2283,8 +2283,7 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, if (sm->wpa_auth->conf.force_kdk_derivation || (sm->wpa_auth->conf.secure_ltf && - sm->rsnxe && sm->rsnxe_len >= 4 && - sm->rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8))) + ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))) kdk_len = WPA_KDK_MAX_LEN; else kdk_len = 0; @@ -2338,8 +2337,7 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk, if (sm->wpa_auth->conf.force_kdk_derivation || (sm->wpa_auth->conf.secure_ltf && - sm->rsnxe && sm->rsnxe_len >= 4 && - sm->rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8))) + ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))) kdk_len = WPA_KDK_MAX_LEN; else kdk_len = 0; @@ -4267,7 +4265,7 @@ int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos) wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit", gsm->GN_bigtk); wpa_hexdump_key(MSG_DEBUG, "WNM: BIGTK in WNM-Sleep Mode exit", - gsm->IGTK[gsm->GN_bigtk - 6], len); + gsm->BIGTK[gsm->GN_bigtk - 6], len); return pos - start; } diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 32b745651ace..e80086b93d8d 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -3198,8 +3198,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, if (sm->wpa_auth->conf.force_kdk_derivation || (sm->wpa_auth->conf.secure_ltf && - sm->rsnxe && sm->rsnxe_len >= 4 && - sm->rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8))) + ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))) kdk_len = WPA_KDK_MAX_LEN; else kdk_len = 0; diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c index 50ce1923c120..8aba713f92ba 100644 --- a/src/common/common_module_tests.c +++ b/src/common/common_module_tests.c @@ -256,87 +256,69 @@ static int sae_tests(void) #ifdef CONFIG_SAE struct sae_data sae; int ret = -1; - /* IEEE P802.11-REVmd/D2.1, Annex J.10 */ - const u8 addr1[ETH_ALEN] = { 0x82, 0x7b, 0x91, 0x9d, 0xd4, 0xb9 }; - const u8 addr2[ETH_ALEN] = { 0x1e, 0xec, 0x49, 0xea, 0x64, 0x88 }; + /* IEEE Std 802.11-2020, Annex J.10 */ + const u8 addr1[ETH_ALEN] = { 0x4d, 0x3f, 0x2f, 0xff, 0xe3, 0x87 }; + const u8 addr2[ETH_ALEN] = { 0xa5, 0xd8, 0xaa, 0x95, 0x8e, 0x3c }; const char *ssid = "byteme"; const char *pw = "mekmitasdigoat"; const char *pwid = "psk4internet"; const u8 local_rand[] = { - 0xa9, 0x06, 0xf6, 0x1e, 0x4d, 0x3a, 0x5d, 0x4e, - 0xb2, 0x96, 0x5f, 0xf3, 0x4c, 0xf9, 0x17, 0xdd, - 0x04, 0x44, 0x45, 0xc8, 0x78, 0xc1, 0x7c, 0xa5, - 0xd5, 0xb9, 0x37, 0x86, 0xda, 0x9f, 0x83, 0xcf + 0x99, 0x24, 0x65, 0xfd, 0x3d, 0xaa, 0x3c, 0x60, + 0xaa, 0x65, 0x65, 0xb7, 0xf6, 0x2a, 0x2a, 0x7f, + 0x2e, 0x12, 0xdd, 0x12, 0xf1, 0x98, 0xfa, 0xf4, + 0xfb, 0xed, 0x89, 0xd7, 0xff, 0x1a, 0xce, 0x94 }; const u8 local_mask[] = { - 0x42, 0x34, 0xb4, 0xfb, 0x17, 0xaa, 0x43, 0x5c, - 0x52, 0xfb, 0xfd, 0xeb, 0xe6, 0x40, 0x39, 0xb4, - 0x34, 0x78, 0x20, 0x0e, 0x54, 0xff, 0x7b, 0x6e, - 0x07, 0xb6, 0x9c, 0xad, 0x74, 0x15, 0x3c, 0x15 + 0x95, 0x07, 0xa9, 0x0f, 0x77, 0x7a, 0x04, 0x4d, + 0x6a, 0x08, 0x30, 0xb9, 0x1e, 0xa3, 0xd5, 0xdd, + 0x70, 0xbe, 0xce, 0x44, 0xe1, 0xac, 0xff, 0xb8, + 0x69, 0x83, 0xb5, 0xe1, 0xbf, 0x9f, 0xb3, 0x22 }; const u8 local_commit[] = { - 0x13, 0x00, 0xeb, 0x3b, 0xab, 0x19, 0x64, 0xe4, - 0xa0, 0xab, 0x05, 0x92, 0x5d, 0xdf, 0x33, 0x39, - 0x51, 0x91, 0x38, 0xbc, 0x65, 0xd6, 0xcd, 0xc0, - 0xf8, 0x13, 0xdd, 0x6f, 0xd4, 0x34, 0x4e, 0xb4, - 0xbf, 0xe4, 0x4b, 0x5c, 0x21, 0x59, 0x76, 0x58, - 0xf4, 0xe3, 0xed, 0xdf, 0xb4, 0xb9, 0x9f, 0x25, - 0xb4, 0xd6, 0x54, 0x0f, 0x32, 0xff, 0x1f, 0xd5, - 0xc5, 0x30, 0xc6, 0x0a, 0x79, 0x44, 0x48, 0x61, - 0x0b, 0xc6, 0xde, 0x3d, 0x92, 0xbd, 0xbb, 0xd4, - 0x7d, 0x93, 0x59, 0x80, 0xca, 0x6c, 0xf8, 0x98, - 0x8a, 0xb6, 0x63, 0x0b, 0xe6, 0x76, 0x4c, 0x88, - 0x5c, 0xeb, 0x97, 0x93, 0x97, 0x0f, 0x69, 0x52, - 0x17, 0xee, 0xff, 0x0d, 0x21, 0x70, 0x73, 0x6b, - 0x34, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, - 0x74 + 0x13, 0x00, 0x2e, 0x2c, 0x0f, 0x0d, 0xb5, 0x24, + 0x40, 0xad, 0x14, 0x6d, 0x96, 0x71, 0x14, 0xce, + 0x00, 0x5c, 0xe1, 0xea, 0xb0, 0xaa, 0x2c, 0x2e, + 0x5c, 0x28, 0x71, 0xb7, 0x74, 0xf6, 0xc2, 0x57, + 0x5c, 0x65, 0xd5, 0xad, 0x9e, 0x00, 0x82, 0x97, + 0x07, 0xaa, 0x36, 0xba, 0x8b, 0x85, 0x97, 0x38, + 0xfc, 0x96, 0x1d, 0x08, 0x24, 0x35, 0x05, 0xf4, + 0x7c, 0x03, 0x53, 0x76, 0xd7, 0xac, 0x4b, 0xc8, + 0xd7, 0xb9, 0x50, 0x83, 0xbf, 0x43, 0x82, 0x7d, + 0x0f, 0xc3, 0x1e, 0xd7, 0x78, 0xdd, 0x36, 0x71, + 0xfd, 0x21, 0xa4, 0x6d, 0x10, 0x91, 0xd6, 0x4b, + 0x6f, 0x9a, 0x1e, 0x12, 0x72, 0x62, 0x13, 0x25, + 0xdb, 0xe1 }; const u8 peer_commit[] = { - 0x13, 0x00, 0x55, 0x64, 0xf0, 0x45, 0xb2, 0xea, - 0x1e, 0x56, 0x6c, 0xf1, 0xdd, 0x74, 0x1f, 0x70, - 0xd9, 0xbe, 0x35, 0xd2, 0xdf, 0x5b, 0x9a, 0x55, - 0x02, 0x94, 0x6e, 0xe0, 0x3c, 0xf8, 0xda, 0xe2, - 0x7e, 0x1e, 0x05, 0xb8, 0x43, 0x0e, 0xb7, 0xa9, - 0x9e, 0x24, 0x87, 0x7c, 0xe6, 0x9b, 0xaf, 0x3d, - 0xc5, 0x80, 0xe3, 0x09, 0x63, 0x3d, 0x6b, 0x38, - 0x5f, 0x83, 0xee, 0x1c, 0x3e, 0xc3, 0x59, 0x1f, - 0x1a, 0x53, 0x93, 0xc0, 0x6e, 0x80, 0x5d, 0xdc, - 0xeb, 0x2f, 0xde, 0x50, 0x93, 0x0d, 0xd7, 0xcf, - 0xeb, 0xb9, 0x87, 0xc6, 0xff, 0x96, 0x66, 0xaf, - 0x16, 0x4e, 0xb5, 0x18, 0x4d, 0x8e, 0x66, 0x62, - 0xed, 0x6a, 0xff, 0x0d, 0x21, 0x70, 0x73, 0x6b, - 0x34, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, - 0x74 + 0x13, 0x00, 0x59, 0x1b, 0x96, 0xf3, 0x39, 0x7f, + 0xb9, 0x45, 0x10, 0x08, 0x48, 0xe7, 0xb5, 0x50, + 0x54, 0x3b, 0x67, 0x20, 0xd8, 0x83, 0x37, 0xee, + 0x93, 0xfc, 0x49, 0xfd, 0x6d, 0xf7, 0xe0, 0x8b, + 0x52, 0x23, 0xe7, 0x1b, 0x9b, 0xb0, 0x48, 0xd3, + 0x87, 0x3f, 0x20, 0x55, 0x69, 0x53, 0xa9, 0x6c, + 0x91, 0x53, 0x6f, 0xd8, 0xee, 0x6c, 0xa9, 0xb4, + 0xa6, 0x8a, 0x14, 0x8b, 0x05, 0x6a, 0x90, 0x9b, + 0xe0, 0x3e, 0x83, 0xae, 0x20, 0x8f, 0x60, 0xf8, + 0xef, 0x55, 0x37, 0x85, 0x80, 0x74, 0xdb, 0x06, + 0x68, 0x70, 0x32, 0x39, 0x98, 0x62, 0x99, 0x9b, + 0x51, 0x1e, 0x0a, 0x15, 0x52, 0xa5, 0xfe, 0xa3, + 0x17, 0xc2 }; const u8 kck[] = { - 0x59, 0x9d, 0x6f, 0x1e, 0x27, 0x54, 0x8b, 0xe8, - 0x49, 0x9d, 0xce, 0xed, 0x2f, 0xec, 0xcf, 0x94, - 0x81, 0x8c, 0xe1, 0xc7, 0x9f, 0x1b, 0x4e, 0xb3, - 0xd6, 0xa5, 0x32, 0x28, 0xa0, 0x9b, 0xf3, 0xed + 0x1e, 0x73, 0x3f, 0x6d, 0x9b, 0xd5, 0x32, 0x56, + 0x28, 0x73, 0x04, 0x33, 0x88, 0x31, 0xb0, 0x9a, + 0x39, 0x40, 0x6d, 0x12, 0x10, 0x17, 0x07, 0x3a, + 0x5c, 0x30, 0xdb, 0x36, 0xf3, 0x6c, 0xb8, 0x1a }; const u8 pmk[] = { - 0x7a, 0xea, 0xd8, 0x6f, 0xba, 0x4c, 0x32, 0x21, - 0xfc, 0x43, 0x7f, 0x5f, 0x14, 0xd7, 0x0d, 0x85, - 0x4e, 0xa5, 0xd5, 0xaa, 0xc1, 0x69, 0x01, 0x16, - 0x79, 0x30, 0x81, 0xed, 0xa4, 0xd5, 0x57, 0xc5 + 0x4e, 0x4d, 0xfa, 0xb1, 0xa2, 0xdd, 0x8a, 0xc1, + 0xa9, 0x17, 0x90, 0xf9, 0x53, 0xfa, 0xaa, 0x45, + 0x2a, 0xe5, 0xc6, 0x87, 0x3a, 0xb7, 0x5b, 0x63, + 0x60, 0x5b, 0xa6, 0x63, 0xf8, 0xa7, 0xfe, 0x59 }; const u8 pmkid[] = { - 0x40, 0xa0, 0x9b, 0x60, 0x17, 0xce, 0xbf, 0x00, - 0x72, 0x84, 0x3b, 0x53, 0x52, 0xaa, 0x2b, 0x4f - }; - const u8 local_confirm[] = { - 0x01, 0x00, 0x12, 0xd9, 0xd5, 0xc7, 0x8c, 0x50, - 0x05, 0x26, 0xd3, 0x6c, 0x41, 0xdb, 0xc5, 0x6a, - 0xed, 0xf2, 0x91, 0x4c, 0xed, 0xdd, 0xd7, 0xca, - 0xd4, 0xa5, 0x8c, 0x48, 0xf8, 0x3d, 0xbd, 0xe9, - 0xfc, 0x77 - }; - const u8 peer_confirm[] = { - 0x01, 0x00, 0x02, 0x87, 0x1c, 0xf9, 0x06, 0x89, - 0x8b, 0x80, 0x60, 0xec, 0x18, 0x41, 0x43, 0xbe, - 0x77, 0xb8, 0xc0, 0x8a, 0x80, 0x19, 0xb1, 0x3e, - 0xb6, 0xd0, 0xae, 0xf0, 0xd8, 0x38, 0x3d, 0xfa, - 0xc2, 0xfd + 0x87, 0x47, 0xa6, 0x00, 0xee, 0xa3, 0xf9, 0xf2, + 0x24, 0x75, 0xdf, 0x58, 0xca, 0x1e, 0x54, 0x98 }; struct wpabuf *buf = NULL; struct crypto_bignum *mask = NULL; @@ -412,7 +394,7 @@ static int sae_tests(void) if (!buf || sae_set_group(&sae, 19) < 0 || sae_prepare_commit(addr1, addr2, (const u8 *) pw, os_strlen(pw), - pwid, &sae) < 0) + &sae) < 0) goto fail; /* Override local values based on SAE test vector */ @@ -434,7 +416,7 @@ static int sae_tests(void) goto fail; /* Check that output matches the test vector */ - if (sae_write_commit(&sae, buf, NULL, pwid) < 0) + if (sae_write_commit(&sae, buf, NULL, NULL) < 0) goto fail; wpa_hexdump_buf(MSG_DEBUG, "SAE: Commit message", buf); @@ -465,21 +447,6 @@ static int sae_tests(void) goto fail; } - buf->used = 0; - sae.send_confirm = 1; - sae_write_confirm(&sae, buf); - wpa_hexdump_buf(MSG_DEBUG, "SAE: Confirm message", buf); - - if (wpabuf_len(buf) != sizeof(local_confirm) || - os_memcmp(wpabuf_head(buf), local_confirm, - sizeof(local_confirm)) != 0) { - wpa_printf(MSG_ERROR, "SAE: Mismatch in local confirm"); - goto fail; - } - - if (sae_check_confirm(&sae, peer_confirm, sizeof(peer_confirm)) < 0) - goto fail; - pt_info = sae_derive_pt(pt_groups, (const u8 *) ssid, os_strlen(ssid), (const u8 *) pw, os_strlen(pw), pwid); diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 5b80db6d3b83..96681843e258 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -2403,6 +2403,35 @@ int ieee802_11_ext_capab(const u8 *ie, unsigned int capab) } +bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len, + unsigned int capab) +{ + const u8 *end; + size_t flen, i; + u32 capabs = 0; + + if (!rsnxe || rsnxe_len == 0) + return false; + end = rsnxe + rsnxe_len; + flen = (rsnxe[0] & 0x0f) + 1; + if (rsnxe + flen > end) + return false; + if (flen > 4) + flen = 4; + for (i = 0; i < flen; i++) + capabs |= rsnxe[i] << (8 * i); + + return capabs & BIT(capab); +} + + +bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab) +{ + return ieee802_11_rsnx_capab_len(rsnxe ? rsnxe + 2 : NULL, + rsnxe ? rsnxe[1] : 0, capab); +} + + void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel, int primary_channel, struct ieee80211_edmg_config *edmg) diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 8a16f1666221..fe2b1bca601b 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -269,6 +269,9 @@ int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, size_t nei_rep_len); int ieee802_11_ext_capab(const u8 *ie, unsigned int capab); +bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len, + unsigned int capab); +bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab); int op_class_to_bandwidth(u8 op_class); int op_class_to_ch_width(u8 op_class); diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index 573e144a63d5..32c93bb84d54 100644 --- a/src/common/qca-vendor.h +++ b/src/common/qca-vendor.h @@ -8445,6 +8445,34 @@ enum qca_wlan_twt_setup_state { * This parameter is used for * 1. TWT SET Request and Response * 2. TWT GET Response + * + * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID: Optional (u8) + * This attribute is used to configure Broadcast TWT ID. + * The Broadcast TWT ID indicates a specific Broadcast TWT for which the + * transmitting STA is providing TWT parameters. The allowed values are 0 to 31. + * This parameter is used for + * 1. TWT SET Request + * 2. TWT TERMINATE Request + * + * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION: Optional (u8) + * This attribute is used to configure Broadcast TWT recommendation. + * The Broadcast TWT Recommendation subfield contains a value that indicates + * recommendations on the types of frames that are transmitted by TWT + * scheduled STAs and scheduling AP during the broadcast TWT SP. + * The allowed values are 0 - 3. + * This parameter is used for + * 1. TWT SET Request + * + * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE: Optional (u8) + * This attribute is used to configure Broadcast TWT Persistence. + * The Broadcast TWT Persistence subfield indicates the number of + * TBTTs during which the Broadcast TWT SPs corresponding to this + * broadcast TWT Parameter set are present. The number of beacon intervals + * during which the Broadcast TWT SPs are present is equal to the value in the + * Broadcast TWT Persistence subfield plus 1 except that the value 255 + * indicates that the Broadcast TWT SPs are present until explicitly terminated. + * This parameter is used for + * 1. TWT SET Request */ enum qca_wlan_vendor_attr_twt_setup { QCA_WLAN_VENDOR_ATTR_TWT_SETUP_INVALID = 0, @@ -8474,6 +8502,10 @@ enum qca_wlan_vendor_attr_twt_setup { QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA = 21, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID = 22, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION = 23, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE = 24, + /* keep last */ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX = @@ -8512,6 +8544,13 @@ enum qca_wlan_vendor_attr_twt_setup { * @QCA_WLAN_VENDOR_TWT_STATUS_ROAM_INITIATED_TERMINATE: FW terminated the TWT * session due to roaming. Used on the TWT_TERMINATE notification from the * firmware. + * @QCA_WLAN_VENDOR_TWT_STATUS_SCC_MCC_CONCURRENCY_TERMINATE: FW terminated the + * TWT session due to SCC (Single Channel Concurrency) and MCC (Multi Channel + * Concurrency). Used on the TWT_TERMINATE notification from the firmware. + * @QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS: FW rejected the TWT setup + * request due to roaming in progress. + * @QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS: FW rejected the TWT + * setup request due to channel switch in progress. */ enum qca_wlan_vendor_twt_status { QCA_WLAN_VENDOR_TWT_STATUS_OK = 0, @@ -8532,6 +8571,9 @@ enum qca_wlan_vendor_twt_status { QCA_WLAN_VENDOR_TWT_STATUS_PARAMS_NOT_IN_RANGE = 15, QCA_WLAN_VENDOR_TWT_STATUS_PEER_INITIATED_TERMINATE = 16, QCA_WLAN_VENDOR_TWT_STATUS_ROAM_INITIATED_TERMINATE = 17, + QCA_WLAN_VENDOR_TWT_STATUS_SCC_MCC_CONCURRENCY_TERMINATE = 18, + QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS = 19, + QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS = 20, }; /** diff --git a/src/common/sae.c b/src/common/sae.c index f0d4c228c5da..74920a78e46a 100644 --- a/src/common/sae.c +++ b/src/common/sae.c @@ -280,13 +280,12 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed, static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, const u8 *addr2, const u8 *password, - size_t password_len, const char *identifier) + size_t password_len) { u8 counter, k; u8 addrs[2 * ETH_ALEN]; - const u8 *addr[3]; - size_t len[3]; - size_t num_elem; + const u8 *addr[2]; + size_t len[2]; u8 *dummy_password, *tmp_password; int pwd_seed_odd = 0; u8 prime[SAE_MAX_ECC_PRIME_LEN]; @@ -324,13 +323,10 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", password, password_len); - if (identifier) - wpa_printf(MSG_DEBUG, "SAE: password identifier: %s", - identifier); /* * H(salt, ikm) = HMAC-SHA256(salt, ikm) - * base = password [|| identifier] + * base = password * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC), * base || counter) */ @@ -338,15 +334,8 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, addr[0] = tmp_password; len[0] = password_len; - num_elem = 1; - if (identifier) { - addr[num_elem] = (const u8 *) identifier; - len[num_elem] = os_strlen(identifier); - num_elem++; - } - addr[num_elem] = &counter; - len[num_elem] = sizeof(counter); - num_elem++; + addr[1] = &counter; + len[1] = sizeof(counter); /* * Continue for at least k iterations to protect against side-channel @@ -367,7 +356,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, wpa_printf(MSG_DEBUG, "SAE: counter = %03u", counter); const_time_select_bin(found, dummy_password, password, password_len, tmp_password); - if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem, + if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len, pwd_seed) < 0) break; @@ -438,13 +427,12 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, const u8 *addr2, const u8 *password, - size_t password_len, const char *identifier) + size_t password_len) { u8 counter, k, sel_counter = 0; u8 addrs[2 * ETH_ALEN]; - const u8 *addr[3]; - size_t len[3]; - size_t num_elem; + const u8 *addr[2]; + size_t len[2]; u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_* * mask */ u8 mask; @@ -468,21 +456,14 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, /* * H(salt, ikm) = HMAC-SHA256(salt, ikm) * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC), - * password [|| identifier] || counter) + * password || counter) */ sae_pwd_seed_key(addr1, addr2, addrs); addr[0] = password; len[0] = password_len; - num_elem = 1; - if (identifier) { - addr[num_elem] = (const u8 *) identifier; - len[num_elem] = os_strlen(identifier); - num_elem++; - } - addr[num_elem] = &counter; - len[num_elem] = sizeof(counter); - num_elem++; + addr[1] = &counter; + len[1] = sizeof(counter); k = dragonfly_min_pwe_loop_iter(sae->group); @@ -497,7 +478,7 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, } wpa_printf(MSG_DEBUG, "SAE: counter = %02u", counter); - if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem, + if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len, pwd_seed) < 0) break; res = sae_test_pwd_seed_ffc(sae, pwd_seed, pwe); @@ -1354,15 +1335,13 @@ static int sae_derive_commit(struct sae_data *sae) int sae_prepare_commit(const u8 *addr1, const u8 *addr2, const u8 *password, size_t password_len, - const char *identifier, struct sae_data *sae) + struct sae_data *sae) { if (sae->tmp == NULL || (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password, - password_len, - identifier) < 0) || + password_len) < 0) || (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password, - password_len, - identifier) < 0)) + password_len) < 0)) return -1; sae->h2e = 0; @@ -2268,10 +2247,10 @@ int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf) hash_len = sae->tmp->kck_len; /* Send-Confirm */ - sc = wpabuf_put(buf, 0); - wpabuf_put_le16(buf, sae->send_confirm); if (sae->send_confirm < 0xffff) sae->send_confirm++; + sc = wpabuf_put(buf, 0); + wpabuf_put_le16(buf, sae->send_confirm); if (sae->tmp->ec) res = sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar, diff --git a/src/common/sae.h b/src/common/sae.h index 2243c0f339b0..93fc5fb39712 100644 --- a/src/common/sae.h +++ b/src/common/sae.h @@ -122,7 +122,7 @@ void sae_clear_data(struct sae_data *sae); int sae_prepare_commit(const u8 *addr1, const u8 *addr2, const u8 *password, size_t password_len, - const char *identifier, struct sae_data *sae); + struct sae_data *sae); int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt, const u8 *addr1, const u8 *addr2, int *rejected_groups, const struct sae_pk *pk); diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index 493da18d7265..04461516f138 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -3428,8 +3428,8 @@ int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher) */ void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group, u8 wrapped_data_format, - struct wpabuf *pubkey, bool compressed, - struct wpabuf *comeback, int after) + const struct wpabuf *pubkey, bool compressed, + const struct wpabuf *comeback, int after) { struct pasn_parameter_ie *params; diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index e51e19483e79..a1ff895659cb 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -662,8 +662,8 @@ int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group, u8 wrapped_data_format, - struct wpabuf *pubkey, bool compressed, - struct wpabuf *comeback, int after); + const struct wpabuf *pubkey, bool compressed, + const struct wpabuf *comeback, int after); int wpa_pasn_add_wrapped_data(struct wpabuf *buf, struct wpabuf *wrapped_data_buf); diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c index 72f93c19255a..a4b1083bb4c1 100644 --- a/src/crypto/crypto_openssl.c +++ b/src/crypto/crypto_openssl.c @@ -81,12 +81,14 @@ static void EVP_MD_CTX_free(EVP_MD_CTX *ctx) } +#ifdef CONFIG_ECC static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey) { if (pkey->type != EVP_PKEY_EC) return NULL; return pkey->pkey.ec; } +#endif /* CONFIG_ECC */ #endif /* OpenSSL version < 1.1.0 */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 5b2c71ca0fd0..8ef9ea23a986 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -4553,6 +4553,12 @@ struct wpa_driver_ops { * explicitly allow reception of broadcast Public Action frames. */ int (*dpp_listen)(void *priv, bool enable); + +#ifdef CONFIG_TESTING_OPTIONS + int (*register_frame)(void *priv, u16 type, + const u8 *match, size_t match_len, + bool multicast); +#endif /* CONFIG_TESTING_OPTIONS */ }; /** diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 35526fc2fe06..ed194be2a8a6 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -656,12 +656,10 @@ struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd) static struct nl_msg * -nl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex, - int flags, uint8_t cmd) +nl80211_ifindex_msg_build(struct wpa_driver_nl80211_data *drv, + struct nl_msg *msg, int ifindex, int flags, + uint8_t cmd) { - struct nl_msg *msg; - - msg = nlmsg_alloc(); if (!msg) return NULL; @@ -675,6 +673,15 @@ nl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex, } +static struct nl_msg * +nl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex, + int flags, uint8_t cmd) +{ + return nl80211_ifindex_msg_build(drv, nlmsg_alloc(), ifindex, flags, + cmd); +} + + struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags, uint8_t cmd) { @@ -4151,6 +4158,7 @@ static int wpa_driver_nl80211_set_acl(void *priv, struct nl_msg *acl; unsigned int i; int ret; + size_t acl_nla_sz, acl_nlmsg_sz, nla_sz, nlmsg_sz; if (!(drv->capa.max_acl_mac_addrs)) return -ENOTSUP; @@ -4161,7 +4169,9 @@ static int wpa_driver_nl80211_set_acl(void *priv, wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)", params->acl_policy ? "Accept" : "Deny", params->num_mac_acl); - acl = nlmsg_alloc(); + acl_nla_sz = nla_total_size(ETH_ALEN) * params->num_mac_acl; + acl_nlmsg_sz = nlmsg_total_size(acl_nla_sz); + acl = nlmsg_alloc_size(acl_nlmsg_sz); if (!acl) return -ENOMEM; for (i = 0; i < params->num_mac_acl; i++) { @@ -4171,7 +4181,19 @@ static int wpa_driver_nl80211_set_acl(void *priv, } } - if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MAC_ACL)) || + /* + * genetlink message header (Length of user header is 0) + + * u32 attr: NL80211_ATTR_IFINDEX + + * u32 attr: NL80211_ATTR_ACL_POLICY + + * nested acl attr + */ + nla_sz = GENL_HDRLEN + + nla_total_size(4) * 2 + + nla_total_size(acl_nla_sz); + nlmsg_sz = nlmsg_total_size(nla_sz); + if (!(msg = nl80211_ifindex_msg_build(drv, nlmsg_alloc_size(nlmsg_sz), + drv->ifindex, 0, + NL80211_CMD_SET_MAC_ACL)) || nla_put_u32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ? NL80211_ACL_POLICY_DENY_UNLESS_LISTED : NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED) || @@ -5789,6 +5811,7 @@ static int driver_nl80211_sta_set_airtime_weight(void *priv, const u8 *addr, { struct i802_bss *bss = priv; struct nl_msg *msg; + int ret; wpa_printf(MSG_DEBUG, "nl80211: Set STA airtime weight - ifname=%s addr=" MACSTR @@ -5799,7 +5822,13 @@ static int driver_nl80211_sta_set_airtime_weight(void *priv, const u8 *addr, nla_put_u16(msg, NL80211_ATTR_AIRTIME_WEIGHT, weight)) goto fail; - return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL); + if (ret) { + wpa_printf(MSG_DEBUG, + "nl80211: SET_STATION[AIRTIME_WEIGHT] failed: ret=%d (%s)", + ret, strerror(-ret)); + } + return ret; fail: nlmsg_free(msg); return -ENOBUFS; @@ -12028,6 +12057,23 @@ static int nl80211_dpp_listen(void *priv, bool enable) #endif /* CONFIG_DPP */ +#ifdef CONFIG_TESTING_OPTIONS +static int testing_nl80211_register_frame(void *priv, u16 type, + const u8 *match, size_t match_len, + bool multicast) +{ + struct i802_bss *bss = priv; + struct nl_sock *handle; + + if (!bss->nl_mgmt) + return -1; + handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID); + return nl80211_register_frame(bss, handle, type, match, match_len, + multicast); +} +#endif /* CONFIG_TESTING_OPTIONS */ + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -12166,4 +12212,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { #ifdef CONFIG_DPP .dpp_listen = nl80211_dpp_listen, #endif /* CONFIG_DPP */ +#ifdef CONFIG_TESTING_OPTIONS + .register_frame = testing_nl80211_register_frame, +#endif /* CONFIG_TESTING_OPTIONS */ }; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index d3d43d48a7cb..cd596e311e59 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -891,7 +891,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) if (tb[NL80211_ATTR_MAC_ACL_MAX]) capa->max_acl_mac_addrs = - nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]); + nla_get_u32(tb[NL80211_ATTR_MAC_ACL_MAX]); wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]); wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]); diff --git a/src/eap_common/eap_sim_common.c b/src/eap_common/eap_sim_common.c index 4a9324406509..ab9bd86774b3 100644 --- a/src/eap_common/eap_sim_common.c +++ b/src/eap_common/eap_sim_common.c @@ -1210,9 +1210,24 @@ void eap_sim_report_notification(void *msg_ctx, int notification, int aka) } +static const u8 * get_last_char(const u8 *val, size_t len, char c) +{ + while (len > 0) { + const u8 *pos = &val[len - 1]; + + if (*pos == (u8) c) + return pos; + len--; + } + + return NULL; +} + + int eap_sim_anonymous_username(const u8 *id, size_t id_len) { static const char *anonymous_id_prefix = "anonymous@"; + const u8 *decorated; size_t anonymous_id_len = os_strlen(anonymous_id_prefix); if (id_len > anonymous_id_len && @@ -1226,5 +1241,14 @@ int eap_sim_anonymous_username(const u8 *id, size_t id_len) if (id_len > 1 && id[0] == '@') return 1; /* '@realm' */ + /* RFC 7542 decorated username, for example: + * homerealm.example.org!anonymous@otherrealm.example.net */ + decorated = get_last_char(id, id_len, '!'); + if (decorated) { + decorated++; + return eap_sim_anonymous_username(decorated, + id + id_len - decorated); + } + return 0; } diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 9a5ba7b877c5..78e2380b15e8 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -451,6 +451,10 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START, NULL, 0, &buflen, NULL); if (buf) { + /* Set and reset eapFail to allow EAP state machine to + * proceed with new authentication. */ + eapol_sm_notify_eap_fail(sm->eapol, true); + eapol_sm_notify_eap_fail(sm->eapol, false); wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL, buf, buflen); os_free(buf); @@ -605,8 +609,8 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, #endif /* CONFIG_OWE */ if (sm->force_kdk_derivation || - (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 && - sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8))) + (sm->secure_ltf && + ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))) kdk_len = WPA_KDK_MAX_LEN; else kdk_len = 0; @@ -4372,8 +4376,8 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data, } if (sm->force_kdk_derivation || - (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 && - sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8))) + (sm->secure_ltf && + ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))) kdk_len = WPA_KDK_MAX_LEN; else kdk_len = 0; diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index fce6e77e7fb9..2669da9b3fa8 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -69,8 +69,8 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, wpa_ft_pasn_store_r1kh(sm, src_addr); if (sm->force_kdk_derivation || - (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 && - sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8))) + (sm->secure_ltf && + ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))) kdk_len = WPA_KDK_MAX_LEN; else kdk_len = 0; @@ -672,8 +672,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, wpa_ft_pasn_store_r1kh(sm, bssid); if (sm->force_kdk_derivation || - (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 && - sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8))) + (sm->secure_ltf && + ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))) kdk_len = WPA_KDK_MAX_LEN; else kdk_len = 0; diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 0db936744327..45f7e947e0fd 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -1320,13 +1320,9 @@ static int wps_set_ie(struct wps_registrar *reg) } beacon = wpabuf_alloc(400 + vendor_len); - if (beacon == NULL) - return -1; probe = wpabuf_alloc(500 + vendor_len); - if (probe == NULL) { - wpabuf_free(beacon); - return -1; - } + if (!beacon || !probe) + goto fail; auth_macs = wps_authorized_macs(reg, &count); @@ -1342,19 +1338,13 @@ static int wps_set_ie(struct wps_registrar *reg) (reg->dualband && wps_build_rf_bands(®->wps->dev, beacon, 0)) || wps_build_wfa_ext(beacon, 0, auth_macs, count, 0) || wps_build_vendor_ext(®->wps->dev, beacon) || - wps_build_application_ext(®->wps->dev, beacon)) { - wpabuf_free(beacon); - wpabuf_free(probe); - return -1; - } + wps_build_application_ext(®->wps->dev, beacon)) + goto fail; #ifdef CONFIG_P2P if (wps_build_dev_name(®->wps->dev, beacon) || - wps_build_primary_dev_type(®->wps->dev, beacon)) { - wpabuf_free(beacon); - wpabuf_free(probe); - return -1; - } + wps_build_primary_dev_type(®->wps->dev, beacon)) + goto fail; #endif /* CONFIG_P2P */ wpa_printf(MSG_DEBUG, "WPS: Build Probe Response IEs"); @@ -1373,22 +1363,20 @@ static int wps_set_ie(struct wps_registrar *reg) (reg->dualband && wps_build_rf_bands(®->wps->dev, probe, 0)) || wps_build_wfa_ext(probe, 0, auth_macs, count, 0) || wps_build_vendor_ext(®->wps->dev, probe) || - wps_build_application_ext(®->wps->dev, probe)) { - wpabuf_free(beacon); - wpabuf_free(probe); - return -1; - } + wps_build_application_ext(®->wps->dev, probe)) + goto fail; beacon = wps_ie_encapsulate(beacon); probe = wps_ie_encapsulate(probe); - if (!beacon || !probe) { - wpabuf_free(beacon); - wpabuf_free(probe); - return -1; - } + if (!beacon || !probe) + goto fail; return wps_cb_set_ie(reg, beacon, probe); +fail: + wpabuf_free(beacon); + wpabuf_free(probe); + return -1; } diff --git a/tests/hwsim/example-hostapd.config b/tests/hwsim/example-hostapd.config index 8b466e8aeca3..d01a1d2edcfe 100644 --- a/tests/hwsim/example-hostapd.config +++ b/tests/hwsim/example-hostapd.config @@ -113,3 +113,4 @@ CONFIG_DPP=y CONFIG_DPP2=y CONFIG_WEP=y CONFIG_PASN=y +CONFIG_AIRTIME_POLICY=y diff --git a/tests/hwsim/hostapd.py b/tests/hwsim/hostapd.py index d484f67bc47f..5ea68444c1b9 100644 --- a/tests/hwsim/hostapd.py +++ b/tests/hwsim/hostapd.py @@ -419,6 +419,12 @@ def dpp_qr_code(self, uri): raise Exception("Failed to parse QR Code URI") return int(res) + def dpp_nfc_uri(self, uri): + res = self.request("DPP_NFC_URI " + uri) + if "FAIL" in res: + raise Exception("Failed to parse NFC URI") + return int(res) + def dpp_bootstrap_gen(self, type="qrcode", chan=None, mac=None, info=None, curve=None, key=None): cmd = "DPP_BOOTSTRAP_GEN type=" + type @@ -466,10 +472,14 @@ def dpp_listen(self, freq, netrole=None, qr=None, role=None): def dpp_auth_init(self, peer=None, uri=None, conf=None, configurator=None, extra=None, own=None, role=None, neg_freq=None, - ssid=None, passphrase=None, expect_fail=False): + ssid=None, passphrase=None, expect_fail=False, + conn_status=False, nfc_uri=None): cmd = "DPP_AUTH_INIT" if peer is None: - peer = self.dpp_qr_code(uri) + if nfc_uri: + peer = self.dpp_nfc_uri(nfc_uri) + else: + peer = self.dpp_qr_code(uri) cmd += " peer=%d" % peer if own is not None: cmd += " own=%d" % own @@ -487,6 +497,8 @@ def dpp_auth_init(self, peer=None, uri=None, conf=None, configurator=None, cmd += " ssid=" + binascii.hexlify(ssid.encode()).decode() if passphrase: cmd += " pass=" + binascii.hexlify(passphrase.encode()).decode() + if conn_status: + cmd += " conn_status=1" res = self.request(cmd) if expect_fail: if "FAIL" not in res: diff --git a/tests/hwsim/test_ap_eap.py b/tests/hwsim/test_ap_eap.py index 9efa2b47d888..d5e1d995b81e 100644 --- a/tests/hwsim/test_ap_eap.py +++ b/tests/hwsim/test_ap_eap.py @@ -881,6 +881,7 @@ def test_ap_wpa2_eap_sim_ext_anonymous(dev, apdev): try: run_ap_wpa2_eap_sim_ext_anonymous(dev, "anonymous@example.org") run_ap_wpa2_eap_sim_ext_anonymous(dev, "@example.org") + run_ap_wpa2_eap_sim_ext_anonymous(dev, "example.org!anonymous@otherexample.org") finally: dev[0].request("SET external_sim 0") diff --git a/tests/hwsim/test_ap_ft.py b/tests/hwsim/test_ap_ft.py index c28dd26e1e68..00b1635db072 100644 --- a/tests/hwsim/test_ap_ft.py +++ b/tests/hwsim/test_ap_ft.py @@ -137,7 +137,7 @@ def run_roams(dev, apdev, hapd0, hapd1, ssid, passphrase, over_ds=False, sae_password_id=None, sae_and_psk=False, pmksa_caching=False, roam_with_reassoc=False, also_non_ft=False, only_one_way=False, wait_before_roam=0, return_after_initial=False, ieee80211w="1", - sae_transition=False): + sae_transition=False, beacon_prot=False): logger.info("Connect to first AP") copts = {} @@ -151,6 +151,8 @@ def run_roams(dev, apdev, hapd0, hapd1, ssid, passphrase, over_ds=False, copts["group_mgmt"] = group_mgmt if ocv: copts["ocv"] = ocv + if beacon_prot: + copts["beacon_prot"] = "1" if eap: if pmksa_caching: copts["ft_eap_pmksa_caching"] = "1" @@ -221,6 +223,10 @@ def run_roams(dev, apdev, hapd0, hapd1, ssid, passphrase, over_ds=False, dev.scan_for_bss(ap2['bssid'], freq="2412") for i in range(0, roams): + dev.dump_monitor() + hapd1ap.dump_monitor() + hapd2ap.dump_monitor() + # Roaming artificially fast can make data test fail because the key is # set later. time.sleep(0.01) @@ -239,11 +245,18 @@ def run_roams(dev, apdev, hapd0, hapd1, ssid, passphrase, over_ds=False, raise Exception("Did not connect to correct AP") if (i == 0 or i == roams - 1) and test_connectivity: hapd2ap.wait_sta() + dev.dump_monitor() + hapd1ap.dump_monitor() + hapd2ap.dump_monitor() if conndev: hwsim_utils.test_connectivity_iface(dev, hapd2ap, conndev) else: hwsim_utils.test_connectivity(dev, hapd2ap) + dev.dump_monitor() + hapd1ap.dump_monitor() + hapd2ap.dump_monitor() + if only_one_way: return # Roaming artificially fast can make data test fail because the key is @@ -262,6 +275,9 @@ def run_roams(dev, apdev, hapd0, hapd1, ssid, passphrase, over_ds=False, raise Exception("Did not connect to correct AP") if (i == 0 or i == roams - 1) and test_connectivity: hapd1ap.wait_sta() + dev.dump_monitor() + hapd1ap.dump_monitor() + hapd2ap.dump_monitor() if conndev: hwsim_utils.test_connectivity_iface(dev, hapd1ap, conndev) else: @@ -477,15 +493,23 @@ def test_ap_ft_pmf_required_over_ds(dev, apdev): """WPA2-PSK-FT AP with PMF required on STA (over DS)""" run_ap_ft_pmf(dev, apdev, "2", over_ds=True) -def run_ap_ft_pmf(dev, apdev, ieee80211w, over_ds=False): +def test_ap_ft_pmf_beacon_prot(dev, apdev): + """WPA2-PSK-FT AP with PMF and beacon protection""" + run_ap_ft_pmf(dev, apdev, "1", beacon_prot=True) + +def run_ap_ft_pmf(dev, apdev, ieee80211w, over_ds=False, beacon_prot=False): ssid = "test-ft" passphrase = "12345678" params = ft_params1(ssid=ssid, passphrase=passphrase) params["ieee80211w"] = "2" + if beacon_prot: + params["beacon_prot"] = "1" hapd0 = hostapd.add_ap(apdev[0], params) params = ft_params2(ssid=ssid, passphrase=passphrase) params["ieee80211w"] = "2" + if beacon_prot: + params["beacon_prot"] = "1" hapd1 = hostapd.add_ap(apdev[1], params) Wlantest.setup(hapd0) @@ -494,7 +518,7 @@ def run_ap_ft_pmf(dev, apdev, ieee80211w, over_ds=False): wt.add_passphrase(passphrase) run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, - ieee80211w=ieee80211w, over_ds=over_ds) + ieee80211w=ieee80211w, over_ds=over_ds, beacon_prot=beacon_prot) def test_ap_ft_pmf_required_mismatch(dev, apdev): """WPA2-PSK-FT AP with PMF required on STA but AP2 not enabling PMF""" diff --git a/tests/hwsim/test_ap_ht.py b/tests/hwsim/test_ap_ht.py index 99adb12a36a4..510fe0836fc5 100644 --- a/tests/hwsim/test_ap_ht.py +++ b/tests/hwsim/test_ap_ht.py @@ -1370,13 +1370,15 @@ def test_ap_ht40_scan_broken_ap(dev, apdev): hwsim_utils.test_connectivity(dev[1], hapd2) def run_op_class(dev, apdev, hw_mode, channel, country, ht_capab, sec_chan, - freq, opclass): + freq, opclass, use_op_class=False): clear_scan_cache(apdev[0]) try: params = {"ssid": "test-ht40", "hw_mode": hw_mode, "channel": channel, "ht_capab": ht_capab} + if use_op_class: + params['op_class'] = str(opclass) if country: params['country_code'] = country hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) @@ -1397,6 +1399,7 @@ def run_op_class(dev, apdev, hw_mode, channel, country, ht_capab, sec_chan, if rx_opclass != opclass: raise Exception("Unexpected operating class: %d" % rx_opclass) hapd.disable() + hapd.dump_monitor() dev[0].request("REMOVE_NETWORK all") dev[0].request("ABORT_SCAN") dev[0].wait_disconnected() @@ -1407,67 +1410,99 @@ def run_op_class(dev, apdev, hw_mode, channel, country, ht_capab, sec_chan, def test_ap_ht_op_class_81(dev, apdev): """HT20 on operationg class 81""" - run_op_class(dev, apdev, "g", "1", None, "", "0", "2412", 81) + for o in [False, True]: + run_op_class(dev, apdev, "g", "1", None, "", "0", "2412", 81, + use_op_class=o) def test_ap_ht_op_class_83(dev, apdev): """HT40 on operationg class 83""" - run_op_class(dev, apdev, "g", "1", None, "[HT40+]", "1", "2412", 83) + for o in [False, True]: + run_op_class(dev, apdev, "g", "1", None, "[HT40+]", "1", "2412", 83, + use_op_class=o) def test_ap_ht_op_class_84(dev, apdev): """HT40 on operationg class 84""" - run_op_class(dev, apdev, "g", "11", None, "[HT40-]", "-1", "2462", 84) + for o in [False, True]: + run_op_class(dev, apdev, "g", "11", None, "[HT40-]", "-1", "2462", 84, + use_op_class=o) def test_ap_ht_op_class_115(dev, apdev): """HT20 on operationg class 115""" - run_op_class(dev, apdev, "a", "36", "FI", "", "0", "5180", 115) + for o in [False, True]: + run_op_class(dev, apdev, "a", "36", "FI", "", "0", "5180", 115, + use_op_class=o) def test_ap_ht_op_class_116(dev, apdev): """HT40 on operationg class 116""" - run_op_class(dev, apdev, "a", "36", "FI", "[HT40+]", "1", "5180", 116) + for o in [False, True]: + run_op_class(dev, apdev, "a", "36", "FI", "[HT40+]", "1", "5180", 116, + use_op_class=o) def test_ap_ht_op_class_117(dev, apdev): """HT40 on operationg class 117""" - run_op_class(dev, apdev, "a", "40", "FI", "[HT40-]", "-1", "5200", 117) + for o in [False, True]: + run_op_class(dev, apdev, "a", "40", "FI", "[HT40-]", "-1", "5200", 117, + use_op_class=o) def test_ap_ht_op_class_118(dev, apdev): """HT20 on operationg class 118""" - run_op_class(dev, apdev, "a", "60", "RS", "", "0", "5300", 118) + for o in [False, True]: + run_op_class(dev, apdev, "a", "60", "PA", "", "0", "5300", 118, + use_op_class=o) def test_ap_ht_op_class_119(dev, apdev): """HT40 on operationg class 119""" - run_op_class(dev, apdev, "a", "60", "RS", "[HT40+]", "1", "5300", 119) + for o in [False, True]: + run_op_class(dev, apdev, "a", "60", "PA", "[HT40+]", "1", "5300", 119, + use_op_class=o) def test_ap_ht_op_class_120(dev, apdev): """HT40 on operationg class 120""" - run_op_class(dev, apdev, "a", "64", "RS", "[HT40-]", "-1", "5320", 120) + for o in [False, True]: + run_op_class(dev, apdev, "a", "64", "PA", "[HT40-]", "-1", "5320", 120, + use_op_class=o) def test_ap_ht_op_class_121(dev, apdev): """HT20 on operationg class 121""" - run_op_class(dev, apdev, "a", "100", "ZA", "", "0", "5500", 121) + for o in [False, True]: + run_op_class(dev, apdev, "a", "100", "ZA", "", "0", "5500", 121, + use_op_class=o) def test_ap_ht_op_class_122(dev, apdev): """HT40 on operationg class 122""" - run_op_class(dev, apdev, "a", "100", "ZA", "[HT40+]", "1", "5500", 122) + for o in [False, True]: + run_op_class(dev, apdev, "a", "100", "ZA", "[HT40+]", "1", "5500", 122, + use_op_class=o) def test_ap_ht_op_class_123(dev, apdev): """HT40 on operationg class 123""" - run_op_class(dev, apdev, "a", "104", "ZA", "[HT40-]", "-1", "5520", 123) + for o in [False, True]: + run_op_class(dev, apdev, "a", "104", "ZA", "[HT40-]", "-1", "5520", 123, + use_op_class=o) def test_ap_ht_op_class_124(dev, apdev): """HT20 on operationg class 124""" - run_op_class(dev, apdev, "a", "149", "US", "", "0", "5745", 124) + for o in [False, True]: + run_op_class(dev, apdev, "a", "149", "US", "", "0", "5745", 124, + use_op_class=o) def test_ap_ht_op_class_125(dev, apdev): """HT20 on operationg class 125""" - run_op_class(dev, apdev, "a", "169", "NL", "", "0", "5845", 125) + for o in [False, True]: + run_op_class(dev, apdev, "a", "169", "NL", "", "0", "5845", 125, + use_op_class=o) def test_ap_ht_op_class_126(dev, apdev): """HT40 on operationg class 126""" - run_op_class(dev, apdev, "a", "149", "US", "[HT40+]", "1", "5745", 126) + for o in [False, True]: + run_op_class(dev, apdev, "a", "149", "US", "[HT40+]", "1", "5745", 126, + use_op_class=o) def test_ap_ht_op_class_127(dev, apdev): """HT40 on operationg class 127""" - run_op_class(dev, apdev, "a", "153", "US", "[HT40-]", "-1", "5765", 127) + for o in [False, True]: + run_op_class(dev, apdev, "a", "153", "US", "[HT40-]", "-1", "5765", 127, + use_op_class=o) def test_ap_ht40_plus_minus1(dev, apdev): """HT40 with both plus and minus allowed (1)""" diff --git a/tests/hwsim/test_ap_params.py b/tests/hwsim/test_ap_params.py index 5da861593948..72ac8e443ff9 100644 --- a/tests/hwsim/test_ap_params.py +++ b/tests/hwsim/test_ap_params.py @@ -909,3 +909,64 @@ def test_ap_notify_mgmt_frames_disabled(dev, apdev): ev = hapd.wait_event(["AP-MGMT-FRAME-RECEIVED"], timeout=0.1) if ev is not None: raise Exception("Unexpected AP-MGMT-FRAME-RECEIVED") + +def test_ap_airtime_policy_static(dev, apdev): + """Airtime policy - static""" + ssid = "test-wpa2-psk" + passphrase = 'qwertyuiop' + params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase) + params['airtime_mode'] = "1" + params['airtime_update_interval'] = "200" + params['airtime_sta_weight'] = dev[0].own_addr() + " 512" + hapd = hostapd.add_ap(apdev[0], params) + dev[0].connect(ssid, psk=passphrase, scan_freq="2412") + dev[1].connect(ssid, psk=passphrase, scan_freq="2412") + time.sleep(1) + +def test_ap_airtime_policy_per_bss_dynamic(dev, apdev): + """Airtime policy - per-BSS dynamic""" + ssid = "test-wpa2-psk" + passphrase = 'qwertyuiop' + params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase) + params['airtime_mode'] = "2" + params['airtime_update_interval'] = "200" + params['airtime_bss_weight'] = "2" + hapd = hostapd.add_ap(apdev[0], params) + dev[0].connect(ssid, psk=passphrase, scan_freq="2412") + dev[1].connect(ssid, psk=passphrase, scan_freq="2412") + time.sleep(1) + +def test_ap_airtime_policy_per_bss_limit(dev, apdev): + """Airtime policy - per-BSS limit""" + ssid = "test-wpa2-psk" + passphrase = 'qwertyuiop' + params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase) + params['airtime_mode'] = "3" + params['airtime_update_interval'] = "200" + params['airtime_bss_weight'] = "2" + params['airtime_bss_limit'] = "1" + hapd = hostapd.add_ap(apdev[0], params) + dev[0].connect(ssid, psk=passphrase, scan_freq="2412") + dev[1].connect(ssid, psk=passphrase, scan_freq="2412") + time.sleep(1) + hapd.set("force_backlog_bytes", "1") + time.sleep(1) + +def test_ap_airtime_policy_per_bss_limit_invalid(dev, apdev): + """Airtime policy - per-BSS limit (invalid)""" + ssid = "test-wpa2-psk" + passphrase = 'qwertyuiop' + params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase) + params['airtime_mode'] = "3" + params['airtime_update_interval'] = "0" + params['airtime_bss_weight'] = "2" + params['airtime_bss_limit'] = "1" + hapd = hostapd.add_ap(apdev[0], params, no_enable=True) + if "FAIL" not in hapd.request("ENABLE"): + raise Exception("Invalid airtime policy configuration accepted") + hapd.set("airtime_update_interval", "200") + hapd.enable() + hapd.set("airtime_update_interval", "0") + dev[0].connect(ssid, psk=passphrase, scan_freq="2412") + dev[1].connect(ssid, psk=passphrase, scan_freq="2412") + time.sleep(1) diff --git a/tests/hwsim/test_ap_psk.py b/tests/hwsim/test_ap_psk.py index be6a88b2a164..b6048be13844 100644 --- a/tests/hwsim/test_ap_psk.py +++ b/tests/hwsim/test_ap_psk.py @@ -500,6 +500,22 @@ def test_ap_wpa2_gtk_rekey_request(dev, apdev): raise Exception("GTK rekey timed out") hwsim_utils.test_connectivity(dev[0], hapd) +def test_ap_wpa2_gtk_rekey_failure(dev, apdev): + """WPA2-PSK AP and GTK rekey failure""" + ssid = "test-wpa2-psk" + passphrase = 'qwertyuiop' + params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase) + hapd = hostapd.add_ap(apdev[0], params) + dev[0].connect(ssid, psk=passphrase, scan_freq="2412") + with fail_test(hapd, 1, "wpa_group_config_group_keys"): + if "OK" not in hapd.request("REKEY_GTK"): + raise Exception("REKEY_GTK failed") + wait_fail_trigger(hapd, "GET_FAIL") + ev = dev[0].wait_event(["WPA: Group rekeying completed"], timeout=2) + if ev is None: + raise Exception("GTK rekey timed out") + dev[0].wait_disconnected() + @remote_compatible def test_ap_wpa_gtk_rekey(dev, apdev): """WPA-PSK/TKIP AP and GTK rekey enforced by AP""" diff --git a/tests/hwsim/test_ap_track.py b/tests/hwsim/test_ap_track.py index 9d9e2cd460ee..ba8f3eb252cd 100644 --- a/tests/hwsim/test_ap_track.py +++ b/tests/hwsim/test_ap_track.py @@ -403,3 +403,35 @@ def _test_ap_track_taxonomy(dev, apdev): raise Exception("Unexpected SIGNATURE prefix") if "|assoc:" not in res: raise Exception("Missing assoc info in SIGNATURE") + +def test_ap_track_taxonomy_5g(dev, apdev): + """AP tracking STA taxonomy (5 GHz)""" + try: + _test_ap_track_taxonomy_5g(dev, apdev) + finally: + subprocess.call(['iw', 'reg', 'set', '00']) + dev[0].flush_scan_cache() + +def _test_ap_track_taxonomy_5g(dev, apdev): + params = {"ssid": "track", + "country_code": "US", + "hw_mode": "a", + "channel": "40", + "track_sta_max_num": "2"} + hapd = hostapd.add_ap(apdev[0], params) + bssid = apdev[0]['bssid'] + + dev[0].scan_for_bss(bssid, freq=5200, force_scan=True) + addr0 = dev[0].own_addr() + dev[0].connect("track", key_mgmt="NONE", scan_freq="5200") + + res = hapd.request("SIGNATURE " + addr0) + logger.info("sta0: " + res) + if not res.startswith("wifi4|probe:"): + raise Exception("Unexpected SIGNATURE prefix") + if "|assoc:" not in res: + raise Exception("Missing assoc info in SIGNATURE") + if ",htcap:" not in res: + raise Exception("Missing HT info in SIGNATURE") + if ",vhtcap:" not in res: + raise Exception("Missing VHT info in SIGNATURE") diff --git a/tests/hwsim/test_ap_wps.py b/tests/hwsim/test_ap_wps.py index 08be5f41f230..a07ed60b8218 100644 --- a/tests/hwsim/test_ap_wps.py +++ b/tests/hwsim/test_ap_wps.py @@ -44,10 +44,12 @@ from utils import * from test_ap_eap import int_eap_server_params -def wps_start_ap(apdev, ssid="test-wps-conf"): +def wps_start_ap(apdev, ssid="test-wps-conf", extra_cred=None): params = {"ssid": ssid, "eap_server": "1", "wps_state": "2", "wpa_passphrase": "12345678", "wpa": "2", "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"} + if extra_cred: + params['extra_cred'] = extra_cred return hostapd.add_ap(apdev, params) @remote_compatible @@ -1067,6 +1069,43 @@ def test_ap_wps_pbc_overlap_2sta(dev, apdev): dev[0].flush_scan_cache() dev[1].flush_scan_cache() +def test_ap_wps_pbc_session_workaround(dev, apdev): + """WPS PBC session overlap workaround""" + ssid = "test-wps-pbc-overlap" + hapd = hostapd.add_ap(apdev[0], + {"ssid": ssid, "eap_server": "1", "wps_state": "2", + "wpa_passphrase": "12345678", "wpa": "2", + "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP"}) + bssid = hapd.own_addr() + hapd.request("WPS_PBC") + dev[0].scan_for_bss(bssid, freq="2412") + dev[0].request("WPS_PBC " + bssid) + dev[0].wait_connected(timeout=30) + + dev[0].request("REMOVE_NETWORK all") + dev[0].wait_disconnected(timeout=30) + dev[0].dump_monitor() + # Trigger AP/Registrar to ignore PBC activation immediately after + # successfully completed provisioning + dev[0].request("WPS_PBC " + bssid) + ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10) + if ev is None: + raise Exception("No scan results reported") + dev[0].request("WPS_CANCEL") + dev[0].dump_monitor() + + # Verify that PBC session overlap does not prevent connection + hapd.request("WPS_PBC") + dev[1].scan_for_bss(bssid, freq="2412") + dev[1].request("WPS_PBC " + bssid) + dev[1].wait_connected() + dev[1].request("REMOVE_NETWORK all") + dev[1].wait_disconnected() + + hapd.request("DISABLE") + dev[0].flush_scan_cache() + dev[1].flush_scan_cache() + @remote_compatible def test_ap_wps_cancel(dev, apdev): """WPS AP cancelling enabled config method""" @@ -4358,10 +4397,12 @@ def wps_er_stop(dev, sock, server, on_alloc_fail=False): raise Exception("No WPS-ER-AP-REMOVE event on max-age timeout") dev.request("WPS_ER_STOP") -def run_wps_er_proto_test(dev, handler, no_event_url=False, location_url=None): +def run_wps_er_proto_test(dev, handler, no_event_url=False, location_url=None, + max_age=1): try: uuid = '27ea801a-9e5c-4e73-bd82-f89cbcd10d7e' - server, sock = wps_er_start(dev, handler, location_url=location_url) + server, sock = wps_er_start(dev, handler, location_url=location_url, + max_age=max_age) global wps_event_url wps_event_url = None server.handle_request() @@ -5105,6 +5146,15 @@ def handle_upnp_info(self): run_wps_er_proto_test(dev[0], WPSAPHTTPServer_req_as_resp, no_event_url=True) +def test_ap_wps_er_http_client_timeout(dev, apdev): + """WPS ER and HTTP client timeout""" + class WPSAPHTTPServer_timeout(WPSAPHTTPServer): + def handle_upnp_info(self): + time.sleep(31) + self.wfile.write(b"GET / HTTP/1.1\r\n\r\n") + run_wps_er_proto_test(dev[0], WPSAPHTTPServer_timeout, + no_event_url=True, max_age=60) + def test_ap_wps_init_oom(dev, apdev): """wps_init OOM cases""" ssid = "test-wps" @@ -10464,3 +10514,55 @@ def run_ap_wps_ap_timeout(dev, apdev, cmd): logger.info("BSS after timeout: " + str(bss)) if bss['ie'].endswith("0106ffffffffffff"): raise Exception("Authorized MAC not removed") + +def test_ap_wps_er_unsubscribe_errors(dev, apdev): + """WPS ER and UNSUBSCRIBE errors""" + start_wps_ap(apdev[0]) + tests = [(1, "http_client_url_parse;wps_er_ap_unsubscribe"), + (1, "wpabuf_alloc;wps_er_ap_unsubscribe"), + (1, "http_client_addr;wps_er_ap_unsubscribe")] + try: + for count, func in tests: + start_wps_er(dev[0]) + with alloc_fail(dev[0], count, func): + dev[0].request("WPS_ER_STOP") + dev[0].request("REMOVE_NETWORK all") + dev[0].wait_disconnected() + dev[0].dump_monitor() + finally: + dev[0].request("WPS_ER_STOP") + +def start_wps_ap(apdev): + ssid = "wps-er-ap-config" + ap_pin = "12345670" + ap_uuid = "27ea801a-9e5c-4e73-bd82-f89cbcd10d7e" + params = {"ssid": ssid, "eap_server": "1", "wps_state": "2", + "wpa_passphrase": "12345678", "wpa": "2", + "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP", + "device_name": "Wireless AP", "manufacturer": "Company", + "model_name": "WAP", "model_number": "123", + "serial_number": "12345", "device_type": "6-0050F204-1", + "os_version": "01020300", + "config_methods": "label push_button", + "ap_pin": ap_pin, "uuid": ap_uuid, "upnp_iface": "lo"} + hostapd.add_ap(apdev, params) + +def start_wps_er(dev): + ssid = "wps-er-ap-config" + dev.connect(ssid, psk="12345678", scan_freq="2412") + dev.request("WPS_ER_START ifname=lo") + ev = dev.wait_event(["WPS-ER-AP-ADD"], timeout=15) + if ev is None: + raise Exception("AP discovery timed out") + +def test_ap_wps_registrar_init_errors(dev, apdev): + """WPS Registrar init errors""" + hapd = wps_start_ap(apdev[0], extra_cred="wps-mixed-cred") + hapd.disable() + tests = [(1, "wps_registrar_init"), + (1, "wpabuf_alloc_copy;wps_registrar_init"), + (1, "wps_set_ie;wps_registrar_init")] + for count, func in tests: + with alloc_fail(hapd, count, func): + if "FAIL" not in hapd.request("ENABLE"): + raise Exception("ENABLE succeeded unexpectedly") diff --git a/tests/hwsim/test_dpp.py b/tests/hwsim/test_dpp.py index 3ba99bb1b0c7..b696c5d1dc2e 100644 --- a/tests/hwsim/test_dpp.py +++ b/tests/hwsim/test_dpp.py @@ -2581,6 +2581,14 @@ def test_dpp_pkex_hostapd_errors(dev, apdev): def test_dpp_hostapd_configurator(dev, apdev): """DPP with hostapd as configurator/initiator""" + run_dpp_hostapd_configurator(dev, apdev) + +def test_dpp_hostapd_configurator_enrollee_v1(dev, apdev): + """DPP with hostapd as configurator/initiator with v1 enrollee""" + dev[0].set("dpp_version_override", "1") + run_dpp_hostapd_configurator(dev, apdev) + +def run_dpp_hostapd_configurator(dev, apdev): check_dpp_capab(dev[0]) hapd = hostapd.add_ap(apdev[0], {"ssid": "unconfigured", "channel": "1"}) @@ -2640,6 +2648,340 @@ def test_dpp_hostapd_configurator_fragmentation(dev, apdev): wait_auth_success(dev[0], hapd, configurator=hapd, enrollee=dev[0], stop_responder=True) +def test_dpp_hostapd_enrollee_fragmentation(dev, apdev): + """DPP and hostapd as Enrollee with GAS fragmentation""" + check_dpp_capab(dev[0]) + hapd = hostapd.add_ap(apdev[0], {"ssid": "unconfigured", + "channel": "6"}) + check_dpp_capab(hapd) + conf_id = dev[0].dpp_configurator_add() + id0 = dev[0].dpp_bootstrap_gen(chan="81/6", mac=True) + uri0 = dev[0].request("DPP_BOOTSTRAP_GET_URI %d" % id0) + conf = '{"wi-fi_tech":"infra", "discovery":{"ssid":"test"},"cred":{"akm":"psk","pass":"secret passphrase"}}' + 3000*' ' + dev[0].set("dpp_config_obj_override", conf) + dev[0].set("dpp_configurator_params", + " conf=ap-dpp configurator=%d" % conf_id) + dev[0].dpp_listen(2437, role="configurator") + hapd.dpp_auth_init(uri=uri0, role="enrollee") + wait_auth_success(dev[0], hapd, configurator=dev[0], enrollee=hapd, + stop_responder=True) + +def test_dpp_hostapd_enrollee_gas_timeout(dev, apdev): + """DPP and hostapd as Enrollee with GAS timeout""" + check_dpp_capab(dev[0]) + hapd = hostapd.add_ap(apdev[0], {"ssid": "unconfigured", + "channel": "6"}) + check_dpp_capab(hapd) + conf_id = dev[0].dpp_configurator_add() + id0 = dev[0].dpp_bootstrap_gen(chan="81/6", mac=True) + uri0 = dev[0].request("DPP_BOOTSTRAP_GET_URI %d" % id0) + conf = '{"wi-fi_tech":"infra", "discovery":{"ssid":"test"},"cred":{"akm":"psk","pass":"secret passphrase"}}' + 3000*' ' + dev[0].set("dpp_config_obj_override", conf) + dev[0].set("dpp_configurator_params", + "conf=ap-dpp configurator=%d" % conf_id) + dev[0].set("ext_mgmt_frame_handling", "1") + dev[0].dpp_listen(2437, role="configurator") + hapd.dpp_auth_init(uri=uri0, role="enrollee") + process_dpp_frames(dev[0]) + ev = hapd.wait_event(["GAS-QUERY-DONE"], timeout=10) + if "result=TIMEOUT" not in ev: + raise Exception("GAS timeout not reported") + +def test_dpp_hostapd_enrollee_gas_timeout_comeback(dev, apdev): + """DPP and hostapd as Enrollee with GAS timeout during comeback""" + check_dpp_capab(dev[0]) + hapd = hostapd.add_ap(apdev[0], {"ssid": "unconfigured", + "channel": "6"}) + check_dpp_capab(hapd) + conf_id = dev[0].dpp_configurator_add() + id0 = dev[0].dpp_bootstrap_gen(chan="81/6", mac=True) + uri0 = dev[0].request("DPP_BOOTSTRAP_GET_URI %d" % id0) + conf = '{"wi-fi_tech":"infra", "discovery":{"ssid":"test"},"cred":{"akm":"psk","pass":"secret passphrase"}}' + 3000*' ' + dev[0].set("dpp_config_obj_override", conf) + dev[0].set("dpp_configurator_params", + "conf=ap-dpp configurator=%d" % conf_id) + dev[0].set("ext_mgmt_frame_handling", "1") + dev[0].dpp_listen(2437, role="configurator") + hapd.dpp_auth_init(uri=uri0, role="enrollee") + process_dpp_frames(dev[0], count=4) + ev = hapd.wait_event(["GAS-QUERY-DONE"], timeout=10) + if "result=TIMEOUT" not in ev: + raise Exception("GAS timeout not reported") + +def process_dpp_frames(dev, count=3): + for i in range(count): + msg = dev.mgmt_rx() + cmd = "MGMT_RX_PROCESS freq={} datarate={} ssi_signal={} frame={}".format(msg['freq'], msg['datarate'], msg['ssi_signal'], binascii.hexlify(msg['frame']).decode()) + if "OK" not in dev.request(cmd): + raise Exception("MGMT_RX_PROCESS failed") + +def test_dpp_hostapd_enrollee_gas_errors(dev, apdev): + """DPP and hostapd as Enrollee with GAS query local errors""" + check_dpp_capab(dev[0]) + hapd = hostapd.add_ap(apdev[0], {"ssid": "unconfigured", + "channel": "6"}) + check_dpp_capab(hapd) + conf_id = dev[0].dpp_configurator_add() + id0 = dev[0].dpp_bootstrap_gen(chan="81/6", mac=True) + uri0 = dev[0].request("DPP_BOOTSTRAP_GET_URI %d" % id0) + dev[0].set("dpp_configurator_params", + "conf=ap-dpp configurator=%d" % conf_id) + dev[0].set("ext_mgmt_frame_handling", "1") + + # GAS without comeback + tests = [(1, "gas_query_append;gas_query_rx_initial", 3, True), + (1, "gas_query_rx_initial", 3, True), + (1, "gas_query_tx_initial_req", 2, True), + (1, "gas_query_ap_req", 2, False)] + for count, func, frame_count, wait_ev in tests: + dev[0].request("DPP_STOP_LISTEN") + dev[0].dpp_listen(2437, role="configurator") + dev[0].dump_monitor() + hapd.dump_monitor() + with alloc_fail(hapd, count, func): + hapd.dpp_auth_init(uri=uri0, role="enrollee") + process_dpp_frames(dev[0], count=frame_count) + if wait_ev: + ev = hapd.wait_event(["GAS-QUERY-DONE"], timeout=10) + if not ev or "result=INTERNAL_ERROR" not in ev: + raise Exception("Unexpect GAS query result: " + str(ev)) + + # GAS with comeback + conf = '{"wi-fi_tech":"infra", "discovery":{"ssid":"test"},"cred":{"akm":"psk","pass":"secret passphrase"}}' + 3000*' ' + dev[0].set("dpp_config_obj_override", conf) + + tests = [(1, "gas_query_append;gas_query_rx_comeback", 4), + (1, "wpabuf_alloc;gas_query_tx_comeback_req", 3), + (1, "hostapd_drv_send_action;gas_query_tx_comeback_req", 3)] + for count, func, frame_count in tests: + dev[0].request("DPP_STOP_LISTEN") + dev[0].dpp_listen(2437, role="configurator") + dev[0].dump_monitor() + hapd.dump_monitor() + with alloc_fail(hapd, count, func): + hapd.dpp_auth_init(uri=uri0, role="enrollee") + process_dpp_frames(dev[0], count=frame_count) + ev = hapd.wait_event(["GAS-QUERY-DONE"], timeout=10) + if not ev or "result=INTERNAL_ERROR" not in ev: + raise Exception("Unexpect GAS query result: " + str(ev)) + +def test_dpp_hostapd_enrollee_gas_proto(dev, apdev): + """DPP and hostapd as Enrollee with GAS query protocol testing""" + check_dpp_capab(dev[0]) + hapd = hostapd.add_ap(apdev[0], {"ssid": "unconfigured", + "channel": "6"}) + check_dpp_capab(hapd) + bssid = hapd.own_addr() + conf_id = dev[0].dpp_configurator_add() + id0 = dev[0].dpp_bootstrap_gen(chan="81/6", mac=True) + uri0 = dev[0].request("DPP_BOOTSTRAP_GET_URI %d" % id0) + dev[0].set("dpp_configurator_params", + "conf=ap-dpp configurator=%d" % conf_id) + conf = '{"wi-fi_tech":"infra", "discovery":{"ssid":"test"},"cred":{"akm":"psk","pass":"secret passphrase"}}' + 3000*' ' + dev[0].set("dpp_config_obj_override", conf) + dev[0].set("ext_mgmt_frame_handling", "1") + dev[0].dpp_listen(2437, role="configurator") + hapd.dpp_auth_init(uri=uri0, role="enrollee") + process_dpp_frames(dev[0], count=3) + msg = dev[0].mgmt_rx() + payload = msg['payload'] + dialog_token, = struct.unpack('B', payload[2:3]) + hdr = struct.pack(' +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import struct +import time + +import hostapd +from utils import * + +def register_mcsc_req(hapd): + type = 0x00d0 + match = "1304" + if "OK" not in hapd.request("REGISTER_FRAME %04x %s" % (type, match)): + raise Exception("Could not register frame reception for Robust AV Streaming") + +def handle_mscs_req(hapd, wrong_dialog=False, status_code=0): + msg = hapd.mgmt_rx() + if msg['subtype'] != 13: + logger.info("RX:" + str(msg)) + raise Exception("Received unexpected Management frame") + categ, act, dialog_token = struct.unpack('BBB', msg['payload'][0:3]) + if categ != 19 or act != 4: + logger.info("RX:" + str(msg)) + raise Exception("Received unexpected Action frame") + + if wrong_dialog: + dialog_token = (dialog_token + 1) % 256 + msg['da'] = msg['sa'] + msg['sa'] = hapd.own_addr() + msg['payload'] = struct.pack(' 0: + res = dev[0].global_request("P2P_PEER NEXT-" + addr) + addr = res.splitlines()[0] + if addr == "FAIL": + break + peers.append(addr) + limit -= 1 + logger.info("Peers: " + str(peers)) + + if len(peers) != 100: + raise Exception("Unexpected number of peer entries") + oldest = "02:02:02:02:02:00" + if oldest in peers: + raise Exception("Oldest entry is still present") + for i in range(101): + addr = "02:02:02:02:02:%02x" % i + if addr == oldest: + continue + if addr not in peers: + raise Exception("Peer missing from table: " + addr) + + # Provision Discovery Request from the oldest peer (SA) using internally + # different P2P Device Address as a regression test for incorrect processing + # for this corner case. + dst = dev[0].own_addr().replace(':', '') + src = peers[99].replace(':', '') + devaddr = "0202020202ff" + pdreq = "d0004000" + dst + src + dst + "d0000409506f9a090701dd29506f9a0902020025000d1d00" + devaddr + "1108000000000000000000101100084465766963652041dd0a0050f204100800020008" + if "OK" not in dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=60 ssi_signal=-30 frame=" + pdreq): + raise Exception("MGMT_RX_PROCESS failed") diff --git a/tests/hwsim/test_pasn.py b/tests/hwsim/test_pasn.py index f2c7b3b221b6..c8bcd63f6ac7 100644 --- a/tests/hwsim/test_pasn.py +++ b/tests/hwsim/test_pasn.py @@ -13,6 +13,7 @@ import socket import struct import subprocess +import re import hwsim_utils import hostapd @@ -231,18 +232,23 @@ def test_pasn_sae_pmksa_cache(dev, apdev): params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678") params['wpa_key_mgmt'] = 'SAE PASN' + params['sae_pwe'] = "2" hapd = start_pasn_ap(apdev[0], params) - dev[0].set("sae_groups", "19") - dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412") + try: + dev[0].set("sae_groups", "19") + dev[0].set("sae_pwe", "2") + dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412") - hapd.wait_sta() - hwsim_utils.test_connectivity(dev[0], hapd) + hapd.wait_sta() + hwsim_utils.test_connectivity(dev[0], hapd) - dev[0].request("DISCONNECT") - dev[0].wait_disconnected() + dev[0].request("DISCONNECT") + dev[0].wait_disconnected() - check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP") + check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP") + finally: + dev[0].set("sae_pwe", "0") def check_pasn_fils_pmksa_cache(dev, apdev, params, key_mgmt): check_fils_capa(dev[0]) @@ -298,16 +304,19 @@ def test_pasn_sae_kdk(dev, apdev): params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678") params['wpa_key_mgmt'] = 'SAE PASN' + params['sae_pwe'] = "2" params['force_kdk_derivation'] = "1" hapd = start_pasn_ap(apdev[0], params) dev[0].set("force_kdk_derivation", "1") + dev[0].set("sae_pwe", "2") dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412") check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=False) finally: dev[0].set("force_kdk_derivation", "0") + dev[0].set("sae_pwe", "0") def check_pasn_fils_kdk(dev, apdev, params, key_mgmt): @@ -383,23 +392,28 @@ def test_pasn_sae(dev, apdev): params = hostapd.wpa2_params(ssid="test-pasn-sae", passphrase="12345678") params['wpa_key_mgmt'] = 'SAE PASN' + params['sae_pwe'] = "2" hapd = start_pasn_ap(apdev[0], params) - dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412", - only_add_network=True) + try: + dev[0].set("sae_pwe", "2") + dev[0].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE", + scan_freq="2412", only_add_network=True) - # first test with a valid PSK - check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="0") + # first test with a valid PSK + check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="0") - # And now with PMKSA caching - check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP") + # And now with PMKSA caching + check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP") - # And now with a wrong passphrase - if "FAIL" in dev[0].request("PMKSA_FLUSH"): - raise Exception("PMKSA_FLUSH failed") + # And now with a wrong passphrase + if "FAIL" in dev[0].request("PMKSA_FLUSH"): + raise Exception("PMKSA_FLUSH failed") - dev[0].set_network_quoted(0, "psk", "12345678787") - check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", status=1, nid="0") + dev[0].set_network_quoted(0, "psk", "12345678787") + check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", status=1, nid="0") + finally: + dev[0].set("sae_pwe", "0") @remote_compatible def test_pasn_sae_while_connected_same_channel(dev, apdev): @@ -411,18 +425,23 @@ def test_pasn_sae_while_connected_same_channel(dev, apdev): passphrase="12345678") hapd = hostapd.add_ap(apdev[0], params) - dev[0].connect("test-pasn-wpa2-psk", psk="12345678", scan_freq="2412") + try: + dev[0].set("sae_pwe", "2") + dev[0].connect("test-pasn-wpa2-psk", psk="12345678", scan_freq="2412") - params = hostapd.wpa2_params(ssid="test-pasn-sae", - passphrase="12345678") + params = hostapd.wpa2_params(ssid="test-pasn-sae", + passphrase="12345678") - params['wpa_key_mgmt'] = 'SAE PASN' - hapd = start_pasn_ap(apdev[1], params) + params['wpa_key_mgmt'] = 'SAE PASN' + params['sae_pwe'] = "2" + hapd = start_pasn_ap(apdev[1], params) - dev[0].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE", - scan_freq="2412", only_add_network=True) + dev[0].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE", + scan_freq="2412", only_add_network=True) - check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="1") + check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="1") + finally: + dev[0].set("sae_pwe", "0") @remote_compatible def test_pasn_sae_while_connected_diff_channel(dev, apdev): @@ -442,18 +461,23 @@ def test_pasn_sae_while_connected_diff_channel(dev, apdev): params['channel'] = "6" hapd = hostapd.add_ap(apdev[0], params) - wpas.connect("test-pasn-wpa2-psk", psk="12345678", scan_freq="2437") + try: + wpas.set("sae_pwe", "2") + wpas.connect("test-pasn-wpa2-psk", psk="12345678", scan_freq="2437") - params = hostapd.wpa2_params(ssid="test-pasn-sae", - passphrase="12345678") + params = hostapd.wpa2_params(ssid="test-pasn-sae", + passphrase="12345678") - params['wpa_key_mgmt'] = 'SAE PASN' - hapd = start_pasn_ap(apdev[1], params) + params['wpa_key_mgmt'] = 'SAE PASN' + params['sae_pwe'] = "2" + hapd = start_pasn_ap(apdev[1], params) - wpas.connect("test-pasn-sae", psk="12345678", key_mgmt="SAE", - scan_freq="2412", only_add_network=True) + wpas.connect("test-pasn-sae", psk="12345678", key_mgmt="SAE", + scan_freq="2412", only_add_network=True) - check_pasn_akmp_cipher(wpas, hapd, "SAE", "CCMP", nid="1") + check_pasn_akmp_cipher(wpas, hapd, "SAE", "CCMP", nid="1") + finally: + wpas.set("sae_pwe", "0") def pasn_fils_setup(wpas, apdev, params, key_mgmt): check_fils_capa(wpas) @@ -681,3 +705,146 @@ def test_pasn_ap_mic_error(dev, apdev): check_pasn_akmp_cipher(dev[0], hapd1, "PASN", "CCMP", status=1) check_pasn_akmp_cipher(dev[0], hapd0, "PASN", "CCMP") + +@remote_compatible +def test_pasn_comeback(dev, apdev, params): + """PASN authentication with comeback flow""" + check_pasn_capab(dev[0]) + + params = pasn_ap_params("PASN", "CCMP", "19") + params['sae_anti_clogging_threshold'] = '0' + hapd = hostapd.add_ap(apdev[0], params) + bssid = hapd.own_addr() + + dev[0].scan(type="ONLY", freq=2412) + cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19" % bssid + + resp = dev[0].request(cmd) + if "OK" not in resp: + raise Exception("Failed to start PASN authentication") + + ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3) + if not ev: + raise Exception("PASN: PASN-AUTH-STATUS not seen") + + if bssid + " akmp=PASN, status=30 comeback_after=" not in ev: + raise Exception("PASN: unexpected status") + + comeback = re.split("comeback=", ev)[1] + + cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19 comeback=%s" % \ + (bssid, comeback) + + resp = dev[0].request(cmd) + if "OK" not in resp: + raise Exception("Failed to start PASN authentication") + + ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3) + if not ev: + raise Exception("PASN: PASN-AUTH-STATUS not seen") + + if bssid + " akmp=PASN, status=0" not in ev: + raise Exception("PASN: unexpected status with comeback token") + + check_pasn_ptk(dev[0], hapd, "CCMP") + +@remote_compatible +def test_pasn_comeback_after_0(dev, apdev, params): + """PASN authentication with comeback flow with comeback after set to 0""" + check_pasn_capab(dev[0]) + + params = pasn_ap_params("PASN", "CCMP", "19") + params['anti_clogging_threshold'] = '0' + params['pasn_comeback_after'] = '0' + hapd = start_pasn_ap(apdev[0], params) + + check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP") + +@remote_compatible +def test_pasn_comeback_after_0_sae(dev, apdev): + """PASN authentication with SAE, with comeback flow where comeback after is set to 0""" + check_pasn_capab(dev[0]) + check_sae_capab(dev[0]) + + params = hostapd.wpa2_params(ssid="test-pasn-sae", + passphrase="12345678") + params['wpa_key_mgmt'] = 'SAE PASN' + params['anti_clogging_threshold'] = '0' + params['pasn_comeback_after'] = '0' + params['sae_pwe'] = "2" + hapd = start_pasn_ap(apdev[0], params) + + try: + dev[0].set("sae_pwe", "2") + dev[0].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE", + scan_freq="2412", only_add_network=True) + + # first test with a valid PSK + check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="0") + + # And now with PMKSA caching + check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP") + + # And now with a wrong passphrase + if "FAIL" in dev[0].request("PMKSA_FLUSH"): + raise Exception("PMKSA_FLUSH failed") + + dev[0].set_network_quoted(0, "psk", "12345678787") + check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", status=1, nid="0") + finally: + dev[0].set("sae_pwe", "0") + +@remote_compatible +def test_pasn_comeback_multi(dev, apdev): + """PASN authentication with SAE, with multiple stations with comeback""" + check_pasn_capab(dev[0]) + check_sae_capab(dev[0]) + + params = hostapd.wpa2_params(ssid="test-pasn-sae", + passphrase="12345678") + params['wpa_key_mgmt'] = 'SAE PASN' + params['anti_clogging_threshold'] = '1' + params['pasn_comeback_after'] = '0' + hapd = start_pasn_ap(apdev[0], params) + bssid = hapd.own_addr() + + id = {} + for i in range(0, 2): + dev[i].flush_scan_cache() + dev[i].scan(type="ONLY", freq=2412) + id[i] = dev[i].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE", + scan_freq="2412", only_add_network=True) + + for i in range(0, 2): + cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19, nid=%s" % (bssid, id[i]) + resp = dev[i].request(cmd) + + if "OK" not in resp: + raise Exception("Failed to start pasn authentication") + + for i in range(0, 2): + ev = dev[i].wait_event(["PASN-AUTH-STATUS"], 3) + if not ev: + raise Exception("PASN: PASN-AUTH-STATUS not seen") + + if bssid + " akmp=PASN, status=0" not in ev: + raise Exception("PASN: unexpected status") + + check_pasn_ptk(dev[i], hapd, "CCMP") + +def test_pasn_kdk_derivation(dev, apdev): + """PASN authentication with forced KDK derivation""" + check_pasn_capab(dev[0]) + + params = pasn_ap_params("PASN", "CCMP", "19") + hapd0 = start_pasn_ap(apdev[0], params) + + params['force_kdk_derivation'] = "1" + hapd1 = start_pasn_ap(apdev[1], params) + + try: + check_pasn_akmp_cipher(dev[0], hapd0, "PASN", "CCMP") + dev[0].set("force_kdk_derivation", "1") + check_pasn_akmp_cipher(dev[0], hapd1, "PASN", "CCMP") + finally: + dev[0].set("force_kdk_derivation", "0") diff --git a/tests/hwsim/test_pmksa_cache.py b/tests/hwsim/test_pmksa_cache.py index 526f7f455685..10d76a394f8d 100644 --- a/tests/hwsim/test_pmksa_cache.py +++ b/tests/hwsim/test_pmksa_cache.py @@ -1251,3 +1251,17 @@ def test_rsn_preauth_local_errors(dev, apdev): raise Exception("ENABLE failed") sock.send(_bssid + foreign + proto + struct.pack('>BBH', 2, 1, 0)) sock.send(_bssid + foreign2 + proto + struct.pack('>BBH', 2, 1, 0)) + +def test_pmksa_cache_add_failure(dev, apdev): + """PMKSA cache add failure""" + params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache") + hostapd.add_ap(apdev[0], params) + bssid = apdev[0]['bssid'] + with alloc_fail(dev[0], 1, "pmksa_cache_add"): + dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP", + eap="GPSK", identity="gpsk user", + password="abcdefghijklmnop0123456789abcdef", + scan_freq="2412") + pmksa = dev[0].get_pmksa(bssid) + if pmksa is None: + raise Exception("No PMKSA cache entry created") diff --git a/tests/hwsim/test_rrm.py b/tests/hwsim/test_rrm.py index 84318f6cb64f..9111a357eaca 100644 --- a/tests/hwsim/test_rrm.py +++ b/tests/hwsim/test_rrm.py @@ -212,6 +212,20 @@ def test_rrm_neighbor_db(dev, apdev): if apdev[0]['bssid'] not in res: raise Exception("Own BSS not visible in SHOW_NEIGHBOR output") +def test_rrm_neighbor_db_failures(dev, apdev): + """hostapd ctrl_iface SET_NEIGHBOR failures""" + params = {"ssid": "test", "rrm_neighbor_report": "1"} + hapd = hostapd.add_ap(apdev[0]['ifname'], params) + cmd = "SET_NEIGHBOR 00:11:22:33:44:55 ssid=\"test1\" nr=" + nr + " lci=" + lci + " civic=" + civic + tests = [(1, "hostapd_neighbor_add"), + (1, "wpabuf_dup;hostapd_neighbor_set"), + (2, "wpabuf_dup;hostapd_neighbor_set"), + (3, "wpabuf_dup;hostapd_neighbor_set")] + for count, func in tests: + with alloc_fail(hapd, count, func): + if "FAIL" not in hapd.request(cmd): + raise Exception("Set neighbor succeeded") + def test_rrm_neighbor_db_disabled(dev, apdev): """hostapd ctrl_iface SHOW_NEIGHBOR while neighbor report disabled""" params = {"ssid": "test"} diff --git a/tests/hwsim/test_wnm.py b/tests/hwsim/test_wnm.py index 10b07559b9ce..354822327210 100644 --- a/tests/hwsim/test_wnm.py +++ b/tests/hwsim/test_wnm.py @@ -37,7 +37,8 @@ def start_wnm_ap(apdev, bss_transition=True, time_adv=False, ssid=None, wnm_sleep_mode=False, wnm_sleep_mode_no_keys=False, rsn=False, ocv=False, ap_max_inactivity=0, coloc_intf_reporting=False, hw_mode=None, channel=None, country_code=None, country3=None, - pmf=True, passphrase=None, ht=True, vht=False, mbo=False): + pmf=True, passphrase=None, ht=True, vht=False, mbo=False, + beacon_prot=False): if rsn: if not ssid: ssid = "test-wnm-rsn" @@ -47,6 +48,8 @@ def start_wnm_ap(apdev, bss_transition=True, time_adv=False, ssid=None, if pmf: params["wpa_key_mgmt"] = "WPA-PSK-SHA256" params["ieee80211w"] = "2" + if beacon_prot: + params["beacon_prot"] = "1" else: params = {"ssid": "test-wnm"} if bss_transition: @@ -195,7 +198,8 @@ def test_wnm_ess_disassoc_imminent_pmf(dev, apdev): if ev is None: raise Exception("Timeout while waiting for re-connection scan") -def check_wnm_sleep_mode_enter_exit(hapd, dev, interval=None, tfs_req=None): +def check_wnm_sleep_mode_enter_exit(hapd, dev, interval=None, tfs_req=None, + rekey=False): addr = dev.p2p_interface_addr() sta = hapd.get_sta(addr) if "[WNM_SLEEP_MODE]" in sta['flags']: @@ -219,6 +223,14 @@ def check_wnm_sleep_mode_enter_exit(hapd, dev, interval=None, tfs_req=None): if not ok: raise Exception("Station failed to enter WNM-Sleep Mode") + if rekey: + time.sleep(0.1) + if "OK" not in hapd.request("REKEY_GTK"): + raise Exception("REKEY_GTK failed") + ev = dev.wait_event(["WPA: Group rekeying completed"], timeout=0.1) + if ev is not None: + raise Exception("Unexpected report of GTK rekey during WNM-Sleep Mode") + logger.info("Waking up from WNM Sleep Mode") ok = False dev.request("WNM_SLEEP exit") @@ -231,6 +243,14 @@ def check_wnm_sleep_mode_enter_exit(hapd, dev, interval=None, tfs_req=None): if not ok: raise Exception("Station failed to exit WNM-Sleep Mode") + if rekey: + time.sleep(0.1) + if "OK" not in hapd.request("REKEY_GTK"): + raise Exception("REKEY_GTK failed") + ev = dev.wait_event(["WPA: Group rekeying completed"], timeout=2) + if ev is None: + raise Exception("GTK rekey timed out") + @remote_compatible def test_wnm_sleep_mode_open(dev, apdev): """WNM Sleep Mode - open""" @@ -303,6 +323,19 @@ def test_wnm_sleep_mode_rsn_pmf(dev, apdev): raise Exception("No connection event received from hostapd") check_wnm_sleep_mode_enter_exit(hapd, dev[0]) +def test_wnm_sleep_mode_rsn_beacon_prot(dev, apdev): + """WNM Sleep Mode - RSN with PMF and beacon protection""" + hapd = start_wnm_ap(apdev[0], rsn=True, wnm_sleep_mode=True, time_adv=True, + beacon_prot=True) + dev[0].connect("test-wnm-rsn", psk="12345678", ieee80211w="2", + beacon_prot="1", + key_mgmt="WPA-PSK-SHA256", proto="WPA2", scan_freq="2412") + ev = hapd.wait_event(["AP-STA-CONNECTED"], timeout=5) + if ev is None: + raise Exception("No connection event received from hostapd") + check_wnm_sleep_mode_enter_exit(hapd, dev[0]) + check_wnm_sleep_mode_enter_exit(hapd, dev[0], rekey=True) + @remote_compatible def test_wnm_sleep_mode_rsn_ocv(dev, apdev): """WNM Sleep Mode - RSN with OCV""" diff --git a/tests/hwsim/test_wpas_ctrl.py b/tests/hwsim/test_wpas_ctrl.py index a99e2f49af83..210c11907ee7 100644 --- a/tests/hwsim/test_wpas_ctrl.py +++ b/tests/hwsim/test_wpas_ctrl.py @@ -1402,6 +1402,8 @@ def test_wpas_ctrl_driver_event(dev, apdev): """wpa_supplicant ctrl_iface DRIVER_EVENT""" if "FAIL" not in dev[0].request("DRIVER_EVENT foo"): raise Exception("Invalid DRIVER_EVENT accepted") + if "OK" not in dev[0].request("DRIVER_EVENT ASSOC reassoc=1 req_ies=0000 resp_ies=0000 resp_frame=0000 beacon_ies=0000 freq=2412 wmm::info_bitmap=0 wmm::uapsd_queues=0 addr=02:02:02:02:02:02 authorized=0 key_replay_ctr=00 ptk_kck=00 ptk_kek=00 subnet_status=0 fils_erp_next_seq_num=0 fils_pmk=00 fils_pmkid=" + 16*"00"): + raise Exception("DRIVER_EVENT ASSOC did not succeed") @remote_compatible def test_wpas_ctrl_eapol_rx(dev, apdev): @@ -2147,3 +2149,11 @@ def test_wpas_ctrl_get_pref_freq_list_override(dev): dev[0].set("get_pref_freq_list_override", "") res = dev[0].request("GET_PREF_FREQ_LIST STATION").strip() logger.info("STATION (without override): " + res) + +def test_wpas_ctrl_interface_add_driver_init_failure(dev, apdev): + """wpa_supplicant INTERFACE_ADD and driver init failing""" + for i in range(1000): + res = dev[0].global_request("INTERFACE_ADD FOO") + if "FAIL" not in res: + raise Exception("Unexpected result: " + res) + dev[0].dump_monitor() diff --git a/tests/hwsim/vm/inside.sh b/tests/hwsim/vm/inside.sh index 6ccad4bec487..9d4a933fe729 100755 --- a/tests/hwsim/vm/inside.sh +++ b/tests/hwsim/vm/inside.sh @@ -15,11 +15,16 @@ mount sysfs -t sysfs /sys # needed for tracing mount debugfs -t debugfs /sys/kernel/debug +mkdir /tmp/wireshark-share +mount --bind /usr/share/wireshark /tmp/wireshark-share +mount tmpfs -t tmpfs /usr/share/wireshark + # for inside telnet mkdir /dev/pts mount devpts -t devpts /dev/pts export PATH=/usr/sbin:$PATH +export HOME=/tmp # reboot on any sort of crash sysctl kernel.panic_on_oops=1 diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index b54d7d4968d8..bf83e41686a0 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -512,6 +512,19 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) { eapol_sm_configure(wpa_s->eapol, -1, -1, -1, atoi(value)); +#ifdef CONFIG_TESTING_OPTIONS + } else if (os_strcasecmp(cmd, "EAPOL::portControl") == 0) { + if (os_strcmp(value, "Auto") == 0) + eapol_sm_notify_portControl(wpa_s->eapol, Auto); + else if (os_strcmp(value, "ForceUnauthorized") == 0) + eapol_sm_notify_portControl(wpa_s->eapol, + ForceUnauthorized); + else if (os_strcmp(value, "ForceAuthorized") == 0) + eapol_sm_notify_portControl(wpa_s->eapol, + ForceAuthorized); + else + ret = -1; +#endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) { if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, atoi(value))) { @@ -2999,19 +3012,17 @@ static int wpa_supplicant_ctrl_iface_scan_result( ie2, 2 + ie2[1]); } rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX); - if (rsnxe && rsnxe[1] >= 1) { - if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)) { - ret = os_snprintf(pos, end - pos, "[SAE-H2E]"); - if (os_snprintf_error(end - pos, ret)) - return -1; - pos += ret; - } - if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_PK)) { - ret = os_snprintf(pos, end - pos, "[SAE-PK]"); - if (os_snprintf_error(end - pos, ret)) - return -1; - pos += ret; - } + if (ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SAE_H2E)) { + ret = os_snprintf(pos, end - pos, "[SAE-H2E]"); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + if (ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SAE_PK)) { + ret = os_snprintf(pos, end - pos, "[SAE-PK]"); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; } osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); if (osen_ie) @@ -5099,19 +5110,17 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, mesh ? "RSN" : "WPA2", ie2, 2 + ie2[1]); rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX); - if (rsnxe && rsnxe[1] >= 1) { - if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)) { - ret = os_snprintf(pos, end - pos, "[SAE-H2E]"); - if (os_snprintf_error(end - pos, ret)) - return -1; - pos += ret; - } - if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_PK)) { - ret = os_snprintf(pos, end - pos, "[SAE-PK]"); - if (os_snprintf_error(end - pos, ret)) - return -1; - pos += ret; - } + if (ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SAE_H2E)) { + ret = os_snprintf(pos, end - pos, "[SAE-H2E]"); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + if (ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SAE_PK)) { + ret = os_snprintf(pos, end - pos, "[SAE-PK]"); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; } osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); if (osen_ie) @@ -9300,6 +9309,132 @@ static int wpas_ctrl_iface_driver_scan_res(struct wpa_supplicant *wpa_s, } +static int wpas_ctrl_iface_driver_event_assoc(struct wpa_supplicant *wpa_s, + char *param) +{ + union wpa_event_data event; + struct assoc_info *ai; + char *ctx = NULL; + int ret = -1; + struct wpabuf *req_ies = NULL; + struct wpabuf *resp_ies = NULL; + struct wpabuf *resp_frame = NULL; + struct wpabuf *beacon_ies = NULL; + struct wpabuf *key_replay_ctr = NULL; + struct wpabuf *ptk_kck = NULL; + struct wpabuf *ptk_kek = NULL; + struct wpabuf *fils_pmk = NULL; + char *str, *pos; + u8 addr[ETH_ALEN]; + u8 fils_pmkid[PMKID_LEN]; + + os_memset(&event, 0, sizeof(event)); + ai = &event.assoc_info; + + while ((str = str_token(param, " ", &ctx))) { + pos = os_strchr(str, '='); + if (!pos) + goto fail; + *pos++ = '\0'; + + if (os_strcmp(str, "reassoc") == 0) { + ai->reassoc = atoi(pos); + } else if (os_strcmp(str, "req_ies") == 0) { + wpabuf_free(req_ies); + req_ies = wpabuf_parse_bin(pos); + if (!req_ies) + goto fail; + ai->req_ies = wpabuf_head(req_ies); + ai->req_ies_len = wpabuf_len(req_ies); + } else if (os_strcmp(str, "resp_ies") == 0) { + wpabuf_free(resp_ies); + resp_ies = wpabuf_parse_bin(pos); + if (!resp_ies) + goto fail; + ai->resp_ies = wpabuf_head(resp_ies); + ai->resp_ies_len = wpabuf_len(resp_ies); + } else if (os_strcmp(str, "resp_frame") == 0) { + wpabuf_free(resp_frame); + resp_frame = wpabuf_parse_bin(pos); + if (!resp_frame) + goto fail; + ai->resp_frame = wpabuf_head(resp_frame); + ai->resp_frame_len = wpabuf_len(resp_frame); + } else if (os_strcmp(str, "beacon_ies") == 0) { + wpabuf_free(beacon_ies); + beacon_ies = wpabuf_parse_bin(pos); + if (!beacon_ies) + goto fail; + ai->beacon_ies = wpabuf_head(beacon_ies); + ai->beacon_ies_len = wpabuf_len(beacon_ies); + } else if (os_strcmp(str, "freq") == 0) { + ai->freq = atoi(pos); + } else if (os_strcmp(str, "wmm::info_bitmap") == 0) { + ai->wmm_params.info_bitmap = atoi(pos); + } else if (os_strcmp(str, "wmm::uapsd_queues") == 0) { + ai->wmm_params.uapsd_queues = atoi(pos); + } else if (os_strcmp(str, "addr") == 0) { + if (hwaddr_aton(pos, addr)) + goto fail; + ai->addr = addr; + } else if (os_strcmp(str, "authorized") == 0) { + ai->authorized = atoi(pos); + } else if (os_strcmp(str, "key_replay_ctr") == 0) { + wpabuf_free(key_replay_ctr); + key_replay_ctr = wpabuf_parse_bin(pos); + if (!key_replay_ctr) + goto fail; + ai->key_replay_ctr = wpabuf_head(key_replay_ctr); + ai->key_replay_ctr_len = wpabuf_len(key_replay_ctr); + } else if (os_strcmp(str, "ptk_kck") == 0) { + wpabuf_free(ptk_kck); + ptk_kck = wpabuf_parse_bin(pos); + if (!ptk_kck) + goto fail; + ai->ptk_kck = wpabuf_head(ptk_kck); + ai->ptk_kck_len = wpabuf_len(ptk_kck); + } else if (os_strcmp(str, "ptk_kek") == 0) { + wpabuf_free(ptk_kek); + ptk_kek = wpabuf_parse_bin(pos); + if (!ptk_kek) + goto fail; + ai->ptk_kek = wpabuf_head(ptk_kek); + ai->ptk_kek_len = wpabuf_len(ptk_kek); + } else if (os_strcmp(str, "subnet_status") == 0) { + ai->subnet_status = atoi(pos); + } else if (os_strcmp(str, "fils_erp_next_seq_num") == 0) { + ai->fils_erp_next_seq_num = atoi(pos); + } else if (os_strcmp(str, "fils_pmk") == 0) { + wpabuf_free(fils_pmk); + fils_pmk = wpabuf_parse_bin(pos); + if (!fils_pmk) + goto fail; + ai->fils_pmk = wpabuf_head(fils_pmk); + ai->fils_pmk_len = wpabuf_len(fils_pmk); + } else if (os_strcmp(str, "fils_pmkid") == 0) { + if (hexstr2bin(pos, fils_pmkid, PMKID_LEN) < 0) + goto fail; + ai->fils_pmkid = fils_pmkid; + } else { + goto fail; + } + } + + wpa_supplicant_event(wpa_s, EVENT_ASSOC, &event); + ret = 0; +fail: + wpabuf_free(req_ies); + wpabuf_free(resp_ies); + wpabuf_free(resp_frame); + wpabuf_free(beacon_ies); + wpabuf_free(key_replay_ctr); + wpabuf_free(ptk_kck); + wpabuf_free(ptk_kek); + wpabuf_free(fils_pmk); + return ret; +} + + static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd) { char *pos, *param; @@ -9332,6 +9467,8 @@ static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd) return 0; } else if (os_strcmp(cmd, "SCAN_RES") == 0) { return wpas_ctrl_iface_driver_scan_res(wpa_s, param); + } else if (os_strcmp(cmd, "ASSOC") == 0) { + return wpas_ctrl_iface_driver_event_assoc(wpa_s, param); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s", cmd); @@ -10598,15 +10735,18 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd) u8 bssid[ETH_ALEN]; int akmp = -1, cipher = -1, got_bssid = 0; u16 group = 0xFFFF; - int id = 0; + u8 *comeback = NULL; + size_t comeback_len = 0; + int id = 0, ret = -1; /* * Entry format: bssid= akmp= cipher= group= + * [comeback=] */ while ((token = str_token(cmd, " ", &context))) { if (os_strncmp(token, "bssid=", 6) == 0) { if (hwaddr_aton(token + 6, bssid)) - return -1; + goto out; got_bssid = 1; } else if (os_strcmp(token, "akmp=PASN") == 0) { akmp = WPA_KEY_MGMT_PASN; @@ -10640,20 +10780,34 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd) group = atoi(token + 6); } else if (os_strncmp(token, "nid=", 4) == 0) { id = atoi(token + 4); + } else if (os_strncmp(token, "comeback=", 9) == 0) { + comeback_len = os_strlen(token + 9); + if (comeback || !comeback_len || comeback_len % 2) + goto out; + + comeback_len /= 2; + comeback = os_malloc(comeback_len); + if (!comeback || + hexstr2bin(token + 9, comeback, comeback_len)) + goto out; } else { wpa_printf(MSG_DEBUG, "CTRL: PASN Invalid parameter: '%s'", token); - return -1; + goto out; } } if (!got_bssid || akmp == -1 || cipher == -1 || group == 0xFFFF) { wpa_printf(MSG_DEBUG,"CTRL: PASN missing parameter"); - return -1; + goto out; } - return wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id); + ret = wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id, + comeback, comeback_len); +out: + os_free(comeback); + return ret; } diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h index 510668d49353..dfbd25a03b1b 100644 --- a/wpa_supplicant/ctrl_iface.h +++ b/wpa_supplicant/ctrl_iface.h @@ -70,14 +70,17 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s); /** * wpa_supplicant_ctrl_iface_deinit - Deinitialize control interface + * @wpa_s: Pointer to wpa_supplicant data * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init() * * Deinitialize the control interface that was initialized with - * wpa_supplicant_ctrl_iface_init(). + * wpa_supplicant_ctrl_iface_init() and any data related to the wpa_s instance. + * @priv may be %NULL if the control interface has not yet been initialized. * * Required to be implemented in each control interface backend. */ -void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv); +void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s, + struct ctrl_iface_priv *priv); /** * wpa_supplicant_ctrl_iface_wait - Wait for ctrl_iface monitor @@ -128,7 +131,8 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) } static inline void -wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) +wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s, + struct ctrl_iface_priv *priv) { } diff --git a/wpa_supplicant/ctrl_iface_named_pipe.c b/wpa_supplicant/ctrl_iface_named_pipe.c index 79ff7871db8d..bddc0414245e 100644 --- a/wpa_supplicant/ctrl_iface_named_pipe.c +++ b/wpa_supplicant/ctrl_iface_named_pipe.c @@ -462,8 +462,11 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) } -void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) +void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s, + struct ctrl_iface_priv *priv) { + if (!priv) + return; while (priv->ctrl_dst) ctrl_close_pipe(priv->ctrl_dst); if (priv->sec_attr_set) diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c index 1512080d6b3b..1cbf7fa28d3f 100644 --- a/wpa_supplicant/ctrl_iface_udp.c +++ b/wpa_supplicant/ctrl_iface_udp.c @@ -490,8 +490,12 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) } -void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) +void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s, + struct ctrl_iface_priv *priv) { + if (!priv) + return; + if (priv->sock > -1) { eloop_unregister_read_sock(priv->sock); if (priv->ctrl_dst) { diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c index 953fd2ccfe50..639573dae75e 100644 --- a/wpa_supplicant/ctrl_iface_unix.c +++ b/wpa_supplicant/ctrl_iface_unix.c @@ -800,12 +800,52 @@ static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s, } -void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) +static void +wpas_global_ctrl_iface_flush_queued_msg(struct wpa_global *global, + struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_global_priv *gpriv; + struct ctrl_iface_msg *msg, *prev_msg; + unsigned int count = 0; + + if (!global || !global->ctrl_iface) + return; + + gpriv = global->ctrl_iface; + dl_list_for_each_safe(msg, prev_msg, &gpriv->msg_queue, + struct ctrl_iface_msg, list) { + if (msg->wpa_s == wpa_s) { + count++; + dl_list_del(&msg->list); + os_free(msg); + } + } + + if (count) { + wpa_printf(MSG_DEBUG, + "CTRL: Dropped %u pending message(s) for interface that is being removed", + count); + } +} + + +void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s, + struct ctrl_iface_priv *priv) { struct wpa_ctrl_dst *dst, *prev; struct ctrl_iface_msg *msg, *prev_msg; struct ctrl_iface_global_priv *gpriv; + if (!priv) { + /* Control interface has not yet been initialized, so there is + * nothing to deinitialize here. However, there might be a + * pending message for this interface, so get rid of any such + * entry before completing interface removal. */ + wpas_global_ctrl_iface_flush_queued_msg(wpa_s->global, wpa_s); + eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, wpa_s, NULL); + return; + } + if (priv->sock > -1) { char *fname; char *buf, *dir = NULL; @@ -877,6 +917,7 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) } } } + wpas_global_ctrl_iface_flush_queued_msg(wpa_s->global, wpa_s); eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, priv->wpa_s, NULL); os_free(priv); } diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c index d137ad6ac5ab..e256ac50eec4 100644 --- a/wpa_supplicant/eapol_test.c +++ b/wpa_supplicant/eapol_test.c @@ -674,10 +674,8 @@ static void test_eapol_clean(struct eapol_test_data *e, os_free(e->radius_conf); e->radius_conf = NULL; scard_deinit(wpa_s->scard); - if (wpa_s->ctrl_iface) { - wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); - wpa_s->ctrl_iface = NULL; - } + wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface); + wpa_s->ctrl_iface = NULL; ext_password_deinit(wpa_s->ext_pw); wpa_s->ext_pw = NULL; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 5e73ab406d02..b3c07f926b69 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1102,14 +1102,11 @@ static bool sae_pk_acceptable_bss_with_pk(struct wpa_supplicant *wpa_s, dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { int count; const u8 *ie; - u8 rsnxe_capa = 0; if (bss == orig_bss) continue; ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX); - if (ie && ie[1] >= 1) - rsnxe_capa = ie[2]; - if (!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK))) + if (!(ieee802_11_rsnx_capab(ie, WLAN_RSNX_CAPAB_SAE_PK))) continue; /* TODO: Could be more thorough in checking what kind of @@ -4405,6 +4402,8 @@ static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s, wpa_supplicant_event_port_authorized(wpa_s); + wpa_s->last_eapol_matches_bssid = 1; + wpa_sm_set_rx_replay_ctr(wpa_s->wpa, data->assoc_info.key_replay_ctr); wpa_sm_set_ptk_kck_kek(wpa_s->wpa, data->assoc_info.ptk_kck, data->assoc_info.ptk_kck_len, diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c index 834c7a1ccc88..65daa77c2c98 100644 --- a/wpa_supplicant/mesh_rsn.c +++ b/wpa_supplicant/mesh_rsn.c @@ -344,7 +344,6 @@ static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s, } return sae_prepare_commit(wpa_s->own_addr, sta->addr, (u8 *) password, os_strlen(password), - ssid->sae_password_id, sta->sae); } diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c index e6adf73f3e42..baf4c2643e42 100644 --- a/wpa_supplicant/pasn_supplicant.c +++ b/wpa_supplicant/pasn_supplicant.c @@ -33,9 +33,18 @@ struct wpa_pasn_auth_work { int cipher; u16 group; int network_id; + struct wpabuf *comeback; }; +static void wpas_pasn_free_auth_work(struct wpa_pasn_auth_work *awork) +{ + wpabuf_free(awork->comeback); + awork->comeback = NULL; + os_free(awork); +} + + static void wpas_pasn_auth_work_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; @@ -56,8 +65,30 @@ static void wpas_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s) static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid, - int akmp, int cipher, u8 status) + int akmp, int cipher, u8 status, + struct wpabuf *comeback, + u16 comeback_after) { + if (comeback) { + size_t comeback_len = wpabuf_len(comeback); + size_t buflen = comeback_len * 2 + 1; + char *comeback_txt = os_malloc(buflen); + + if (comeback_txt) { + wpa_snprintf_hex(comeback_txt, buflen, + wpabuf_head(comeback), comeback_len); + + wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR + " akmp=%s, status=%u comeback_after=%u comeback=%s", + MAC2STR(bssid), + wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN), + status, comeback_after, comeback_txt); + + os_free(comeback_txt); + return; + } + } + wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u", MAC2STR(bssid), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN), @@ -71,30 +102,17 @@ static struct wpabuf * wpas_pasn_wd_sae_commit(struct wpa_supplicant *wpa_s) { struct wpas_pasn *pasn = &wpa_s->pasn; struct wpabuf *buf = NULL; - const char *password = NULL; int ret; - if (pasn->ssid) { - password = pasn->ssid->sae_password; - if (!password) - password = pasn->ssid->passphrase; - } - - if (!password) { - wpa_printf(MSG_DEBUG, "PASN: SAE without a password"); - return NULL; - } - ret = sae_set_group(&pasn->sae, pasn->group); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group"); return NULL; } - /* TODO: SAE H2E */ - ret = sae_prepare_commit(wpa_s->own_addr, pasn->bssid, - (const u8 *) password, os_strlen(password), 0, - &pasn->sae); + ret = sae_prepare_commit_pt(&pasn->sae, pasn->ssid->pt, + wpa_s->own_addr, pasn->bssid, + NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit"); return NULL; @@ -109,7 +127,7 @@ static struct wpabuf * wpas_pasn_wd_sae_commit(struct wpa_supplicant *wpa_s) wpabuf_put_le16(buf, WLAN_AUTH_SAE); wpabuf_put_le16(buf, 1); - wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); + wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT); sae_write_commit(&pasn->sae, buf, NULL, 0); pasn->sae.state = SAE_COMMITTED; @@ -155,14 +173,14 @@ static int wpas_pasn_wd_sae_rx(struct wpa_supplicant *wpa_s, struct wpabuf *wd) wpa_printf(MSG_DEBUG, "PASN: SAE: commit: alg=%u, seq=%u, status=%u", alg, seq, status); - /* TODO: SAE H2E */ - if (alg != WLAN_AUTH_SAE || seq != 1 || status != WLAN_STATUS_SUCCESS) { + if (alg != WLAN_AUTH_SAE || seq != 1 || + status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) { wpa_printf(MSG_DEBUG, "PASN: SAE: dropping peer commit"); return -1; } res = sae_parse_commit(&pasn->sae, data + 6, len - 6, NULL, 0, groups, - 0); + 1); if (res != WLAN_STATUS_SUCCESS) { wpa_printf(MSG_DEBUG, "PASN: SAE failed parsing commit"); return -1; @@ -240,6 +258,31 @@ static struct wpabuf * wpas_pasn_wd_sae_confirm(struct wpa_supplicant *wpa_s) return buf; } + +static int wpas_pasn_sae_setup_pt(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, int group) +{ + const char *password = ssid->sae_password; + int groups[2] = { group, 0 }; + + if (!password) + password = ssid->passphrase; + + if (!password) { + wpa_printf(MSG_DEBUG, "PASN: SAE without a password"); + return -1; + } + + if (ssid->pt) + return 0; /* PT already derived */ + + ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len, + (const u8 *) password, os_strlen(password), + ssid->sae_password_id); + + return ssid->pt ? 0 : -1; +} + #endif /* CONFIG_SAE */ @@ -612,7 +655,8 @@ static u8 wpas_pasn_get_wrapped_data_format(struct wpas_pasn *pasn) } -static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s) +static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s, + const struct wpabuf *comeback) { struct wpas_pasn *pasn = &wpa_s->pasn; struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL; @@ -680,14 +724,14 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s) wrapped_data = WPA_PASN_WRAPPED_DATA_NO; wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data, - pubkey, true, NULL, -1); + pubkey, true, comeback, -1); if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0) goto fail; /* Add own RNSXE */ - /* TODO: How to handle protected TWT and SAE H2E? */ capab = 0; + capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF); if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT) @@ -828,6 +872,10 @@ static void wpas_pasn_reset(struct wpa_supplicant *wpa_s) wpabuf_free(pasn->beacon_rsne_rsnxe); pasn->beacon_rsne_rsnxe = NULL; + wpabuf_free(pasn->comeback); + pasn->comeback = NULL; + pasn->comeback_after = 0; + #ifdef CONFIG_SAE sae_clear_data(&pasn->sae); #endif /* CONFIG_SAE */ @@ -946,7 +994,7 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid, int akmp, int cipher, u16 group, int freq, const u8 *beacon_rsne, u8 beacon_rsne_len, const u8 *beacon_rsnxe, u8 beacon_rsnxe_len, - int network_id) + int network_id, struct wpabuf *comeback) { struct wpas_pasn *pasn = &wpa_s->pasn; struct wpa_ssid *ssid = NULL; @@ -972,6 +1020,20 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid, "PASN: No network profile found for SAE"); return -1; } + + if (!ieee802_11_rsnx_capab(beacon_rsnxe, + WLAN_RSNX_CAPAB_SAE_H2E)) { + wpa_printf(MSG_DEBUG, + "PASN: AP does not support SAE H2E"); + return -1; + } + + if (wpas_pasn_sae_setup_pt(wpa_s, ssid, group) < 0) { + wpa_printf(MSG_DEBUG, + "PASN: Failed to derive PT"); + return -1; + } + pasn->sae.state = SAE_NOTHING; pasn->sae.send_confirm = 0; pasn->ssid = ssid; @@ -1016,6 +1078,15 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid, pasn->cipher = cipher; pasn->group = group; pasn->freq = freq; + + if (wpa_s->conf->force_kdk_derivation || + (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF && + ieee802_11_rsnx_capab(beacon_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))) + pasn->kdk_len = WPA_KDK_MAX_LEN; + else + pasn->kdk_len = 0; + wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len); + os_memcpy(pasn->bssid, bssid, ETH_ALEN); wpa_printf(MSG_DEBUG, @@ -1023,7 +1094,7 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid, MAC2STR(pasn->bssid), pasn->akmp, pasn->cipher, pasn->group); - frame = wpas_pasn_build_auth_1(wpa_s); + frame = wpas_pasn_build_auth_1(wpa_s, comeback); if (!frame) { wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame"); goto fail; @@ -1105,7 +1176,8 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit) wpa_s, NULL); wpa_s->pasn_auth_work = NULL; } - os_free(awork); + + wpas_pasn_free_auth_work(awork); return; } @@ -1132,24 +1204,29 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit) ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher, awork->group, bss->freq, rsne, *(rsne + 1) + 2, rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0, - awork->network_id); + awork->network_id, awork->comeback); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed to start PASN authentication"); goto fail; } + /* comeback token is no longer needed at this stage */ + wpabuf_free(awork->comeback); + awork->comeback = NULL; + wpa_s->pasn_auth_work = work; return; fail: - os_free(awork); + wpas_pasn_free_auth_work(awork); work->ctx = NULL; radio_work_done(work); } int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid, - int akmp, int cipher, u16 group, int network_id) + int akmp, int cipher, u16 group, int network_id, + const u8 *comeback, size_t comeback_len) { struct wpa_pasn_auth_work *awork; struct wpa_bss *bss; @@ -1195,9 +1272,17 @@ int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid, awork->group = group; awork->network_id = network_id; + if (comeback && comeback_len) { + awork->comeback = wpabuf_alloc_copy(comeback, comeback_len); + if (!awork->comeback) { + wpas_pasn_free_auth_work(awork); + return -1; + } + } + if (radio_add_work(wpa_s, bss->freq, "pasn-start-auth", 1, wpas_pasn_auth_start_cb, awork) < 0) { - os_free(awork); + wpas_pasn_free_auth_work(awork); return -1; } @@ -1216,12 +1301,33 @@ void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "PASN: Stopping authentication"); wpas_pasn_auth_status(wpa_s, pasn->bssid, pasn->akmp, pasn->cipher, - pasn->status); + pasn->status, pasn->comeback, + pasn->comeback_after); wpas_pasn_reset(wpa_s); } +static int wpas_pasn_immediate_retry(struct wpa_supplicant *wpa_s, + struct wpas_pasn *pasn, + struct wpa_pasn_params_data *params) +{ + int akmp = pasn->akmp; + int cipher = pasn->cipher; + u16 group = pasn->group; + u8 bssid[ETH_ALEN]; + int network_id = pasn->ssid ? pasn->ssid->id : 0; + + wpa_printf(MSG_DEBUG, "PASN: Immediate retry"); + os_memcpy(bssid, pasn->bssid, ETH_ALEN); + wpas_pasn_reset(wpa_s); + + return wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, + network_id, + params->comeback, params->comeback_len); +} + + int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s, const struct ieee80211_mgmt *mgmt, size_t len) { @@ -1315,10 +1421,26 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s, goto fail; } - /* TODO: handle comeback flow */ if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) { wpa_printf(MSG_DEBUG, "PASN: Authentication temporarily rejected"); + + if (pasn_params.comeback && pasn_params.comeback_len) { + wpa_printf(MSG_DEBUG, + "PASN: Comeback token available. After=%u", + pasn_params.after); + + if (!pasn_params.after) + return wpas_pasn_immediate_retry(wpa_s, pasn, + &pasn_params); + + pasn->comeback = wpabuf_alloc_copy( + pasn_params.comeback, pasn_params.comeback_len); + if (pasn->comeback) + pasn->comeback_after = pasn_params.after; + } + + pasn->status = status; goto fail; } @@ -1393,7 +1515,7 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s, wpa_s->own_addr, pasn->bssid, wpabuf_head(secret), wpabuf_len(secret), &pasn->ptk, pasn->akmp, pasn->cipher, - WPA_KDK_MAX_LEN); + pasn->kdk_len); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK"); goto fail; @@ -1456,7 +1578,11 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s, * the frame and terminate the authentication exchange. However, better * reply to the AP with an error status. */ - pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE; + if (status == WLAN_STATUS_SUCCESS) + pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE; + else + pasn->status = status; + wpas_pasn_auth_stop(wpa_s); return -1; } diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c index de49948f71e4..97c16fb80d27 100644 --- a/wpa_supplicant/preauth_test.c +++ b/wpa_supplicant/preauth_test.c @@ -193,10 +193,8 @@ static void test_eapol_clean(struct wpa_supplicant *wpa_s) pmksa_candidate_free(wpa_s->wpa); wpa_sm_deinit(wpa_s->wpa); scard_deinit(wpa_s->scard); - if (wpa_s->ctrl_iface) { - wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); - wpa_s->ctrl_iface = NULL; - } + wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface); + wpa_s->ctrl_iface = NULL; wpa_config_free(wpa_s->conf); } diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c index f6da56eeda9b..39d282f0870d 100644 --- a/wpa_supplicant/robust_av.c +++ b/wpa_supplicant/robust_av.c @@ -118,7 +118,7 @@ void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s, return; } - status_code = *buf; + status_code = WPA_GET_LE16(buf); wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR " status_code=%u", MAC2STR(src), status_code); wpa_s->mscs_setup_done = status_code == WLAN_STATUS_SUCCESS; diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index dde80863a988..72aa9b5b8f18 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -186,7 +186,6 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, 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; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 90e8a466aba2..835b33575760 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1158,8 +1158,8 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s) os_strcmp(conf->ctrl_interface, wpa_s->conf->ctrl_interface) != 0); - if (reconf_ctrl && wpa_s->ctrl_iface) { - wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); + if (reconf_ctrl) { + wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface); wpa_s->ctrl_iface = NULL; } @@ -6748,10 +6748,8 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s, if (terminate) wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING); - if (wpa_s->ctrl_iface) { - wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); - wpa_s->ctrl_iface = NULL; - } + wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface); + wpa_s->ctrl_iface = NULL; #ifdef CONFIG_MESH if (wpa_s->ifmsh) { diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 7ed8c0ee4d92..49007cfc2e8f 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -539,6 +539,7 @@ struct wpas_pasn { int cipher; u16 group; int freq; + size_t kdk_len; u8 trans_seq; u8 status; @@ -554,6 +555,9 @@ struct wpas_pasn { struct wpa_ptk ptk; struct crypto_ecdh *ecdh; + struct wpabuf *comeback; + u16 comeback_after; + #ifdef CONFIG_SAE struct sae_data sae; #endif /* CONFIG_SAE */ @@ -1730,7 +1734,8 @@ void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid, int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid, int akmp, int cipher, - u16 group, int network_id); + u16 group, int network_id, + const u8 *comeback, size_t comeback_len); void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s); int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s, const u8 *data, size_t data_len, u8 acked);