From 40a42613e6f1e6861bec75b551f6766e31c987d4 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 20 Nov 2022 11:43:53 +0200 Subject: [PATCH] FT: Simplify FTE parsing for FT-SAE-EXT-KEY using MIC Length subfield Commit 25b52e5f83f1 ("FT: Extend FTE parsing for FT-SAE-EXT-KEY") used possible MIC length iteration to try to figure out the length of the MIC field in FTE. That was the only option available at the time, but FTE is now being extended in IEEE 802.11-REVme to explicitly indicate the length of the MIC field for the new FT-SAE-EXT-KEY AKM to make this easier. Use the new design from the approved comment resolution (*) in REVme/D2.0 ballot CID 3135 to simplify implementation. This gets rid of the need to pass in key length and the somewhat strange need_{r0kh,r1kh} parameters to wpa_ft_parse_ies(). (*) https://mentor.ieee.org/802.11/dcn/22/11-22-1991-02-000m-proposed-resolutions-to-some-lb270-comments.docx Signed-off-by: Jouni Malinen --- src/ap/wpa_auth_ft.c | 19 +++++----- src/common/wpa_common.c | 80 +++++++++++++++++------------------------ src/common/wpa_common.h | 15 ++++++-- src/rsn_supp/wpa.c | 3 +- src/rsn_supp/wpa_ft.c | 25 +++++++------ wlantest/rx_mgmt.c | 14 ++++---- 6 files changed, 75 insertions(+), 81 deletions(-) diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index e5d3b6aff..91e4a2560 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -814,6 +814,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int key_mgmt, size_t key_len, { u8 *pos = buf, *ielen; size_t hdrlen; + u16 mic_control = rsnxe_used ? FTE_MIC_CTRL_RSNXE_USED : 0; if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && key_len == SHA256_MAC_LEN) @@ -842,7 +843,8 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int key_mgmt, size_t key_len, os_memset(hdr, 0, sizeof(*hdr)); pos += sizeof(*hdr); - WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used); + mic_control |= FTE_MIC_LEN_32 << FTE_MIC_CTRL_MIC_LEN_SHIFT; + WPA_PUT_LE16(hdr->mic_control, mic_control); if (anonce) os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN); if (snonce) @@ -854,7 +856,8 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int key_mgmt, size_t key_len, os_memset(hdr, 0, sizeof(*hdr)); pos += sizeof(*hdr); - WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used); + mic_control |= FTE_MIC_LEN_24 << FTE_MIC_CTRL_MIC_LEN_SHIFT; + WPA_PUT_LE16(hdr->mic_control, mic_control); if (anonce) os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN); if (snonce) @@ -864,7 +867,8 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int key_mgmt, size_t key_len, os_memset(hdr, 0, sizeof(*hdr)); pos += sizeof(*hdr); - WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used); + mic_control |= FTE_MIC_LEN_16 << FTE_MIC_CTRL_MIC_LEN_SHIFT; + WPA_PUT_LE16(hdr->mic_control, mic_control); if (anonce) os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN); if (snonce) @@ -2788,8 +2792,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, sm->wpa_key_mgmt, - key_len, false, false) == 0 && parse.ric) { + if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse, + sm->wpa_key_mgmt) == 0 && parse.ric) { pos = wpa_ft_process_ric(sm, pos, end, parse.ric, parse.ric_len); if (auth_alg == WLAN_AUTH_FT) @@ -3165,7 +3169,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, 0, 0, false, false)) { + if (wpa_ft_parse_ies(ies, ies_len, &parse, 0)) { wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs"); return WLAN_STATUS_UNSPECIFIED_FAILURE; } @@ -3463,8 +3467,7 @@ 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, sm->wpa_key_mgmt, - sm->pmk_r1_len, true, true) < 0) { + if (wpa_ft_parse_ies(ies, ies_len, &parse, sm->wpa_key_mgmt) < 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 9f3ebd50a..32e37468d 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -1090,19 +1090,46 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, } -static int wpa_ft_parse_fte(const u8 *ie, size_t len, size_t mic_len, +static int wpa_ft_parse_fte(int key_mgmt, const u8 *ie, size_t len, struct wpa_ft_ies *parse) { + size_t mic_len; + u8 mic_len_info; 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_rsnxe_used = pos[0] & FTE_MIC_CTRL_RSNXE_USED; + mic_len_info = (pos[0] & FTE_MIC_CTRL_MIC_LEN_MASK) >> + FTE_MIC_CTRL_MIC_LEN_SHIFT; parse->fte_elem_count = pos[1]; pos += 2; - if (mic_len > (size_t) (end - pos)) + if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) { + switch (mic_len_info) { + case FTE_MIC_LEN_16: + mic_len = 16; + break; + case FTE_MIC_LEN_24: + mic_len = 24; + break; + case FTE_MIC_LEN_32: + mic_len = 32; + break; + default: + wpa_printf(MSG_DEBUG, + "FT: Unknown MIC Length subfield value %u", + mic_len_info); + return -1; + } + } else { + mic_len = wpa_key_mgmt_sha384(key_mgmt) ? 24 : 16; + } + if (mic_len > (size_t) (end - pos)) { + wpa_printf(MSG_DEBUG, "FT: No room for %zu octet MIC in FTE", + mic_len); return -1; + } wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC", pos, mic_len); parse->fte_mic = pos; parse->fte_mic_len = mic_len; @@ -1124,8 +1151,7 @@ static int wpa_ft_parse_fte(const u8 *ie, size_t len, size_t mic_len, 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) + int key_mgmt) { const u8 *end, *pos; struct wpa_ie_data data; @@ -1195,49 +1221,7 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse, 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 (wpa_ft_parse_fte(pos, len, 16, parse) < 0) + if (wpa_ft_parse_fte(key_mgmt, pos, len, 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 acb975ce5..05b1a8a05 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -186,6 +186,18 @@ WPA_CIPHER_BIP_CMAC_256) #define FT_R1KH_ID_LEN 6 #define WPA_PMK_NAME_LEN 16 +/* FTE - MIC Control - RSNXE Used */ +#define FTE_MIC_CTRL_RSNXE_USED BIT(0) +#define FTE_MIC_CTRL_MIC_LEN_MASK (BIT(1) | BIT(2) | BIT(3)) +#define FTE_MIC_CTRL_MIC_LEN_SHIFT 1 + +/* FTE - MIC Length subfield values */ +enum ft_mic_len_subfield { + FTE_MIC_LEN_16 = 0, + FTE_MIC_LEN_24 = 1, + FTE_MIC_LEN_32 = 2, +}; + /* IEEE 802.11, 8.5.2 EAPOL-Key frames */ #define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2))) @@ -612,8 +624,7 @@ 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 key_mgmt, size_t key_len, bool need_r0kh_id, - bool need_r1kh_id); + int key_mgmt); struct wpa_eapol_ie_parse { const u8 *wpa_ie; diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 889bb0fc5..689db834b 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -5196,8 +5196,7 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data, } if (wpa_ft_parse_ies(pos, end - pos, &parse, - sm->key_mgmt, sm->xxkey_len, true, - true) < 0) { + sm->key_mgmt) < 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 fdf921d5d..eca09f7f4 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -127,8 +127,7 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) return 0; } - if (wpa_ft_parse_ies(ies, ies_len, &ft, sm->key_mgmt, - sm->xxkey_len, false, false) < 0) + if (wpa_ft_parse_ies(ies, ies_len, &ft, sm->key_mgmt) < 0) return -1; if (ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) @@ -217,6 +216,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, size_t rsnxe_len; int rsnxe_used; int res; + u8 mic_control; sm->ft_completed = 0; sm->ft_reassoc_completed = 0; @@ -348,12 +348,14 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, rsnxe_used); } #endif /* CONFIG_TESTING_OPTIONS */ + mic_control = rsnxe_used ? FTE_MIC_CTRL_RSNXE_USED : 0; if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && sm->pmk_r0_len == SHA512_MAC_LEN) { struct rsn_ftie_sha512 *ftie; ftie = (struct rsn_ftie_sha512 *) pos; - ftie->mic_control[0] = !!rsnxe_used; + mic_control |= FTE_MIC_LEN_32 << FTE_MIC_CTRL_MIC_LEN_SHIFT; + ftie->mic_control[0] = mic_control; fte_mic = ftie->mic; elem_count = &ftie->mic_control[1]; pos += sizeof(*ftie); @@ -366,7 +368,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, struct rsn_ftie_sha384 *ftie; ftie = (struct rsn_ftie_sha384 *) pos; - ftie->mic_control[0] = !!rsnxe_used; + mic_control |= FTE_MIC_LEN_24 << FTE_MIC_CTRL_MIC_LEN_SHIFT; + ftie->mic_control[0] = mic_control; fte_mic = ftie->mic; elem_count = &ftie->mic_control[1]; pos += sizeof(*ftie); @@ -377,7 +380,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, struct rsn_ftie *ftie; ftie = (struct rsn_ftie *) pos; - ftie->mic_control[0] = !!rsnxe_used; + mic_control |= FTE_MIC_LEN_16 << FTE_MIC_CTRL_MIC_LEN_SHIFT; + ftie->mic_control[0] = mic_control; fte_mic = ftie->mic; elem_count = &ftie->mic_control[1]; pos += sizeof(*ftie); @@ -584,7 +588,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, key_len; + size_t kck_len, kdk_len; wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len); @@ -610,11 +614,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, return -1; } - 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) { + if (wpa_ft_parse_ies(ies, ies_len, &parse, sm->key_mgmt) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); return -1; } @@ -1032,8 +1032,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, return 0; } - if (wpa_ft_parse_ies(ies, ies_len, &parse, sm->key_mgmt, - sm->xxkey_len, true, true) < 0) { + if (wpa_ft_parse_ies(ies, ies_len, &parse, sm->key_mgmt) < 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 2a32510f1..49813ce78 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, 0, 0, false, false)) { + &parse, 0)) { add_note(wt, MSG_INFO, "Could not parse FT Authentication Response frame"); return; @@ -829,7 +829,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, false, false) == 0) { + if (wpa_ft_parse_ies(ies, ies_len, &parse, 0) == 0) { if (parse.r0kh_id) { os_memcpy(bss->r0kh_id, parse.r0kh_id, parse.r0kh_id_len); @@ -925,8 +925,7 @@ 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, sta->key_mgmt, - 0, false, false) < 0) { + if (wpa_ft_parse_ies(ie, ie_len, &parse, sta->key_mgmt) < 0) { add_note(wt, MSG_INFO, "FT: Failed to parse FT IEs"); return; } @@ -1419,8 +1418,7 @@ 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, sta->key_mgmt, - 0, false, false) < 0) { + if (wpa_ft_parse_ies(ies, ies_len, &parse, sta->key_mgmt) < 0) { add_note(wt, MSG_INFO, "FT: Failed to parse FT IEs"); return; } @@ -1730,7 +1728,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, 0, 0, false, false)) { + if (wpa_ft_parse_ies(ies, ies_len, &parse, 0)) { add_note(wt, MSG_INFO, "Could not parse FT Request frame body"); return; } @@ -1779,7 +1777,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, 0, 0, false, false)) { + if (wpa_ft_parse_ies(ies, ies_len, &parse, 0)) { add_note(wt, MSG_INFO, "Could not parse FT Response frame body"); return;