FT: Fix FT 4-Way Handshake to include PMKR1Name in messages 2 and 3
IEEE Std 802.11r-2008, 11A.4.2 describes FT initial mobility domain association in an RSN to include PMKR1Name in the PMKID-List field in RSN IE in messages 2/4 and 3/4. This makes the RSN IE not be bitwise identical with the values used in Beacon, Probe Response, (Re)association Request frames. The previous versions of wpa_supplicant and hostapd did not add the PMKR1Name value in EAPOL-Key frame and did not accept it if added (due to bitwise comparison of RSN IEs). This commit fixes the implementation to be compliant with the standard by adding the PMKR1Name value into EAPOL-Key messages during FT 4-Way Handshake and by verifying that the received value matches with the value derived locally. This breaks interoperability with previous wpa_supplicant/hostapd versions.
This commit is contained in:
parent
738a1cb286
commit
26e23750b9
7 changed files with 247 additions and 14 deletions
|
@ -609,6 +609,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
|
|||
SMK_M1, SMK_M3, SMK_ERROR } msg;
|
||||
char *msgtxt;
|
||||
struct wpa_eapol_ie_parse kde;
|
||||
int ft;
|
||||
|
||||
if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
|
||||
return;
|
||||
|
@ -739,9 +740,12 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
|
|||
sm->wpa_ptk_state);
|
||||
return;
|
||||
}
|
||||
ft = sm->wpa == WPA_VERSION_WPA2 &&
|
||||
wpa_key_mgmt_ft(sm->wpa_key_mgmt);
|
||||
if (sm->wpa_ie == NULL ||
|
||||
sm->wpa_ie_len != key_data_length ||
|
||||
os_memcmp(sm->wpa_ie, key + 1, key_data_length) != 0) {
|
||||
wpa_compare_rsn_ie(ft,
|
||||
sm->wpa_ie, sm->wpa_ie_len,
|
||||
(u8 *) (key + 1), key_data_length)) {
|
||||
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
|
||||
"WPA IE from (Re)AssocReq did not "
|
||||
"match with msg 2/4");
|
||||
|
@ -755,6 +759,22 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
|
|||
wpa_sta_disconnect(wpa_auth, sm->addr);
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (ft) {
|
||||
struct wpa_ie_data ie;
|
||||
if (wpa_parse_wpa_ie_rsn((u8 *) (key + 1),
|
||||
key_data_length, &ie) < 0 ||
|
||||
ie.num_pmkid != 1 || ie.pmkid == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
|
||||
"FT 4-way handshake message 2/4");
|
||||
wpa_sta_disconnect(wpa_auth, sm->addr);
|
||||
return;
|
||||
}
|
||||
os_memcpy(sm->sup_pmk_r1_name, ie.pmkid, PMKID_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Supplicant",
|
||||
sm->sup_pmk_r1_name, PMKID_LEN);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
break;
|
||||
case PAIRWISE_4:
|
||||
if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
|
||||
|
@ -1487,6 +1507,27 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
|
||||
/*
|
||||
* Verify that PMKR1Name from EAPOL-Key message 2/4 matches
|
||||
* with the value we derived.
|
||||
*/
|
||||
if (os_memcmp(sm->sup_pmk_r1_name, sm->pmk_r1_name,
|
||||
WPA_PMK_NAME_LEN) != 0) {
|
||||
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"PMKR1Name mismatch in FT 4-way "
|
||||
"handshake");
|
||||
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from "
|
||||
"Supplicant",
|
||||
sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
|
||||
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
|
||||
|
||||
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
|
||||
|
@ -1611,6 +1652,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
|
|||
kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
|
||||
if (gtk)
|
||||
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
|
||||
kde_len += 2 + PMKID_LEN;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
kde = os_malloc(kde_len);
|
||||
if (kde == NULL)
|
||||
return;
|
||||
|
@ -1618,6 +1663,18 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
|
|||
pos = kde;
|
||||
os_memcpy(pos, wpa_ie, wpa_ie_len);
|
||||
pos += wpa_ie_len;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
|
||||
int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_ERROR, "FT: Failed to insert "
|
||||
"PMKR1Name into RSN IE in EAPOL-Key data");
|
||||
os_free(kde);
|
||||
return;
|
||||
}
|
||||
pos += res;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
if (gtk) {
|
||||
u8 hdr[2];
|
||||
hdr[0] = keyidx & 0x03;
|
||||
|
|
|
@ -356,7 +356,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
|
|||
struct wpa_ptk *ptk, size_t ptk_len)
|
||||
{
|
||||
u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
|
||||
u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
|
||||
u8 pmk_r1[PMK_LEN];
|
||||
u8 ptk_name[WPA_PMK_NAME_LEN];
|
||||
const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
|
||||
const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
|
||||
|
@ -380,14 +380,15 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
|
|||
sm->pairwise);
|
||||
|
||||
wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
|
||||
pmk_r1, pmk_r1_name);
|
||||
pmk_r1, sm->pmk_r1_name);
|
||||
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
|
||||
wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_name,
|
||||
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
|
||||
WPA_PMK_NAME_LEN);
|
||||
wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
|
||||
sm->pairwise);
|
||||
|
||||
wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
|
||||
sm->wpa_auth->addr, pmk_r1_name,
|
||||
sm->wpa_auth->addr, sm->pmk_r1_name,
|
||||
(u8 *) ptk, ptk_len, ptk_name);
|
||||
wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
|
||||
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
|
||||
|
|
|
@ -116,6 +116,8 @@ struct wpa_state_machine {
|
|||
* Request */
|
||||
u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */
|
||||
size_t r0kh_id_len;
|
||||
u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key
|
||||
* message 2/4 */
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue