mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-08 05:48:36 +00:00
esp_wifi: WPA3-SAE support for softAP
This commit is contained in:

committed by
Jiang Jiang Jian

parent
ad19981af8
commit
2b8e40e760
@@ -11,6 +11,9 @@
|
||||
#include "utils/eloop.h"
|
||||
#include "utils/state_machine.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/sae.h"
|
||||
#include "ap/sta_info.h"
|
||||
#include "ap/ieee802_11.h"
|
||||
#include "ap/wpa_auth.h"
|
||||
#include "ap/wpa_auth_i.h"
|
||||
#include "ap/wpa_auth_ie.h"
|
||||
@@ -20,7 +23,9 @@
|
||||
#include "ap/ap_config.h"
|
||||
#include "ap/sta_info.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "ap/pmksa_cache_auth.h"
|
||||
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/aes_wrap.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/sha1.h"
|
||||
@@ -32,6 +37,7 @@
|
||||
#include "esp_private/wifi.h"
|
||||
#include "esp_wpas_glue.h"
|
||||
#include "esp_wps_i.h"
|
||||
#include "esp_hostap.h"
|
||||
|
||||
#define STATE_MACHINE_DATA struct wpa_state_machine
|
||||
#define STATE_MACHINE_DEBUG_PREFIX "WPA"
|
||||
@@ -127,6 +133,20 @@ static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
|
||||
if (!sta->sae || prev_psk)
|
||||
return NULL;
|
||||
return sta->sae->pmk;
|
||||
}
|
||||
if (sta && wpa_auth_uses_sae(sta->wpa_sm)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"No PSK for STA trying to use SAE with PMKSA caching");
|
||||
return NULL;
|
||||
}
|
||||
#endif /*CONFIG_SAE*/
|
||||
|
||||
return (u8*)hostapd_get_psk(hapd->conf, addr, prev_psk);
|
||||
}
|
||||
|
||||
@@ -246,6 +266,23 @@ static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
|
||||
wpa_sm_step(sm);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
|
||||
{
|
||||
if (sm->pmksa == ctx)
|
||||
sm->pmksa = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
|
||||
void *ctx)
|
||||
{
|
||||
struct wpa_authenticator *wpa_auth = ctx;
|
||||
wpa_auth_for_each_sta(wpa_auth, wpa_auth_pmksa_clear_cb, entry);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_group *group)
|
||||
{
|
||||
@@ -351,6 +388,17 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb,
|
||||
wpa_auth);
|
||||
if (wpa_auth->pmksa == NULL) {
|
||||
wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
|
||||
os_free(wpa_auth->group);
|
||||
os_free(wpa_auth->wpa_ie);
|
||||
os_free(wpa_auth);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
|
||||
if (wpa_auth->ft_pmk_cache == NULL) {
|
||||
@@ -446,7 +494,13 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
|
||||
|
||||
void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
|
||||
{
|
||||
#ifdef ESP_SUPPLICANT
|
||||
if (esp_wifi_ap_is_sta_sae_reauth_node(sm->addr)) {
|
||||
wpa_printf( MSG_DEBUG, "deinit old sm=%p\n", sm);
|
||||
}
|
||||
#else /* ESP_SUPPLICANT */
|
||||
wpa_printf( MSG_DEBUG, "deinit sm=%p\n", sm);
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
if (sm == NULL)
|
||||
return;
|
||||
|
||||
@@ -652,15 +706,21 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *s
|
||||
sm->pairwise == WPA_CIPHER_GCMP) {
|
||||
if (wpa_use_aes_cmac(sm) &&
|
||||
!wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
|
||||
!wpa_use_akm_defined(sm->wpa_key_mgmt) &&
|
||||
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wpa_use_aes_cmac(sm) &&
|
||||
!wpa_use_akm_defined(sm->wpa_key_mgmt) &&
|
||||
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (wpa_use_akm_defined(sm->wpa_key_mgmt) &&
|
||||
ver != WPA_KEY_INFO_TYPE_AKM_DEFINED){
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (key_info & WPA_KEY_INFO_REQUEST) {
|
||||
@@ -882,6 +942,21 @@ continue_processing:
|
||||
wpa_sm_step(sm);
|
||||
}
|
||||
|
||||
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
const u8 *pmk, const u8 *pmkid, bool cache_pmksa)
|
||||
{
|
||||
if (cache_pmksa)
|
||||
return -1;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", pmk, PMK_LEN);
|
||||
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, pmkid,
|
||||
NULL, 0,
|
||||
wpa_auth->addr, addr, 0, NULL,
|
||||
WPA_KEY_MGMT_SAE))
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
|
||||
const u8 *gnonce, u8 *gtk, size_t gtk_len)
|
||||
@@ -937,6 +1012,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
|
||||
|
||||
if (force_version)
|
||||
version = force_version;
|
||||
else if (wpa_use_akm_defined(sm->wpa_key_mgmt))
|
||||
version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
|
||||
else if (wpa_use_aes_cmac(sm))
|
||||
version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
|
||||
else if (sm->pairwise != WPA_CIPHER_TKIP)
|
||||
@@ -944,7 +1021,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
|
||||
else
|
||||
version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
|
||||
|
||||
pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
|
||||
pairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
|
||||
|
||||
wpa_printf( MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d "
|
||||
"ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d "
|
||||
@@ -959,6 +1036,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
|
||||
key_data_len = kde_len;
|
||||
|
||||
if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
|
||||
wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
|
||||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
|
||||
pad_len = key_data_len % 8;
|
||||
if (pad_len)
|
||||
@@ -1027,6 +1105,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
|
||||
wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
|
||||
buf, key_data_len);
|
||||
if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
|
||||
wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
|
||||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
|
||||
if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, (key_data_len - 8) / 8, buf,
|
||||
(u8 *) (key + 1))) {
|
||||
@@ -1423,6 +1502,13 @@ SM_STATE(WPA_PTK, INITPSK)
|
||||
sm->xxkey_len = PMK_LEN;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
}
|
||||
#ifdef CONFIG_SAE
|
||||
if (wpa_auth_uses_sae(sm) && sm->pmksa) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: PMK from PMKSA cache");
|
||||
os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
|
||||
sm->pmk_len = sm->pmksa->pmk_len;
|
||||
}
|
||||
#endif
|
||||
sm->req_replay_counter_used = 0;
|
||||
}
|
||||
|
||||
@@ -1448,7 +1534,8 @@ SM_STATE(WPA_PTK, PTKSTART)
|
||||
* one possible PSK for this STA.
|
||||
*/
|
||||
if (sm->wpa == WPA_VERSION_WPA2 &&
|
||||
wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt)) {
|
||||
(wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) ||
|
||||
wpa_key_mgmt_sae(sm->wpa_key_mgmt))) {
|
||||
pmkid = buf;
|
||||
pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
|
||||
pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
|
||||
@@ -1493,6 +1580,10 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
struct wpa_ptk PTK;
|
||||
int ok = 0;
|
||||
const u8 *pmk = NULL;
|
||||
u16 key_data_length;
|
||||
struct ieee802_1x_hdr *hdr;
|
||||
struct wpa_eapol_key *key;
|
||||
struct wpa_eapol_ie_parse kde;
|
||||
|
||||
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
|
||||
sm->EAPOLKeyReceived = FALSE;
|
||||
@@ -1502,7 +1593,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
* WPA-PSK: iterate through possible PSKs and select the one matching
|
||||
* the packet */
|
||||
for (;;) {
|
||||
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
|
||||
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
|
||||
!wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
|
||||
wpa_printf( MSG_DEBUG, "wpa psk");
|
||||
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk);
|
||||
if (pmk == NULL){
|
||||
@@ -1513,6 +1605,11 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
pmk = sm->PMK;
|
||||
}
|
||||
|
||||
if (!pmk && sm->pmksa) {
|
||||
wpa_printf(MSG_DEBUG, "WPA: Use PMK from PMKSA cache");
|
||||
pmk = sm->pmksa->pmk;
|
||||
}
|
||||
|
||||
wpa_derive_ptk(sm, sm->SNonce, pmk, &PTK);
|
||||
|
||||
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
|
||||
@@ -1535,6 +1632,19 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
return;
|
||||
}
|
||||
|
||||
hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key;
|
||||
key = (struct wpa_eapol_key *) (hdr + 1);
|
||||
key_data_length = WPA_GET_BE16(key->key_data_length);
|
||||
if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
|
||||
sizeof(*key))
|
||||
return;
|
||||
|
||||
if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length, &kde) < 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"received EAPOL-Key msg 2/4 with invalid Key Data contents");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
|
||||
/*
|
||||
@@ -1553,6 +1663,21 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
if ((!sm->rsnxe && kde.rsnxe) ||
|
||||
(sm->rsnxe && !kde.rsnxe) ||
|
||||
(sm->rsnxe && kde.rsnxe &&
|
||||
(sm->rsnxe_len != kde.rsnxe_len ||
|
||||
os_memcmp(sm->rsnxe, kde.rsnxe, sm->rsnxe_len) != 0))) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RSNXE from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
|
||||
wpa_hexdump(MSG_DEBUG, "RSNXE in AssocReq",
|
||||
sm->rsnxe, sm->rsnxe_len);
|
||||
wpa_hexdump(MSG_DEBUG, "RSNXE in EAPOL-Key msg 2/4",
|
||||
kde.rsnxe, kde.rsnxe_len);
|
||||
wpa_sta_disconnect(sm->wpa_auth, sm->addr);
|
||||
return;
|
||||
}
|
||||
|
||||
sm->pending_1_of_4_timeout = 0;
|
||||
eloop_cancel_timeout(resend_eapol_handle, (void*)(sm->index), NULL);
|
||||
|
||||
@@ -1664,6 +1789,8 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
|
||||
wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
|
||||
/* WPA-only STA, remove RSN IE */
|
||||
wpa_ie = wpa_ie + wpa_ie[1] + 2;
|
||||
if (wpa_ie[0] == WLAN_EID_RSNX)
|
||||
wpa_ie = wpa_ie + wpa_ie[1] + 2;
|
||||
wpa_ie_len = wpa_ie[1] + 2;
|
||||
}
|
||||
if (sm->wpa == WPA_VERSION_WPA2) {
|
||||
@@ -1888,9 +2015,13 @@ SM_STEP(WPA_PTK)
|
||||
}
|
||||
break;
|
||||
case WPA_PTK_INITPSK:
|
||||
if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL))
|
||||
if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL)) {
|
||||
SM_ENTER(WPA_PTK, PTKSTART);
|
||||
else {
|
||||
#ifdef CONFIG_SAE
|
||||
} else if (wpa_auth_uses_sae(sm) && sm->pmksa) {
|
||||
SM_ENTER(WPA_PTK, PTKSTART);
|
||||
#endif /* CONFIG_SAE */
|
||||
} else {
|
||||
SM_ENTER(WPA_PTK, DISCONNECT);
|
||||
}
|
||||
break;
|
||||
@@ -2359,11 +2490,35 @@ static int wpa_sm_step(struct wpa_state_machine *sm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool wpa_ap_join(struct sta_info *sta, uint8_t *bssid, uint8_t *wpa_ie, uint8_t wpa_ie_len, bool *pmf_enable)
|
||||
void wpa_deinit(struct wpa_authenticator *wpa_auth)
|
||||
{
|
||||
struct wpa_group *group, *prev;
|
||||
pmksa_cache_auth_deinit(wpa_auth->pmksa);
|
||||
if (wpa_auth->wpa_ie != NULL) {
|
||||
os_free(wpa_auth->wpa_ie);
|
||||
}
|
||||
if (wpa_auth->group != NULL) {
|
||||
group = wpa_auth->group;
|
||||
while (group) {
|
||||
prev = group;
|
||||
group = group->next;
|
||||
bin_clear_free(prev, sizeof(*prev));
|
||||
}
|
||||
}
|
||||
os_free(wpa_auth);
|
||||
|
||||
}
|
||||
|
||||
bool wpa_ap_join(struct sta_info *sta, uint8_t *bssid, uint8_t *wpa_ie,
|
||||
uint8_t wpa_ie_len, uint8_t *rsnxe, uint8_t rsnxe_len,
|
||||
bool *pmf_enable, int subtype)
|
||||
{
|
||||
struct hostapd_data *hapd = (struct hostapd_data*)esp_wifi_get_hostap_private_internal();
|
||||
enum wpa_validate_result status_code = WPA_IE_OK;
|
||||
int resp = WLAN_STATUS_SUCCESS;
|
||||
bool omit_rsnxe = false;
|
||||
|
||||
if (!sta || !bssid || !wpa_ie){
|
||||
if (!sta || !bssid || !wpa_ie) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2377,15 +2532,28 @@ bool wpa_ap_join(struct sta_info *sta, uint8_t *bssid, uint8_t *wpa_ie, uint8_t
|
||||
wpa_printf( MSG_DEBUG, "init wpa sm=%p", sta->wpa_sm);
|
||||
|
||||
if (sta->wpa_sm == NULL) {
|
||||
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
|
||||
goto send_resp;
|
||||
}
|
||||
|
||||
status_code = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, wpa_ie, wpa_ie_len, rsnxe, rsnxe_len);
|
||||
resp = wpa_res_to_status_code(status_code);
|
||||
|
||||
send_resp:
|
||||
if (!rsnxe) {
|
||||
omit_rsnxe = true;
|
||||
}
|
||||
|
||||
if (esp_send_assoc_resp(hapd, sta, bssid, resp, omit_rsnxe, subtype) != WLAN_STATUS_SUCCESS) {
|
||||
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
|
||||
}
|
||||
|
||||
if (resp != WLAN_STATUS_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, wpa_ie, wpa_ie_len)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check whether AP uses Management Frame Protection for this connection
|
||||
*pmf_enable = wpa_auth_uses_mfp(sta->wpa_sm);
|
||||
//Check whether AP uses Management Frame Protection for this connection
|
||||
*pmf_enable = wpa_auth_uses_mfp(sta->wpa_sm);
|
||||
}
|
||||
|
||||
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
|
||||
@@ -2416,11 +2584,23 @@ bool wpa_ap_remove(void* sta_info)
|
||||
if (!sta_info || !hapd) {
|
||||
return false;
|
||||
}
|
||||
struct sta_info *sta = NULL;
|
||||
sta = (struct sta_info*)sta_info;
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
if (sta->lock) {
|
||||
if (os_mutex_lock(sta->lock)) {
|
||||
ap_free_sta(hapd, sta);
|
||||
} else {
|
||||
sta->remove_pending = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
#ifdef CONFIG_WPS_REGISTRAR
|
||||
wpa_printf(MSG_DEBUG, "wps_status=%d", wps_get_status());
|
||||
if (wps_get_status() == WPS_STATUS_PENDING) {
|
||||
struct sta_info *sta = (struct sta_info *)sta_info;
|
||||
u8 *addr = os_malloc(ETH_ALEN);
|
||||
|
||||
if (!addr) {
|
||||
@@ -2430,7 +2610,29 @@ bool wpa_ap_remove(void* sta_info)
|
||||
eloop_register_timeout(0, 10000, ap_free_sta_timeout, hapd, addr);
|
||||
} else
|
||||
#endif
|
||||
ap_free_sta(hapd, sta_info);
|
||||
ap_free_sta(hapd, sta);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *sta_addr)
|
||||
{
|
||||
struct rsn_pmksa_cache_entry *pmksa;
|
||||
|
||||
if (wpa_auth == NULL || wpa_auth->pmksa == NULL)
|
||||
return;
|
||||
pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
|
||||
if (pmksa) {
|
||||
wpa_printf(MSG_DEBUG, "WPA: Remove PMKSA cache entry for "
|
||||
MACSTR " based on request", MAC2STR(sta_addr));
|
||||
pmksa_cache_free_entry(wpa_auth->pmksa, pmksa);
|
||||
}
|
||||
}
|
||||
|
||||
int wpa_auth_uses_sae(struct wpa_state_machine *sm)
|
||||
{
|
||||
if (sm == NULL)
|
||||
return 0;
|
||||
return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
|
||||
}
|
||||
|
Reference in New Issue
Block a user