[PATCH v3 17/27] EPPKE: Add support for EPPKE authentication for SME-in-Userspace case

Benjamin Berg benjamin at sipsolutions.net
Thu Jan 22 05:18:19 PST 2026


Hi,

On Thu, 2026-01-15 at 22:02 +0530, Ainy Kumari wrote:
> 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       | 154 +++++++++++++++++--------
>  src/pasn/pasn_responder.c       |   4 +-
>  wpa_supplicant/sme.c            | 196 +++++++++++++++++++++++++++++++-
>  wpa_supplicant/wpa_supplicant.c |   1 +
>  6 files changed, 309 insertions(+), 63 deletions(-)
> 
> diff --git a/src/pasn/pasn_common.c b/src/pasn/pasn_common.c
> index f9ec5ca9c..35b91b32d 100644
> --- a/src/pasn/pasn_common.c
> +++ b/src/pasn/pasn_common.c
> @@ -331,14 +331,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 45ac3b4ce..cf9ef93b1 100644
> --- a/src/pasn/pasn_common.h
> +++ b/src/pasn/pasn_common.h
> @@ -183,6 +183,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,
> @@ -193,6 +197,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 68a4f09fa..ec356173a 100644
> --- a/src/pasn/pasn_initiator.c
> +++ b/src/pasn/pasn_initiator.c
> @@ -582,9 +582,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)) {
> @@ -682,7 +688,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];
> @@ -703,13 +710,18 @@ static struct wpabuf * wpas_pasn_build_auth_3(struct pasn_data *pasn)
>  	if (!buf)
>  		goto fail;
>  
> -	wrapped_data = wpas_pasn_get_wrapped_data_format(pasn);
> +	if (!is_sme_drv) {
> +		wpabuf_put_le16(buf, WLAN_AUTH_TR_SEQ_PASN_AUTH3);
> +		wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
> +	} else {
> +		wpa_pasn_build_auth_header(buf, pasn->bssid,
> +					   pasn->own_addr, pasn->peer_addr,
> +					   WLAN_AUTH_TR_SEQ_PASN_AUTH3,
> +					   WLAN_STATUS_SUCCESS,
> +					   pasn->auth_alg == WLAN_AUTH_EPPKE);
> +	}
>  
> -	wpa_pasn_build_auth_header(buf, pasn->bssid,
> -				   pasn->own_addr, pasn->peer_addr,
> -				   WLAN_AUTH_TR_SEQ_PASN_AUTH3,
> -				   WLAN_STATUS_SUCCESS,
> -				   pasn->auth_alg == WLAN_AUTH_EPPKE);
> +	wrapped_data = wpas_pasn_get_wrapped_data_format(pasn);
>  
>  	wrapped_data_buf = wpas_pasn_get_wrapped_data(pasn);
>  
> @@ -1010,7 +1022,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;
> @@ -1153,36 +1165,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,
> @@ -1190,10 +1193,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;
> @@ -1354,14 +1355,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 */
> @@ -1421,12 +1432,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;
> @@ -1451,21 +1511,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 1aa72de11..f7f1bc413 100644
> --- a/src/pasn/pasn_responder.c
> +++ b/src/pasn/pasn_responder.c
> @@ -1184,7 +1184,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 fba6508bc..3510faf74 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,20 @@ 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);
> +

You are not handling the error case here if (resp == NULL).

Benjamin

> +		params.auth_data = wpabuf_head(resp);
> +		params.auth_data_len = wpabuf_len(resp);
> +		wpa_s->sme.auth_alg = params.auth_alg;
> +	}
> +#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,
> @@ -1167,7 +1320,9 @@ no_fils:
>  		wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
>  
>  	eapol_sm_notify_portValid(wpa_s->eapol, false);
> -	wpa_clear_keys(wpa_s, bss->bssid);
> +	if (wpa_s->sme.auth_alg != WPA_AUTH_ALG_EPPKE) {
> +		wpa_clear_keys(wpa_s, bss->bssid);
> +	}
>  	wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
>  	if (old_ssid != wpa_s->current_ssid)
>  		wpas_notify_network_changed(wpa_s);
> @@ -2080,6 +2235,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 293d4920e..70c92ea00 100644
> --- a/wpa_supplicant/wpa_supplicant.c
> +++ b/wpa_supplicant/wpa_supplicant.c
> @@ -9476,6 +9476,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);



More information about the Hostap mailing list