SSID protection in 4-way handshake on AP
Add support for SSID protection in 4-way handshake based on the mechanism added in IEEE 802.11REVme/D6.0. This is a mitigation against CVE-2023-52424 (a.k.a. the SSID Confusion Attack). This functionality is disabled by default and can be enabled with ssid_protection=1. Once there has been more testing of this to confirm there is no significant interoperability issues, the goal is to be able to change this to be enabled by default. Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
This commit is contained in:
parent
dab7549d68
commit
37a289f8bc
10 changed files with 89 additions and 15 deletions
|
@ -5044,6 +5044,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||||
return 1;
|
return 1;
|
||||||
} else if (os_strcmp(buf, "rnr") == 0) {
|
} else if (os_strcmp(buf, "rnr") == 0) {
|
||||||
bss->rnr = atoi(pos);
|
bss->rnr = atoi(pos);
|
||||||
|
} else if (os_strcmp(buf, "ssid_protection") == 0) {
|
||||||
|
int val = atoi(pos);
|
||||||
|
|
||||||
|
if (val < 0 || val > 1)
|
||||||
|
return 1;
|
||||||
|
bss->ssid_protection = val;
|
||||||
#ifdef CONFIG_IEEE80211BE
|
#ifdef CONFIG_IEEE80211BE
|
||||||
} else if (os_strcmp(buf, "ieee80211be") == 0) {
|
} else if (os_strcmp(buf, "ieee80211be") == 0) {
|
||||||
conf->ieee80211be = atoi(pos);
|
conf->ieee80211be = atoi(pos);
|
||||||
|
|
|
@ -2268,6 +2268,25 @@ own_ip_addr=127.0.0.1
|
||||||
# (default: 1 = activated)
|
# (default: 1 = activated)
|
||||||
#pasn_noauth=1
|
#pasn_noauth=1
|
||||||
|
|
||||||
|
# SSID protection in 4-way handshake
|
||||||
|
# The IEEE 802.11i-2004 RSN design did not provide means for protecting the
|
||||||
|
# SSID in the general case. IEEE P802.11REVme/D6.0 added support for this in
|
||||||
|
# 4-way handshake. This capability allows a STA to confirm that the AP has the
|
||||||
|
# same understanding on which SSID is being used for an association in a
|
||||||
|
# protected manner in cases where both the AP and the STA has this capability.
|
||||||
|
# This can be used to mitigate CVE-2023-52424 (a.k.a. the SSID Confusion
|
||||||
|
# Attack).
|
||||||
|
#
|
||||||
|
# Ideally, this capability would be enabled by default on the AP, but since this
|
||||||
|
# is new functionality with limited testing, the default is to disable this for
|
||||||
|
# now and require explicitly configuration to enable. The default behavior is
|
||||||
|
# like to change once this capability has received more testing.
|
||||||
|
#
|
||||||
|
# 0 = SSID protection in 4-way handshake disabled (default)
|
||||||
|
# 1 = SSID protection in 4-way handshake enabled
|
||||||
|
#
|
||||||
|
#ssid_protection=0
|
||||||
|
|
||||||
##### IEEE 802.11r configuration ##############################################
|
##### IEEE 802.11r configuration ##############################################
|
||||||
|
|
||||||
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
|
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
|
||||||
|
|
|
@ -960,6 +960,8 @@ struct hostapd_bss_config {
|
||||||
char *config_id;
|
char *config_id;
|
||||||
bool xrates_supported;
|
bool xrates_supported;
|
||||||
|
|
||||||
|
bool ssid_protection;
|
||||||
|
|
||||||
#ifdef CONFIG_IEEE80211BE
|
#ifdef CONFIG_IEEE80211BE
|
||||||
/* The AP is part of an AP MLD */
|
/* The AP is part of an AP MLD */
|
||||||
u8 mld_ap;
|
u8 mld_ap;
|
||||||
|
|
|
@ -4192,6 +4192,13 @@ static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
"association");
|
"association");
|
||||||
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
|
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wpa_auth_set_ssid_protection(
|
||||||
|
sta->wpa_sm,
|
||||||
|
hapd->conf->ssid_protection &&
|
||||||
|
ieee802_11_rsnx_capab_len(
|
||||||
|
elems->rsnxe, elems->rsnxe_len,
|
||||||
|
WLAN_RSNX_CAPAB_SSID_PROTECTION));
|
||||||
#ifdef CONFIG_HS20
|
#ifdef CONFIG_HS20
|
||||||
} else if (hapd->conf->osen) {
|
} else if (hapd->conf->osen) {
|
||||||
if (!elems->osen) {
|
if (!elems->osen) {
|
||||||
|
|
|
@ -1097,7 +1097,7 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||||
{
|
{
|
||||||
u8 *pos = eid;
|
u8 *pos = eid;
|
||||||
bool sae_pk = false;
|
bool sae_pk = false;
|
||||||
u16 capab = 0;
|
u32 capab = 0, tmp;
|
||||||
size_t flen;
|
size_t flen;
|
||||||
|
|
||||||
if (!(hapd->conf->wpa & WPA_PROTO_RSN))
|
if (!(hapd->conf->wpa & WPA_PROTO_RSN))
|
||||||
|
@ -1126,18 +1126,28 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||||
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
|
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
|
||||||
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP)
|
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP)
|
||||||
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
|
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
|
||||||
|
if (hapd->conf->ssid_protection)
|
||||||
|
capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
|
||||||
|
|
||||||
flen = (capab & 0xff00) ? 2 : 1;
|
if (!capab)
|
||||||
if (len < 2 + flen || !capab)
|
return eid; /* no supported extended RSN capabilities */
|
||||||
|
tmp = capab;
|
||||||
|
flen = 0;
|
||||||
|
while (tmp) {
|
||||||
|
flen++;
|
||||||
|
tmp >>= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < 2 + flen)
|
||||||
return eid; /* no supported extended RSN capabilities */
|
return eid; /* no supported extended RSN capabilities */
|
||||||
capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
|
capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
|
||||||
|
|
||||||
*pos++ = WLAN_EID_RSNX;
|
*pos++ = WLAN_EID_RSNX;
|
||||||
*pos++ = flen;
|
*pos++ = flen;
|
||||||
*pos++ = capab & 0x00ff;
|
while (capab) {
|
||||||
|
*pos++ = capab & 0xff;
|
||||||
capab >>= 8;
|
capab >>= 8;
|
||||||
if (capab)
|
}
|
||||||
*pos++ = capab;
|
|
||||||
|
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4684,6 +4684,9 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
|
||||||
|
|
||||||
kde_len += wpa_auth_ml_kdes_len(sm);
|
kde_len += wpa_auth_ml_kdes_len(sm);
|
||||||
|
|
||||||
|
if (sm->ssid_protection)
|
||||||
|
kde_len += 2 + conf->ssid_len;
|
||||||
|
|
||||||
#ifdef CONFIG_TESTING_OPTIONS
|
#ifdef CONFIG_TESTING_OPTIONS
|
||||||
if (conf->eapol_m3_elements)
|
if (conf->eapol_m3_elements)
|
||||||
kde_len += wpabuf_len(conf->eapol_m3_elements);
|
kde_len += wpabuf_len(conf->eapol_m3_elements);
|
||||||
|
@ -4803,6 +4806,13 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
|
||||||
|
|
||||||
pos = wpa_auth_ml_kdes(sm, pos);
|
pos = wpa_auth_ml_kdes(sm, pos);
|
||||||
|
|
||||||
|
if (sm->ssid_protection) {
|
||||||
|
*pos++ = WLAN_EID_SSID;
|
||||||
|
*pos++ = conf->ssid_len;
|
||||||
|
os_memcpy(pos, conf->ssid, conf->ssid_len);
|
||||||
|
pos += conf->ssid_len;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_TESTING_OPTIONS
|
#ifdef CONFIG_TESTING_OPTIONS
|
||||||
if (conf->eapol_m3_elements) {
|
if (conf->eapol_m3_elements) {
|
||||||
os_memcpy(pos, wpabuf_head(conf->eapol_m3_elements),
|
os_memcpy(pos, wpabuf_head(conf->eapol_m3_elements),
|
||||||
|
@ -6787,6 +6797,13 @@ void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
|
||||||
#endif /* CONFIG_DPP2 */
|
#endif /* CONFIG_DPP2 */
|
||||||
|
|
||||||
|
|
||||||
|
void wpa_auth_set_ssid_protection(struct wpa_state_machine *sm, bool val)
|
||||||
|
{
|
||||||
|
if (sm)
|
||||||
|
sm->ssid_protection = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
|
void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
|
||||||
u8 val)
|
u8 val)
|
||||||
{
|
{
|
||||||
|
|
|
@ -198,9 +198,9 @@ struct wpa_auth_config {
|
||||||
#ifdef CONFIG_OCV
|
#ifdef CONFIG_OCV
|
||||||
int ocv; /* Operating Channel Validation */
|
int ocv; /* Operating Channel Validation */
|
||||||
#endif /* CONFIG_OCV */
|
#endif /* CONFIG_OCV */
|
||||||
#ifdef CONFIG_IEEE80211R_AP
|
|
||||||
u8 ssid[SSID_MAX_LEN];
|
u8 ssid[SSID_MAX_LEN];
|
||||||
size_t ssid_len;
|
size_t ssid_len;
|
||||||
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
|
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
|
||||||
u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
|
u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
|
||||||
size_t r0_key_holder_len;
|
size_t r0_key_holder_len;
|
||||||
|
@ -293,6 +293,8 @@ struct wpa_auth_config {
|
||||||
int link_id;
|
int link_id;
|
||||||
struct wpa_authenticator *first_link_auth;
|
struct wpa_authenticator *first_link_auth;
|
||||||
#endif /* CONFIG_IEEE80211BE */
|
#endif /* CONFIG_IEEE80211BE */
|
||||||
|
|
||||||
|
bool ssid_protection;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -604,6 +606,7 @@ bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
|
||||||
u8 *fd_rsn_info);
|
u8 *fd_rsn_info);
|
||||||
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
|
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
|
||||||
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
|
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
|
||||||
|
void wpa_auth_set_ssid_protection(struct wpa_state_machine *sm, bool val);
|
||||||
void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
|
void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
|
||||||
u8 val);
|
u8 val);
|
||||||
|
|
||||||
|
|
|
@ -73,11 +73,12 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||||
wconf->beacon_prot = conf->beacon_prot;
|
wconf->beacon_prot = conf->beacon_prot;
|
||||||
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
|
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
|
||||||
wconf->sae_require_mfp = conf->sae_require_mfp;
|
wconf->sae_require_mfp = conf->sae_require_mfp;
|
||||||
#ifdef CONFIG_IEEE80211R_AP
|
wconf->ssid_protection = conf->ssid_protection;
|
||||||
wconf->ssid_len = conf->ssid.ssid_len;
|
wconf->ssid_len = conf->ssid.ssid_len;
|
||||||
if (wconf->ssid_len > SSID_MAX_LEN)
|
if (wconf->ssid_len > SSID_MAX_LEN)
|
||||||
wconf->ssid_len = SSID_MAX_LEN;
|
wconf->ssid_len = SSID_MAX_LEN;
|
||||||
os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
|
os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
|
||||||
|
#ifdef CONFIG_IEEE80211R_AP
|
||||||
os_memcpy(wconf->mobility_domain, conf->mobility_domain,
|
os_memcpy(wconf->mobility_domain, conf->mobility_domain,
|
||||||
MOBILITY_DOMAIN_ID_LEN);
|
MOBILITY_DOMAIN_ID_LEN);
|
||||||
if (conf->nas_identifier &&
|
if (conf->nas_identifier &&
|
||||||
|
|
|
@ -183,6 +183,8 @@ struct wpa_state_machine {
|
||||||
struct wpa_authenticator *wpa_auth;
|
struct wpa_authenticator *wpa_auth;
|
||||||
} mld_links[MAX_NUM_MLD_LINKS];
|
} mld_links[MAX_NUM_MLD_LINKS];
|
||||||
#endif /* CONFIG_IEEE80211BE */
|
#endif /* CONFIG_IEEE80211BE */
|
||||||
|
|
||||||
|
bool ssid_protection;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -409,7 +409,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||||
int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
|
int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
|
||||||
{
|
{
|
||||||
u8 *pos = buf;
|
u8 *pos = buf;
|
||||||
u16 capab = 0;
|
u32 capab = 0, tmp;
|
||||||
size_t flen;
|
size_t flen;
|
||||||
|
|
||||||
if (wpa_key_mgmt_sae(conf->wpa_key_mgmt) &&
|
if (wpa_key_mgmt_sae(conf->wpa_key_mgmt) &&
|
||||||
|
@ -429,20 +429,27 @@ int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
|
||||||
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
|
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
|
||||||
if (conf->prot_range_neg)
|
if (conf->prot_range_neg)
|
||||||
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
|
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
|
||||||
|
if (conf->ssid_protection)
|
||||||
|
capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
|
||||||
|
|
||||||
flen = (capab & 0xff00) ? 2 : 1;
|
|
||||||
if (!capab)
|
if (!capab)
|
||||||
return 0; /* no supported extended RSN capabilities */
|
return 0; /* no supported extended RSN capabilities */
|
||||||
|
tmp = capab;
|
||||||
|
flen = 0;
|
||||||
|
while (tmp) {
|
||||||
|
flen++;
|
||||||
|
tmp >>= 8;
|
||||||
|
}
|
||||||
if (len < 2 + flen)
|
if (len < 2 + flen)
|
||||||
return -1;
|
return -1;
|
||||||
capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
|
capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
|
||||||
|
|
||||||
*pos++ = WLAN_EID_RSNX;
|
*pos++ = WLAN_EID_RSNX;
|
||||||
*pos++ = flen;
|
*pos++ = flen;
|
||||||
*pos++ = capab & 0x00ff;
|
while (capab) {
|
||||||
|
*pos++ = capab & 0xff;
|
||||||
capab >>= 8;
|
capab >>= 8;
|
||||||
if (capab)
|
}
|
||||||
*pos++ = capab;
|
|
||||||
|
|
||||||
return pos - buf;
|
return pos - buf;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue