FT: FTE parsing for SHA384-based AKM

The MIC field is now a variable length field, so make the FTE parser
aware of the two different field lengths.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2018-06-04 15:16:54 +03:00
parent 8c2715b358
commit 9a33737a0b
6 changed files with 190 additions and 60 deletions

View File

@ -2317,10 +2317,12 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
u8 *anonce, *snonce; u8 *anonce, *snonce;
const u8 *kck; const u8 *kck;
size_t kck_len; size_t kck_len;
int use_sha384;
if (sm == NULL) if (sm == NULL)
return pos; return pos;
use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
conf = &sm->wpa_auth->conf; conf = &sm->wpa_auth->conf;
if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt)) if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt))
@ -2398,7 +2400,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
_ftie->mic_control[1] = 3; /* Information element count */ _ftie->mic_control[1] = 3; /* Information element count */
ric_start = pos; ric_start = pos;
if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) { if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse, use_sha384) == 0
&& parse.ric) {
pos = wpa_ft_process_ric(sm, pos, end, parse.ric, pos = wpa_ft_process_ric(sm, pos, end, parse.ric,
parse.ric_len); parse.ric_len);
if (auth_alg == WLAN_AUTH_FT) if (auth_alg == WLAN_AUTH_FT)
@ -2683,7 +2686,6 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
u8 **resp_ies, size_t *resp_ies_len) u8 **resp_ies, size_t *resp_ies_len)
{ {
struct rsn_mdie *mdie; struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
u8 pmk_r1[PMK_LEN_MAX], pmk_r1_name[WPA_PMK_NAME_LEN]; u8 pmk_r1[PMK_LEN_MAX], pmk_r1_name[WPA_PMK_NAME_LEN];
u8 ptk_name[WPA_PMK_NAME_LEN]; u8 ptk_name[WPA_PMK_NAME_LEN];
struct wpa_auth_config *conf; struct wpa_auth_config *conf;
@ -2695,8 +2697,8 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
struct vlan_description vlan; struct vlan_description vlan;
const u8 *identity, *radius_cui; const u8 *identity, *radius_cui;
size_t identity_len = 0, radius_cui_len = 0; size_t identity_len = 0, radius_cui_len = 0;
int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt); int use_sha384;
size_t pmk_r1_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN; size_t pmk_r1_len;
*resp_ies = NULL; *resp_ies = NULL;
*resp_ies_len = 0; *resp_ies_len = 0;
@ -2707,10 +2709,12 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs", wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
ies, ies_len); ies, ies_len);
if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { if (wpa_ft_parse_ies(ies, ies_len, &parse, -1)) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs"); wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
return WLAN_STATUS_UNSPECIFIED_FAILURE; return WLAN_STATUS_UNSPECIFIED_FAILURE;
} }
use_sha384 = wpa_key_mgmt_sha384(parse.key_mgmt);
pmk_r1_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
mdie = (struct rsn_mdie *) parse.mdie; mdie = (struct rsn_mdie *) parse.mdie;
if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
@ -2721,13 +2725,27 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
return WLAN_STATUS_INVALID_MDIE; return WLAN_STATUS_INVALID_MDIE;
} }
ftie = (struct rsn_ftie *) parse.ftie; if (use_sha384) {
if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { struct rsn_ftie_sha384 *ftie;
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
return WLAN_STATUS_INVALID_FTIE;
}
os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN); ftie = (struct rsn_ftie_sha384 *) parse.ftie;
if (!ftie || parse.ftie_len < sizeof(*ftie)) {
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
return WLAN_STATUS_INVALID_FTIE;
}
os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
} else {
struct rsn_ftie *ftie;
ftie = (struct rsn_ftie *) parse.ftie;
if (!ftie || parse.ftie_len < sizeof(*ftie)) {
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
return WLAN_STATUS_INVALID_FTIE;
}
os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
}
if (parse.r0kh_id == NULL) { if (parse.r0kh_id == NULL) {
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID"); wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID");
@ -2917,19 +2935,23 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
{ {
struct wpa_ft_ies parse; struct wpa_ft_ies parse;
struct rsn_mdie *mdie; struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN]; u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
size_t mic_len = 16; size_t mic_len = 16;
unsigned int count; unsigned int count;
const u8 *kck; const u8 *kck;
size_t kck_len; size_t kck_len;
int use_sha384;
const u8 *anonce, *snonce, *fte_mic;
u8 fte_elem_count;
if (sm == NULL) if (sm == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE; return WLAN_STATUS_UNSPECIFIED_FAILURE;
use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len); wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs"); wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
return WLAN_STATUS_UNSPECIFIED_FAILURE; return WLAN_STATUS_UNSPECIFIED_FAILURE;
} }
@ -2960,25 +2982,47 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_INVALID_MDIE; return WLAN_STATUS_INVALID_MDIE;
} }
ftie = (struct rsn_ftie *) parse.ftie; if (use_sha384) {
if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { struct rsn_ftie_sha384 *ftie;
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
return WLAN_STATUS_INVALID_FTIE; ftie = (struct rsn_ftie_sha384 *) parse.ftie;
if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
return WLAN_STATUS_INVALID_FTIE;
}
anonce = ftie->anonce;
snonce = ftie->snonce;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
} else {
struct rsn_ftie *ftie;
ftie = (struct rsn_ftie *) parse.ftie;
if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
return WLAN_STATUS_INVALID_FTIE;
}
anonce = ftie->anonce;
snonce = ftie->snonce;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
} }
if (os_memcmp(ftie->snonce, sm->SNonce, WPA_NONCE_LEN) != 0) { if (os_memcmp(snonce, sm->SNonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
ftie->snonce, WPA_NONCE_LEN); snonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
sm->SNonce, WPA_NONCE_LEN); sm->SNonce, WPA_NONCE_LEN);
return WLAN_STATUS_INVALID_FTIE; return WLAN_STATUS_INVALID_FTIE;
} }
if (os_memcmp(ftie->anonce, sm->ANonce, WPA_NONCE_LEN) != 0) { if (os_memcmp(anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE"); wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received ANonce", wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
ftie->anonce, WPA_NONCE_LEN); anonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce", wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
sm->ANonce, WPA_NONCE_LEN); sm->ANonce, WPA_NONCE_LEN);
return WLAN_STATUS_INVALID_FTIE; return WLAN_STATUS_INVALID_FTIE;
@ -3029,10 +3073,10 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
count = 3; count = 3;
if (parse.ric) if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len); count += ieee802_11_ie_count(parse.ric, parse.ric_len);
if (ftie->mic_control[1] != count) { if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u", "Control: received %u expected %u",
ftie->mic_control[1], count); fte_elem_count, count);
return WLAN_STATUS_UNSPECIFIED_FAILURE; return WLAN_STATUS_UNSPECIFIED_FAILURE;
} }
@ -3053,12 +3097,12 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_UNSPECIFIED_FAILURE; return WLAN_STATUS_UNSPECIFIED_FAILURE;
} }
if (os_memcmp_const(mic, ftie->mic, mic_len) != 0) { if (os_memcmp_const(mic, fte_mic, mic_len) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE"); wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR, wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr)); MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC",
ftie->mic, mic_len); fte_mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, mic_len); wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "FT: MDIE", wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
parse.mdie - 2, parse.mdie_len + 2); parse.mdie - 2, parse.mdie_len + 2);

View File

@ -828,23 +828,27 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
struct wpa_ft_ies *parse) struct wpa_ft_ies *parse, int use_sha384)
{ {
const u8 *end, *pos; const u8 *end, *pos;
parse->ftie = ie; parse->ftie = ie;
parse->ftie_len = ie_len; parse->ftie_len = ie_len;
pos = ie + sizeof(struct rsn_ftie); pos = ie + (use_sha384 ? sizeof(struct rsn_ftie_sha384) :
sizeof(struct rsn_ftie));
end = ie + ie_len; end = ie + ie_len;
wpa_hexdump(MSG_DEBUG, "FT: Parse FTE subelements", pos, end - pos);
while (end - pos >= 2) { while (end - pos >= 2) {
u8 id, len; u8 id, len;
id = *pos++; id = *pos++;
len = *pos++; len = *pos++;
if (len > end - pos) if (len > end - pos) {
wpa_printf(MSG_DEBUG, "FT: Truncated subelement");
break; break;
}
switch (id) { switch (id) {
case FTIE_SUBELEM_R1KH_ID: case FTIE_SUBELEM_R1KH_ID:
@ -876,6 +880,9 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
parse->igtk_len = len; parse->igtk_len = len;
break; break;
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */
default:
wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
break;
} }
pos += len; pos += len;
@ -886,13 +893,19 @@ 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, int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
struct wpa_ft_ies *parse) struct wpa_ft_ies *parse, int use_sha384)
{ {
const u8 *end, *pos; const u8 *end, *pos;
struct wpa_ie_data data; struct wpa_ie_data data;
int ret; int ret;
const struct rsn_ftie *ftie; const struct rsn_ftie *ftie;
int prot_ie_count = 0; 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)); os_memset(parse, 0, sizeof(*parse));
if (ies == NULL) if (ies == NULL)
@ -924,6 +937,11 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
parse->rsn_pmkid = data.pmkid; parse->rsn_pmkid = data.pmkid;
parse->key_mgmt = data.key_mgmt; parse->key_mgmt = data.key_mgmt;
parse->pairwise_cipher = data.pairwise_cipher; parse->pairwise_cipher = data.pairwise_cipher;
if (update_use_sha384) {
use_sha384 =
wpa_key_mgmt_sha384(parse->key_mgmt);
update_use_sha384 = 0;
}
break; break;
case WLAN_EID_MOBILITY_DOMAIN: case WLAN_EID_MOBILITY_DOMAIN:
if (len < sizeof(struct rsn_mdie)) if (len < sizeof(struct rsn_mdie))
@ -932,11 +950,24 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
parse->mdie_len = len; parse->mdie_len = len;
break; break;
case WLAN_EID_FAST_BSS_TRANSITION: case WLAN_EID_FAST_BSS_TRANSITION:
if (use_sha384) {
const struct rsn_ftie_sha384 *ftie_sha384;
if (len < sizeof(*ftie_sha384))
return -1;
ftie_sha384 =
(const struct rsn_ftie_sha384 *) pos;
prot_ie_count = ftie_sha384->mic_control[1];
if (wpa_ft_parse_ftie(pos, len, parse, 1) < 0)
return -1;
break;
}
if (len < sizeof(*ftie)) if (len < sizeof(*ftie))
return -1; return -1;
ftie = (const struct rsn_ftie *) pos; ftie = (const struct rsn_ftie *) pos;
prot_ie_count = ftie->mic_control[1]; prot_ie_count = ftie->mic_control[1];
if (wpa_ft_parse_ftie(pos, len, parse) < 0) if (wpa_ft_parse_ftie(pos, len, parse, 0) < 0)
return -1; return -1;
break; break;
case WLAN_EID_TIMEOUT_INTERVAL: case WLAN_EID_TIMEOUT_INTERVAL:

View File

@ -314,6 +314,14 @@ struct rsn_ftie {
/* followed by optional parameters */ /* followed by optional parameters */
} STRUCT_PACKED; } STRUCT_PACKED;
struct rsn_ftie_sha384 {
u8 mic_control[2];
u8 mic[24];
u8 anonce[WPA_NONCE_LEN];
u8 snonce[WPA_NONCE_LEN];
/* followed by optional parameters */
} STRUCT_PACKED;
#define FTIE_SUBELEM_R1KH_ID 1 #define FTIE_SUBELEM_R1KH_ID 1
#define FTIE_SUBELEM_GTK 2 #define FTIE_SUBELEM_GTK 2
#define FTIE_SUBELEM_R0KH_ID 3 #define FTIE_SUBELEM_R0KH_ID 3
@ -449,7 +457,8 @@ struct wpa_ft_ies {
int pairwise_cipher; int pairwise_cipher;
}; };
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse); int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
int use_sha384);
int wpa_cipher_key_len(int cipher); int wpa_cipher_key_len(int cipher);
int wpa_cipher_rsc_len(int cipher); int wpa_cipher_rsc_len(int cipher);

View File

@ -3547,7 +3547,8 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
goto fail; goto fail;
} }
if (wpa_ft_parse_ies(pos, end - pos, &parse) < 0) { if (wpa_ft_parse_ies(pos, end - pos, &parse,
wpa_key_mgmt_sha384(sm->key_mgmt)) < 0) {
wpa_printf(MSG_DEBUG, "FILS+FT: Failed to parse IEs"); wpa_printf(MSG_DEBUG, "FILS+FT: Failed to parse IEs");
goto fail; goto fail;
} }

View File

@ -65,11 +65,13 @@ 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) int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
{ {
struct wpa_ft_ies ft; struct wpa_ft_ies ft;
int use_sha384;
if (sm == NULL) if (sm == NULL)
return 0; return 0;
if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0) use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
if (wpa_ft_parse_ies(ies, ies_len, &ft, use_sha384) < 0)
return -1; return -1;
if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
@ -423,12 +425,13 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
size_t ft_ies_len; size_t ft_ies_len;
struct wpa_ft_ies parse; struct wpa_ft_ies parse;
struct rsn_mdie *mdie; struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
u8 ptk_name[WPA_PMK_NAME_LEN]; u8 ptk_name[WPA_PMK_NAME_LEN];
int ret; int ret;
const u8 *bssid; const u8 *bssid;
const u8 *kck; const u8 *kck;
size_t kck_len; size_t kck_len;
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
const u8 *anonce, *snonce;
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len); wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len);
@ -454,7 +457,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
return -1; return -1;
} }
if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
return -1; return -1;
} }
@ -467,16 +470,34 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
return -1; return -1;
} }
ftie = (struct rsn_ftie *) parse.ftie; if (use_sha384) {
if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { struct rsn_ftie_sha384 *ftie;
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
return -1; ftie = (struct rsn_ftie_sha384 *) parse.ftie;
if (!ftie || parse.ftie_len < sizeof(*ftie)) {
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
return -1;
}
anonce = ftie->anonce;
snonce = ftie->snonce;
} else {
struct rsn_ftie *ftie;
ftie = (struct rsn_ftie *) parse.ftie;
if (!ftie || parse.ftie_len < sizeof(*ftie)) {
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
return -1;
}
anonce = ftie->anonce;
snonce = ftie->snonce;
} }
if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { if (os_memcmp(snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
ftie->snonce, WPA_NONCE_LEN); snonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
sm->snonce, WPA_NONCE_LEN); sm->snonce, WPA_NONCE_LEN);
return -1; return -1;
@ -515,8 +536,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN); os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN); wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN);
os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN); os_memcpy(sm->anonce, anonce, WPA_NONCE_LEN);
if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name, if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
sm->r1kh_id, sm->own_addr, sm->pmk_r1, sm->r1kh_id, sm->own_addr, sm->pmk_r1,
sm->pmk_r1_name) < 0) sm->pmk_r1_name) < 0)
@ -528,7 +549,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
bssid = target_ap; bssid = target_ap;
if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce,
ftie->anonce, sm->own_addr, bssid, anonce, sm->own_addr, bssid,
sm->pmk_r1_name, &sm->ptk, ptk_name, sm->key_mgmt, sm->pmk_r1_name, &sm->ptk, ptk_name, sm->key_mgmt,
sm->pairwise_cipher) < 0) sm->pairwise_cipher) < 0)
return -1; return -1;
@ -540,7 +561,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
kck = sm->ptk.kck; kck = sm->ptk.kck;
kck_len = sm->ptk.kck_len; kck_len = sm->ptk.kck_len;
} }
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce, ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, anonce,
sm->pmk_r1_name, sm->pmk_r1_name,
kck, kck_len, bssid, kck, kck_len, bssid,
ric_ies, ric_ies_len, ric_ies, ric_ies_len,
@ -731,11 +752,13 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
{ {
struct wpa_ft_ies parse; struct wpa_ft_ies parse;
struct rsn_mdie *mdie; struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
unsigned int count; unsigned int count;
u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN]; u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
const u8 *kck; const u8 *kck;
size_t kck_len; size_t kck_len;
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
const u8 *anonce, *snonce, *fte_mic;
u8 fte_elem_count;
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
@ -750,7 +773,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return 0; return 0;
} }
if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
return -1; return -1;
} }
@ -763,25 +786,47 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1; return -1;
} }
ftie = (struct rsn_ftie *) parse.ftie; if (use_sha384) {
if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { struct rsn_ftie_sha384 *ftie;
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
return -1; ftie = (struct rsn_ftie_sha384 *) parse.ftie;
if (!ftie || parse.ftie_len < sizeof(*ftie)) {
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
return -1;
}
anonce = ftie->anonce;
snonce = ftie->snonce;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
} else {
struct rsn_ftie *ftie;
ftie = (struct rsn_ftie *) parse.ftie;
if (!ftie || parse.ftie_len < sizeof(*ftie)) {
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
return -1;
}
anonce = ftie->anonce;
snonce = ftie->snonce;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
} }
if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { if (os_memcmp(snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
ftie->snonce, WPA_NONCE_LEN); snonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
sm->snonce, WPA_NONCE_LEN); sm->snonce, WPA_NONCE_LEN);
return -1; return -1;
} }
if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) { if (os_memcmp(anonce, sm->anonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE"); wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received ANonce", wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
ftie->anonce, WPA_NONCE_LEN); anonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce", wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
sm->anonce, WPA_NONCE_LEN); sm->anonce, WPA_NONCE_LEN);
return -1; return -1;
@ -826,10 +871,10 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
count = 3; count = 3;
if (parse.ric) if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len); count += ieee802_11_ie_count(parse.ric, parse.ric_len);
if (ftie->mic_control[1] != count) { if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u", "Control: received %u expected %u",
ftie->mic_control[1], count); fte_elem_count, count);
return -1; return -1;
} }
@ -851,9 +896,9 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1; return -1;
} }
if (os_memcmp_const(mic, ftie->mic, 16) != 0) { if (os_memcmp_const(mic, fte_mic, 16) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE"); wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16); wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", fte_mic, 16);
wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16); wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
return -1; return -1;
} }

View File

@ -656,7 +656,7 @@ static void rx_mgmt_assoc_resp(struct wlantest *wt, const u8 *data, size_t len)
sta->state = STATE3; sta->state = STATE3;
} }
if (wpa_ft_parse_ies(ies, ies_len, &parse) == 0) { if (wpa_ft_parse_ies(ies, ies_len, &parse, 0) == 0) {
if (parse.r0kh_id) { if (parse.r0kh_id) {
os_memcpy(bss->r0kh_id, parse.r0kh_id, os_memcpy(bss->r0kh_id, parse.r0kh_id,
parse.r0kh_id_len); parse.r0kh_id_len);