]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
FT: Extend FTE parsing for FT-SAE-EXT-KEY
authorJouni Malinen <quic_jouni@quicinc.com>
Sun, 16 Oct 2022 13:38:27 +0000 (16:38 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 16 Oct 2022 14:17:49 +0000 (17:17 +0300)
Provide AKM, key length, and information about needed subelements to the
parser function so that the variable length MIC field cases can be
recognized for FT-SAE-EXT-KEY. Knowledge about R0KH-ID/R1KH-ID being
needed is required to be able to iterate over possible MIC field lengths
for the case where the AP does not yet know the correct key length at
the beginning of FT protocol.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
src/ap/wpa_auth_ft.c
src/common/wpa_common.c
src/common/wpa_common.h
src/rsn_supp/wpa.c
src/rsn_supp/wpa_ft.c
wlantest/rx_mgmt.c

index eb167cb603e3b65351b85f85b30d6c9708c26b5f..27a2ba3cf91a9e114a406e822532ec12f2ad2a7e 100644 (file)
@@ -2772,8 +2772,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
                *elem_count = 3; /* Information element count */
 
        ric_start = pos;
-       if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse, use_sha384) == 0
-           && parse.ric) {
+       if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse, sm->wpa_key_mgmt,
+                            key_len, false, false) == 0 && parse.ric) {
                pos = wpa_ft_process_ric(sm, pos, end, parse.ric,
                                         parse.ric_len);
                if (auth_alg == WLAN_AUTH_FT)
@@ -3146,7 +3146,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
        wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
                    ies, ies_len);
 
