From 9d94e4bb6bbbcd9db336c82ac477b81644aff546 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 23 Mar 2018 17:45:44 +0200 Subject: [PATCH] SAE: Fix PMKID in EAPOL-Key msg 1/4 Previously, the association that used SAE authentication ended up recalculating the PMKID for EAPOL-Key msg 1/4 using incorrect PMK-to-PMKID derivation instead of using the previously derived PMKID from SAE. The correct PMKID was used only when going through PMKSA caching exchange with a previously derived PMKSA from SAE. Fix this by storing the SAE PMKID into the state machine entry for the initial SAE authentication case when there is no explicit PMKSA entry attached to the station. Signed-off-by: Jouni Malinen --- src/ap/ieee802_11.c | 4 ++++ src/ap/wpa_auth.c | 30 ++++++++++++++++++++++++++++++ src/ap/wpa_auth.h | 1 + src/ap/wpa_auth_i.h | 2 ++ 4 files changed, 37 insertions(+) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 71b6c4366..68bc33303 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -2538,6 +2538,10 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, #endif /* CONFIG_IEEE80211R_AP */ #ifdef CONFIG_SAE + if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae && + sta->sae->state == SAE_ACCEPTED) + wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid); + if (wpa_auth_uses_sae(sta->wpa_sm) && sta->auth_alg == WLAN_AUTH_OPEN) { struct rsn_pmksa_cache_entry *sa; diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 203329eeb..8dde1d0aa 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -2035,11 +2035,31 @@ SM_STATE(WPA_PTK, PTKSTART) pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN; RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID); if (sm->pmksa) { + wpa_hexdump(MSG_DEBUG, + "RSN: Message 1/4 PMKID from PMKSA entry", + sm->pmksa->pmkid, PMKID_LEN); os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN], sm->pmksa->pmkid, PMKID_LEN); } else if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt)) { /* No KCK available to derive PMKID */ + wpa_printf(MSG_DEBUG, + "RSN: No KCK available to derive PMKID for message 1/4"); pmkid = NULL; +#ifdef CONFIG_SAE + } else if (wpa_key_mgmt_sae(sm->wpa_key_mgmt)) { + if (sm->pmkid_set) { + wpa_hexdump(MSG_DEBUG, + "RSN: Message 1/4 PMKID from SAE", + sm->pmkid, PMKID_LEN); + os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN], + sm->pmkid, PMKID_LEN); + } else { + /* No PMKID available */ + wpa_printf(MSG_DEBUG, + "RSN: No SAE PMKID available for message 1/4"); + pmkid = NULL; + } +#endif /* CONFIG_SAE */ } else { /* * Calculate PMKID since no PMKSA cache entry was @@ -2048,6 +2068,9 @@ SM_STATE(WPA_PTK, PTKSTART) rsn_pmkid(sm->PMK, sm->pmk_len, sm->wpa_auth->addr, sm->addr, &pmkid[2 + RSN_SELECTOR_LEN], sm->wpa_key_mgmt); + wpa_hexdump(MSG_DEBUG, + "RSN: Message 1/4 PMKID derived from PMK", + &pmkid[2 + RSN_SELECTOR_LEN], PMKID_LEN); } } wpa_send_eapol(sm->wpa_auth, sm, @@ -4040,6 +4063,13 @@ int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr, } +void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid) +{ + os_memcpy(sm->pmkid, pmkid, PMKID_LEN); + sm->pmkid_set = 1; +} + + int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *pmk, size_t pmk_len, const u8 *pmkid, int session_timeout, int akmp) diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 1bfacdc7a..6b1887bdc 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -332,6 +332,7 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, struct eapol_state_machine *eapol); int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *pmk, const u8 *pmkid); +void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid); int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *pmk, size_t pmk_len, const u8 *pmkid, int session_timeout, int akmp); diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index befa8007f..609405a26 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -58,6 +58,7 @@ struct wpa_state_machine { u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN]; u8 PMK[PMK_LEN_MAX]; unsigned int pmk_len; + u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */ struct wpa_ptk PTK; Boolean PTK_valid; Boolean pairwise_set; @@ -90,6 +91,7 @@ struct wpa_state_machine { unsigned int pmk_r1_name_valid:1; #endif /* CONFIG_IEEE80211R_AP */ unsigned int is_wnmsleep:1; + unsigned int pmkid_set:1; u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN]; int req_replay_counter_used;