[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