diff --git a/components/wpa_supplicant/src/ap/ieee802_11.c b/components/wpa_supplicant/src/ap/ieee802_11.c index a6f74183485..7aee02ac93a 100644 --- a/components/wpa_supplicant/src/ap/ieee802_11.c +++ b/components/wpa_supplicant/src/ap/ieee802_11.c @@ -20,6 +20,13 @@ #include "esp_wpa3_i.h" #include "esp_hostap.h" +#ifdef CONFIG_OWE_SOFTAP +#include "crypto/crypto.h" +#include "ap/wpa_auth_i.h" +#define OWE_DH_GRP19 19 +#define OWE_DHIE_LEN 37 +#endif + #ifdef CONFIG_SAE static void sae_set_state(struct sta_info *sta, enum sae_state state, @@ -775,14 +782,29 @@ u16 wpa_res_to_status_code(enum wpa_validate_result res) } #ifdef CONFIG_OWE_SOFTAP -#include "ap/wpa_auth_i.h" -#include "crypto/crypto.h" -#define OWE_DH_GRP19 19 -#define OWE_DHIE_LEN 37 -uint16_t owe_process_assoc_req(struct sta_info *sta, const uint8_t *owe_dh, - uint8_t owe_dh_len) -{ +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, const u8 *dpp_pkhash) +{ + if (!wpa_auth || wpa_auth->conf.disable_pmksa_caching) + return -1; + + struct rsn_pmksa_cache_entry *entry; + + wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (3)", pmk, PMK_LEN); + entry = pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid, + NULL, 0, wpa_auth->addr, addr, session_timeout, + NULL, akmp); + if (!entry) + return -1; + + return 0; +} + +uint16_t owe_process_assoc_req(struct hostapd_data *hapd, struct sta_info *sta, const u8 *owe_dh, + u8 owe_dh_len) +{ const u8 *addr[2]; size_t len[2]; struct wpabuf *hkey, *pub, *secret; @@ -791,6 +813,11 @@ uint16_t owe_process_assoc_req(struct sta_info *sta, const uint8_t *owe_dh, u8 pmkid[SHA256_MAC_LEN]; int res; + if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) { + wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching"); + return WLAN_STATUS_SUCCESS; + } + if (!owe_dh) { wpa_printf(MSG_ERROR, "OWE: Invalid DH data received"); return WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -801,11 +828,25 @@ uint16_t owe_process_assoc_req(struct sta_info *sta, const uint8_t *owe_dh, if (sta->owe_group != OWE_DH_GRP19) return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; - crypto_ecdh_deinit(sta->owe_ecdh); - sta->owe_ecdh = crypto_ecdh_init(OWE_DH_GRP19); - if (!sta->owe_ecdh) { - wpa_printf(MSG_ERROR, "OWE: Error initializing ECDH for STA"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; + if (sta->owe_ecdh) { + /* This is a workaround for mac80211 behavior of retransmitting + * the Association Request frames multiple times if the link + * layer retries (i.e., seq# remains same) fail. The mac80211 + * initiated retransmission will use a different seq# and as + * such, will go through duplicate detection. If we were to + * change our DH key for that attempt, there would be two + * different DH shared secrets and the STA would likely select + * the wrong one. */ + wpa_printf(MSG_DEBUG, + "OWE: Try to reuse own previous DH key since the STA tried to go through OWE association again"); + } else { + + crypto_ecdh_deinit(sta->owe_ecdh); + sta->owe_ecdh = crypto_ecdh_init(OWE_DH_GRP19); + if (!sta->owe_ecdh) { + wpa_printf(MSG_ERROR, "OWE: Error initializing ECDH for STA"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } } // Set up the DH shared secret @@ -888,13 +929,27 @@ uint16_t owe_process_assoc_req(struct sta_info *sta, const uint8_t *owe_dh, wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, PMK_LEN); wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN); + sta->owe_pmk_len = SHA256_MAC_LEN; + + // Add the PMK to the PMKSA cache + wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk, sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE, NULL); + + // Update the PMKID in the STA's WPA state machine + os_memcpy(sta->wpa_sm->pmkid, pmkid, PMKID_LEN); + sta->wpa_sm->pmkid_set = 1; + return WLAN_STATUS_SUCCESS; } uint8_t *owe_build_assoc_resp_dhie(struct hostapd_data *hapd, const u8 *bssid, int *owe_ie_len) { - + + if (!hapd || !hapd->wpa_auth || !hapd->wpa_auth->wpa_ie) { + wpa_printf(MSG_ERROR, "Invalid hapd or WPA auth data"); + return NULL; + } + struct wpabuf *pub; struct sta_info *sta = ap_get_sta(hapd, bssid); if (!sta) { @@ -907,34 +962,39 @@ uint8_t *owe_build_assoc_resp_dhie(struct hostapd_data *hapd, const u8 *bssid, i return NULL; } - u8 *pos, buf[128]; + // If PMKSA caching is used, write and return only RSN IE with PMKID + if (sta->wpa_sm && sta->wpa_sm->pmksa) { + u8 *pos, buf[128]; + pos = buf; - pos = buf; - - pos = wpa_auth_write_assoc_resp_owe(hapd, sta->wpa_sm, pos, + wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching for Assoc Resp"); + pos = wpa_auth_write_assoc_resp_owe(hapd, sta->wpa_sm, pos, buf + sizeof(buf) - pos); - wpabuf_resize(&owe_buf, pos - buf); - wpabuf_put_data(owe_buf, buf, pos - buf); - *owe_ie_len = pos - buf; - - pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0); - if (!pub) { - return NULL; + wpabuf_resize(&owe_buf, pos - buf); + wpabuf_put_data(owe_buf, buf, pos - buf); + *owe_ie_len = pos - buf; + return (uint8_t *)wpabuf_head(owe_buf); } + if (sta->owe_ecdh) { + pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0); + if (!pub) { + return NULL; + } - wpa_hexdump_buf(MSG_DEBUG, "Own public key", pub); + wpa_hexdump_buf(MSG_DEBUG, "Own public key", pub); - wpabuf_resize(&owe_buf, OWE_DHIE_LEN); - wpabuf_put_u8(owe_buf, WLAN_EID_EXTENSION); - wpabuf_put_u8(owe_buf, 1 + 2 + wpabuf_len(pub)); - wpabuf_put_u8(owe_buf, WLAN_EID_EXT_OWE_DH_PARAM); - wpabuf_put_le16(owe_buf, IANA_SECP256R1); - wpabuf_put_buf(owe_buf, pub); - wpabuf_free(pub); + wpabuf_resize(&owe_buf, OWE_DHIE_LEN); + wpabuf_put_u8(owe_buf, WLAN_EID_EXTENSION); + wpabuf_put_u8(owe_buf, 1 + 2 + wpabuf_len(pub)); + wpabuf_put_u8(owe_buf, WLAN_EID_EXT_OWE_DH_PARAM); + wpabuf_put_le16(owe_buf, IANA_SECP256R1); + wpabuf_put_buf(owe_buf, pub); + wpabuf_free(pub); - wpa_hexdump_buf(MSG_DEBUG, "OWE: Buffer", owe_buf); + wpa_hexdump_buf(MSG_DEBUG, "OWE: Buffer", owe_buf); + } *owe_ie_len = wpabuf_len(owe_buf); return (uint8_t *)wpabuf_head(owe_buf); diff --git a/components/wpa_supplicant/src/ap/ieee802_11.h b/components/wpa_supplicant/src/ap/ieee802_11.h index e7af3edf4e0..d4d54246e2a 100644 --- a/components/wpa_supplicant/src/ap/ieee802_11.h +++ b/components/wpa_supplicant/src/ap/ieee802_11.h @@ -17,7 +17,7 @@ int handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, u16 auth_transaction, u16 status); u16 wpa_res_to_status_code(enum wpa_validate_result res); #ifdef CONFIG_OWE_SOFTAP -uint16_t owe_process_assoc_req(struct sta_info *sta, const u8 *owe_dh, +uint16_t owe_process_assoc_req(struct hostapd_data *hapd, struct sta_info *sta, const u8 *owe_dh, u8 owe_dh_len); uint8_t *owe_build_assoc_resp_dhie(struct hostapd_data *hapd, const u8 *bssid, int *owe_ie_len); #endif /* CONFIG_OWE_SOFTAP */ diff --git a/components/wpa_supplicant/src/ap/sta_info.h b/components/wpa_supplicant/src/ap/sta_info.h index c99a9fb17d9..4bc2e42c6aa 100644 --- a/components/wpa_supplicant/src/ap/sta_info.h +++ b/components/wpa_supplicant/src/ap/sta_info.h @@ -72,6 +72,7 @@ struct sta_info { #ifdef CONFIG_OWE_SOFTAP u16 owe_group; u8 *owe_pmk; + size_t owe_pmk_len; struct crypto_ecdh *owe_ecdh; #endif /* CONFIG_OWE_SOFTAP */ diff --git a/components/wpa_supplicant/src/ap/wpa_auth.c b/components/wpa_supplicant/src/ap/wpa_auth.c index 65786a90295..5967cab302a 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth.c +++ b/components/wpa_supplicant/src/ap/wpa_auth.c @@ -152,9 +152,20 @@ static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth, #endif /*CONFIG_SAE*/ #ifdef CONFIG_OWE_SOFTAP - if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && sta && sta->owe_pmk) { - return sta->owe_pmk; - } + if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && + sta && sta->owe_pmk) { + return sta->owe_pmk; + } + + if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && sta) { + struct rsn_pmksa_cache_entry *sa; + + sa = wpa_auth_sta_get_pmksa(sta->wpa_sm); + if (sa && sa->akmp == WPA_KEY_MGMT_OWE) { + return sa->pmk; + } + } + #endif /* CONFIG_OWE_SOFTAP */ #endif /* defined(CONFIG_SAE) || defined(CONFIG_OWE_SOFTAP) */ @@ -1038,6 +1049,12 @@ void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid) sm->pmkid_set = 1; } +struct rsn_pmksa_cache_entry * +wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm) +{ + return sm ? sm->pmksa : NULL; +} + static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr, const u8 *gnonce, u8 *gtk, size_t gtk_len) { @@ -1633,6 +1650,9 @@ SM_STATE(WPA_PTK, INITPSK) psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL); if (psk) { memcpy(sm->PMK, psk, PMK_LEN); +#ifdef CONFIG_OWE_SOFTAP + sm->pmk_len = PMK_LEN; +#endif #ifdef CONFIG_IEEE80211R_AP memcpy(sm->xxkey, psk, PMK_LEN); sm->xxkey_len = PMK_LEN; @@ -1671,6 +1691,7 @@ SM_STATE(WPA_PTK, PTKSTART) */ if (sm->wpa == WPA_VERSION_WPA2 && (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) || + (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && sm->pmksa) || wpa_key_mgmt_sae(sm->wpa_key_mgmt))) { pmkid = buf; pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN; diff --git a/components/wpa_supplicant/src/ap/wpa_auth_ie.c b/components/wpa_supplicant/src/ap/wpa_auth_ie.c index dbfc4bc75eb..634d5b4750f 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth_ie.c +++ b/components/wpa_supplicant/src/ap/wpa_auth_ie.c @@ -876,7 +876,8 @@ uint8_t *wpa_auth_write_assoc_resp_owe(struct hostapd_data *hapd, struct wpa_sta { int res; - res = wpa_write_rsn_ie(&hapd->wpa_auth->conf, pos, max_len, NULL); + res = wpa_write_rsn_ie(&hapd->wpa_auth->conf, pos, max_len, + sm->pmksa ? sm->pmksa->pmkid : NULL, hapd->wpa_auth->conf.group_mgmt_cipher); if (res < 0) return pos; return pos + res;