-       if (wpa_ft_parse_ies(ies, ies_len, &parse, -1)) {
+       if (wpa_ft_parse_ies(ies, ies_len, &parse, 0, 0, false, false)) {
                wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
        }
@@ -3410,7 +3410,8 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
 
        wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
 
-       if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
+       if (wpa_ft_parse_ies(ies, ies_len, &parse, sm->wpa_key_mgmt,
+                            sm->pmk_r1_len, true, true) < 0) {
                wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
        }
index 8c19ace797ecc961e6ab616d1b18ed6789ab9d85..7c1049e0b02a95329977decc909ff21f239af4d9 100644 (file)
@@ -1010,15 +1010,14 @@ int wpa_ft_mic(int key_mgmt, const u8 *kck, size_t kck_len, const u8 *sta_addr,
 
 
 static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
-                            struct wpa_ft_ies *parse, int use_sha384)
+                            struct wpa_ft_ies *parse, const u8 *opt)
 {
        const u8 *end, *pos;
 
        parse->ftie = ie;
        parse->ftie_len = ie_len;
 
-       pos = ie + (use_sha384 ? sizeof(struct rsn_ftie_sha384) :
-                   sizeof(struct rsn_ftie));
+       pos = opt;
        end = ie + ie_len;
        wpa_hexdump(MSG_DEBUG, "FT: Parse FTE subelements", pos, end - pos);
 
@@ -1029,7 +1028,7 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
                len = *pos++;
                if (len > end - pos) {
                        wpa_printf(MSG_DEBUG, "FT: Truncated subelement");
-                       break;
+                       return -1;
                }
 
                switch (id) {
@@ -1082,20 +1081,47 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
 }
 
 
-int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-                    struct wpa_ft_ies *parse, int use_sha384)
+static int wpa_ft_parse_fte(const u8 *ie, size_t len, size_t mic_len,
+                           struct wpa_ft_ies *parse)
+{
+       const u8 *pos = ie;
+       const u8 *end = pos + len;
+
+       wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control", pos, 2);
+       parse->fte_rsnxe_used = pos[0] & 0x01;
+       parse->fte_elem_count = pos[1];
+       pos += 2;
+
+       if (mic_len > (size_t) (end - pos))
+               return -1;
+       wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC", pos, mic_len);
+       parse->fte_mic = pos;
+       parse->fte_mic_len = mic_len;
+       pos += mic_len;
+
+       if (2 * WPA_NONCE_LEN > end - pos)
+               return -1;
+       parse->fte_anonce = pos;
+       wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
+                   parse->fte_anonce, WPA_NONCE_LEN);
+       pos += WPA_NONCE_LEN;
+       parse->fte_snonce = pos;
+       wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
+                   parse->fte_snonce, WPA_NONCE_LEN);
+       pos += WPA_NONCE_LEN;
+
+       return wpa_ft_parse_ftie(ie, len, parse, pos);
+}
+
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
+                    int key_mgmt, size_t key_len, bool need_r0kh_id,
+                    bool need_r1kh_id)
 {
        const u8 *end, *pos;
        struct wpa_ie_data data;
        int ret;
-       const struct rsn_ftie *ftie;
        int prot_ie_count = 0;
-       int update_use_sha384 = 0;
-
-       if (use_sha384 < 0) {
-               use_sha384 = 0;
-               update_use_sha384 = 1;
-       }
 
        os_memset(parse, 0, sizeof(*parse));
        if (ies == NULL)
@@ -1129,11 +1155,8 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
                                parse->rsn_pmkid = data.pmkid;
                        parse->key_mgmt = data.key_mgmt;
                        parse->pairwise_cipher = data.pairwise_cipher;
-                       if (update_use_sha384) {
-                               use_sha384 =
-                                       wpa_key_mgmt_sha384(parse->key_mgmt);
-                               update_use_sha384 = 0;
-                       }
+                       if (!key_mgmt)
+                               key_mgmt = parse->key_mgmt;
                        break;
                case WLAN_EID_RSNX:
                        wpa_hexdump(MSG_DEBUG, "FT: RSNXE", pos, len);
@@ -1151,47 +1174,61 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
                        break;
                case WLAN_EID_FAST_BSS_TRANSITION:
                        wpa_hexdump(MSG_DEBUG, "FT: FTE", pos, len);
-                       if (use_sha384) {
-                               const struct rsn_ftie_sha384 *ftie_sha384;
+                       /* The first two octets (MIC Control field) is in the
+                        * same offset for all cases, but the second field (MIC)
+                        * has variable length with three different values.
+                        * In particular the FT-SAE-EXT-KEY is inconvinient to
+                        * parse, so try to handle this in pieces instead of
+                        * using the struct rsn_ftie* definitions. */
+
+                       if (len < 2)
+                               return -1;
+                       prot_ie_count = pos[1]; /* Element Count field in
+                                                * MIC Control */
 
-                               if (len < sizeof(*ftie_sha384))
-                                       return -1;
-                               ftie_sha384 =
-                                       (const struct rsn_ftie_sha384 *) pos;
-                               wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
-                                           ftie_sha384->mic_control, 2);
-                               wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
-                                           ftie_sha384->mic,
-                                           sizeof(ftie_sha384->mic));
-                               parse->fte_anonce = ftie_sha384->anonce;
-                               wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
-                                           ftie_sha384->anonce,
-                                           WPA_NONCE_LEN);
-                               parse->fte_snonce = ftie_sha384->snonce;
-                               wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
-                                           ftie_sha384->snonce,
-                                           WPA_NONCE_LEN);
-                               prot_ie_count = ftie_sha384->mic_control[1];
-                               if (wpa_ft_parse_ftie(pos, len, parse, 1) < 0)
+                       if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY &&
+                           (key_len == SHA512_MAC_LEN || !key_len)) {
+                               wpa_printf(MSG_DEBUG,
+                                          "FT: Trying to parse FTE for FT-SAE-EXT-KEY - SHA512");
+                               if (wpa_ft_parse_fte(pos, len, 32, parse) ==
+                                   0 &&
+                                   (!need_r0kh_id || parse->r0kh_id) &&
+                                   (!need_r1kh_id || parse->r1kh_id))
+                                       break;
+                       }
+                       if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY &&
+                           (key_len == SHA384_MAC_LEN || !key_len)) {
+                               wpa_printf(MSG_DEBUG,
+                                          "FT: Trying to parse FTE for FT-SAE-EXT-KEY - SHA384");
+                               if (wpa_ft_parse_fte(pos, len, 24, parse) ==
+                                   0 &&
+                                   (!need_r0kh_id || parse->r0kh_id) &&
+                                   (!need_r1kh_id || parse->r1kh_id))
+                                       break;
+                       }
+                       if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY &&
+                           (key_len == SHA256_MAC_LEN || !key_len)) {
+                               wpa_printf(MSG_DEBUG,
+                                          "FT: Trying to parse FTE for FT-SAE-EXT-KEY - SHA256");
+                               if (wpa_ft_parse_fte(pos, len, 16, parse) ==
+                                   0 &&
+                                   (!need_r0kh_id || parse->r0kh_id) &&
+                                   (!need_r1kh_id || parse->r1kh_id))
+                                       break;
+                       }
+                       if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
+                               wpa_printf(MSG_DEBUG,
+                                          "FT: Failed to parse FTE for FT-SAE-EXT-KEY");
+                               return -1;
+                       }
+
+                       if (wpa_key_mgmt_sha384(key_mgmt)) {
+                               if (wpa_ft_parse_fte(pos, len, 24, parse) < 0)
                                        return -1;
                                break;
                        }
 
