[PATCH v3 27/27] tests: Add EPPKE authentication test cases
Sai Pratyusha Magam
sai.magam at oss.qualcomm.com
Mon Feb 23 03:14:21 PST 2026
On 1/23/2026 12:34 PM, Benjamin Berg wrote:
> [resend to avoid list size limit]
>
> Hi,
>
> for most of the tests you already have a run_* function as they are
> almost identical. I did notice these two though that could also share
> code by using a run_ handler (maybe there are others):
> * test_eppke_mld_ap_with_base_akm_sae_legacy_client_pmksa_cached
> * test_eppke_mld_ap_with_base_akm_sae_ext_legacy_client_pmksa_cached
>
Thanks, will do
> One more comment inline at the end.
>
> On Thu, 2026-01-15 at 22:03 +0530, Ainy Kumari wrote:
>> From: Sai Pratyusha Magam <smagam at qti.qualcomm.com>
>>
>> Add hwsim test cases to verify EPPKE authentication,
>> including (Re)Association frame encryption in
>> multi-link and legacy 11ax scenarios. Tests cover AP and
>> MLD configurations with SAE and SAE-EXT-KEY base AKMs,
>> SAE-EXT-KEY AKM with different groups, PMKSA Caching,
>> validating RSNXE flags, AKM suite selection, and
>> authentication algorithm handling.
>>
>> Signed-off-by: Ainy Kumari <ainy.kumari at oss.qualcomm.com>
>> Signed-off-by: Sai Pratyusha Magam <smagam at qti.qualcomm.com>
>> ---
>> tests/hwsim/test_eppke.py | 675 ++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 675 insertions(+)
>> create mode 100644 tests/hwsim/test_eppke.py
>>
>> diff --git a/tests/hwsim/test_eppke.py b/tests/hwsim/test_eppke.py
>> new file mode 100644
>> index 000000000..e52e96e1e
>> --- /dev/null
>> +++ b/tests/hwsim/test_eppke.py
>> @@ -0,0 +1,675 @@
>> +# Test cases for Enhanced Privacy Protection Key Exchange(EPPKE)
>> +# Copyright (c) 2025, Qualcomm Innovation Center, Inc.
>> +#
>> +# This software may be distributed under the terms of the BSD license.
>> +# See README for more details.
>> +
>> +import time
>> +
>> +import hostapd
>> +from wpasupplicant import WpaSupplicant
>> +from utils import *
>> +from hwsim import HWSimRadio
>> +from test_eht import eht_mld_ap_wpa2_params, eht_mld_enable_ap, traffic_test, eht_verify_status
>> +
>> +def test_eppke_akm_suite_and_rsnxe_feature_flags(dev, apdev):
>> + """AP EPPKE AKM Advertisement with SAE base AKM and EPPKE related feature flags"""
>> + ssid = "test-eppke-authentication"
>> + params = hostapd.wpa3_params(ssid=ssid,
>> + password = "1234567890")
>> + params['wpa_key_mgmt'] = params['wpa_key_mgmt'] + ' ' + 'EPPKE'
>> + params['assoc_frame_encryption'] = '1'
>> + params['pmksa_caching_privacy'] = '1'
>> + params['eap_using_authentication_frames'] = '1'
>> + params['sae_pwe'] = '2'
>> +
>> + hapd = hostapd.add_ap(apdev[0], params)
>> + time.sleep(2)
>> + #TODO: Add pcap file checks to validate correct
>> + #RSNXE bits and AKM suite presence in Beacon frames
>> +
>> + #Disable all EPPKE related RSNXE flags and test
>> + params['assoc_frame_encryption'] = '0'
>> + params['pmksa_caching_privacy'] = '0'
>> + params['eap_using_authentication_frames'] = '0'
>> + hapd = hostapd.add_ap(apdev[0], params)
>> + time.sleep(2)
>> +
>> +def test_eppke_ap_with_base_akm_sae_legacy_client(dev, apdev):
>> + """EPPKE authentication with a Non-MLO AP with base AKM SAE and legacy client"""
>> + ssid = "test-eppke-authentication"
>> + passphrase = '1234567890'
>> + params = hostapd.wpa3_params(ssid=ssid,
>> + password = passphrase)
>> + params['wpa_key_mgmt'] = params['wpa_key_mgmt'] + ' ' + 'EPPKE'
>> + params['assoc_frame_encryption'] = '1'
>> + params['pmksa_caching_privacy'] = '1'
>> + params['eap_using_authentication_frames'] = '1'
>> + params['sae_pwe'] = '2'
>> + hapd = hostapd.add_ap(apdev[0], params)
>> +
>> + try:
>> + dev[0].set("sae_groups", "")
>> + dev[0].set("sae_pwe", "1")
>> + dev[0].connect(ssid, sae_password=passphrase, scan_freq="2412",
>> + key_mgmt="SAE", ieee80211w="2", beacon_prot="1",
>> + pairwise="CCMP")
>> + hapd.wait_sta();
>> + sta = hapd.get_sta(dev[0].own_addr())
>> + if sta["AKMSuiteSelector"] != '00-0f-ac-8' or sta["auth_alg"] != '9':
>> + raise Exception("Incorrect Auth Algo/AKMSuiteSelector value")
>> +
>> + finally:
>> + dev[0].set("sae_groups", "")
>> + dev[0].set("sae_pwe", "0")
>> +
>> +def run_eppke_sae_ext_key(dev, apdev, group):
>> + """EPPKE authentication with a Non-MLO AP with base AKM SAE-EXT-KEY and legacy client"""
>> + ssid = "test-eppke-authentication"
>> + passphrase = '1234567890'
>> + params = hostapd.wpa3_params(ssid=ssid,
>> + password = passphrase)
>> + params['wpa_key_mgmt'] = params['wpa_key_mgmt'] + ' ' + 'SAE-EXT-KEY EPPKE'
>> + params['assoc_frame_encryption'] = '1'
>> + params['pmksa_caching_privacy'] = '1'
>> + params['eap_using_authentication_frames'] = '1'
>> + params['sae_pwe'] = '2'
>> + params['pasn_groups'] = str(group)
>> + params['sae_groups'] = str(group)
>> + hapd = hostapd.add_ap(apdev[0], params)
>> +
>> + try:
>> + dev[0].set("sae_groups", str(group))
>> + dev[0].set("sae_pwe", "1")
>> + dev[0].connect(ssid, sae_password=passphrase, scan_freq="2412",
>> + key_mgmt="SAE-EXT-KEY", ieee80211w="2", beacon_prot="1",
>> + pairwise="CCMP")
>> + hapd.wait_sta();
>> + sta = hapd.get_sta(dev[0].own_addr())
>> + if sta["AKMSuiteSelector"] != '00-0f-ac-24' or sta["auth_alg"] != '9':
>> + raise Exception("Incorrect Auth Algo/AKMSuiteSelector value")
>> +
>> + finally:
>> + dev[0].set("sae_groups", "")
>> + dev[0].set("sae_pwe", "0")
>> +
>> +def test_eppke_ap_with_base_akm_sae_ext_legacy_client_19(dev, apdev):
>> + """EPPKE authentication with a Non-MLO AP with base AKM SAE-EXT-KEY and legacy client, group 19"""
>> + run_eppke_sae_ext_key(dev, apdev, 19)
>> +
>> +def test_eppke_ap_with_base_akm_sae_ext_legacy_client_20(dev, apdev):
>> + """EPPKE authentication with a Non-MLO AP with base AKM SAE-EXT-KEY and legacy client, group 20"""
>> + run_eppke_sae_ext_key(dev, apdev, 20)
>> +
>> +def test_eppke_ap_with_base_akm_sae_ext_legacy_client_21(dev, apdev):
>> + """EPPKE authentication with a Non-MLO AP with base AKM SAE-EXT-KEY and legacy client, group 21"""
>> + run_eppke_sae_ext_key(dev, apdev, 21)
>> +
>> +def test_eppke_mld_ap_with_base_akm_sae_legacy_client(dev, apdev):
>> + """EPPKE authentication with an MLD AP with base AKM SAE and legacy client"""
>> + with HWSimRadio(use_mlo=True) as (hapd_radio, hapd_iface):
>> + passphrase = '1234567890'
>> + ssid = "test-eppke-authentication"
>> + params = eht_mld_ap_wpa2_params(ssid, passphrase,
>> + key_mgmt="SAE", mfp="2", pwe='1')
>> + params['wpa_key_mgmt'] = params['wpa_key_mgmt'] + ' ' + 'EPPKE'
>> + params['assoc_frame_encryption'] = '1'
>> + params['pmksa_caching_privacy'] = '1'
>> + params['eap_using_authentication_frames'] = '1'
>> + params['rsn_pairwise'] = "CCMP GCMP-256"
>> +
>> + hapd0 = eht_mld_enable_ap(hapd_iface, 0, params)
>> +
>> + params['channel'] = '6'
>> + hapd1 = eht_mld_enable_ap(hapd_iface, 1, params)
>> +
>> + try:
>> + dev[0].set("sae_groups", "")
>> + dev[0].set("sae_pwe", "1")
>> + dev[0].connect(ssid, sae_password=passphrase, scan_freq="2412",
>> + key_mgmt="SAE", ieee80211w="2", beacon_prot="1",
>> + pairwise="CCMP GCMP-256")
>> + bssid = dev[0].get_status_field("bssid")
>> + if hapd0.own_addr() == bssid:
>> + hapd0.wait_sta();
>> + sta = hapd0.get_sta(dev[0].own_addr())
>> + if sta["AKMSuiteSelector"] != '00-0f-ac-8' or sta["auth_alg"] != '9':
>> + raise Exception("Incorrect Auth Algo/AKMSuiteSelector value")
>> + elif hapd1.own_addr() == bssid:
>> + hapd1.wait_sta();
>> + sta = hapd1.get_sta(dev[0].own_addr())
>> + if sta["AKMSuiteSelector"] != '00-0f-ac-8' or sta["auth_alg"] != '9':
>> + raise Exception("Incorrect Auth Algo/AKMSuiteSelector value")
>> + else:
>> + raise Exception("Unknown BSSID: " + bssid)
>
> I see this pattern quite a bit in the patch. For
> https://patchwork.ozlabs.org/project/hostap/patch/20251016143754.2532665-3-benjamin@sipsolutions.net/
> I added a simple "mld_wait_event" helper, that will accept the event
> from any of the given hapd instances.
>
> Maybe you could pick it up and add it to your patch? Thinking about it
> now, it could make sense to return a tuple with (hapd, event) instead,
> so the API user knows which hostapd instance replied.
> Feel free to improve further if you find the API suboptimal.
>
Hi Benjamin,
Thanks for pointing out the "mld_wait_event" helper. It seems useful
especially for the cases when the event can appear on any of the AP MLD
link. In test_eppke_mld_ap_with_base_akm_sae_legacy_client, the
scan_freq in connect call always ensures the non-ml connection is on
hapd0, so the wait_sta on hapd1 was actually not needed. Will clean it up.
> Benjamin
>
>> [Removed rest of the patch]
More information about the Hostap
mailing list