diff --git a/src/eapol.c b/src/eapol.c index 5a3ef7a0..fce5ff8e 100644 --- a/src/eapol.c +++ b/src/eapol.c @@ -1623,11 +1623,13 @@ static void eapol_handle_ptk_3_of_4(struct eapol_sm *sm, const uint8_t *igtk = NULL; size_t igtk_len; const uint8_t *rsne; + struct ie_rsn_info rsn_info; const uint8_t *optional_rsne = NULL; const uint8_t *transition_disable; size_t transition_disable_len; uint8_t gtk_key_index; uint16_t igtk_key_index; + int r; l_debug("ifindex=%u", hs->ifindex); @@ -1667,20 +1669,26 @@ static void eapol_handle_ptk_3_of_4(struct eapol_sm *sm, if (!rsne) goto error_ie_different; - if (!handshake_util_ap_ie_matches(rsne, hs->authenticator_ie, - hs->wpa_ie)) + if (!hs->wpa_ie) + r = ie_parse_rsne_from_data(rsne, rsne[1] + 2, &rsn_info); + else + r = ie_parse_wpa_from_data(rsne, rsne[1] + 2, &rsn_info); + + if (r < 0) + goto error_ie_different; + + if ((rsne[1] != hs->authenticator_ie[1] || + memcmp(rsne + 2, hs->authenticator_ie + 2, rsne[1])) && + !handshake_util_ap_ie_matches(&rsn_info, + hs->authenticator_ie, + hs->wpa_ie)) goto error_ie_different; if (hs->akm_suite & (IE_RSN_AKM_SUITE_FT_OVER_8021X | IE_RSN_AKM_SUITE_FT_USING_PSK | IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256)) { - struct ie_rsn_info ie_info; - - if (ie_parse_rsne_from_data(rsne, rsne[1] + 2, &ie_info) < 0) - goto error_ie_different; - - if (ie_info.num_pmkids != 1 || memcmp(ie_info.pmkids, + if (rsn_info.num_pmkids != 1 || memcmp(rsn_info.pmkids, hs->pmk_r1_name, 16)) goto error_ie_different; @@ -1727,13 +1735,9 @@ static void eapol_handle_ptk_3_of_4(struct eapol_sm *sm, * RSNE or deauthenticates." */ if (optional_rsne) { - struct ie_rsn_info info1; struct ie_rsn_info info2; uint16_t override; - if (ie_parse_rsne_from_data(rsne, rsne[1] + 2, &info1) < 0) - goto error_ie_different; - if (ie_parse_rsne_from_data(optional_rsne, optional_rsne[1] + 2, &info2) < 0) goto error_ie_different; @@ -1757,14 +1761,14 @@ static void eapol_handle_ptk_3_of_4(struct eapol_sm *sm, * and rsne2 * - Check that rsne2 pairwise_ciphers is a subset of rsne */ - if (info1.akm_suites != info2.akm_suites || - info1.group_cipher != info2.group_cipher) + if (rsn_info.akm_suites != info2.akm_suites || + rsn_info.group_cipher != info2.group_cipher) goto error_ie_different; override = info2.pairwise_ciphers; - if (override == info1.pairwise_ciphers || - !(info1.pairwise_ciphers & override) || + if (override == rsn_info.pairwise_ciphers || + !(rsn_info.pairwise_ciphers & override) || __builtin_popcount(override) != 1) { handshake_failed(sm, MMPDU_REASON_CODE_INVALID_PAIRWISE_CIPHER); diff --git a/src/ft.c b/src/ft.c index 13733019..aafb11fc 100644 --- a/src/ft.c +++ b/src/ft.c @@ -323,7 +323,7 @@ static bool ft_verify_rsne(const uint8_t *rsne, const uint8_t *pmk_r0_name, memcmp(msg2_rsne.pmkids, pmk_r0_name, 16)) return false; - if (!handshake_util_ap_ie_matches(rsne, authenticator_ie, false)) + if (!handshake_util_ap_ie_matches(&msg2_rsne, authenticator_ie, false)) return false; return true; @@ -674,7 +674,8 @@ static int ft_rx_associate(struct auth_proto *ap, const uint8_t *frame, memcmp(msg4_rsne.pmkids, hs->pmk_r1_name, 16)) return -EBADMSG; - if (!handshake_util_ap_ie_matches(rsne, hs->authenticator_ie, + if (!handshake_util_ap_ie_matches(&msg4_rsne, + hs->authenticator_ie, false)) return -EBADMSG; } else { diff --git a/src/handshake.c b/src/handshake.c index 88c89b51..59711ca8 100644 --- a/src/handshake.c +++ b/src/handshake.c @@ -759,90 +759,69 @@ void handshake_state_set_gtk(struct handshake_state *s, const uint8_t *key, * results vs the RSN/WPA IE obtained as part of the 4-way handshake. If they * don't match, the EAPoL packet must be silently discarded. */ -bool handshake_util_ap_ie_matches(const uint8_t *msg_ie, +bool handshake_util_ap_ie_matches(const struct ie_rsn_info *msg_info, const uint8_t *scan_ie, bool is_wpa) { - struct ie_rsn_info msg_info; struct ie_rsn_info scan_info; + int r; - /* - * First check that the sizes match, if they do, run a bitwise - * comparison. - */ - if (msg_ie[1] == scan_ie[1] && - !memcmp(msg_ie + 2, scan_ie + 2, msg_ie[1])) - return true; + if (!is_wpa) + r = ie_parse_rsne_from_data(scan_ie, + scan_ie[1] + 2, &scan_info); + else + r = ie_parse_wpa_from_data(scan_ie, scan_ie[1] + 2, &scan_info); - /* - * Otherwise we have to parse the IEs and compare the individual - * fields - */ - if (!is_wpa) { - if (ie_parse_rsne_from_data(msg_ie, msg_ie[1] + 2, - &msg_info) < 0) - return false; - - if (ie_parse_rsne_from_data(scan_ie, scan_ie[1] + 2, - &scan_info) < 0) - return false; - } else { - if (ie_parse_wpa_from_data(msg_ie, msg_ie[1] + 2, - &msg_info) < 0) - return false; - - if (ie_parse_wpa_from_data(scan_ie, scan_ie[1] + 2, - &scan_info) < 0) - return false; - } - - if (msg_info.group_cipher != scan_info.group_cipher) + if (r < 0) return false; - if (msg_info.pairwise_ciphers != scan_info.pairwise_ciphers) + if (msg_info->group_cipher != scan_info.group_cipher) return false; - if (msg_info.akm_suites != scan_info.akm_suites) + if (msg_info->pairwise_ciphers != scan_info.pairwise_ciphers) return false; - if (msg_info.preauthentication != scan_info.preauthentication) + if (msg_info->akm_suites != scan_info.akm_suites) return false; - if (msg_info.no_pairwise != scan_info.no_pairwise) + if (msg_info->preauthentication != scan_info.preauthentication) return false; - if (msg_info.ptksa_replay_counter != scan_info.ptksa_replay_counter) + if (msg_info->no_pairwise != scan_info.no_pairwise) return false; - if (msg_info.gtksa_replay_counter != scan_info.gtksa_replay_counter) + if (msg_info->ptksa_replay_counter != scan_info.ptksa_replay_counter) return false; - if (msg_info.mfpr != scan_info.mfpr) + if (msg_info->gtksa_replay_counter != scan_info.gtksa_replay_counter) return false; - if (msg_info.mfpc != scan_info.mfpc) + if (msg_info->mfpr != scan_info.mfpr) return false; - if (msg_info.peerkey_enabled != scan_info.peerkey_enabled) + if (msg_info->mfpc != scan_info.mfpc) return false; - if (msg_info.spp_a_msdu_capable != scan_info.spp_a_msdu_capable) + if (msg_info->peerkey_enabled != scan_info.peerkey_enabled) return false; - if (msg_info.spp_a_msdu_required != scan_info.spp_a_msdu_required) + if (msg_info->spp_a_msdu_capable != scan_info.spp_a_msdu_capable) return false; - if (msg_info.pbac != scan_info.pbac) + if (msg_info->spp_a_msdu_required != scan_info.spp_a_msdu_required) return false; - if (msg_info.extended_key_id != scan_info.extended_key_id) + if (msg_info->pbac != scan_info.pbac) return false; - if (msg_info.ocvc != scan_info.ocvc) + if (msg_info->extended_key_id != scan_info.extended_key_id) + return false; + + if (msg_info->ocvc != scan_info.ocvc) return false; /* We don't check the PMKIDs since these might actually be different */ - if (msg_info.group_management_cipher != + if (msg_info->group_management_cipher != scan_info.group_management_cipher) return false; diff --git a/src/handshake.h b/src/handshake.h index e41cc744..fa12faa7 100644 --- a/src/handshake.h +++ b/src/handshake.h @@ -242,7 +242,7 @@ bool handshake_decode_fte_key(struct handshake_state *s, const uint8_t *wrapped, void handshake_state_set_gtk(struct handshake_state *s, const uint8_t *key, unsigned int key_index, const uint8_t *rsc); -bool handshake_util_ap_ie_matches(const uint8_t *msg_ie, +bool handshake_util_ap_ie_matches(const struct ie_rsn_info *msg_info, const uint8_t *scan_ie, bool is_wpa); const uint8_t *handshake_util_find_kde(enum handshake_kde selector,