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:
parent
8c2715b358
commit
9a33737a0b
6 changed files with 190 additions and 60 deletions
|
@ -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);
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue