[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