]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
MBSSID: Use BIGTK from the transmitted BSS for beacon protection
authorJouni Malinen <quic_jouni@quicinc.com>
Fri, 24 Nov 2023 10:53:09 +0000 (12:53 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 24 Nov 2023 10:53:09 +0000 (12:53 +0200)
MBSSID shares a single Beacon frame with multiple BSSs. This implies
that the key used for beacon protection (BIGTK) needs to be shared. The
nontransmitted BSSs managed their own BIGTK previously and that resulted
in providing incorrect value to the stations associated with those BSSs.
Use the BIGTK from the transmitted BSS to fix this.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_ft.c
src/ap/wpa_auth_glue.c
src/ap/wpa_auth_i.h

index 385eceaa043ae44bbf49d5233978892e8b53d754..1d41b2b91d9e136df7867f97b03cdeb3a3247ee6 100644 (file)
@@ -595,6 +595,15 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
        }
 #endif /* CONFIG_P2P */
 
+       if (conf->tx_bss_auth && conf->beacon_prot) {
+               conf->tx_bss_auth->non_tx_beacon_prot = true;
+               if (!conf->tx_bss_auth->conf.beacon_prot)
+                       conf->tx_bss_auth->conf.beacon_prot = true;
+               if (!conf->tx_bss_auth->conf.group_mgmt_cipher)
+                       conf->tx_bss_auth->conf.group_mgmt_cipher =
+                               conf->group_mgmt_cipher;
+       }
+
        return wpa_auth;
 }
 
@@ -3566,14 +3575,18 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
 static int ieee80211w_kde_len(struct wpa_state_machine *sm)
 {
        size_t len = 0;
+       struct wpa_authenticator *wpa_auth = sm->wpa_auth;
 
        if (sm->mgmt_frame_prot) {
                len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN;
-               len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+               len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
        }
+
+       if (wpa_auth->conf.tx_bss_auth)
+               wpa_auth = wpa_auth->conf.tx_bss_auth;
        if (sm->mgmt_frame_prot && sm->wpa_auth->conf.beacon_prot) {
                len += 2 + RSN_SELECTOR_LEN + WPA_BIGTK_KDE_PREFIX_LEN;
-               len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+               len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
        }
 
        return len;
@@ -3586,7 +3599,8 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
        struct wpa_bigtk_kde bigtk;
        struct wpa_group *gsm = sm->group;
        u8 rsc[WPA_KEY_RSC_LEN];
-       struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+       struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+       struct wpa_auth_config *conf = &wpa_auth->conf;
        size_t len = wpa_cipher_key_len(conf->group_mgmt_cipher);
 
        if (!sm->mgmt_frame_prot)
@@ -3618,7 +3632,14 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
                          NULL, 0);
        forced_memzero(&igtk, sizeof(igtk));
 
-       if (!conf->beacon_prot)
+       if (wpa_auth->conf.tx_bss_auth) {
+               wpa_auth = wpa_auth->conf.tx_bss_auth;
+               conf = &wpa_auth->conf;
+               len = wpa_cipher_key_len(conf->group_mgmt_cipher);
+               gsm = wpa_auth->group;
+       }
+
+       if (!sm->wpa_auth->conf.beacon_prot)
                return pos;
 
        bigtk.keyid[0] = gsm->GN_bigtk;
@@ -3776,6 +3797,11 @@ void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
        if (!beacon_prot)
                return;
 
+       if (a->conf.tx_bss_auth) {
+               a = a->conf.tx_bss_auth;
+               gsm = a->group;
+       }
+
        info->bigtkidx = gsm->GN_bigtk;
        info->bigtk = gsm->BIGTK[gsm->GN_bigtk - 6];
 
