FT: Extend FTE parsing for FT-SAE-EXT-KEY

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>
This commit is contained in:
Jouni Malinen 2022-10-16 16:38:27 +03:00 committed by Jouni Malinen
parent 4f58afee9a
commit 25b52e5f83
6 changed files with 122 additions and 72 deletions

View 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;
}

View 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 < sizeof(*ftie_sha384))
if (len < 2)
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)
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:

View 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;

View 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;
}

View 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;
}

View 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;