-                       if (len < sizeof(*ftie))
-                               return -1;
-                       ftie = (const struct rsn_ftie *) pos;
-                       wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
-                                   ftie->mic_control, 2);
-                       wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
-                                   ftie->mic, sizeof(ftie->mic));
-                       parse->fte_anonce = ftie->anonce;
-                       wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
-                                   ftie->anonce, WPA_NONCE_LEN);
-                       parse->fte_snonce = ftie->snonce;
-                       wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
-                                   ftie->snonce, WPA_NONCE_LEN);
-                       prot_ie_count = ftie->mic_control[1];
-                       if (wpa_ft_parse_ftie(pos, len, parse, 0) < 0)
+                       if (wpa_ft_parse_fte(pos, len, 16, parse) < 0)
                                return -1;
                        break;
                case WLAN_EID_TIMEOUT_INTERVAL:
index 4af22bf65fd93fdc528216eca82bfda491105ad5..561f926ae642fe59786befd3544620b94074705a 100644 (file)
@@ -553,6 +553,10 @@ struct wpa_ft_ies {
        size_t r0kh_id_len;
        const u8 *fte_anonce;
        const u8 *fte_snonce;
+       bool fte_rsnxe_used;
+       unsigned int fte_elem_count;
+       const u8 *fte_mic;
+       size_t fte_mic_len;
        const u8 *rsn;
        size_t rsn_len;
        u16 rsn_capab;
@@ -608,7 +612,8 @@ struct wpa_pasn_params_data {
 #define WPA_PASN_PUBKEY_UNCOMPRESSED 0x04
 
 int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
-                    int use_sha384);
+                    int key_mgmt, size_t key_len, bool need_r0kh_id,
+                    bool need_r1kh_id);
 
 struct wpa_eapol_ie_parse {
        const u8 *wpa_ie;
index 0192ed0901b325dd6f4083843d79d65818490d27..10bef1a4a79d776ef73ce2419f518da53345c2de 100644 (file)
@@ -4320,7 +4320,8 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
                }
 
                if (wpa_ft_parse_ies(pos, end - pos, &parse,
-                                    wpa_key_mgmt_sha384(sm->key_mgmt)) < 0) {
+                                    sm->key_mgmt, sm->xxkey_len, true,
+                                    true) < 0) {
                        wpa_printf(MSG_DEBUG, "FILS+FT: Failed to parse IEs");
                        goto fail;
                }
index 1c27a79bd1632a807c75408c0501dbfd556b8fb1..372d6872bc9cbb1c5f1b000a4138448cf813feb5 100644 (file)
@@ -105,7 +105,6 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
 int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
 {
        struct wpa_ft_ies ft;
-       int use_sha384;
 
        if (sm == NULL)
                return 0;
@@ -121,8 +120,8 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
                return 0;
        }
 
-       use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
-       if (wpa_ft_parse_ies(ies, ies_len, &ft, use_sha384) < 0)
+       if (wpa_ft_parse_ies(ies, ies_len, &ft, sm->key_mgmt,
+                            sm->xxkey_len, false, false) < 0)
                return -1;
 
        if (ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
@@ -563,7 +562,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
        int ret;
        const u8 *bssid;
        const u8 *kck;
-       size_t kck_len, kdk_len;
+       size_t kck_len, kdk_len, key_len;
        int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
        const u8 *anonce, *snonce;
 
@@ -591,7 +590,11 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
                return -1;
        }
 
