esp_wifi: WPA3-SAE support for softAP

This commit is contained in:
Shreyas Sheth
2023-02-28 12:25:05 +08:00
committed by Jiang Jiang Jian
parent ad19981af8
commit 2b8e40e760
44 changed files with 2773 additions and 249 deletions

View File

@@ -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);
}