diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index eb167cb60..27a2ba3cf 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -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; } diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index 8c19ace79..7c1049e0b 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -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 < 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 (len < 2) + return -1; + prot_ie_count = pos[1]; /* Element Count field in + * MIC Control */ + + 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: diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 4af22bf65..561f926ae 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -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; diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 0192ed090..10bef1a4a 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -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; } diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index 1c27a79bd..372d6872b 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -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; } diff --git a/wlantest/rx_mgmt.c b/wlantest/rx_mgmt.c index 2a9a03058..c649d4de5 100644 --- a/wlantest/rx_mgmt.c +++ b/wlantest/rx_mgmt.c @@ -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;