-       if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
+       key_len = sm->xxkey_len;
+       if (!key_len)
+               key_len = sm->pmk_r1_len;
+       if (wpa_ft_parse_ies(ies, ies_len, &parse, sm->key_mgmt,
+                            key_len, true, false) < 0) {
                wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
                return -1;
        }
@@ -1026,7 +1029,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
                return 0;
        }
 
-       if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
+       if (wpa_ft_parse_ies(ies, ies_len, &parse, sm->key_mgmt,
+                            sm->xxkey_len, true, true) < 0) {
                wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
                return -1;
        }
index 2a9a03058e5be08df911080870ac2deeef565f06..c649d4de59a362b9f3964f3d11591bdfe380258b 100644 (file)
@@ -250,7 +250,7 @@ static void process_ft_auth(struct wlantest *wt, struct wlantest_bss *bss,
 
        if (wpa_ft_parse_ies(mgmt->u.auth.variable,
                             len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth),
-                            &parse, -1)) {
+                            &parse, 0, 0, false, false)) {
                add_note(wt, MSG_INFO,
                         "Could not parse FT Authentication Response frame");
                return;
@@ -833,7 +833,7 @@ static void rx_mgmt_assoc_resp(struct wlantest *wt, const u8 *data, size_t len)
                sta->state = STATE3;
        }
 
-       if (wpa_ft_parse_ies(ies, ies_len, &parse, 0) == 0) {
+       if (wpa_ft_parse_ies(ies, ies_len, &parse, 0, 0, false, false) == 0) {
                if (parse.r0kh_id) {
                        os_memcpy(bss->r0kh_id, parse.r0kh_id,
                                  parse.r0kh_id_len);
@@ -929,7 +929,8 @@ static void rx_mgmt_reassoc_req(struct wlantest *wt, const u8 *data,
 
                use_sha384 = wpa_key_mgmt_sha384(sta->key_mgmt);
 
-               if (wpa_ft_parse_ies(ie, ie_len, &parse, use_sha384) < 0) {
+               if (wpa_ft_parse_ies(ie, ie_len, &parse, sta->key_mgmt,
+                                    0, false, false) < 0) {
                        add_note(wt, MSG_INFO, "FT: Failed to parse FT IEs");
                        return;
                }
@@ -1422,7 +1423,8 @@ static void rx_mgmt_reassoc_resp(struct wlantest *wt, const u8 *data,
 
                use_sha384 = wpa_key_mgmt_sha384(sta->key_mgmt);
 
-               if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
+               if (wpa_ft_parse_ies(ies, ies_len, &parse, sta->key_mgmt,
+                                    0, false, false) < 0) {
                        add_note(wt, MSG_INFO, "FT: Failed to parse FT IEs");
                        return;
                }
@@ -1732,7 +1734,7 @@ static void rx_mgmt_action_ft_request(struct wlantest *wt,
        ies_len = len - (24 + 2 + 2 * ETH_ALEN);
        wpa_hexdump(MSG_DEBUG, "FT Request frame body", ies, ies_len);
 
-       if (wpa_ft_parse_ies(ies, ies_len, &parse, -1)) {
+       if (wpa_ft_parse_ies(ies, ies_len, &parse, 0, 0, false, false)) {
                add_note(wt, MSG_INFO, "Could not parse FT Request frame body");
                return;
        }
@@ -1781,7 +1783,7 @@ static void rx_mgmt_action_ft_response(struct wlantest *wt,
        ies_len = len - (24 + 2 + 2 * ETH_ALEN);
        wpa_hexdump(MSG_DEBUG, "FT Response frame body", ies, ies_len);
 
-       if (wpa_ft_parse_ies(ies, ies_len, &parse, -1)) {
+       if (wpa_ft_parse_ies(ies, ies_len, &parse, 0, 0, false, false)) {
                add_note(wt, MSG_INFO,
                         "Could not parse FT Response frame body");
                return;