@@ -3798,6 +3824,7 @@ static void wpa_auth_get_ml_key_info(struct wpa_authenticator *wpa_auth,
 
 static size_t wpa_auth_ml_group_kdes_len(struct wpa_state_machine *sm)
 {
+       struct wpa_authenticator *wpa_auth = sm->wpa_auth;
        struct wpa_group *gsm = sm->group;
        size_t gtk_len = gsm->GTK_len;
        size_t igtk_len;
@@ -3816,10 +3843,15 @@ static size_t wpa_auth_ml_group_kdes_len(struct wpa_state_machine *sm)
                return kde_len;
 
        /* MLO IGTK KDE for each link */
-       igtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+       igtk_len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
        kde_len += n_links * (2 + RSN_SELECTOR_LEN + 2 + 6 + 1 + igtk_len);
 
-       if (!sm->wpa_auth->conf.beacon_prot)
+       if (wpa_auth->conf.tx_bss_auth) {
+               wpa_auth = wpa_auth->conf.tx_bss_auth;
+               igtk_len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+       }
+
+       if (!wpa_auth->conf.beacon_prot)
                return kde_len;
 
        /* MLO BIGTK KDE for each link */
@@ -4903,19 +4935,30 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
                                group->IGTK[group->GN_igtk - 4], len);
        }
 
-       if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
-           conf->beacon_prot) {
-               len = wpa_cipher_key_len(conf->group_mgmt_cipher);
-               os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
-               inc_byte_array(group->Counter, WPA_NONCE_LEN);
-               if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion",
-                                  wpa_auth->addr, group->GNonce,
-                                  group->BIGTK[group->GN_bigtk - 6], len) < 0)
-                       ret = -1;
-               wpa_hexdump_key(MSG_DEBUG, "BIGTK",
-                               group->BIGTK[group->GN_bigtk - 6], len);
+       if (!wpa_auth->non_tx_beacon_prot &&
+           conf->ieee80211w == NO_MGMT_FRAME_PROTECTION)
+               return ret;
+       if (!conf->beacon_prot)
+               return ret;
+
+       if (wpa_auth->conf.tx_bss_auth) {
+               group = wpa_auth->conf.tx_bss_auth->group;
+               if (group->bigtk_set)
+                       return ret;
+               wpa_printf(MSG_DEBUG, "Set up BIGTK for TX BSS");
        }
 
+       len = wpa_cipher_key_len(conf->group_mgmt_cipher);
+       os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+       inc_byte_array(group->Counter, WPA_NONCE_LEN);
+       if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion",
+                          wpa_auth->addr, group->GNonce,
+                          group->BIGTK[group->GN_bigtk - 6], len) < 0)
+               return -1;
+       group->bigtk_set = true;
+       wpa_hexdump_key(MSG_DEBUG, "BIGTK",
+                       group->BIGTK[group->GN_bigtk - 6], len);
+
        return ret;
 }
 
