[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