[PATCH 20/29] EPPKE: Add support for EPPKE authentication for SME-in-Userspace case
Sai Pratyusha Magam
smagam at qti.qualcomm.com
Thu Dec 11 05:14:34 PST 2025
From: Ainy Kumari <ainy.kumari at oss.qualcomm.com>
Extend existing PASN Implementation for authentication frame construction
and processing logic to align with IEEE 802.11bi/D2.0, section 12.16.9.3.2
for EPPKE authentication support. Apply PASN logic for EPPKE authentication
with necessary differences to support SME-in-Userspace scenarios.
Below are the Key Changes:
1. Modify PASN Authentication request frame construction APIs:
- Remove 'static' from M1 and M3 frame building functions to make them
globally accessible.
- Add 'is_sme_drv' parameter to differentiate between frames sent via
%NL80211_CMD_AUTHENTICATE (false) and %NL80211_CMD_FRAME (true)
interface and prepare auth_data for authentication request frames
accordingly.
2. Refactor PASN authentication response frame parsing API:
- Introduce a new helper function wpas_parse_pasn_frame() to handle
authentication response frame parsing in a modular way. This
separates the frame parsing logic from wpa_pasn_auth_rx() and
enables reuse for SME-in-Userspace scenarios.
- Simplify pasn_parse_encrypted_data() by removing ieee80211_mgmt
dependency and enables reuse for SME-in-Userspace scenarios.
3. Update SME code to integrate EPPKE flow:
- Add initialization, frame construction and event handling for EPPKE
using extended PASN APIs for building authentication request frames
and parsing the authentication response frame.
Signed-off-by: Ainy Kumari <ainy.kumari at oss.qualcomm.com>
---
src/pasn/pasn_common.c | 9 +-
src/pasn/pasn_common.h | 8 ++
src/pasn/pasn_initiator.c | 151 +++++++++++++++++--------
src/pasn/pasn_responder.c | 4 +-
wpa_supplicant/sme.c | 191 +++++++++++++++++++++++++++++++-
wpa_supplicant/wpa_supplicant.c | 1 +
6 files changed, 304 insertions(+), 60 deletions(-)
diff --git a/src/pasn/pasn_common.c b/src/pasn/pasn_common.c
index e9b30ba99..9e2f6c922 100644
--- a/src/pasn/pasn_common.c
+++ b/src/pasn/pasn_common.c
@@ -330,14 +330,7 @@ int pasn_parse_encrypted_data(struct pasn_data *pasn, const u8 *data,
u8 *buf;
u16 buf_len;
struct ieee802_11_elems elems;
- const struct ieee80211_mgmt *mgmt =
- (const struct ieee80211_mgmt *) data;
-
- if (len < 24 + 6 ||
- ieee802_11_parse_elems(mgmt->u.auth.variable,
- len - offsetof(struct ieee80211_mgmt,
- u.auth.variable),
- &elems, 0) == ParseFailed) {
+ if (ieee802_11_parse_elems(data, len, &elems, 0) == ParseFailed) {
wpa_printf(MSG_DEBUG,
"PASN: Failed parsing Authentication frame");
return -1;
diff --git a/src/pasn/pasn_common.h b/src/pasn/pasn_common.h
index ffc3c8b21..09a6a15b0 100644
--- a/src/pasn/pasn_common.h
+++ b/src/pasn/pasn_common.h
@@ -184,6 +184,10 @@ int wpas_pasn_start(struct pasn_data *pasn, const u8 *own_addr,
int freq, const u8 *beacon_rsne, u8 beacon_rsne_len,
const u8 *beacon_rsnxe, u8 beacon_rsnxe_len,
const struct wpabuf *comeback);
+struct wpabuf *wpas_pasn_build_auth_1(struct pasn_data *pasn,
+ const struct wpabuf *comeback,
+ bool verify, bool is_sme_drv);
+struct wpabuf *wpas_pasn_build_auth_3(struct pasn_data *pasn, bool is_sme_drv);
int wpa_pasn_verify(struct pasn_data *pasn, const u8 *own_addr,
const u8 *peer_addr, const u8 *bssid,
int akmp, int cipher, u16 group,
@@ -194,6 +198,10 @@ int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len,
struct wpa_pasn_params_data *pasn_params);
int wpa_pasn_auth_tx_status(struct pasn_data *pasn,
const u8 *data, size_t data_len, u8 acked);
+int wpas_parse_pasn_frame(struct pasn_data *pasn, u16 auth_type, u16 auth_transaction,
+ u16 status_code, const u8 *frame_data, size_t frame_data_len,
+ struct wpa_pasn_params_data *pasn_params);
+
/* Responder */
int handle_auth_pasn_1(struct pasn_data *pasn,
diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c
index 94a9d79cb..5669daa84 100644
--- a/src/pasn/pasn_initiator.c
+++ b/src/pasn/pasn_initiator.c
@@ -581,9 +581,9 @@ static u8 wpas_pasn_get_wrapped_data_format(struct pasn_data *pasn)
}
-static struct wpabuf * wpas_pasn_build_auth_1(struct pasn_data *pasn,
+struct wpabuf *wpas_pasn_build_auth_1(struct pasn_data *pasn,
const struct wpabuf *comeback,
- bool verify)
+ bool verify, bool is_sme_drv)
{
struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
const u8 *pmkid;
@@ -609,10 +609,16 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct pasn_data *pasn,
wrapped_data = wpas_pasn_get_wrapped_data_format(pasn);
- wpa_pasn_build_auth_header(buf, pasn->bssid,
- pasn->own_addr, pasn->peer_addr,
- pasn->trans_seq + 1, WLAN_STATUS_SUCCESS,
- pasn->auth_alg == WLAN_AUTH_EPPKE);
+ if (!is_sme_drv) {
+ wpabuf_put_le16(buf, pasn->trans_seq + 1);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ } else {
+ wpa_pasn_build_auth_header(buf, pasn->bssid,
+ pasn->own_addr, pasn->peer_addr,
+ pasn->trans_seq + 1,
+ WLAN_STATUS_SUCCESS,
+ pasn->auth_alg == WLAN_AUTH_EPPKE);
+ }
pmkid = NULL;
if (wpa_key_mgmt_ft(pasn->akmp)) {
@@ -683,7 +689,8 @@ fail:
}
-static struct wpabuf * wpas_pasn_build_auth_3(struct pasn_data *pasn)
+struct wpabuf *wpas_pasn_build_auth_3(struct pasn_data *pasn,
+ bool is_sme_drv)
{
struct wpabuf *buf, *wrapped_data_buf = NULL;
u8 mic[WPA_PASN_MAX_MIC_LEN];
@@ -705,10 +712,16 @@ static struct wpabuf * wpas_pasn_build_auth_3(struct pasn_data *pasn)
wrapped_data = wpas_pasn_get_wrapped_data_format(pasn);
- wpa_pasn_build_auth_header(buf, pasn->bssid,
- pasn->own_addr, pasn->peer_addr,
- pasn->trans_seq + 1, WLAN_STATUS_SUCCESS,
- pasn->auth_alg == WLAN_AUTH_EPPKE);
+ if (!is_sme_drv) {
+ wpabuf_put_le16(buf, pasn->trans_seq + 1);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ } else {
+ wpa_pasn_build_auth_header(buf, pasn->bssid,
+ pasn->own_addr, pasn->peer_addr,
+ pasn->trans_seq + 1,
+ WLAN_STATUS_SUCCESS,
+ pasn->auth_alg == WLAN_AUTH_EPPKE);
+ }
wrapped_data_buf = wpas_pasn_get_wrapped_data(pasn);
@@ -1011,7 +1024,7 @@ static int wpas_pasn_send_auth_1(struct pasn_data *pasn, const u8 *own_addr,
MAC2STR(pasn->peer_addr), pasn->akmp, pasn->cipher,
pasn->group);
- frame = wpas_pasn_build_auth_1(pasn, comeback, verify);
+ frame = wpas_pasn_build_auth_1(pasn, comeback, verify, true);
if (!frame) {
wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame");
goto fail;
@@ -1154,36 +1167,27 @@ static bool is_pasn_auth_frame(struct pasn_data *pasn,
}
-int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len,
- struct wpa_pasn_params_data *pasn_params)
-
+int wpas_parse_pasn_frame(struct pasn_data *pasn, u16 auth_type,
+ u16 auth_transaction, u16 status,
+ const u8 *auth_data, size_t auth_data_len,
+ struct wpa_pasn_params_data *pasn_params)
{
struct ieee802_11_elems elems;
struct wpa_ie_data rsn_data;
- const struct ieee80211_mgmt *mgmt =
- (const struct ieee80211_mgmt *) data;
- struct wpabuf *wrapped_data = NULL, *secret = NULL, *frame = NULL;
+ struct wpabuf *wrapped_data = NULL, *secret = NULL;
u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
u8 mic_len;
- u16 status;
int ret, inc_y;
u8 *copy = NULL;
size_t mic_offset, copy_len;
- if (!is_pasn_auth_frame(pasn, mgmt, len, true))
- return -2;
-
- if (mgmt->u.auth.auth_transaction !=
- host_to_le16(pasn->trans_seq + 1)) {
+ if (auth_transaction != pasn->trans_seq + 1) {
wpa_printf(MSG_DEBUG,
"PASN: RX: Invalid transaction sequence: (%u != %u)",
- le_to_host16(mgmt->u.auth.auth_transaction),
- pasn->trans_seq + 1);
+ auth_transaction, pasn->trans_seq + 1);
return -3;
}
- status = le_to_host16(mgmt->u.auth.status_code);
-
if (status != WLAN_STATUS_SUCCESS &&
status != WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
wpa_printf(MSG_DEBUG,
@@ -1191,10 +1195,8 @@ int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len,
goto fail;
}
- if (ieee802_11_parse_elems(mgmt->u.auth.variable,
- len - offsetof(struct ieee80211_mgmt,
- u.auth.variable),
- &elems, 0) == ParseFailed) {
+ if (ieee802_11_parse_elems(auth_data, auth_data_len, &elems, 0) ==
+ ParseFailed) {
wpa_printf(MSG_DEBUG,
"PASN: Failed parsing Authentication frame");
goto fail;
@@ -1355,14 +1357,24 @@ int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len,
/* Use a copy of the message since we need to clear the MIC field */
if (!elems.mic)
goto fail;
- mic_offset = elems.mic - (const u8 *) &mgmt->u.auth;
- copy_len = len - offsetof(struct ieee80211_mgmt, u.auth);
- if (mic_offset + mic_len > copy_len)
- goto fail;
- copy = os_memdup(&mgmt->u.auth, copy_len);
+
+ mic_offset = elems.mic - auth_data;
+ /* 6 bytes for auth algorithm, auth transaction and status code.
+ * 2 bytes each.
+ */
+ copy = os_malloc(auth_data_len + 6);
if (!copy)
goto fail;
- os_memset(copy + mic_offset, 0, mic_len);
+
+ os_memcpy(copy, &auth_type, 2);
+ os_memcpy(copy + 2, &auth_transaction, 2);
+ os_memcpy(copy + 4, &status, 2);
+ os_memcpy(copy + 6, auth_data, auth_data_len);
+ copy_len = auth_data_len + 6;
+ if (mic_offset + mic_len > auth_data_len)
+ goto fail;
+
+ os_memset(copy + mic_offset + 6, 0, mic_len);
if (pasn->beacon_rsne_rsnxe) {
/* Verify the MIC */
@@ -1422,12 +1434,61 @@ int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len,
wpa_printf(MSG_DEBUG, "PASN: Success verifying Authentication frame");
- if (pasn_parse_encrypted_data(pasn, data, len) < 0) {
+ if (pasn_parse_encrypted_data(pasn, auth_data, auth_data_len) < 0) {
wpa_printf(MSG_DEBUG, "PASN: Encrypted data processing failed");
goto fail;
}
- frame = wpas_pasn_build_auth_3(pasn);
+ return 0;
+fail:
+ wpabuf_free(wrapped_data);
+ wpabuf_free(secret);
+ os_free(copy);
+
+ /*
+ * TODO: In case of an error the standard allows to silently drop
+ * the frame and terminate the authentication exchange. However, better
+ * reply to the AP with an error status.
+ */
+ if (status == WLAN_STATUS_SUCCESS)
+ pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ else
+ pasn->status = status;
+
+ return -1;
+
+}
+
+
+int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len,
+ struct wpa_pasn_params_data *pasn_params)
+{
+ const struct ieee80211_mgmt *mgmt =
+ (const struct ieee80211_mgmt *) data;
+ struct wpabuf *frame = NULL;
+ int ret;
+
+ if (!is_pasn_auth_frame(pasn, mgmt, len, true))
+ return -2;
+
+ ret = wpas_parse_pasn_frame(pasn, le_to_host16(mgmt->u.auth.auth_alg),
+ le_to_host16(mgmt->u.auth.auth_transaction),
+ le_to_host16(mgmt->u.auth.status_code),
+ mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable), pasn_params);
+
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed parsing PASN M2 auth frame");
+ goto fail;
+ }
+
+ if (ret == 1) {
+ wpa_printf(MSG_DEBUG, "PASN: Temporary rejection, Retry");
+ return 1;
+ }
+
+ frame = wpas_pasn_build_auth_3(pasn, true);
if (!frame) {
wpa_printf(MSG_DEBUG, "PASN: Failed building 3rd auth frame");
goto fail;
@@ -1452,21 +1513,17 @@ int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len,
return 0;
fail:
- wpa_printf(MSG_DEBUG, "PASN: Failed RX processing - terminating");
- wpabuf_free(wrapped_data);
- wpabuf_free(secret);
- os_free(copy);
-
/*
* TODO: In case of an error the standard allows to silently drop
* the frame and terminate the authentication exchange. However, better
* reply to the AP with an error status.
*/
- if (status == WLAN_STATUS_SUCCESS)
+ if (le_to_host16(mgmt->u.auth.status_code) == WLAN_STATUS_SUCCESS)
pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
else
- pasn->status = status;
+ pasn->status = le_to_host16(mgmt->u.auth.status_code);
+ wpa_printf(MSG_DEBUG, "PASN: Failed RX processing - terminating");
return -1;
}
diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c
index 8c9222386..a1d2974e8 100644
--- a/src/pasn/pasn_responder.c
+++ b/src/pasn/pasn_responder.c
@@ -1195,7 +1195,9 @@ int handle_auth_pasn_3(struct pasn_data *pasn, const u8 *own_addr,
wpabuf_free(wrapped_data);
}
- if (pasn_parse_encrypted_data(pasn, (const u8 *) mgmt, len) < 0) {
+ if (pasn_parse_encrypted_data(pasn, (const u8 *) mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable)) < 0) {
wpa_printf(MSG_DEBUG, "PASN: Encrypted data processing failed");
goto fail;
}
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index dfa71581e..50b56aaa1 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -32,6 +32,9 @@
#include "scan.h"
#include "sme.h"
#include "hs20_supplicant.h"
+#include "pasn/pasn_common.h"
+#include "common/dragonfly.h"
+#include "common/ptksa_cache.h"
#define SME_AUTH_TIMEOUT 5
#define SME_ASSOC_TIMEOUT 5
@@ -41,6 +44,7 @@ static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx);
static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx);
static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
+static const int dot11RSNAConfigPMKLifetime = 43200;
#ifdef CONFIG_SAE
@@ -597,6 +601,133 @@ static void sme_add_assoc_req_ie(struct wpa_supplicant *wpa_s,
}
}
+#ifdef CONFIG_ENC_ASSOC
+static struct sae_pt *
+sme_eppke_sae_derive_pt(struct wpa_ssid *ssid, int group)
+{
+ const char *password = ssid->sae_password;
+ int groups[2] = { group, 0 };
+
+ if (!password)
+ password = ssid->passphrase;
+
+ if (!password) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE without a password");
+ return NULL;
+ }
+
+ return sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
+ (const u8 *) password, os_strlen(password),
+ (const u8 *) ssid->sae_password_id,
+ ssid->sae_password_id ?
+ os_strlen(ssid->sae_password_id) : 0);
+}
+
+static void wpas_eppke_initialize(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ struct wpa_ssid *ssid)
+{
+ struct pasn_data *pasn;
+ const u8 *beacon_rsne, *beacon_rsnxe;
+ u8 beacon_rsne_len, beacon_rsnxe_len;
+ u32 capab = 0;
+ int group;
+
+ pasn = &wpa_s->pasn;
+
+ if (sme_set_sae_group(wpa_s, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "EPPKE: Failed to select group");
+ return;
+ }
+ group = wpa_s->sme.sae.group;
+
+ if (!dragonfly_suitable_group(group, 1)) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Reject unsuitable group %u", group);
+ return;
+ }
+
+ beacon_rsne = wpa_bss_get_rsne(wpa_s, bss, NULL, false);
+ if (!beacon_rsne) {
+ wpa_printf(MSG_DEBUG, "EPPKE: Can't connect without RSNE");
+ return;
+ }
+
+ beacon_rsnxe = wpa_bss_get_rsnxe(wpa_s, bss, NULL, false);
+
+ beacon_rsne_len = *(beacon_rsne + 1) + 2;
+ beacon_rsnxe_len = beacon_rsnxe ? *(beacon_rsnxe + 1) + 2 : 0;
+ if (beacon_rsne && beacon_rsne_len) {
+ wpabuf_free(pasn->beacon_rsne_rsnxe);
+ pasn->beacon_rsne_rsnxe = wpabuf_alloc(beacon_rsne_len +
+ beacon_rsnxe_len);
+ if (!pasn->beacon_rsne_rsnxe) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed storing beacon RSNE/RSNXE");
+ return;
+ }
+
+ wpabuf_put_data(pasn->beacon_rsne_rsnxe, beacon_rsne,
+ beacon_rsne_len);
+ if (beacon_rsnxe && beacon_rsnxe_len)
+ wpabuf_put_data(pasn->beacon_rsne_rsnxe,
+ beacon_rsnxe, beacon_rsnxe_len);
+ }
+ capab |= BIT(WLAN_RSNX_CAPAB_KEK_IN_PASN);
+ capab |= BIT(WLAN_RSNX_CAPAB_ASSOC_FRAME_ENCRYPTION);
+
+#ifdef CONFIG_SAE
+ if (wpa_key_mgmt_sae(ssid->key_mgmt)) {
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+ if (beacon_rsnxe && !ieee802_11_rsnx_capab(beacon_rsnxe,
+ WLAN_RSNX_CAPAB_SAE_H2E)) {
+ wpa_printf(MSG_DEBUG, "PASN: AP does not support SAE H2E");
+ return;
+ }
+ if (pasn->pt)
+ sae_deinit_pt(pasn->pt);
+ pasn_set_pt(pasn, sme_eppke_sae_derive_pt(ssid, group));
+ if (!pasn->pt) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive PT");
+ return;
+ }
+ pasn->sae.state = SAE_NOTHING;
+ pasn->sae.send_confirm = 0;
+ } else {
+ wpa_msg(wpa_s, MSG_INFO, "Base AKM not present");
+ return;
+ }
+#endif /* CONFIG_SAE */
+
+ pasn_set_rsnxe_caps(pasn, capab);
+ pasn_set_initiator_pmksa(pasn, wpa_sm_get_pmksa_cache(wpa_s->wpa));
+
+ if (pasn->ecdh)
+ crypto_ecdh_deinit(pasn->ecdh);
+ pasn->ecdh = crypto_ecdh_init(group);
+ if (!pasn->ecdh) {
+ wpa_printf(MSG_INFO, "PASN: Failed to init ECDH");
+ return;
+ }
+ pasn->akmp = wpa_s->key_mgmt;
+ pasn->cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 1);
+ pasn->group = group;
+ pasn->freq = bss->freq;
+ pasn->auth_alg = WLAN_AUTH_EPPKE;
+
+ os_memcpy(pasn->own_addr, wpa_s->own_addr, ETH_ALEN);
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO)
+ os_memcpy(pasn->peer_addr, wpa_s->ap_mld_addr, ETH_ALEN);
+ else
+ os_memcpy(pasn->peer_addr, bss->bssid, ETH_ALEN);
+ os_memcpy(pasn->bssid, bss->bssid, ETH_ALEN);
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: Init: " MACSTR " akmp=0x%x, cipher=0x%x, group=%u",
+ MAC2STR(pasn->peer_addr), pasn->akmp,
+ pasn->cipher, pasn->group);
+}
+#endif /* CONFIG_ENC_ASSOC */
+
static void sme_send_authentication(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
@@ -698,14 +829,22 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
if (!rsn) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SAE enabled, but target BSS does not advertise RSN");
+ }
+ if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied)) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE data");
+ return;
#ifdef CONFIG_DPP
- } else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
- (ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+ } else if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
(ied.key_mgmt & WPA_KEY_MGMT_DPP)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Prefer DPP over SAE when both are enabled");
#endif /* CONFIG_DPP */
- } else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
- wpa_key_mgmt_sae(ied.key_mgmt)) {
+#ifdef CONFIG_ENC_ASSOC
+ } else if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_EPPKE &&
+ (ied.key_mgmt & WPA_KEY_MGMT_EPPKE)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Prefer EPPKE over SAE when both are enabled");
+ params.auth_alg = WPA_AUTH_ALG_EPPKE;
+#endif /* CONFIG_ENC_ASSOC */
+ } else if (wpa_key_mgmt_sae(ied.key_mgmt)) {
if (wpas_is_sae_avoided(wpa_s, ssid, &ied)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SAE enabled, but disallowing SAE auth_alg without PMF");
@@ -1026,6 +1165,19 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_MBO */
+#ifdef CONFIG_ENC_ASSOC
+ if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_EPPKE) {
+ wpas_eppke_initialize(wpa_s, bss, ssid);
+ if (start)
+ resp = wpas_pasn_build_auth_1(&wpa_s->pasn, NULL,
+ false, 0);
+ else
+ resp = wpas_pasn_build_auth_3(&wpa_s->pasn, 0);
+
+ params.auth_data = wpabuf_head(resp);
+ params.auth_data_len = wpabuf_len(resp);
+ }
+#endif /* CONFIG_ENC_ASSOC */
#ifdef CONFIG_SAE
if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
pmksa_cache_set_current(wpa_s->wpa, NULL,
@@ -2080,6 +2232,37 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+#ifdef CONFIG_ENC_ASSOC
+ if (data->auth.auth_type == WLAN_AUTH_EPPKE) {
+ struct pasn_data *pasn = &wpa_s->pasn;
+ struct wpa_pasn_params_data pasn_params;
+ int res;
+
+ res = wpas_parse_pasn_frame(pasn, data->auth.auth_type,
+ data->auth.auth_transaction,
+ data->auth.status_code,
+ data->auth.ies, data->auth.ies_len,
+ &pasn_params);
+
+ if (res < 0) {
+ wpas_connection_failed(wpa_s, wpa_s->pending_bssid,
+ NULL);
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+ }
+
+ ptksa_cache_add(wpa_s->ptksa, pasn->own_addr, pasn->peer_addr,
+ pasn_get_cipher(pasn),
+ dot11RSNAConfigPMKLifetime,
+ pasn_get_ptk(pasn), NULL, NULL,
+ pasn_get_akmp(pasn));
+
+ if (pasn->pmksa_entry)
+ wpa_sm_set_cur_pmksa(wpa_s->wpa, pasn->pmksa_entry);
+
+ sme_send_authentication(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, 0);
+ }
+#endif /* CONFIG_ENC_ASSOC */
#ifdef CONFIG_SAE
if (data->auth.auth_type == WLAN_AUTH_SAE) {
const u8 *addr = wpa_s->pending_bssid;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 56d8ba018..6b415c0be 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -9435,6 +9435,7 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_s->last_owe_group = 0;
+ wpa_pasn_reset(&wpa_s->pasn);
if (wpa_supplicant_fast_associate(wpa_s) != 1)
wpa_supplicant_req_scan(wpa_s, 0, 0);
--
2.34.1
More information about the Hostap
mailing list