]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
SSID protection in 4-way handshake on AP
authorJouni Malinen <quic_jouni@quicinc.com>
Tue, 18 Jun 2024 22:09:52 +0000 (01:09 +0300)
committerJouni Malinen <j@w1.fi>
Wed, 19 Jun 2024 09:38:14 +0000 (12:38 +0300)
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>
hostapd/config_file.c
hostapd/hostapd.conf
src/ap/ap_config.h
src/ap/ieee802_11.c
src/ap/ieee802_11_shared.c
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_glue.c
src/ap/wpa_auth_i.h
src/ap/wpa_auth_ie.c

index d728be888bcff3a85aa94b1ddd928ec8d44d6f93..96c28aea277c9ea9f25906cc7919f12aea95bd27 100644 (file)
@@ -5044,6 +5044,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        return 1;
        } else if (os_strcmp(buf, "rnr") == 0) {
                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
        } else if (os_strcmp(buf, "ieee80211be") == 0) {
                conf->ieee80211be = atoi(pos);
index bc9099bc821611a8830cca009173b664bbcf03bf..e3367b708ecbc6d38cffe31cff50961538ab22b3 100644 (file)
@@ -2268,6 +2268,25 @@ own_ip_addr=127.0.0.1
 # (default: 1 = activated)
 #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 ##############################################
 
 # Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
index 0008583225a4a705cad5d45331653285612de145..fda937ecf534692e525f55d2614ca5e08753449a 100644 (file)
@@ -960,6 +960,8 @@ struct hostapd_bss_config {
        char *config_id;
        bool xrates_supported;
 
+       bool ssid_protection;
+
 #ifdef CONFIG_IEEE80211BE
        /* The AP is part of an AP MLD */
        u8 mld_ap;
index 80e54b267ac8e075575375325d9d90cad3846517..6a5137d87b653b896a0b5ee69f01898aa56ac8f4 100644 (file)
@@ -4192,6 +4192,13 @@ static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                                       "association");
                        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
        } else if (hapd->conf->osen) {
                if (!elems->osen) {
index fd8ec6004ab836c8269fcb1bd1850966c7aabc9b..3dd3a6a7719e8ca25e2ac264e3a074821b11601c 100644 (file)
@@ -1097,7 +1097,7 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
 {
        u8 *pos = eid;
        bool sae_pk = false;
-       u16 capab = 0;
+       u32 capab = 0, tmp;
        size_t flen;
 
        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);
        if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP)
                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 (len < 2 + flen || !capab)
+       if (!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 */
        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;
 }
index 08260c4b32efbe3c2655887834e6ddf59e534510..7302e6247ae693e870c32a18c2c86f30146e12dd 100644 (file)
@@ -4684,6 +4684,9 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 
        kde_len += wpa_auth_ml_kdes_len(sm);
 
+       if (sm->ssid_protection)
+               kde_len += 2 + conf->ssid_len;
+
 #ifdef CONFIG_TESTING_OPTIONS
        if (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);
 
+       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
        if (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 */
 
 
+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,
                                     u8 val)
 {
index 89bc5e7f2d62a6b1421bd871981a72ddd984e207..b588f9fdcd78e4031b305682ad6a37184e4d2eb5 100644 (file)
@@ -198,9 +198,9 @@ struct wpa_auth_config {
 #ifdef CONFIG_OCV
        int ocv; /* Operating Channel Validation */
 #endif /* CONFIG_OCV */
-#ifdef CONFIG_IEEE80211R_AP
        u8 ssid[SSID_MAX_LEN];
        size_t ssid_len;
+#ifdef CONFIG_IEEE80211R_AP
        u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
        u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
        size_t r0_key_holder_len;
@@ -293,6 +293,8 @@ struct wpa_auth_config {
        int link_id;
        struct wpa_authenticator *first_link_auth;
 #endif /* CONFIG_IEEE80211BE */
+
+       bool ssid_protection;
 };
 
 typedef enum {
@@ -604,6 +606,7 @@ bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
                                u8 *fd_rsn_info);
 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_ssid_protection(struct wpa_state_machine *sm, bool val);
 void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
                                     u8 val);
 
index 9f84510046132bc70df46320b4742d76ccc6733d..e725615d932cb8e315c51357dbbfaff7514a19bf 100644 (file)
@@ -73,11 +73,12 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
        wconf->beacon_prot = conf->beacon_prot;
        wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
        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;
        if (wconf->ssid_len > SSID_MAX_LEN)
                wconf->ssid_len = SSID_MAX_LEN;
        os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
+#ifdef CONFIG_IEEE80211R_AP
        os_memcpy(wconf->mobility_domain, conf->mobility_domain,
                  MOBILITY_DOMAIN_ID_LEN);
        if (conf->nas_identifier &&
index 97cb0501edb768507d0648d25768f7e35e278929..4e5ba3e2ed6f2d9223c81b384800aee04c24c20f 100644 (file)
@@ -183,6 +183,8 @@ struct wpa_state_machine {
                struct wpa_authenticator *wpa_auth;
        } mld_links[MAX_NUM_MLD_LINKS];
 #endif /* CONFIG_IEEE80211BE */
+
+       bool ssid_protection;
 };
 
 
index 5a17f7c34321a631492610c8333ad582b3760092..2efadf896186c07cc8d9bc580fe544bcc05e559e 100644 (file)
@@ -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)
 {
        u8 *pos = buf;
-       u16 capab = 0;
+       u32 capab = 0, tmp;
        size_t flen;
 
        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);
        if (conf->prot_range_neg)
                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)
                return 0; /* no supported extended RSN capabilities */
+       tmp = capab;
+       flen = 0;
+       while (tmp) {
+               flen++;
+               tmp >>= 8;
+       }
        if (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 - buf;
 }