diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 5b39a61e1..0fe631026 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -616,6 +616,7 @@ #define WLAN_RSNX_CAPAB_SECURE_RTT 9 #define WLAN_RSNX_CAPAB_URNM_MFPR_X20 10 #define WLAN_RSNX_CAPAB_URNM_MFPR 15 +#define WLAN_RSNX_CAPAB_SSID_PROTECTION 21 /* Multiple BSSID element subelements */ #define WLAN_MBSSID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE 0 diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index 6ea3311ce..94ce43dde 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -3743,6 +3743,11 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) ie->supp_oper_classes = pos + 2; ie->supp_oper_classes_len = pos[1]; } + } else if (*pos == WLAN_EID_SSID) { + ie->ssid = pos + 2; + ie->ssid_len = pos[1]; + wpa_hexdump_ascii(MSG_DEBUG, "RSN: SSID in EAPOL-Key", + ie->ssid, ie->ssid_len); } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { ret = wpa_parse_generic(pos, ie); if (ret == 1) { diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 8f52984a4..1e3136843 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -698,6 +698,8 @@ struct wpa_eapol_ie_parse { size_t supp_channels_len; const u8 *supp_oper_classes; size_t supp_oper_classes_len; + const u8 *ssid; + size_t ssid_len; u8 qosinfo; u16 aid; const u8 *wmm; diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 8956c4072..21dfeb5fb 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -2542,6 +2542,28 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) goto failed; + if (sm->ssid_protection) { + if (!ie.ssid) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: No SSID included in EAPOL-Key msg 3/4"); + goto failed; + } + + if (ie.ssid_len != sm->ssid_len || + os_memcmp(ie.ssid, sm->ssid, sm->ssid_len) != 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: SSID mismatch in EAPOL-Key msg 3/4"); + wpa_hexdump_ascii(MSG_DEBUG, "RSN: Received SSID", + ie.ssid, ie.ssid_len); + wpa_hexdump_ascii(MSG_DEBUG, "RSN: Expected SSID", + sm->ssid, sm->ssid_len); + goto failed; + } + + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: SSID matched expected value"); + } + if (mlo && !ie.valid_mlo_gtks) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "MLO RSN: No GTK KDE included in EAPOL-Key msg 3/4"); @@ -4460,6 +4482,20 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) } +void wpa_sm_set_ssid(struct wpa_sm *sm, const u8 *ssid, size_t ssid_len) +{ + if (!sm) + return; + + if (ssid) { + os_memcpy(sm->ssid, ssid, ssid_len); + sm->ssid_len = ssid_len; + } else { + sm->ssid_len = 0; + } +} + + int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo) { int i; @@ -4689,6 +4725,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, case WPA_PARAM_FT_PREPEND_PMKID: sm->ft_prepend_pmkid = value; break; + case WPA_PARAM_SSID_PROTECTION: + sm->ssid_protection = value; + break; default: break; } @@ -4960,6 +4999,14 @@ int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len) sm->assoc_rsnxe_len = len; } + if (sm->ssid_protection && + !ieee802_11_rsnx_capab(sm->assoc_rsnxe, + WLAN_RSNX_CAPAB_SSID_PROTECTION)) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "RSN: Disabling SSID protection based on own RSNXE update"); + sm->ssid_protection = 0; + } + return 0; } diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index ba5c3e1b4..c3ea68906 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -135,6 +135,7 @@ enum wpa_sm_conf_params { WPA_PARAM_ENCRYPT_EAPOL_M2, WPA_PARAM_ENCRYPT_EAPOL_M4, WPA_PARAM_FT_PREPEND_PMKID, + WPA_PARAM_SSID_PROTECTION, }; struct rsn_supp_config { @@ -188,6 +189,7 @@ void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm); void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth); void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx); void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config); +void wpa_sm_set_ssid(struct wpa_sm *sm, const u8 *ssid, size_t ssid_len); void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr); void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname, const char *bridge_ifname); diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index ca97c1293..dc429b8b2 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -112,6 +112,7 @@ struct wpa_sm { unsigned int secure_ltf:1; unsigned int secure_rtt:1; unsigned int prot_range_neg:1; + unsigned int ssid_protection:1; u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */ size_t assoc_wpa_ie_len; diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index d1510aad7..eeedf8ba5 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -366,7 +366,7 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len) { u8 *pos = rsnxe; - u16 capab = 0; + u32 capab = 0, tmp; size_t flen; if (wpa_key_mgmt_sae(sm->key_mgmt) && @@ -385,20 +385,27 @@ int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len) capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT); if (sm->prot_range_neg) capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR); + if (sm->ssid_protection) + capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION); - flen = (capab & 0xff00) ? 2 : 1; if (!capab) return 0; /* no supported extended RSN capabilities */ + tmp = capab; + flen = 0; + while (tmp) { + flen++; + tmp >>= 8; + } if (rsnxe_len < 2 + flen) return -1; capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */ *pos++ = WLAN_EID_RSNX; *pos++ = flen; - *pos++ = capab & 0x00ff; - capab >>= 8; - if (capab) - *pos++ = capab; + while (capab) { + *pos++ = capab & 0xff; + capab >>= 8; + } return pos - rsnxe; } diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 858c9b312..24861c68f 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2755,6 +2755,7 @@ static const struct parse_data ssid_fields[] = { { INT_RANGE(disable_eht, 0, 1)}, { INT_RANGE(enable_4addr_mode, 0, 1)}, { INT_RANGE(max_idle, 0, 65535)}, + { INT_RANGE(ssid_protection, 0, 1)}, }; #undef OFFSET diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 6dffcaf77..ad37bcf22 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -894,6 +894,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT(disable_eht); INT(enable_4addr_mode); INT(max_idle); + INT(ssid_protection); #undef STR #undef INT diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 74f7fed89..d64c30508 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -1278,6 +1278,11 @@ struct wpa_ssid { * as the maximum idle period for the STA during association. */ int max_idle; + + /** + * ssid_protection - Whether to use SSID protection in 4-way handshake + */ + bool ssid_protection; }; #endif /* CONFIG_SSID_H */ diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index a6f51a5f0..906fa1036 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -1048,6 +1048,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, old_ssid = wpa_s->current_ssid; wpa_s->current_ssid = ssid; wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); + wpa_sm_set_ssid(wpa_s->wpa, bss->ssid, bss->ssid_len); wpa_supplicant_initiate_eapol(wpa_s); #ifdef CONFIG_FILS diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 5bca64e54..1b5a26090 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -443,6 +443,7 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s, wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP, wpa_s->mgmt_group_cipher); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION, 0); pmksa_cache_clear_current(wpa_s->wpa); os_memset(&mlo, 0, sizeof(mlo)); @@ -2024,6 +2025,22 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wmm = !!wpa_bss_get_vendor_ie(bss, WMM_IE_VENDOR_TYPE); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_WMM_ENABLED, wmm); + if (ssid->ssid_protection && proto == WPA_PROTO_RSN) { + bool ssid_prot; + + /* Enable SSID protection based on the AP advertising support + * for it to avoid potential interoperability issues with + * incorrect AP behavior if we were to send an "unexpected" + * RSNXE with multiple octets of payload. */ + ssid_prot = ieee802_11_rsnx_capab( + bss_rsnx, WLAN_RSNX_CAPAB_SSID_PROTECTION); + if (!skip_default_rsne) + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION, + proto == WPA_PROTO_RSN && ssid_prot); + } else { + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION, false); + } + if (!skip_default_rsne) { if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) { @@ -4550,6 +4567,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); + if (bss) + wpa_sm_set_ssid(wpa_s->wpa, bss->ssid, bss->ssid_len); wpa_supplicant_initiate_eapol(wpa_s); if (old_ssid != wpa_s->current_ssid) wpas_notify_network_changed(wpa_s);