]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Add BIGTK KDE and subelement similarly to IGTK
authorJouni Malinen <jouni@codeaurora.org>
Mon, 17 Feb 2020 21:08:05 +0000 (23:08 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 17 Feb 2020 21:48:24 +0000 (23:48 +0200)
This provides the BIGTK updates to associated stations similarly to
IGTK.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
src/ap/wnm_ap.c
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_ft.c
src/common/ieee802_11_defs.h

index 29ca950926d91bee2d959b4cac071ac3dc53ba56..891f90f298a0dd888f83065e0060ca8341e8bd3b 100644 (file)
@@ -54,6 +54,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
        size_t len;
        size_t gtk_elem_len = 0;
        size_t igtk_elem_len = 0;
+       size_t bigtk_elem_len = 0;
        struct wnm_sleep_element wnmsleep_ie;
        u8 *wnmtfs_ie, *oci_ie;
        u8 wnmsleep_ie_len, oci_ie_len;
@@ -122,8 +123,10 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
 
 #define MAX_GTK_SUBELEM_LEN 45
 #define MAX_IGTK_SUBELEM_LEN 26
+#define MAX_BIGTK_SUBELEM_LEN 26
        mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
                         MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
+                        MAX_BIGTK_SUBELEM_LEN +
                         oci_ie_len);
        if (mgmt == NULL) {
                wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
@@ -157,10 +160,19 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
                pos += igtk_elem_len;
                wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
                           (int) igtk_elem_len);
+               if (hapd->conf->beacon_prot) {
+                       res = wpa_wnmsleep_bigtk_subelem(sta->wpa_sm, pos);
+                       if (res < 0)
+                               goto fail;
+                       bigtk_elem_len = res;
+                       pos += bigtk_elem_len;
+                       wpa_printf(MSG_DEBUG, "Pass 4 bigtk_len = %d",
+                                  (int) bigtk_elem_len);
+               }
 
                WPA_PUT_LE16((u8 *)
                             &mgmt->u.action.u.wnm_sleep_resp.keydata_len,
-                            gtk_elem_len + igtk_elem_len);
+                            gtk_elem_len + igtk_elem_len + bigtk_elem_len);
        }
        os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
        /* copy TFS IE here */
@@ -176,7 +188,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
 #endif /* CONFIG_OCV */
 
        len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
-               igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
+               igtk_elem_len + bigtk_elem_len +
+               wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
 
        /* In driver, response frame should be forced to sent when STA is in
         * PS mode */
@@ -189,8 +202,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
 
                /* when entering wnmsleep
                 * 1. pause the node in driver
-                * 2. mark the node so that AP won't update GTK/IGTK during
-                * WNM Sleep
+                * 2. mark the node so that AP won't update GTK/IGTK/BIGTK
+                * during WNM Sleep
                 */
                if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
                    wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
@@ -201,7 +214,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
                }
                /* when exiting wnmsleep
                 * 1. unmark the node
-                * 2. start GTK/IGTK update if MFP is not used
+                * 2. start GTK/IGTK/BIGTK update if MFP is not used
                 * 3. unpause the node in driver
                 */
                if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
@@ -221,6 +234,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
 
 #undef MAX_GTK_SUBELEM_LEN
 #undef MAX_IGTK_SUBELEM_LEN
+#undef MAX_BIGTK_SUBELEM_LEN
 fail:
        os_free(wnmtfs_ie);
        os_free(oci_ie);
index ee75837db9837bd4881e54c466ebada35e086b92..1f835d80a00192a0dc652d111bd3b941c05915d4 100644 (file)
@@ -63,6 +63,7 @@ static void wpa_group_get(struct wpa_authenticator *wpa_auth,
                          struct wpa_group *group);
 static void wpa_group_put(struct wpa_authenticator *wpa_auth,
                          struct wpa_group *group);
+static int ieee80211w_kde_len(struct wpa_state_machine *sm);
 static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
 
 static const u32 eapol_key_timeout_first = 100; /* ms */
@@ -2679,7 +2680,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
        size_t gtk_len;
        struct wpa_group *gsm;
 
-       plain = wpabuf_alloc(1000);
+       plain = wpabuf_alloc(1000 + ieee80211w_kde_len(sm));
        if (!plain)
                return NULL;
 
@@ -2727,7 +2728,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
                           gtk, gtk_len);
        wpabuf_put(plain, tmp2 - tmp);
 
-       /* IGTK KDE */
+       /* IGTK KDE and BIGTK KDE */
        tmp = wpabuf_put(plain, 0);
        tmp2 = ieee80211w_kde_add(sm, tmp);
        wpabuf_put(plain, tmp2 - tmp);
@@ -3105,19 +3106,25 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
 
 static int ieee80211w_kde_len(struct wpa_state_machine *sm)
 {
+       size_t len = 0;
+
        if (sm->mgmt_frame_prot) {
-               size_t len;
-               len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
-               return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len;
+               len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN;
+               len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+       }
+       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);
        }
 