@@ -5076,9 +5119,10 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
 
 int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos)
 {
-       struct wpa_group *gsm = sm->group;
+       struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+       struct wpa_group *gsm = wpa_auth->group;
        u8 *start = pos;
-       size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+       size_t len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
 
        /*
         * BIGTK subelement:
@@ -5088,7 +5132,7 @@ int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos)
        *pos++ = 2 + 6 + len;
        WPA_PUT_LE16(pos, gsm->GN_bigtk);
        pos += 2;
-       if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos) != 0)
+       if (wpa_auth_get_seqnum(wpa_auth, NULL, gsm->GN_bigtk, pos) != 0)
                return 0;
        pos += 6;
 
@@ -5178,12 +5222,21 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
                                     KEY_FLAG_GROUP_TX_DEFAULT) < 0)
                        ret = -1;
 
-               if (ret == 0 && conf->beacon_prot &&
-                   wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
+               if (ret || !conf->beacon_prot)
+                       return ret;
+               if (wpa_auth->conf.tx_bss_auth) {
+                       wpa_auth = wpa_auth->conf.tx_bss_auth;
+                       group = wpa_auth->group;
+                       if (!group->bigtk_set || group->bigtk_configured)
+                               return ret;
+               }
+               if (wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
                                     broadcast_ether_addr, group->GN_bigtk,
                                     group->BIGTK[group->GN_bigtk - 6], len,
                                     KEY_FLAG_GROUP_TX_DEFAULT) < 0)
                        ret = -1;
+               else
+                       group->bigtk_configured = true;
        }
 
        return ret;
@@ -5328,9 +5381,11 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
                tmp = group->GM_igtk;
                group->GM_igtk = group->GN_igtk;
                group->GN_igtk = tmp;
-               tmp = group->GM_bigtk;
-               group->GM_bigtk = group->GN_bigtk;
-               group->GN_bigtk = tmp;
+               if (!wpa_auth->conf.tx_bss_auth) {
+                       tmp = group->GM_bigtk;
+                       group->GM_bigtk = group->GN_bigtk;
+                       group->GN_bigtk = tmp;
+               }
                wpa_gtk_update(wpa_auth, group);
                wpa_group_config_group_keys(wpa_auth, group);
        }
index d6ed6772bb8a61f67d34bb1b393ed8e9d3aa4541..0b1ddf49cdddc85e5db2f6eb541ca16c9fb3bcfe 100644 (file)
@@ -277,6 +277,11 @@ struct wpa_auth_config {
        bool force_kdk_derivation;
 
        bool radius_psk;
+
+       /* Pointer to Multi-BSSID transmitted BSS authenticator instance.
+        * Set only in nontransmitted BSSs, i.e., is NULL for transmitted BSS
+        * and in BSSs that are not part of a Multi-BSSID set. */
+       struct wpa_authenticator *tx_bss_auth;
 };
 
 typedef enum {
index 4b16f62df9df60a4dcb67c2dc4bee022fb309481..daf4cab461057b9cae5356f42a8292c37e9bb066 100644 (file)
@@ -2366,7 +2366,8 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
 static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
 {
        u8 *subelem, *pos;
-       struct wpa_group *gsm = sm->group;
+       struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+       struct wpa_group *gsm = wpa_auth->group;
        size_t subelem_len;
        const u8 *kek, *bigtk;
        size_t kek_len;
@@ -2381,7 +2382,7 @@ static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
                kek_len = sm->PTK.kek_len;
        }
 
-       bigtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+       bigtk_len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
 
        /* Sub-elem ID[1] | Length[1] | KeyID[2] | BIPN[6] | Key Length[1] |
         * Key[16+8] */
@@ -2395,7 +2396,7 @@ static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
        *pos++ = subelem_len - 2;
        WPA_PUT_LE16(pos, gsm->GN_bigtk);
        pos += 2;
-       wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos);
+       wpa_auth_get_seqnum(wpa_auth, NULL, gsm->GN_bigtk, pos);
        pos += 6;
        *pos++ = bigtk_len;
        bigtk = gsm->BIGTK[gsm->GN_bigtk - 6];
index fbe82779a5d3748d81042f9bd671f2035a86446c..23c7bbe2b7bb55983e09286241ef640ee749d11f 100644 (file)
@@ -1673,9 +1673,13 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
        };
        const u8 *wpa_ie;
        size_t wpa_ie_len;
+       struct hostapd_data *tx_bss;
 
        hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf);
        _conf.msg_ctx = hapd->msg_ctx;
+       tx_bss = hostapd_mbssid_get_tx_bss(hapd);
+       if (tx_bss != hapd)
+               _conf.tx_bss_auth = tx_bss->wpa_auth;
        if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
                _conf.tx_status = 1;
        if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
index 74ae5ad2e361649dd683768311cc0f4dc307caa1..b2fa789128e3794ede46c45cb908431de2449d9b 100644 (file)
@@ -222,6 +222,8 @@ struct wpa_group {
        u8 BIGTK[2][WPA_IGTK_MAX_LEN];
        int GN_igtk, GM_igtk;
        int GN_bigtk, GM_bigtk;
+       bool bigtk_set;
+       bool bigtk_configured;
        /* Number of references except those in struct wpa_group->next */
        unsigned int references;
        unsigned int num_setup_iface;
@@ -257,6 +259,8 @@ struct wpa_authenticator {
        struct rsn_pmksa_cache *pmksa;
        struct wpa_ft_pmk_cache *ft_pmk_cache;
 
+       bool non_tx_beacon_prot;
+
 #ifdef CONFIG_P2P
        struct bitfield *ip_pool;
 #endif /* CONFIG_P2P */