-       return 0;
+       return len;
 }
 
 
 static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
 {
        struct wpa_igtk_kde igtk;
+       struct wpa_bigtk_kde bigtk;
        struct wpa_group *gsm = sm->group;
        u8 rsc[WPA_KEY_RSC_LEN];
        size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
@@ -3146,6 +3153,21 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
                          (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
                          NULL, 0);
 
+       if (!sm->wpa_auth->conf.beacon_prot)
+               return pos;
+
+       bigtk.keyid[0] = gsm->GN_bigtk;
+       bigtk.keyid[1] = 0;
+       if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
+           wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, rsc) < 0)
+               os_memset(bigtk.pn, 0, sizeof(bigtk.pn));
+       else
+               os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
+       os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+       pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
+                         (const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
+                         NULL, 0);
+
        return pos;
 }
 
@@ -3205,7 +3227,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
        }
 
        /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
-          GTK[GN], IGTK, [FTIE], [TIE * 2])
+          GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
         */
        os_memset(rsc, 0, WPA_KEY_RSC_LEN);
        wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
@@ -3978,6 +4000,36 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
        return pos - start;
 }
 
+
+int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+       struct wpa_group *gsm = sm->group;
+       u8 *start = pos;
+       size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+       /*
+        * BIGTK subelement:
+        * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
+        */
+       *pos++ = WNM_SLEEP_SUBELEM_BIGTK;
+       *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)
+               return 0;
+       pos += 6;
+
+       os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+       pos += len;
+
+       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);
+
+       return pos - start;
+}
+
 #endif /* CONFIG_WNM_AP */
 
 
@@ -5074,7 +5126,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
        int wpa_ie_len, secure, gtkidx, encr = 0;
 
        /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
-          GTK[GN], IGTK, [FTIE], [TIE * 2])
+          GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
         */
 
        /* Use 0 RSC */
index c066d997989f7d426731a7aaaa037fae5debcc57..93e0c745d30b59512ee12b13f0df320c292c18e7 100644 (file)
@@ -438,6 +438,7 @@ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
 void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
 int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
 int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos);
 
 int wpa_auth_uses_sae(struct wpa_state_machine *sm);
 int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
index 462876195a0879a5ad93c0a67df546b300fde7dc..c0b462558f521815c3d6b9203feeb4ac2f12a55d 100644 (file)
@@ -2282,6 +2282,54 @@ 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;
+       size_t subelem_len;
+       const u8 *kek;
+       size_t kek_len;
+       size_t bigtk_len;
+
+       if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+               kek = sm->PTK.kek2;
+               kek_len = sm->PTK.kek2_len;
+       } else {
+               kek = sm->PTK.kek;
+               kek_len = sm->PTK.kek_len;
+       }
+
+       bigtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+       /* Sub-elem ID[1] | Length[1] | KeyID[2] | BIPN[6] | Key Length[1] |
+        * Key[16+8] */
+       subelem_len = 1 + 1 + 2 + 6 + 1 + bigtk_len + 8;
+       subelem = os_zalloc(subelem_len);
+       if (subelem == NULL)
+               return NULL;
+
+       pos = subelem;
+       *pos++ = FTIE_SUBELEM_BIGTK;
+       *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);
+       pos += 6;
+       *pos++ = bigtk_len;
+       if (aes_wrap(kek, kek_len, bigtk_len / 8,
+                    gsm->IGTK[gsm->GN_bigtk - 6], pos)) {
+               wpa_printf(MSG_DEBUG,
+                          "FT: BIGTK subelem encryption failed: kek_len=%d",
+                          (int) kek_len);
+               os_free(subelem);
+               return NULL;
+       }
+
+       *len = subelem_len;
+       return subelem;
+}
+
+
 static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
                                u8 *pos, u8 *end, u8 id, u8 descr_count,
                                const u8 *ies, size_t ies_len)
@@ -2511,6 +2559,29 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
                        subelem_len += igtk_len;
                        os_free(igtk);
                }
+               if (sm->mgmt_frame_prot && conf->beacon_prot) {
+                       u8 *bigtk;
+                       size_t bigtk_len;
+                       u8 *nbuf;
+
+                       bigtk = wpa_ft_bigtk_subelem(sm, &bigtk_len);
+                       if (!bigtk) {
+                               wpa_printf(MSG_DEBUG,
+                                          "FT: Failed to add BIGTK subelement");
+                               os_free(subelem);
+                               return NULL;
+                       }
+                       nbuf = os_realloc(subelem, subelem_len + bigtk_len);
+                       if (!nbuf) {
+                               os_free(subelem);
+                               os_free(bigtk);
+                               return NULL;
+                       }
+                       subelem = nbuf;
+                       os_memcpy(subelem + subelem_len, bigtk, bigtk_len);
+                       subelem_len += bigtk_len;
+                       os_free(bigtk);
+               }
 #ifdef CONFIG_OCV
                if (wpa_auth_uses_ocv(sm)) {
                        struct wpa_channel_info ci;
index 23e739d0e6d89afe939057de3915bee5a2a3b652..a78ed0a122b1b24179046cae3126b0e777cd35f4 100644 (file)
@@ -1875,7 +1875,8 @@ enum wnm_sleep_mode_response_status {
 /* WNM-Sleep Mode subelement IDs */
 enum wnm_sleep_mode_subelement_id {
        WNM_SLEEP_SUBELEM_GTK = 0,
-       WNM_SLEEP_SUBELEM_IGTK = 1
+       WNM_SLEEP_SUBELEM_IGTK = 1,
+       WNM_SLEEP_SUBELEM_BIGTK = 2,
 };
 
 /* Channel Switch modes (802.11h) */