1# Test cases for SAE
2# Copyright (c) 2013-2020, Jouni Malinen <j@w1.fi>
3#
4# This software may be distributed under the terms of the BSD license.
5# See README for more details.
6
7from remotehost import remote_compatible
8import binascii
9import os
10import time
11import logging
12logger = logging.getLogger()
13import socket
14import struct
15import subprocess
16import tempfile
17
18import hwsim_utils
19import hostapd
20from wpasupplicant import WpaSupplicant
21from utils import *
22from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations
23
24@remote_compatible
25def test_sae(dev, apdev):
26    """SAE with default group"""
27    check_sae_capab(dev[0])
28    params = hostapd.wpa2_params(ssid="test-sae",
29                                 passphrase="12345678")
30    params['wpa_key_mgmt'] = 'SAE'
31    hapd = hostapd.add_ap(apdev[0], params)
32    key_mgmt = hapd.get_config()['key_mgmt']
33    if key_mgmt.split(' ')[0] != "SAE":
34        raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
35
36    dev[0].request("SET sae_groups ")
37    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
38                        scan_freq="2412")
39    hapd.wait_sta()
40    if dev[0].get_status_field('sae_group') != '19':
41            raise Exception("Expected default SAE group not used")
42    bss = dev[0].get_bss(apdev[0]['bssid'])
43    if 'flags' not in bss:
44        raise Exception("Could not get BSS flags from BSS table")
45    if "[WPA2-SAE-CCMP]" not in bss['flags']:
46        raise Exception("Unexpected BSS flags: " + bss['flags'])
47
48    res = hapd.request("STA-FIRST")
49    if "sae_group=19" not in res.splitlines():
50        raise Exception("hostapd STA output did not specify SAE group")
51
52    pmk_h = hapd.request("GET_PMK " + dev[0].own_addr())
53    pmk_w = dev[0].get_pmk(id)
54    if pmk_h != pmk_w:
55        raise Exception("Fetched PMK does not match: hostapd %s, wpa_supplicant %s" % (pmk_h, pmk_w))
56    dev[0].request("DISCONNECT")
57    dev[0].wait_disconnected()
58    pmk_h2 = hapd.request("GET_PMK " + dev[0].own_addr())
59    if pmk_h != pmk_h2:
60        raise Exception("Fetched PMK from PMKSA cache does not match: %s, %s" % (pmk_h, pmk_h2))
61    if "FAIL" not in hapd.request("GET_PMK foo"):
62        raise Exception("Invalid GET_PMK did not return failure")
63    if "FAIL" not in hapd.request("GET_PMK 02:ff:ff:ff:ff:ff"):
64        raise Exception("GET_PMK for unknown STA did not return failure")
65
66@remote_compatible
67def test_sae_password_ecc(dev, apdev):
68    """SAE with number of different passwords (ECC)"""
69    check_sae_capab(dev[0])
70    params = hostapd.wpa2_params(ssid="test-sae",
71                                 passphrase="12345678")
72    params['wpa_key_mgmt'] = 'SAE'
73    hapd = hostapd.add_ap(apdev[0], params)
74
75    dev[0].request("SET sae_groups 19")
76
77    for i in range(10):
78        password = "12345678-" + str(i)
79        hapd.set("wpa_passphrase", password)
80        dev[0].connect("test-sae", psk=password, key_mgmt="SAE",
81                       scan_freq="2412")
82        dev[0].request("REMOVE_NETWORK all")
83        dev[0].wait_disconnected()
84
85@remote_compatible
86def test_sae_password_ffc(dev, apdev):
87    """SAE with number of different passwords (FFC)"""
88    check_sae_capab(dev[0])
89    params = hostapd.wpa2_params(ssid="test-sae",
90                                 passphrase="12345678")
91    params['wpa_key_mgmt'] = 'SAE'
92    params['sae_groups'] = '15'
93    hapd = hostapd.add_ap(apdev[0], params)
94
95    dev[0].request("SET sae_groups 15")
96
97    for i in range(10):
98        password = "12345678-" + str(i)
99        hapd.set("wpa_passphrase", password)
100        dev[0].connect("test-sae", psk=password, key_mgmt="SAE",
101                       scan_freq="2412")
102        dev[0].request("REMOVE_NETWORK all")
103        dev[0].wait_disconnected()
104
105@remote_compatible
106def test_sae_pmksa_caching(dev, apdev):
107    """SAE and PMKSA caching"""
108    run_sae_pmksa_caching(dev, apdev)
109
110@remote_compatible
111def test_sae_pmksa_caching_pmkid(dev, apdev):
112    """SAE and PMKSA caching (PMKID in AssocReq after SAE)"""
113    try:
114        dev[0].set("sae_pmkid_in_assoc", "1")
115        run_sae_pmksa_caching(dev, apdev)
116    finally:
117        dev[0].set("sae_pmkid_in_assoc", "0")
118
119def run_sae_pmksa_caching(dev, apdev):
120    check_sae_capab(dev[0])
121    params = hostapd.wpa2_params(ssid="test-sae",
122                                 passphrase="12345678")
123    params['wpa_key_mgmt'] = 'SAE'
124    hapd = hostapd.add_ap(apdev[0], params)
125
126    dev[0].request("SET sae_groups ")
127    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
128                   scan_freq="2412")
129    ev = hapd.wait_event(["AP-STA-CONNECTED"], timeout=5)
130    if ev is None:
131        raise Exception("No connection event received from hostapd")
132    sta0 = hapd.get_sta(dev[0].own_addr())
133    if sta0['wpa'] != '2' or sta0['AKMSuiteSelector'] != '00-0f-ac-8':
134        raise Exception("SAE STA(0) AKM suite selector reported incorrectly")
135    dev[0].request("DISCONNECT")
136    dev[0].wait_disconnected()
137    dev[0].request("RECONNECT")
138    dev[0].wait_connected(timeout=15, error="Reconnect timed out")
139    val = dev[0].get_status_field('sae_group')
140    if val is not None:
141        raise Exception("SAE group claimed to have been used: " + val)
142    sta0 = hapd.get_sta(dev[0].own_addr())
143    if sta0['wpa'] != '2' or sta0['AKMSuiteSelector'] != '00-0f-ac-8':
144        raise Exception("SAE STA(0) AKM suite selector reported incorrectly after PMKSA caching")
145
146@remote_compatible
147def test_sae_pmksa_caching_disabled(dev, apdev):
148    """SAE and PMKSA caching disabled"""
149    check_sae_capab(dev[0])
150    params = hostapd.wpa2_params(ssid="test-sae",
151                                 passphrase="12345678")
152    params['wpa_key_mgmt'] = 'SAE'
153    params['disable_pmksa_caching'] = '1'
154    hapd = hostapd.add_ap(apdev[0], params)
155
156    dev[0].request("SET sae_groups ")
157    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
158                   scan_freq="2412")
159    ev = hapd.wait_event(["AP-STA-CONNECTED"], timeout=5)
160    if ev is None:
161        raise Exception("No connection event received from hostapd")
162    dev[0].request("DISCONNECT")
163    dev[0].wait_disconnected()
164    dev[0].request("RECONNECT")
165    dev[0].wait_connected(timeout=15, error="Reconnect timed out")
166    if dev[0].get_status_field('sae_group') != '19':
167            raise Exception("Expected default SAE group not used")
168
169def test_sae_groups(dev, apdev):
170    """SAE with all supported groups"""
171    check_sae_capab(dev[0])
172    # This is the full list of supported groups, but groups 14-16 (2048-4096 bit
173    # MODP) and group 21 (521-bit random ECP group) are a bit too slow on some
174    # VMs and can result in hitting the mac80211 authentication timeout, so
175    # allow them to fail and just report such failures in the debug log.
176    sae_groups = [19, 25, 26, 20, 21, 1, 2, 5, 14, 15, 16, 22, 23, 24]
177    tls = dev[0].request("GET tls_library")
178    if tls.startswith("OpenSSL") and "run=OpenSSL 1." in tls:
179        logger.info("Add Brainpool EC groups since OpenSSL is new enough")
180        sae_groups += [27, 28, 29, 30]
181    heavy_groups = [14, 15, 16]
182    suitable_groups = [15, 16, 17, 18, 19, 20, 21]
183    groups = [str(g) for g in sae_groups]
184    params = hostapd.wpa2_params(ssid="test-sae-groups",
185                                 passphrase="12345678")
186    params['wpa_key_mgmt'] = 'SAE'
187    params['sae_groups'] = ' '.join(groups)
188    hapd = hostapd.add_ap(apdev[0], params)
189
190    for g in groups:
191        logger.info("Testing SAE group " + g)
192        dev[0].request("SET sae_groups " + g)
193        id = dev[0].connect("test-sae-groups", psk="12345678", key_mgmt="SAE",
194                            scan_freq="2412", wait_connect=False)
195        if int(g) in heavy_groups:
196            ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=5)
197            if ev is None:
198                logger.info("No connection with heavy SAE group %s did not connect - likely hitting timeout in mac80211" % g)
199                dev[0].remove_network(id)
200                time.sleep(0.1)
201                dev[0].dump_monitor()
202                continue
203            logger.info("Connection with heavy SAE group " + g)
204        else:
205            ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=10)
206            if ev is None:
207                if "BoringSSL" in tls and int(g) in [25]:
208                    logger.info("Ignore connection failure with group " + g + " with BoringSSL")
209                    dev[0].remove_network(id)
210                    dev[0].dump_monitor()
211                    continue
212                if int(g) not in suitable_groups:
213                    logger.info("Ignore connection failure with unsuitable group " + g)
214                    dev[0].remove_network(id)
215                    dev[0].dump_monitor()
216                    continue
217                raise Exception("Connection timed out with group " + g)
218        if dev[0].get_status_field('sae_group') != g:
219            raise Exception("Expected SAE group not used")
220        pmksa = dev[0].get_pmksa(hapd.own_addr())
221        if not pmksa:
222            raise Exception("No PMKSA cache entry added")
223        if pmksa['pmkid'] == '00000000000000000000000000000000':
224            raise Exception("All zeros PMKID derived for group %s" % g)
225        dev[0].remove_network(id)
226        dev[0].wait_disconnected()
227        dev[0].dump_monitor()
228
229@remote_compatible
230def test_sae_group_nego(dev, apdev):
231    """SAE group negotiation"""
232    check_sae_capab(dev[0])
233    params = hostapd.wpa2_params(ssid="test-sae-group-nego",
234                                 passphrase="12345678")
235    params['wpa_key_mgmt'] = 'SAE'
236    params['sae_groups'] = '19'
237    hostapd.add_ap(apdev[0], params)
238
239    dev[0].request("SET sae_groups 25 20 19")
240    dev[0].connect("test-sae-group-nego", psk="12345678", key_mgmt="SAE",
241                   scan_freq="2412")
242    if dev[0].get_status_field('sae_group') != '19':
243        raise Exception("Expected SAE group not used")
244
245def test_sae_group_nego_no_match(dev, apdev):
246    """SAE group negotiation (no match)"""
247    check_sae_capab(dev[0])
248    params = hostapd.wpa2_params(ssid="test-sae-group-nego",
249                                 passphrase="12345678")
250    params['wpa_key_mgmt'] = 'SAE'
251    # None-existing SAE group to force all attempts to be rejected
252    params['sae_groups'] = '0'
253    hostapd.add_ap(apdev[0], params)
254
255    dev[0].request("SET sae_groups ")
256    dev[0].connect("test-sae-group-nego", psk="12345678", key_mgmt="SAE",
257                   scan_freq="2412", wait_connect=False)
258    ev = dev[0].wait_event(["CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=10)
259    dev[0].request("REMOVE_NETWORK all")
260    if ev is None:
261        raise Exception("Network profile disabling not reported")
262
263@remote_compatible
264def test_sae_anti_clogging(dev, apdev):
265    """SAE anti clogging"""
266    check_sae_capab(dev[0])
267    check_sae_capab(dev[1])
268    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
269    params['wpa_key_mgmt'] = 'SAE'
270    params['sae_anti_clogging_threshold'] = '1'
271    hostapd.add_ap(apdev[0], params)
272
273    dev[0].request("SET sae_groups ")
274    dev[1].request("SET sae_groups ")
275    id = {}
276    for i in range(0, 2):
277        dev[i].scan(freq="2412")
278        id[i] = dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
279                               scan_freq="2412", only_add_network=True)
280    for i in range(0, 2):
281        dev[i].select_network(id[i])
282    for i in range(0, 2):
283        dev[i].wait_connected(timeout=10)
284
285def test_sae_forced_anti_clogging(dev, apdev):
286    """SAE anti clogging (forced)"""
287    check_sae_capab(dev[0])
288    check_sae_capab(dev[1])
289    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
290    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
291    params['sae_anti_clogging_threshold'] = '0'
292    hostapd.add_ap(apdev[0], params)
293    dev[2].connect("test-sae", psk="12345678", scan_freq="2412")
294    for i in range(0, 2):
295        dev[i].request("SET sae_groups ")
296        dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
297                       scan_freq="2412")
298
299def test_sae_mixed(dev, apdev):
300    """Mixed SAE and non-SAE network"""
301    check_sae_capab(dev[0])
302    check_sae_capab(dev[1])
303    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
304    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
305    params['sae_anti_clogging_threshold'] = '0'
306    hapd = hostapd.add_ap(apdev[0], params)
307
308    dev[2].connect("test-sae", psk="12345678", scan_freq="2412")
309    for i in range(0, 2):
310        dev[i].request("SET sae_groups ")
311        dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
312                       scan_freq="2412")
313    sta0 = hapd.get_sta(dev[0].own_addr())
314    sta2 = hapd.get_sta(dev[2].own_addr())
315    if sta0['wpa'] != '2' or sta0['AKMSuiteSelector'] != '00-0f-ac-8':
316        raise Exception("SAE STA(0) AKM suite selector reported incorrectly")
317    if sta2['wpa'] != '2' or sta2['AKMSuiteSelector'] != '00-0f-ac-2':
318        raise Exception("PSK STA(2) AKM suite selector reported incorrectly")
319
320def test_sae_and_psk(dev, apdev):
321    """SAE and PSK enabled in network profile"""
322    check_sae_capab(dev[0])
323    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
324    params['wpa_key_mgmt'] = 'SAE'
325    hostapd.add_ap(apdev[0], params)
326
327    dev[0].request("SET sae_groups ")
328    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE WPA-PSK",
329                   scan_freq="2412")
330
331def test_sae_and_psk2(dev, apdev):
332    """SAE and PSK enabled in network profile (use PSK)"""
333    check_sae_capab(dev[0])
334    params = hostapd.wpa2_params(ssid="test-psk", passphrase="12345678")
335    hostapd.add_ap(apdev[0], params)
336
337    dev[0].request("SET sae_groups ")
338    dev[0].connect("test-psk", psk="12345678", key_mgmt="SAE WPA-PSK",
339                   scan_freq="2412")
340
341def test_sae_wpa3_roam(dev, apdev):
342    """SAE and WPA3-Personal transition mode roaming"""
343    check_sae_capab(dev[0])
344
345    # WPA3-Personal only AP
346    params = hostapd.wpa2_params(ssid="test", passphrase="12345678")
347    params['ieee80211w'] = '2'
348    params['wpa_key_mgmt'] = 'SAE'
349    hapd0 = hostapd.add_ap(apdev[0], params)
350
351    # WPA2-Personal only AP
352    params = hostapd.wpa2_params(ssid="test", passphrase="12345678")
353    hapd1 = hostapd.add_ap(apdev[1], params)
354
355    dev[0].set("sae_groups", "")
356    dev[0].connect("test", psk="12345678", key_mgmt="SAE WPA-PSK",
357                   ieee80211w="1", scan_freq="2412")
358    bssid = dev[0].get_status_field('bssid')
359
360    # Disable the current AP to force roam to the other one
361    if bssid == apdev[0]['bssid']:
362        hapd0.disable()
363    else:
364        hapd1.disable()
365    dev[0].wait_connected()
366
367    # Disable the current AP to force roam to the other (previous) one
368    if bssid == apdev[0]['bssid']:
369        hapd0.enable()
370        hapd1.disable()
371    else:
372        hapd1.enable()
373        hapd0.disable()
374    dev[0].wait_connected()
375
376    # Force roam to an AP in WPA3-Personal transition mode
377    if bssid == apdev[0]['bssid']:
378        hapd1.set("ieee80211w", "1")
379        hapd1.set("sae_require_mfp", "1")
380        hapd1.set("wpa_key_mgmt", "SAE WPA-PSK")
381        hapd1.enable()
382        hapd0.disable()
383    else:
384        hapd0.set("ieee80211w", "1")
385        hapd0.set("sae_require_mfp", "1")
386        hapd0.set("wpa_key_mgmt", "SAE WPA-PSK")
387        hapd0.enable()
388        hapd1.disable()
389    dev[0].wait_connected()
390    status = dev[0].get_status()
391    if status['key_mgmt'] != "SAE":
392        raise Exception("Did not use SAE with WPA3-Personal transition mode AP")
393    if status['pmf'] != "1":
394        raise Exception("Did not use PMF with WPA3-Personal transition mode AP")
395
396def test_sae_mixed_mfp(dev, apdev):
397    """Mixed SAE and non-SAE network and MFP required with SAE"""
398    check_sae_capab(dev[0])
399    check_sae_capab(dev[1])
400    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
401    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
402    params["ieee80211w"] = "1"
403    params['sae_require_mfp'] = '1'
404    hostapd.add_ap(apdev[0], params)
405
406    dev[0].request("SET sae_groups ")
407    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", ieee80211w="2",
408                   scan_freq="2412")
409    dev[0].dump_monitor()
410
411    dev[1].request("SET sae_groups ")
412    dev[1].connect("test-sae", psk="12345678", key_mgmt="SAE", ieee80211w="0",
413                   scan_freq="2412", wait_connect=False)
414    ev = dev[1].wait_event(["CTRL-EVENT-CONNECTED",
415                            "CTRL-EVENT-ASSOC-REJECT"], timeout=10)
416    if ev is None:
417        raise Exception("No connection result reported")
418    if "CTRL-EVENT-ASSOC-REJECT" not in ev:
419        raise Exception("SAE connection without MFP was not rejected")
420    if "status_code=31" not in ev:
421        raise Exception("Unexpected status code in rejection: " + ev)
422    dev[1].request("DISCONNECT")
423    dev[1].dump_monitor()
424
425    dev[2].connect("test-sae", psk="12345678", ieee80211w="0", scan_freq="2412")
426    dev[2].dump_monitor()
427
428def _test_sae_mixed_check_mfp(dev, apdev):
429    """Mixed SAE and non-SAE network with the sae_check_mfp option"""
430    check_sae_capab(dev[0])
431    check_sae_capab(dev[1])
432    check_sae_capab(dev[2])
433
434    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
435    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
436    params["ieee80211w"] = "1"
437    hostapd.add_ap(apdev[0], params)
438
439    params = hostapd.wpa2_params(ssid="test-sae-no-mfp", passphrase="12345678")
440    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
441    params["ieee80211w"] = "0"
442    hostapd.add_ap(apdev[1], params)
443
444    dev[0].set("sae_check_mfp", "0")
445    dev[0].set("sae_groups", "")
446    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE WPA-PSK",
447                   ieee80211w="0", scan_freq="2412")
448    dev[0].dump_monitor()
449    status = dev[0].get_status()
450    if status['key_mgmt'] != "SAE":
451        raise Exception("SAE without sae_check_mfp was not allowed")
452
453    # Confirm SAE is used when sae_check_mfp is not set for non-PMF AP.
454    dev[2].set("sae_check_mfp", "0")
455    dev[2].set("sae_groups", "")
456    dev[2].connect("test-sae-no-mfp", psk="12345678", key_mgmt="SAE WPA-PSK",
457                   ieee80211w="1", scan_freq="2412")
458    status = dev[2].get_status()
459    if status['key_mgmt'] != "SAE":
460        raise Exception("SAE without sae_check_mfp was not allowed")
461    dev[2].dump_monitor()
462
463    # Confirm SAE is not used with the PMF disabled network configuration.
464    dev[1].set("sae_check_mfp", "1")
465    dev[1].set("sae_groups", "")
466    dev[1].connect("test-sae", psk="12345678", key_mgmt="SAE WPA-PSK",
467                   ieee80211w="0", scan_freq="2412")
468    status = dev[1].get_status()
469    dev[1].request("DISCONNECT")
470    dev[1].wait_disconnected()
471    dev[1].dump_monitor()
472    if status['key_mgmt'] != "WPA2-PSK":
473        raise Exception("SAE without MFP was allowed")
474    dev[1].request("REMOVE_NETWORK all")
475
476    # Confirm SAE is not used connecting to PMF disabled AP.
477    dev[1].set("sae_check_mfp", "1")
478    dev[1].set("sae_groups", "")
479    dev[1].connect("test-sae-no-mfp", psk="12345678", key_mgmt="SAE WPA-PSK",
480                   ieee80211w="1", scan_freq="2412")
481    status = dev[1].get_status()
482    if status['key_mgmt'] != "WPA2-PSK":
483        raise Exception("SAE without MFP was allowed")
484
485def test_sae_mixed_check_mfp(dev, apdev):
486    """Mixed SAE and non-SAE network with the sae_check_mfp option"""
487    try:
488        _test_sae_mixed_check_mfp(dev, apdev)
489    finally:
490        dev[0].set("sae_check_mfp", "0")
491        dev[1].set("sae_check_mfp", "0")
492        dev[2].set("sae_check_mfp", "0")
493
494def test_sae_and_psk_transition_disable(dev, apdev):
495    """SAE and PSK transition disable indication"""
496    check_sae_capab(dev[0])
497    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
498    params["ieee80211w"] = "1"
499    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
500    params['transition_disable'] = '0x01'
501    hapd = hostapd.add_ap(apdev[0], params)
502
503    dev[0].request("SET sae_groups ")
504    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE WPA-PSK",
505                        ieee80211w="1", scan_freq="2412", wait_connect=False)
506    ev = dev[0].wait_event(["TRANSITION-DISABLE"], timeout=15)
507    if ev is None:
508        raise Exception("Transition disable not indicated")
509    if ev.split(' ')[1] != "01":
510        raise Exception("Unexpected transition disable bitmap: " + ev)
511
512    val = dev[0].get_network(id, "ieee80211w")
513    if val != "2":
514        raise Exception("Unexpected ieee80211w value: " + val)
515    val = dev[0].get_network(id, "key_mgmt")
516    if val != "SAE":
517        raise Exception("Unexpected key_mgmt value: " + val)
518    val = dev[0].get_network(id, "group")
519    if val != "CCMP":
520        raise Exception("Unexpected group value: " + val)
521    val = dev[0].get_network(id, "proto")
522    if val != "RSN":
523        raise Exception("Unexpected proto value: " + val)
524
525    dev[0].request("DISCONNECT")
526    dev[0].wait_disconnected()
527    dev[0].request("RECONNECT")
528    dev[0].wait_connected()
529
530def test_sae_mfp(dev, apdev):
531    """SAE and MFP enabled without sae_require_mfp"""
532    check_sae_capab(dev[0])
533    check_sae_capab(dev[1])
534    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
535    params['wpa_key_mgmt'] = 'SAE'
536    params["ieee80211w"] = "1"
537    hostapd.add_ap(apdev[0], params)
538
539    dev[0].request("SET sae_groups ")
540    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", ieee80211w="2",
541                   scan_freq="2412")
542
543    dev[1].request("SET sae_groups ")
544    dev[1].connect("test-sae", psk="12345678", key_mgmt="SAE", ieee80211w="0",
545                   scan_freq="2412")
546
547@remote_compatible
548def test_sae_missing_password(dev, apdev):
549    """SAE and missing password"""
550    check_sae_capab(dev[0])
551    params = hostapd.wpa2_params(ssid="test-sae",
552                                 passphrase="12345678")
553    params['wpa_key_mgmt'] = 'SAE'
554    hapd = hostapd.add_ap(apdev[0], params)
555
556    dev[0].request("SET sae_groups ")
557    id = dev[0].connect("test-sae",
558                        raw_psk="46b4a73b8a951ad53ebd2e0afdb9c5483257edd4c21d12b7710759da70945858",
559                        key_mgmt="SAE", scan_freq="2412", wait_connect=False)
560    ev = dev[0].wait_event(['CTRL-EVENT-SSID-TEMP-DISABLED'], timeout=10)
561    if ev is None:
562        raise Exception("Invalid network not temporarily disabled")
563
564
565def test_sae_key_lifetime_in_memory(dev, apdev, params):
566    """SAE and key lifetime in memory"""
567    check_sae_capab(dev[0])
568    password = "5ad144a7c1f5a5503baa6fa01dabc15b1843e8c01662d78d16b70b5cd23cf8b"
569    p = hostapd.wpa2_params(ssid="test-sae", passphrase=password)
570    p['wpa_key_mgmt'] = 'SAE'
571    hapd = hostapd.add_ap(apdev[0], p)
572
573    pid = find_wpas_process(dev[0])
574
575    dev[0].request("SET sae_groups ")
576    id = dev[0].connect("test-sae", psk=password, key_mgmt="SAE",
577                        scan_freq="2412")
578
579    # The decrypted copy of GTK is freed only after the CTRL-EVENT-CONNECTED
580    # event has been delivered, so verify that wpa_supplicant has returned to
581    # eloop before reading process memory.
582    time.sleep(1)
583    dev[0].ping()
584    password = password.encode()
585    buf = read_process_memory(pid, password)
586
587    dev[0].request("DISCONNECT")
588    dev[0].wait_disconnected()
589
590    dev[0].relog()
591    sae_k = None
592    sae_keyseed = None
593    sae_kck = None
594    pmk = None
595    ptk = None
596    gtk = None
597    with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
598        for l in f.readlines():
599            if "SAE: k - hexdump" in l:
600                val = l.strip().split(':')[3].replace(' ', '')
601                sae_k = binascii.unhexlify(val)
602            if "SAE: keyseed - hexdump" in l:
603                val = l.strip().split(':')[3].replace(' ', '')
604                sae_keyseed = binascii.unhexlify(val)
605            if "SAE: KCK - hexdump" in l:
606                val = l.strip().split(':')[3].replace(' ', '')
607                sae_kck = binascii.unhexlify(val)
608            if "SAE: PMK - hexdump" in l:
609                val = l.strip().split(':')[3].replace(' ', '')
610                pmk = binascii.unhexlify(val)
611            if "WPA: PTK - hexdump" in l:
612                val = l.strip().split(':')[3].replace(' ', '')
613                ptk = binascii.unhexlify(val)
614            if "WPA: Group Key - hexdump" in l:
615                val = l.strip().split(':')[3].replace(' ', '')
616                gtk = binascii.unhexlify(val)
617    if not sae_k or not sae_keyseed or not sae_kck or not pmk or not ptk or not gtk:
618        raise Exception("Could not find keys from debug log")
619    if len(gtk) != 16:
620        raise Exception("Unexpected GTK length")
621
622    kck = ptk[0:16]
623    kek = ptk[16:32]
624    tk = ptk[32:48]
625
626    fname = os.path.join(params['logdir'],
627                         'sae_key_lifetime_in_memory.memctx-')
628
629    logger.info("Checking keys in memory while associated")
630    get_key_locations(buf, password, "Password")
631    get_key_locations(buf, pmk, "PMK")
632    if password not in buf:
633        raise HwsimSkip("Password not found while associated")
634    if pmk not in buf:
635        raise HwsimSkip("PMK not found while associated")
636    if kck not in buf:
637        raise Exception("KCK not found while associated")
638    if kek not in buf:
639        raise Exception("KEK not found while associated")
640    #if tk in buf:
641    #    raise Exception("TK found from memory")
642    verify_not_present(buf, sae_k, fname, "SAE(k)")
643    verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
644    verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
645
646    logger.info("Checking keys in memory after disassociation")
647    buf = read_process_memory(pid, password)
648
649    # Note: Password is still present in network configuration
650    # Note: PMK is in PMKSA cache
651
652    get_key_locations(buf, password, "Password")
653    get_key_locations(buf, pmk, "PMK")
654    verify_not_present(buf, kck, fname, "KCK")
655    verify_not_present(buf, kek, fname, "KEK")
656    verify_not_present(buf, tk, fname, "TK")
657    if gtk in buf:
658        get_key_locations(buf, gtk, "GTK")
659    verify_not_present(buf, gtk, fname, "GTK")
660    verify_not_present(buf, sae_k, fname, "SAE(k)")
661    verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
662    verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
663
664    dev[0].request("PMKSA_FLUSH")
665    logger.info("Checking keys in memory after PMKSA cache flush")
666    buf = read_process_memory(pid, password)
667    get_key_locations(buf, password, "Password")
668    get_key_locations(buf, pmk, "PMK")
669    verify_not_present(buf, pmk, fname, "PMK")
670
671    dev[0].request("REMOVE_NETWORK all")
672
673    logger.info("Checking keys in memory after network profile removal")
674    buf = read_process_memory(pid, password)
675
676    get_key_locations(buf, password, "Password")
677    get_key_locations(buf, pmk, "PMK")
678    verify_not_present(buf, password, fname, "password")
679    verify_not_present(buf, pmk, fname, "PMK")
680    verify_not_present(buf, kck, fname, "KCK")
681    verify_not_present(buf, kek, fname, "KEK")
682    verify_not_present(buf, tk, fname, "TK")
683    verify_not_present(buf, gtk, fname, "GTK")
684    verify_not_present(buf, sae_k, fname, "SAE(k)")
685    verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
686    verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
687
688@remote_compatible
689def test_sae_oom_wpas(dev, apdev):
690    """SAE and OOM in wpa_supplicant"""
691    check_sae_capab(dev[0])
692    params = hostapd.wpa2_params(ssid="test-sae",
693                                 passphrase="12345678")
694    params['wpa_key_mgmt'] = 'SAE'
695    params['sae_groups'] = '19 25 26 20'
696    hapd = hostapd.add_ap(apdev[0], params)
697
698    dev[0].request("SET sae_groups 20")
699    with alloc_fail(dev[0], 1, "sae_set_group"):
700        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
701                       scan_freq="2412")
702        dev[0].request("REMOVE_NETWORK all")
703
704    dev[0].request("SET sae_groups ")
705    with alloc_fail(dev[0], 2, "sae_set_group"):
706        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
707                       scan_freq="2412")
708        dev[0].request("REMOVE_NETWORK all")
709
710    with alloc_fail(dev[0], 1, "wpabuf_alloc;sme_auth_build_sae_commit"):
711        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
712                       scan_freq="2412")
713        dev[0].request("REMOVE_NETWORK all")
714
715    with alloc_fail(dev[0], 1, "wpabuf_alloc;sme_auth_build_sae_confirm"):
716        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
717                       scan_freq="2412", wait_connect=False)
718        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
719        dev[0].request("REMOVE_NETWORK all")
720
721    with alloc_fail(dev[0], 1, "=sme_authenticate"):
722        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
723                       scan_freq="2412", wait_connect=False)
724        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
725        dev[0].request("REMOVE_NETWORK all")
726
727    with alloc_fail(dev[0], 1, "radio_add_work;sme_authenticate"):
728        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
729                       scan_freq="2412", wait_connect=False)
730        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
731        dev[0].request("REMOVE_NETWORK all")
732
733@remote_compatible
734def test_sae_proto_ecc(dev, apdev):
735    """SAE protocol testing (ECC)"""
736    check_sae_capab(dev[0])
737    params = hostapd.wpa2_params(ssid="test-sae",
738                                 passphrase="12345678")
739    params['wpa_key_mgmt'] = 'SAE'
740    hapd = hostapd.add_ap(apdev[0], params)
741    bssid = apdev[0]['bssid']
742
743    dev[0].request("SET sae_groups 19")
744
745    tests = [("Confirm mismatch",
746              "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
747              "0000800edebc3f260dc1fe7e0b20888af2b8a3316252ec37388a8504e25b73dc4240"),
748             ("Commit without even full cyclic group field",
749              "13",
750              None),
751             ("Too short commit",
752              "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02",
753              None),
754             ("Invalid commit scalar (0)",
755              "1300" + "0000000000000000000000000000000000000000000000000000000000000000" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
756              None),
757             ("Invalid commit scalar (1)",
758              "1300" + "0000000000000000000000000000000000000000000000000000000000000001" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
759              None),
760             ("Invalid commit scalar (> r)",
761              "1300" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
762              None),
763             ("Commit element not on curve",
764              "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728d0000000000000000000000000000000000000000000000000000000000000000",
765              None),
766             ("Invalid commit element (y coordinate > P)",
767              "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
768              None),
769             ("Invalid commit element (x coordinate > P)",
770              "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
771              None),
772             ("Different group in commit",
773              "1400" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
774              None),
775             ("Too short confirm",
776              "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
777              "0000800edebc3f260dc1fe7e0b20888af2b8a3316252ec37388a8504e25b73dc42")]
778    for (note, commit, confirm) in tests:
779        logger.info(note)
780        dev[0].scan_for_bss(bssid, freq=2412)
781        hapd.set("ext_mgmt_frame_handling", "1")
782        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
783                       scan_freq="2412", wait_connect=False)
784
785        logger.info("Commit")
786        for i in range(0, 10):
787            req = hapd.mgmt_rx()
788            if req is None:
789                raise Exception("MGMT RX wait timed out (commit)")
790            if req['subtype'] == 11:
791                break
792            req = None
793        if not req:
794            raise Exception("Authentication frame (commit) not received")
795
796        hapd.dump_monitor()
797        resp = {}
798        resp['fc'] = req['fc']
799        resp['da'] = req['sa']
800        resp['sa'] = req['da']
801        resp['bssid'] = req['bssid']
802        resp['payload'] = binascii.unhexlify("030001000000" + commit)
803        hapd.mgmt_tx(resp)
804
805        if confirm:
806            logger.info("Confirm")
807            for i in range(0, 10):
808                req = hapd.mgmt_rx()
809                if req is None:
810                    raise Exception("MGMT RX wait timed out (confirm)")
811                if req['subtype'] == 11:
812                    break
813                req = None
814            if not req:
815                raise Exception("Authentication frame (confirm) not received")
816
817            hapd.dump_monitor()
818            resp = {}
819            resp['fc'] = req['fc']
820            resp['da'] = req['sa']
821            resp['sa'] = req['da']
822            resp['bssid'] = req['bssid']
823            resp['payload'] = binascii.unhexlify("030002000000" + confirm)
824            hapd.mgmt_tx(resp)
825
826        time.sleep(0.1)
827        dev[0].request("REMOVE_NETWORK all")
828        hapd.set("ext_mgmt_frame_handling", "0")
829        hapd.dump_monitor()
830
831@remote_compatible
832def test_sae_proto_ffc(dev, apdev):
833    """SAE protocol testing (FFC)"""
834    check_sae_capab(dev[0])
835    params = hostapd.wpa2_params(ssid="test-sae",
836                                 passphrase="12345678")
837    params['wpa_key_mgmt'] = 'SAE'
838    hapd = hostapd.add_ap(apdev[0], params)
839    bssid = apdev[0]['bssid']
840
841    dev[0].request("SET sae_groups 2")
842
843    tests = [("Confirm mismatch",
844              "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "a8c00117493cdffa5dd671e934bc9cb1a69f39e25e9dd9cd9afd3aea2441a0f5491211c7ba50a753563f9ce943b043557cb71193b28e86ed9544f4289c471bf91b70af5c018cf4663e004165b0fd0bc1d8f3f78adf42eee92bcbc55246fd3ee9f107ab965dc7d4986f23eb71d616ebfe6bfe0a6c1ac5dc1718acee17c9a17486",
845              "0000f3116a9731f1259622e3eb55d4b3b50ba16f8c5f5565b28e609b180c51460251"),
846             ("Too short commit",
847              "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "a8c00117493cdffa5dd671e934bc9cb1a69f39e25e9dd9cd9afd3aea2441a0f5491211c7ba50a753563f9ce943b043557cb71193b28e86ed9544f4289c471bf91b70af5c018cf4663e004165b0fd0bc1d8f3f78adf42eee92bcbc55246fd3ee9f107ab965dc7d4986f23eb71d616ebfe6bfe0a6c1ac5dc1718acee17c9a174",
848              None),
849             ("Invalid element (0) in commit",
850              "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
851              None),
852             ("Invalid element (1) in commit",
853              "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
854              None),
855             ("Invalid element (> P) in commit",
856              "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
857              None)]
858    for (note, commit, confirm) in tests:
859        logger.info(note)
860        dev[0].scan_for_bss(bssid, freq=2412)
861        hapd.set("ext_mgmt_frame_handling", "1")
862        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
863                       scan_freq="2412", wait_connect=False)
864
865        logger.info("Commit")
866        for i in range(0, 10):
867            req = hapd.mgmt_rx()
868            if req is None:
869                raise Exception("MGMT RX wait timed out (commit)")
870            if req['subtype'] == 11:
871                break
872            req = None
873        if not req:
874            raise Exception("Authentication frame (commit) not received")
875
876        hapd.dump_monitor()
877        resp = {}
878        resp['fc'] = req['fc']
879        resp['da'] = req['sa']
880        resp['sa'] = req['da']
881        resp['bssid'] = req['bssid']
882        resp['payload'] = binascii.unhexlify("030001000000" + commit)
883        hapd.mgmt_tx(resp)
884
885        if confirm:
886            logger.info("Confirm")
887            for i in range(0, 10):
888                req = hapd.mgmt_rx()
889                if req is None:
890                    raise Exception("MGMT RX wait timed out (confirm)")
891                if req['subtype'] == 11:
892                    break
893                req = None
894            if not req:
895                raise Exception("Authentication frame (confirm) not received")
896
897            hapd.dump_monitor()
898            resp = {}
899            resp['fc'] = req['fc']
900            resp['da'] = req['sa']
901            resp['sa'] = req['da']
902            resp['bssid'] = req['bssid']
903            resp['payload'] = binascii.unhexlify("030002000000" + confirm)
904            hapd.mgmt_tx(resp)
905
906        time.sleep(0.1)
907        dev[0].request("REMOVE_NETWORK all")
908        hapd.set("ext_mgmt_frame_handling", "0")
909        hapd.dump_monitor()
910
911
912def test_sae_proto_commit_delayed(dev, apdev):
913    """SAE protocol testing - Commit delayed"""
914    check_sae_capab(dev[0])
915    params = hostapd.wpa2_params(ssid="test-sae",
916                                 passphrase="12345678")
917    params['wpa_key_mgmt'] = 'SAE'
918    hapd = hostapd.add_ap(apdev[0], params)
919    bssid = apdev[0]['bssid']
920
921    dev[0].request("SET sae_groups 19")
922
923    dev[0].scan_for_bss(bssid, freq=2412)
924    hapd.set("ext_mgmt_frame_handling", "1")
925    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
926                   scan_freq="2412", wait_connect=False)
927
928    logger.info("Commit")
929    for i in range(0, 10):
930        req = hapd.mgmt_rx()
931        if req is None:
932            raise Exception("MGMT RX wait timed out (commit)")
933        if req['subtype'] == 11:
934            break
935        req = None
936    if not req:
937        raise Exception("Authentication frame (commit) not received")
938
939    hapd.dump_monitor()
940    time.sleep(2.5)
941    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
942
943    logger.info("Commit/Confirm")
944    for i in range(0, 10):
945        req = hapd.mgmt_rx()
946        if req is None:
947            raise Exception("MGMT RX wait timed out (confirm)")
948        if req['subtype'] == 11:
949            trans, = struct.unpack('<H', req['payload'][2:4])
950            if trans == 1:
951                logger.info("Extra Commit")
952                hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
953                continue
954            break
955        req = None
956    if not req:
957        raise Exception("Authentication frame (confirm) not received")
958
959    hapd.dump_monitor()
960    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
961
962    logger.info("Association Request")
963    for i in range(0, 10):
964        req = hapd.mgmt_rx()
965        if req is None:
966            raise Exception("MGMT RX wait timed out (AssocReq)")
967        if req['subtype'] == 0:
968            break
969        req = None
970    if not req:
971        raise Exception("Association Request frame not received")
972
973    hapd.dump_monitor()
974    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
975    ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
976    if ev is None:
977        raise Exception("Management frame TX status not reported (1)")
978    if "stype=1 ok=1" not in ev:
979        raise Exception("Unexpected management frame TX status (1): " + ev)
980    cmd = "MGMT_TX_STATUS_PROCESS %s" % (" ".join(ev.split(' ')[1:4]))
981    if "OK" not in hapd.request(cmd):
982        raise Exception("MGMT_TX_STATUS_PROCESS failed")
983
984    hapd.set("ext_mgmt_frame_handling", "0")
985
986    dev[0].wait_connected()
987
988def test_sae_proto_commit_replay(dev, apdev):
989    """SAE protocol testing - Commit replay"""
990    check_sae_capab(dev[0])
991    params = hostapd.wpa2_params(ssid="test-sae",
992                                 passphrase="12345678")
993    params['wpa_key_mgmt'] = 'SAE'
994    hapd = hostapd.add_ap(apdev[0], params)
995    bssid = apdev[0]['bssid']
996
997    dev[0].request("SET sae_groups 19")
998
999    dev[0].scan_for_bss(bssid, freq=2412)
1000    hapd.set("ext_mgmt_frame_handling", "1")
1001    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1002                   scan_freq="2412", wait_connect=False)
1003
1004    logger.info("Commit")
1005    for i in range(0, 10):
1006        req = hapd.mgmt_rx()
1007        if req is None:
1008            raise Exception("MGMT RX wait timed out (commit)")
1009        if req['subtype'] == 11:
1010            break
1011        req = None
1012    if not req:
1013        raise Exception("Authentication frame (commit) not received")
1014
1015    hapd.dump_monitor()
1016    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
1017    logger.info("Replay Commit")
1018    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
1019
1020    logger.info("Confirm")
1021    for i in range(0, 10):
1022        req = hapd.mgmt_rx()
1023        if req is None:
1024            raise Exception("MGMT RX wait timed out (confirm)")
1025        if req['subtype'] == 11:
1026            trans, = struct.unpack('<H', req['payload'][2:4])
1027            if trans == 1:
1028                logger.info("Extra Commit")
1029                hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
1030                continue
1031            break
1032        req = None
1033    if not req:
1034        raise Exception("Authentication frame (confirm) not received")
1035
1036    hapd.dump_monitor()
1037    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
1038
1039    logger.info("Association Request")
1040    for i in range(0, 10):
1041        req = hapd.mgmt_rx()
1042        if req is None:
1043            raise Exception("MGMT RX wait timed out (AssocReq)")
1044        if req['subtype'] == 0:
1045            break
1046        req = None
1047    if not req:
1048        raise Exception("Association Request frame not received")
1049
1050    hapd.dump_monitor()
1051    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
1052    for i in range(0, 10):
1053        ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
1054        if ev is None:
1055            raise Exception("Management frame TX status not reported (1)")
1056        if "stype=11 ok=1" in ev:
1057            continue
1058        if "stype=12 ok=1" in ev:
1059            continue
1060        if "stype=1 ok=1" not in ev:
1061            raise Exception("Unexpected management frame TX status (1): " + ev)
1062        cmd = "MGMT_TX_STATUS_PROCESS %s" % (" ".join(ev.split(' ')[1:4]))
1063        if "OK" not in hapd.request(cmd):
1064            raise Exception("MGMT_TX_STATUS_PROCESS failed")
1065        break
1066
1067    hapd.set("ext_mgmt_frame_handling", "0")
1068
1069    dev[0].wait_connected()
1070
1071def test_sae_proto_confirm_replay(dev, apdev):
1072    """SAE protocol testing - Confirm replay"""
1073    check_sae_capab(dev[0])
1074    params = hostapd.wpa2_params(ssid="test-sae",
1075                                 passphrase="12345678")
1076    params['wpa_key_mgmt'] = 'SAE'
1077    hapd = hostapd.add_ap(apdev[0], params)
1078    bssid = apdev[0]['bssid']
1079
1080    dev[0].request("SET sae_groups 19")
1081
1082    dev[0].scan_for_bss(bssid, freq=2412)
1083    hapd.set("ext_mgmt_frame_handling", "1")
1084    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1085                   scan_freq="2412", wait_connect=False)
1086
1087    logger.info("Commit")
1088    for i in range(0, 10):
1089        req = hapd.mgmt_rx()
1090        if req is None:
1091            raise Exception("MGMT RX wait timed out (commit)")
1092        if req['subtype'] == 11:
1093            break
1094        req = None
1095    if not req:
1096        raise Exception("Authentication frame (commit) not received")
1097
1098    hapd.dump_monitor()
1099    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
1100
1101    logger.info("Confirm")
1102    for i in range(0, 10):
1103        req = hapd.mgmt_rx()
1104        if req is None:
1105            raise Exception("MGMT RX wait timed out (confirm)")
1106        if req['subtype'] == 11:
1107            break
1108        req = None
1109    if not req:
1110        raise Exception("Authentication frame (confirm) not received")
1111
1112    hapd.dump_monitor()
1113    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
1114
1115    logger.info("Replay Confirm")
1116    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
1117
1118    logger.info("Association Request")
1119    for i in range(0, 10):
1120        req = hapd.mgmt_rx()
1121        if req is None:
1122            raise Exception("MGMT RX wait timed out (AssocReq)")
1123        if req['subtype'] == 0:
1124            break
1125        req = None
1126    if not req:
1127        raise Exception("Association Request frame not received")
1128
1129    hapd.dump_monitor()
1130    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
1131    ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
1132    if ev is None:
1133        raise Exception("Management frame TX status not reported (1)")
1134    if "stype=1 ok=1" not in ev:
1135        raise Exception("Unexpected management frame TX status (1): " + ev)
1136    cmd = "MGMT_TX_STATUS_PROCESS %s" % (" ".join(ev.split(' ')[1:4]))
1137    if "OK" not in hapd.request(cmd):
1138        raise Exception("MGMT_TX_STATUS_PROCESS failed")
1139
1140    hapd.set("ext_mgmt_frame_handling", "0")
1141
1142    dev[0].wait_connected()
1143
1144def test_sae_proto_hostapd(dev, apdev):
1145    """SAE protocol testing with hostapd"""
1146    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
1147    params['wpa_key_mgmt'] = 'SAE'
1148    params['sae_groups'] = "19 65535"
1149    hapd = hostapd.add_ap(apdev[0], params)
1150    hapd.set("ext_mgmt_frame_handling", "1")
1151    bssid = hapd.own_addr().replace(':', '')
1152    addr = "020000000000"
1153    addr2 = "020000000001"
1154    hdr = "b0003a01" + bssid + addr + bssid + "1000"
1155    hdr2 = "b0003a01" + bssid + addr2 + bssid + "1000"
1156    group = "1300"
1157    scalar = "f7df19f4a7fef1d3b895ea1de150b7c5a7a705c8ebb31a52b623e0057908bd93"
1158    element_x = "21931572027f2e953e2a49fab3d992944102cc95aa19515fc068b394fb25ae3c"
1159    element_y = "cb4eeb94d7b0b789abfdb73a67ab9d6d5efa94dd553e0e724a6289821cbce530"
1160    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "030001000000" + group + scalar + element_x + element_y)
1161    # "SAE: Not enough data for scalar"
1162    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "030001000000" + group + scalar[:-2])
1163    # "SAE: Do not allow group to be changed"
1164    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "030001000000" + "ffff" + scalar[:-2])
1165    # "SAE: Unsupported Finite Cyclic Group 65535"
1166    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr2 + "030001000000" + "ffff" + scalar[:-2])
1167
1168def test_sae_proto_hostapd_ecc(dev, apdev):
1169    """SAE protocol testing with hostapd (ECC)"""
1170    params = hostapd.wpa2_params(ssid="test-sae", passphrase="foofoofoo")
1171    params['wpa_key_mgmt'] = 'SAE'
1172    params['sae_groups'] = "19"
1173    hapd = hostapd.add_ap(apdev[0], params)
1174    hapd.set("ext_mgmt_frame_handling", "1")
1175    bssid = hapd.own_addr().replace(':', '')
1176    addr = "020000000000"
1177    addr2 = "020000000001"
1178    hdr = "b0003a01" + bssid + addr + bssid + "1000"
1179    hdr2 = "b0003a01" + bssid + addr2 + bssid + "1000"
1180    group = "1300"
1181    scalar = "9e9a959bf2dda875a4a29ce9b2afef46f2d83060930124cd9e39ddce798cd69a"
1182    element_x = "dfc55fd8622b91d362f4d1fc9646474d7fba0ff7cce6ca58b8e96a931e070220"
1183    element_y = "dac8a4e80724f167c1349cc9e1f9dd82a7c77b29d49789b63b72b4c849301a28"
1184    # sae_parse_commit_element_ecc() failure to parse peer element
1185    # (depending on crypto library, either crypto_ec_point_from_bin() failure
1186    # or crypto_ec_point_is_on_curve() returning 0)
1187    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "030001000000" + group + scalar + element_x + element_y)
1188    # Unexpected continuation of the connection attempt with confirm
1189    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "030002000000" + "0000" + "fd7b081ff4e8676f03612a4140eedcd3c179ab3a13b93863c6f7ca451340b9ae")
1190
1191def test_sae_proto_hostapd_ffc(dev, apdev):
1192    """SAE protocol testing with hostapd (FFC)"""
1193    params = hostapd.wpa2_params(ssid="test-sae", passphrase="foofoofoo")
1194    params['wpa_key_mgmt'] = 'SAE'
1195    params['sae_groups'] = "22"
1196    hapd = hostapd.add_ap(apdev[0], params)
1197    hapd.set("ext_mgmt_frame_handling", "1")
1198    bssid = hapd.own_addr().replace(':', '')
1199    addr = "020000000000"
1200    addr2 = "020000000001"
1201    hdr = "b0003a01" + bssid + addr + bssid + "1000"
1202    hdr2 = "b0003a01" + bssid + addr2 + bssid + "1000"
1203    group = "1600"
1204    scalar = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044cc46a73c07ef479dc66ec1f5e8ccf25131fa40"
1205    element = "0f1d67025e12fc874cf718c35b19d1ab2db858215623f1ce661cbd1d7b1d7a09ceda7dba46866cf37044259b5cac4db15e7feb778edc8098854b93a84347c1850c02ee4d7dac46db79c477c731085d5b39f56803cda1eeac4a2fbbccb9a546379e258c00ebe93dfdd0a34cf8ce5c55cf905a89564a590b7e159fb89198e9d5cd"
1206    # sae_parse_commit_element_ffc() failure to parse peer element
1207    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "030001000000" + group + scalar + element)
1208    # Unexpected continuation of the connection attempt with confirm
1209    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "030002000000" + "0000" + "fd7b081ff4e8676f03612a4140eedcd3c179ab3a13b93863c6f7ca451340b9ae")
1210
1211def sae_start_ap(apdev, sae_pwe):
1212    params = hostapd.wpa2_params(ssid="test-sae", passphrase="foofoofoo")
1213    params['wpa_key_mgmt'] = 'SAE'
1214    params['sae_groups'] = "19"
1215    params['sae_pwe'] = str(sae_pwe)
1216    return hostapd.add_ap(apdev, params)
1217
1218def check_commit_status(hapd, use_status, expect_status):
1219    hapd.set("ext_mgmt_frame_handling", "1")
1220    bssid = hapd.own_addr().replace(':', '')
1221    addr = "020000000000"
1222    addr2 = "020000000001"
1223    hdr = "b0003a01" + bssid + addr + bssid + "1000"
1224    hdr2 = "b0003a01" + bssid + addr2 + bssid + "1000"
1225    group = "1300"
1226    scalar = "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03"
1227    element_x = "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728d"
1228    element_y = "d3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8"
1229    status = binascii.hexlify(struct.pack('<H', use_status)).decode()
1230    hapd.dump_monitor()
1231    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "03000100" + status + group + scalar + element_x + element_y)
1232    ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
1233    if ev:
1234        msg = ev.split(' ')[3].split('=')[1]
1235        if not msg.startswith("b0"):
1236            ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
1237    if ev is None:
1238        raise Exception("MGMT-TX-STATUS not seen")
1239    msg = ev.split(' ')[3].split('=')[1]
1240    body = msg[2 * 24:]
1241    status, = struct.unpack('<H', binascii.unhexlify(body[8:12]))
1242    if status != expect_status:
1243        raise Exception("Unexpected status code: %d" % status)
1244
1245def test_sae_proto_hostapd_status_126(dev, apdev):
1246    """SAE protocol testing with hostapd (status code 126)"""
1247    hapd = sae_start_ap(apdev[0], 0)
1248    check_commit_status(hapd, 126, 1)
1249    check_commit_status(hapd, 0, 0)
1250
1251def test_sae_proto_hostapd_status_127(dev, apdev):
1252    """SAE protocol testing with hostapd (status code 127)"""
1253    hapd = sae_start_ap(apdev[0], 2)
1254    check_commit_status(hapd, 127, 1)
1255    check_commit_status(hapd, 0, 0)
1256
1257def test_sae_proto_hostapd_valid_commit_after_fail(dev, apdev):
1258    """SAE protocol testing with hostapd and valid commit after failed one"""
1259    params = hostapd.wpa2_params(ssid="test-sae")
1260    params['sae_password'] = ["foofoofoo", "another|id=pw id"]
1261    params['wpa_key_mgmt'] = 'SAE'
1262    params['sae_groups'] = "19"
1263    hapd = hostapd.add_ap(apdev[0], params)
1264    hapd.set("ext_mgmt_frame_handling", "1")
1265    bssid = hapd.own_addr().replace(':', '')
1266    addr = "020000000000"
1267    addr2 = "020000000001"
1268    hdr = "b0003a01" + bssid + addr + bssid + "1000"
1269    hdr2 = "b0003a01" + bssid + addr2 + bssid + "1000"
1270    group = "1300"
1271    scalar = "f7df19f4a7fef1d3b895ea1de150b7c5a7a705c8ebb31a52b623e0057908bd93"
1272    element_x = "21931572027f2e953e2a49fab3d992944102cc95aa19515fc068b394fb25ae3c"
1273    element_y = "cb4eeb94d7b0b789abfdb73a67ab9d6d5efa94dd553e0e724a6289821cbce530"
1274    pw_id = "ff022130"
1275
1276    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "030001000000" + group + scalar + element_x + element_y + pw_id)
1277    ev = hapd.wait_event(['MGMT-TX-STATUS'], timeout=1)
1278    buf = ev.split(' ')[3].split('=')[1]
1279    # Check for status = Unknown Password ID
1280    if buf[48:] != '0300' + '0100' + '7b00':
1281        raise Exception("Unexpected response to SAE commit with unknown password id: " + buf)
1282
1283    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + hdr + "030001000000" + group + scalar + element_x + element_y)
1284
1285    ev = hapd.wait_event(['MGMT-TX-STATUS'], timeout=1)
1286    if ev is None:
1287        raise Exception("No response to valid SAE commit")
1288    buf = ev.split(' ')[3].split('=')[1]
1289    # Check for status = Success
1290    payload = buf[48:]
1291    if payload[8:12] != '0000':
1292        raise Exception("Unexpected Status Code for valid SAE commit: " + buf)
1293
1294@remote_compatible
1295def test_sae_no_ffc_by_default(dev, apdev):
1296    """SAE and default groups rejecting FFC"""
1297    check_sae_capab(dev[0])
1298    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
1299    params['wpa_key_mgmt'] = 'SAE'
1300    hapd = hostapd.add_ap(apdev[0], params)
1301
1302    dev[0].request("SET sae_groups 15 16")
1303    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412",
1304                   wait_connect=False)
1305    ev = dev[0].wait_event(["SME: Trying to authenticate"], timeout=3)
1306    if ev is None:
1307        raise Exception("Did not try to authenticate")
1308    ev = dev[0].wait_event(["SME: Trying to authenticate"], timeout=3)
1309    if ev is None:
1310        raise Exception("Did not try to authenticate (2)")
1311    dev[0].request("REMOVE_NETWORK all")
1312
1313def sae_reflection_attack(apdev, dev, group):
1314    check_sae_capab(dev)
1315    params = hostapd.wpa2_params(ssid="test-sae",
1316                                 passphrase="no-knowledge-of-passphrase")
1317    params['wpa_key_mgmt'] = 'SAE'
1318    hapd = hostapd.add_ap(apdev, params)
1319    bssid = apdev['bssid']
1320
1321    dev.scan_for_bss(bssid, freq=2412)
1322    hapd.set("ext_mgmt_frame_handling", "1")
1323
1324    dev.request("SET sae_groups %d" % group)
1325    dev.connect("test-sae", psk="reflection-attack", key_mgmt="SAE",
1326                scan_freq="2412", wait_connect=False)
1327
1328    # Commit
1329    for i in range(0, 10):
1330        req = hapd.mgmt_rx()
1331        if req is None:
1332            raise Exception("MGMT RX wait timed out")
1333        if req['subtype'] == 11:
1334            break
1335        req = None
1336    if not req:
1337        raise Exception("Authentication frame not received")
1338
1339    resp = {}
1340    resp['fc'] = req['fc']
1341    resp['da'] = req['sa']
1342    resp['sa'] = req['da']
1343    resp['bssid'] = req['bssid']
1344    resp['payload'] = req['payload']
1345    hapd.mgmt_tx(resp)
1346
1347    # Confirm
1348    req = hapd.mgmt_rx(timeout=0.5)
1349    if req is not None:
1350        if req['subtype'] == 11:
1351            raise Exception("Unexpected Authentication frame seen")
1352
1353@remote_compatible
1354def test_sae_reflection_attack_ecc(dev, apdev):
1355    """SAE reflection attack (ECC)"""
1356    sae_reflection_attack(apdev[0], dev[0], 19)
1357
1358@remote_compatible
1359def test_sae_reflection_attack_ffc(dev, apdev):
1360    """SAE reflection attack (FFC)"""
1361    sae_reflection_attack(apdev[0], dev[0], 15)
1362
1363def sae_reflection_attack_internal(apdev, dev, group):
1364    check_sae_capab(dev)
1365    params = hostapd.wpa2_params(ssid="test-sae",
1366                                 passphrase="no-knowledge-of-passphrase")
1367    params['wpa_key_mgmt'] = 'SAE'
1368    params['sae_reflection_attack'] = '1'
1369    hapd = hostapd.add_ap(apdev, params)
1370    bssid = apdev['bssid']
1371
1372    dev.scan_for_bss(bssid, freq=2412)
1373    dev.request("SET sae_groups %d" % group)
1374    dev.connect("test-sae", psk="reflection-attack", key_mgmt="SAE",
1375                scan_freq="2412", wait_connect=False)
1376    ev = dev.wait_event(["SME: Trying to authenticate"], timeout=10)
1377    if ev is None:
1378        raise Exception("No authentication attempt seen")
1379    ev = dev.wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
1380    if ev is not None:
1381        raise Exception("Unexpected connection")
1382
1383@remote_compatible
1384def test_sae_reflection_attack_ecc_internal(dev, apdev):
1385    """SAE reflection attack (ECC) - internal"""
1386    sae_reflection_attack_internal(apdev[0], dev[0], 19)
1387
1388@remote_compatible
1389def test_sae_reflection_attack_ffc_internal(dev, apdev):
1390    """SAE reflection attack (FFC) - internal"""
1391    sae_reflection_attack_internal(apdev[0], dev[0], 15)
1392
1393@remote_compatible
1394def test_sae_commit_override(dev, apdev):
1395    """SAE commit override (hostapd)"""
1396    check_sae_capab(dev[0])
1397    params = hostapd.wpa2_params(ssid="test-sae",
1398                                 passphrase="12345678")
1399    params['wpa_key_mgmt'] = 'SAE'
1400    params['sae_commit_override'] = '13ffbad00d215867a7c5ff37d87bb9bdb7cb116e520f71e8d7a794ca2606d537ddc6c099c40e7a25372b80a8fd443cd7dd222c8ea21b8ef372d4b3e316c26a73fd999cc79ad483eb826e7b3893ea332da68fa13224bcdeb4fb18b0584dd100a2c514'
1401    hapd = hostapd.add_ap(apdev[0], params)
1402    dev[0].request("SET sae_groups ")
1403    dev[0].connect("test-sae", psk="test-sae", key_mgmt="SAE",
1404                   scan_freq="2412", wait_connect=False)
1405    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
1406    if ev is not None:
1407        raise Exception("Unexpected connection")
1408
1409@remote_compatible
1410def test_sae_commit_override2(dev, apdev):
1411    """SAE commit override (wpa_supplicant)"""
1412    check_sae_capab(dev[0])
1413    params = hostapd.wpa2_params(ssid="test-sae",
1414                                 passphrase="12345678")
1415    params['wpa_key_mgmt'] = 'SAE'
1416    hapd = hostapd.add_ap(apdev[0], params)
1417    dev[0].request("SET sae_groups ")
1418    dev[0].set('sae_commit_override', '13ffbad00d215867a7c5ff37d87bb9bdb7cb116e520f71e8d7a794ca2606d537ddc6c099c40e7a25372b80a8fd443cd7dd222c8ea21b8ef372d4b3e316c26a73fd999cc79ad483eb826e7b3893ea332da68fa13224bcdeb4fb18b0584dd100a2c514')
1419    dev[0].connect("test-sae", psk="test-sae", key_mgmt="SAE",
1420                   scan_freq="2412", wait_connect=False)
1421    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
1422    if ev is not None:
1423        raise Exception("Unexpected connection")
1424
1425def test_sae_commit_invalid_scalar_element_ap(dev, apdev):
1426    """SAE commit invalid scalar/element from AP"""
1427    check_sae_capab(dev[0])
1428    params = hostapd.wpa2_params(ssid="test-sae",
1429                                 passphrase="12345678")
1430    params['wpa_key_mgmt'] = 'SAE'
1431    params['sae_commit_override'] = '1300' + 96*'00'
1432    hapd = hostapd.add_ap(apdev[0], params)
1433    dev[0].request("SET sae_groups ")
1434    dev[0].connect("test-sae", psk="test-sae", key_mgmt="SAE",
1435                   scan_freq="2412", wait_connect=False)
1436    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
1437    if ev is not None:
1438        raise Exception("Unexpected connection")
1439
1440def test_sae_commit_invalid_element_ap(dev, apdev):
1441    """SAE commit invalid element from AP"""
1442    check_sae_capab(dev[0])
1443    params = hostapd.wpa2_params(ssid="test-sae",
1444                                 passphrase="12345678")
1445    params['wpa_key_mgmt'] = 'SAE'
1446    params['sae_commit_override'] = '1300' + 31*'00' + '02' + 64*'00'
1447    hapd = hostapd.add_ap(apdev[0], params)
1448    dev[0].request("SET sae_groups ")
1449    dev[0].connect("test-sae", psk="test-sae", key_mgmt="SAE",
1450                   scan_freq="2412", wait_connect=False)
1451    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
1452    if ev is not None:
1453        raise Exception("Unexpected connection")
1454
1455def test_sae_commit_invalid_scalar_element_sta(dev, apdev):
1456    """SAE commit invalid scalar/element from STA"""
1457    check_sae_capab(dev[0])
1458    params = hostapd.wpa2_params(ssid="test-sae",
1459                                 passphrase="12345678")
1460    params['wpa_key_mgmt'] = 'SAE'
1461    hapd = hostapd.add_ap(apdev[0], params)
1462    dev[0].request("SET sae_groups ")
1463    dev[0].set('sae_commit_override', '1300' + 96*'00')
1464    dev[0].connect("test-sae", psk="test-sae", key_mgmt="SAE",
1465                   scan_freq="2412", wait_connect=False)
1466    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
1467    if ev is not None:
1468        raise Exception("Unexpected connection")
1469
1470def test_sae_commit_invalid_element_sta(dev, apdev):
1471    """SAE commit invalid element from STA"""
1472    check_sae_capab(dev[0])
1473    params = hostapd.wpa2_params(ssid="test-sae",
1474                                 passphrase="12345678")
1475    params['wpa_key_mgmt'] = 'SAE'
1476    hapd = hostapd.add_ap(apdev[0], params)
1477    dev[0].request("SET sae_groups ")
1478    dev[0].set('sae_commit_override', '1300' + 31*'00' + '02' + 64*'00')
1479    dev[0].connect("test-sae", psk="test-sae", key_mgmt="SAE",
1480                   scan_freq="2412", wait_connect=False)
1481    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
1482    if ev is not None:
1483        raise Exception("Unexpected connection")
1484
1485@remote_compatible
1486def test_sae_anti_clogging_proto(dev, apdev):
1487    """SAE anti clogging protocol testing"""
1488    check_sae_capab(dev[0])
1489    params = hostapd.wpa2_params(ssid="test-sae",
1490                                 passphrase="no-knowledge-of-passphrase")
1491    params['wpa_key_mgmt'] = 'SAE'
1492    hapd = hostapd.add_ap(apdev[0], params)
1493    bssid = apdev[0]['bssid']
1494
1495    dev[0].scan_for_bss(bssid, freq=2412)
1496    hapd.set("ext_mgmt_frame_handling", "1")
1497
1498    dev[0].request("SET sae_groups ")
1499    dev[0].connect("test-sae", psk="anti-cloggign", key_mgmt="SAE",
1500                   scan_freq="2412", wait_connect=False)
1501
1502    # Commit
1503    for i in range(0, 10):
1504        req = hapd.mgmt_rx()
1505        if req is None:
1506            raise Exception("MGMT RX wait timed out")
1507        if req['subtype'] == 11:
1508            break
1509        req = None
1510    if not req:
1511        raise Exception("Authentication frame not received")
1512
1513    resp = {}
1514    resp['fc'] = req['fc']
1515    resp['da'] = req['sa']
1516    resp['sa'] = req['da']
1517    resp['bssid'] = req['bssid']
1518    resp['payload'] = binascii.unhexlify("030001004c00" + "ffff00")
1519    hapd.mgmt_tx(resp)
1520
1521    # Confirm (not received due to DH group being rejected)
1522    req = hapd.mgmt_rx(timeout=0.5)
1523    if req is not None:
1524        if req['subtype'] == 11:
1525            raise Exception("Unexpected Authentication frame seen")
1526
1527@remote_compatible
1528def test_sae_no_random(dev, apdev):
1529    """SAE and no random numbers available"""
1530    check_sae_capab(dev[0])
1531    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
1532    params['wpa_key_mgmt'] = 'SAE'
1533    hapd = hostapd.add_ap(apdev[0], params)
1534
1535    dev[0].request("SET sae_groups ")
1536    tests = [(1, "os_get_random;sae_derive_pwe_ecc")]
1537    for count, func in tests:
1538        with fail_test(dev[0], count, func):
1539            dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1540                           scan_freq="2412")
1541            dev[0].request("REMOVE_NETWORK all")
1542            dev[0].wait_disconnected()
1543
1544@remote_compatible
1545def test_sae_pwe_failure(dev, apdev):
1546    """SAE and pwe failure"""
1547    check_sae_capab(dev[0])
1548    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
1549    params['wpa_key_mgmt'] = 'SAE'
1550    params['sae_groups'] = '19 15'
1551    hapd = hostapd.add_ap(apdev[0], params)
1552
1553    dev[0].request("SET sae_groups 19")
1554    with fail_test(dev[0], 1, "hmac_sha256_vector;sae_derive_pwe_ecc"):
1555        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1556                       scan_freq="2412")
1557        dev[0].request("REMOVE_NETWORK all")
1558        dev[0].wait_disconnected()
1559    with fail_test(dev[0], 1, "sae_test_pwd_seed_ecc"):
1560        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1561                       scan_freq="2412")
1562        dev[0].request("REMOVE_NETWORK all")
1563        dev[0].wait_disconnected()
1564
1565    dev[0].request("SET sae_groups 15")
1566    with fail_test(dev[0], 1, "hmac_sha256_vector;sae_derive_pwe_ffc"):
1567        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1568                       scan_freq="2412")
1569        dev[0].request("REMOVE_NETWORK all")
1570        dev[0].wait_disconnected()
1571
1572    dev[0].request("SET sae_groups 15")
1573    with fail_test(dev[0], 1, "sae_test_pwd_seed_ffc"):
1574        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1575                       scan_freq="2412")
1576        dev[0].request("REMOVE_NETWORK all")
1577        dev[0].wait_disconnected()
1578    with fail_test(dev[0], 2, "sae_test_pwd_seed_ffc"):
1579        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1580                       scan_freq="2412")
1581        dev[0].request("REMOVE_NETWORK all")
1582        dev[0].wait_disconnected()
1583
1584@remote_compatible
1585def test_sae_bignum_failure(dev, apdev):
1586    """SAE and bignum failure"""
1587    check_sae_capab(dev[0])
1588    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
1589    params['wpa_key_mgmt'] = 'SAE'
1590    params['sae_groups'] = '19 15 22'
1591    hapd = hostapd.add_ap(apdev[0], params)
1592
1593    dev[0].request("SET sae_groups 19")
1594    tests = [(1, "crypto_bignum_init_set;dragonfly_get_rand_1_to_p_1"),
1595             (1, "crypto_bignum_init;dragonfly_is_quadratic_residue_blind"),
1596             (1, "crypto_bignum_mulmod;dragonfly_is_quadratic_residue_blind"),
1597             (2, "crypto_bignum_mulmod;dragonfly_is_quadratic_residue_blind"),
1598             (3, "crypto_bignum_mulmod;dragonfly_is_quadratic_residue_blind"),
1599             (1, "crypto_bignum_legendre;dragonfly_is_quadratic_residue_blind"),
1600             (1, "crypto_bignum_init_set;sae_test_pwd_seed_ecc"),
1601             (1, "crypto_ec_point_compute_y_sqr;sae_test_pwd_seed_ecc"),
1602             (1, "crypto_bignum_to_bin;sae_derive_pwe_ecc"),
1603             (1, "crypto_ec_point_compute_y_sqr;sae_derive_pwe_ecc"),
1604             (1, "crypto_ec_point_init;sae_derive_commit_element_ecc"),
1605             (1, "crypto_ec_point_mul;sae_derive_commit_element_ecc"),
1606             (1, "crypto_ec_point_invert;sae_derive_commit_element_ecc"),
1607             (1, "crypto_bignum_init;=sae_derive_commit"),
1608             (1, "crypto_ec_point_init;sae_derive_k_ecc"),
1609             (1, "crypto_ec_point_mul;sae_derive_k_ecc"),
1610             (1, "crypto_ec_point_add;sae_derive_k_ecc"),
1611             (2, "crypto_ec_point_mul;sae_derive_k_ecc"),
1612             (1, "crypto_ec_point_to_bin;sae_derive_k_ecc"),
1613             (1, "crypto_bignum_legendre;dragonfly_get_random_qr_qnr"),
1614             (1, "sha256_prf_bits;sae_derive_keys"),
1615             (1, "crypto_bignum_init;sae_derive_keys"),
1616             (1, "crypto_bignum_init_set;sae_parse_commit_scalar"),
1617             (1, "crypto_bignum_to_bin;sae_parse_commit_element_ecc"),
1618             (1, "crypto_ec_point_from_bin;sae_parse_commit_element_ecc")]
1619    for count, func in tests:
1620        with fail_test(dev[0], count, func):
1621            hapd.request("NOTE STA failure testing %d:%s" % (count, func))
1622            dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1623                           scan_freq="2412", wait_connect=False)
1624            wait_fail_trigger(dev[0], "GET_FAIL", timeout=0.1)
1625            dev[0].request("REMOVE_NETWORK all")
1626            dev[0].dump_monitor()
1627            hapd.dump_monitor()
1628
1629    dev[0].request("SET sae_groups 15")
1630    tests = [(1, "crypto_bignum_init_set;sae_set_group"),
1631             (2, "crypto_bignum_init_set;sae_set_group"),
1632             (1, "crypto_bignum_init;sae_derive_commit"),
1633             (2, "crypto_bignum_init;sae_derive_commit"),
1634             (1, "crypto_bignum_init_set;sae_test_pwd_seed_ffc"),
1635             (1, "crypto_bignum_exptmod;sae_test_pwd_seed_ffc"),
1636             (1, "crypto_bignum_init;sae_derive_pwe_ffc"),
1637             (1, "crypto_bignum_init;sae_derive_commit_element_ffc"),
1638             (1, "crypto_bignum_exptmod;sae_derive_commit_element_ffc"),
1639             (1, "crypto_bignum_inverse;sae_derive_commit_element_ffc"),
1640             (1, "crypto_bignum_init;sae_derive_k_ffc"),
1641             (1, "crypto_bignum_exptmod;sae_derive_k_ffc"),
1642             (1, "crypto_bignum_mulmod;sae_derive_k_ffc"),
1643             (2, "crypto_bignum_exptmod;sae_derive_k_ffc"),
1644             (1, "crypto_bignum_to_bin;sae_derive_k_ffc"),
1645             (1, "crypto_bignum_init_set;sae_parse_commit_element_ffc"),
1646             (1, "crypto_bignum_init;sae_parse_commit_element_ffc"),
1647             (2, "crypto_bignum_init_set;sae_parse_commit_element_ffc"),
1648             (1, "crypto_bignum_exptmod;sae_parse_commit_element_ffc")]
1649    for count, func in tests:
1650        with fail_test(dev[0], count, func):
1651            hapd.request("NOTE STA failure testing %d:%s" % (count, func))
1652            dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1653                           scan_freq="2412", wait_connect=False)
1654            wait_fail_trigger(dev[0], "GET_FAIL", timeout=0.1)
1655            dev[0].request("REMOVE_NETWORK all")
1656            dev[0].dump_monitor()
1657            hapd.dump_monitor()
1658
1659def test_sae_bignum_failure_unsafe_group(dev, apdev):
1660    """SAE and bignum failure unsafe group"""
1661    check_sae_capab(dev[0])
1662    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
1663    params['wpa_key_mgmt'] = 'SAE'
1664    params['sae_groups'] = '22'
1665    hapd = hostapd.add_ap(apdev[0], params)
1666
1667    dev[0].request("SET sae_groups 22")
1668    tests = [(1, "crypto_bignum_init_set;sae_test_pwd_seed_ffc"),
1669             (1, "crypto_bignum_sub;sae_test_pwd_seed_ffc"),
1670             (1, "crypto_bignum_div;sae_test_pwd_seed_ffc")]
1671    for count, func in tests:
1672        with fail_test(dev[0], count, func):
1673            hapd.request("NOTE STA failure testing %d:%s" % (count, func))
1674            dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1675                           scan_freq="2412", wait_connect=False)
1676            wait_fail_trigger(dev[0], "GET_FAIL")
1677            dev[0].request("REMOVE_NETWORK all")
1678            dev[0].dump_monitor()
1679            hapd.dump_monitor()
1680
1681def test_sae_invalid_anti_clogging_token_req(dev, apdev):
1682    """SAE and invalid anti-clogging token request"""
1683    check_sae_capab(dev[0])
1684    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
1685    params['wpa_key_mgmt'] = 'SAE'
1686    # Beacon more frequently since Probe Request frames are practically ignored
1687    # in this test setup (ext_mgmt_frame_handled=1 on hostapd side) and
1688    # wpa_supplicant scans may end up getting ignored if no new results are
1689    # available due to the missing Probe Response frames.
1690    params['beacon_int'] = '20'
1691    hapd = hostapd.add_ap(apdev[0], params)
1692    bssid = apdev[0]['bssid']
1693
1694    dev[0].request("SET sae_groups 19")
1695    dev[0].scan_for_bss(bssid, freq=2412)
1696    hapd.set("ext_mgmt_frame_handling", "1")
1697    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1698                   scan_freq="2412", wait_connect=False)
1699    ev = dev[0].wait_event(["SME: Trying to authenticate"])
1700    if ev is None:
1701        raise Exception("No authentication attempt seen (1)")
1702    dev[0].dump_monitor()
1703
1704    for i in range(0, 10):
1705        req = hapd.mgmt_rx()
1706        if req is None:
1707            raise Exception("MGMT RX wait timed out (commit)")
1708        if req['subtype'] == 11:
1709            break
1710        req = None
1711    if not req:
1712        raise Exception("Authentication frame (commit) not received")
1713
1714    hapd.dump_monitor()
1715    resp = {}
1716    resp['fc'] = req['fc']
1717    resp['da'] = req['sa']
1718    resp['sa'] = req['da']
1719    resp['bssid'] = req['bssid']
1720    resp['payload'] = binascii.unhexlify("030001004c0013")
1721    hapd.mgmt_tx(resp)
1722    ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
1723    if ev is None:
1724        raise Exception("Management frame TX status not reported (1)")
1725    if "stype=11 ok=1" not in ev:
1726        raise Exception("Unexpected management frame TX status (1): " + ev)
1727
1728    ev = dev[0].wait_event(["SME: Trying to authenticate"])
1729    if ev is None:
1730        raise Exception("No authentication attempt seen (2)")
1731    dev[0].dump_monitor()
1732
1733    for i in range(0, 10):
1734        req = hapd.mgmt_rx()
1735        if req is None:
1736            raise Exception("MGMT RX wait timed out (commit) (2)")
1737        if req['subtype'] == 11:
1738            break
1739        req = None
1740    if not req:
1741        raise Exception("Authentication frame (commit) not received (2)")
1742
1743    hapd.dump_monitor()
1744    resp = {}
1745    resp['fc'] = req['fc']
1746    resp['da'] = req['sa']
1747    resp['sa'] = req['da']
1748    resp['bssid'] = req['bssid']
1749    resp['payload'] = binascii.unhexlify("030001000100")
1750    hapd.mgmt_tx(resp)
1751    ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
1752    if ev is None:
1753        raise Exception("Management frame TX status not reported (1)")
1754    if "stype=11 ok=1" not in ev:
1755        raise Exception("Unexpected management frame TX status (1): " + ev)
1756
1757    ev = dev[0].wait_event(["SME: Trying to authenticate"])
1758    if ev is None:
1759        raise Exception("No authentication attempt seen (3)")
1760    dev[0].dump_monitor()
1761
1762    dev[0].request("DISCONNECT")
1763
1764def test_sae_password(dev, apdev):
1765    """SAE and sae_password in hostapd configuration"""
1766    check_sae_capab(dev[0])
1767    params = hostapd.wpa2_params(ssid="test-sae",
1768                                 passphrase="12345678")
1769    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
1770    params['sae_password'] = "sae-password"
1771    hapd = hostapd.add_ap(apdev[0], params)
1772
1773    dev[0].request("SET sae_groups ")
1774    dev[0].connect("test-sae", psk="sae-password", key_mgmt="SAE",
1775                   scan_freq="2412")
1776    dev[1].connect("test-sae", psk="12345678", scan_freq="2412")
1777    dev[2].request("SET sae_groups ")
1778    dev[2].connect("test-sae", sae_password="sae-password", key_mgmt="SAE",
1779                   scan_freq="2412")
1780
1781def test_sae_password_short(dev, apdev):
1782    """SAE and short password"""
1783    check_sae_capab(dev[0])
1784    params = hostapd.wpa2_params(ssid="test-sae")
1785    params['wpa_key_mgmt'] = 'SAE'
1786    params['sae_password'] = "secret"
1787    hapd = hostapd.add_ap(apdev[0], params)
1788
1789    dev[0].request("SET sae_groups ")
1790    dev[0].connect("test-sae", sae_password="secret", key_mgmt="SAE",
1791                   scan_freq="2412")
1792
1793def test_sae_password_long(dev, apdev):
1794    """SAE and long password"""
1795    check_sae_capab(dev[0])
1796    params = hostapd.wpa2_params(ssid="test-sae")
1797    params['wpa_key_mgmt'] = 'SAE'
1798    params['sae_password'] = 100*"A"
1799    hapd = hostapd.add_ap(apdev[0], params)
1800
1801    dev[0].request("SET sae_groups ")
1802    dev[0].connect("test-sae", sae_password=100*"A", key_mgmt="SAE",
1803                   scan_freq="2412")
1804
1805def test_sae_password_multiple(dev, apdev):
1806    """SAE with multiple default password entries"""
1807    check_sae_capab(dev[0])
1808    check_sae_capab(dev[1])
1809    check_sae_capab(dev[2])
1810    params = hostapd.wpa3_params(ssid="test-sae",
1811                                 password=["owner", "iot", "guest"])
1812    params['sae_track_password'] = "10"
1813    params['sae_confirm_immediate'] = '1'
1814    hapd = hostapd.add_ap(apdev[0], params)
1815
1816    dev[0].set("sae_groups", "")
1817    dev[0].connect("test-sae", sae_password="owner", key_mgmt="SAE",
1818                   ieee80211w="2", scan_freq="2412")
1819
1820    dev[1].set("sae_groups", "")
1821    dev[1].connect("test-sae", sae_password="iot", key_mgmt="SAE",
1822                   ieee80211w="2", scan_freq="2412")
1823
1824    dev[2].set("sae_groups", "")
1825    dev[2].connect("test-sae", sae_password="guest", key_mgmt="SAE",
1826                   ieee80211w="2", scan_freq="2412")
1827
1828def test_sae_connect_cmd(dev, apdev):
1829    """SAE with connect command"""
1830    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
1831    wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
1832    check_sae_capab(wpas)
1833    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
1834    params['wpa_key_mgmt'] = 'SAE'
1835    hapd = hostapd.add_ap(apdev[0], params)
1836
1837    wpas.request("SET sae_groups ")
1838    wpas.connect("test-sae", psk="12345678", key_mgmt="SAE",
1839                 scan_freq="2412", wait_connect=False)
1840    # mac80211_hwsim does not support SAE offload, so accept both a successful
1841    # connection and association rejection.
1842    ev = wpas.wait_event(["CTRL-EVENT-CONNECTED", "CTRL-EVENT-ASSOC-REJECT",
1843                          "Association request to the driver failed"],
1844                         timeout=15)
1845    if ev is None:
1846        raise Exception("No connection result reported")
1847
1848def run_sae_password_id(dev, apdev, groups=None):
1849    check_sae_capab(dev[0])
1850    params = hostapd.wpa2_params(ssid="test-sae")
1851    params['wpa_key_mgmt'] = 'SAE'
1852    if groups:
1853        params['sae_groups'] = groups
1854    else:
1855        groups = ""
1856    params['sae_password'] = ['secret|mac=ff:ff:ff:ff:ff:ff|id=pw id',
1857                              'foo|mac=02:02:02:02:02:02',
1858                              'another secret|mac=ff:ff:ff:ff:ff:ff|id=' + 29*'A']
1859    hapd = hostapd.add_ap(apdev[0], params)
1860
1861    dev[0].request("SET sae_groups " + groups)
1862    dev[0].connect("test-sae", sae_password="secret", sae_password_id="pw id",
1863                   key_mgmt="SAE", scan_freq="2412")
1864    dev[0].request("REMOVE_NETWORK all")
1865    dev[0].wait_disconnected()
1866
1867    # SAE Password Identifier element with the exact same length as the
1868    # optional Anti-Clogging Token field
1869    dev[0].connect("test-sae", sae_password="another secret",
1870                   sae_password_id=29*'A',
1871                   key_mgmt="SAE", scan_freq="2412")
1872    dev[0].request("REMOVE_NETWORK all")
1873    dev[0].wait_disconnected()
1874
1875    dev[0].connect("test-sae", sae_password="secret", sae_password_id="unknown",
1876                   key_mgmt="SAE", scan_freq="2412", wait_connect=False)
1877
1878    ev = dev[0].wait_event(["CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER"],
1879                           timeout=10)
1880    if ev is None:
1881        raise Exception("Unknown password identifier not reported")
1882    dev[0].request("REMOVE_NETWORK all")
1883
1884def test_sae_password_id(dev, apdev):
1885    """SAE and password identifier"""
1886    run_sae_password_id(dev, apdev, "")
1887
1888def test_sae_password_id_ecc(dev, apdev):
1889    """SAE and password identifier (ECC)"""
1890    run_sae_password_id(dev, apdev, "19")
1891
1892def test_sae_password_id_ffc(dev, apdev):
1893    """SAE and password identifier (FFC)"""
1894    run_sae_password_id(dev, apdev, "15")
1895
1896def test_sae_password_id_only(dev, apdev):
1897    """SAE and password identifier (exclusively)"""
1898    check_sae_capab(dev[0])
1899    params = hostapd.wpa2_params(ssid="test-sae")
1900    params['wpa_key_mgmt'] = 'SAE'
1901    params['sae_password'] = 'secret|id=pw id'
1902    hapd = hostapd.add_ap(apdev[0], params)
1903
1904    dev[0].request("SET sae_groups ")
1905    dev[0].connect("test-sae", sae_password="secret", sae_password_id="pw id",
1906                   key_mgmt="SAE", scan_freq="2412")
1907
1908def test_sae_password_id_pwe_looping(dev, apdev):
1909    """SAE and password identifier with forced PWE looping"""
1910    check_sae_capab(dev[0])
1911    params = hostapd.wpa2_params(ssid="test-sae")
1912    params['wpa_key_mgmt'] = 'SAE'
1913    params['sae_password'] = 'secret|id=pw id'
1914    params['sae_pwe'] = "3"
1915    hapd = hostapd.add_ap(apdev[0], params)
1916
1917    dev[0].request("SET sae_groups ")
1918    try:
1919        dev[0].set("sae_pwe", "3")
1920        dev[0].connect("test-sae", sae_password="secret",
1921                       sae_password_id="pw id",
1922                       key_mgmt="SAE", scan_freq="2412", wait_connect=False)
1923        ev = dev[0].wait_event(["CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER"],
1924                               timeout=10)
1925        dev[0].request("DISCONNECT")
1926        if ev is None:
1927            raise Exception("Unknown password identifier not reported")
1928    finally:
1929        dev[0].set("sae_pwe", "0")
1930
1931def test_sae_password_id_pwe_check_ap(dev, apdev):
1932    """SAE and password identifier with STA using unexpected PWE derivation"""
1933    check_sae_capab(dev[0])
1934    params = hostapd.wpa2_params(ssid="test-sae")
1935    params['wpa_key_mgmt'] = 'SAE'
1936    params['sae_password'] = 'secret|id=pw id'
1937    hapd = hostapd.add_ap(apdev[0], params)
1938
1939    dev[0].request("SET sae_groups ")
1940    try:
1941        dev[0].set("sae_pwe", "3")
1942        dev[0].connect("test-sae", sae_password="secret",
1943                       sae_password_id="pw id",
1944                       key_mgmt="SAE", scan_freq="2412", wait_connect=False)
1945        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
1946                                "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=10)
1947        if ev is None or "CTRL-EVENT-SSID-TEMP-DISABLED" not in ev:
1948            raise Exception("Connection failure not reported")
1949    finally:
1950        dev[0].set("sae_pwe", "0")
1951
1952def test_sae_password_id_pwe_check_sta(dev, apdev):
1953    """SAE and password identifier with AP using unexpected PWE derivation"""
1954    check_sae_capab(dev[0])
1955    params = hostapd.wpa2_params(ssid="test-sae")
1956    params['wpa_key_mgmt'] = 'SAE'
1957    params['sae_pwe'] = "3"
1958    params['sae_password'] = 'secret|id=pw id'
1959    hapd = hostapd.add_ap(apdev[0], params)
1960
1961    dev[0].request("SET sae_groups ")
1962    dev[0].connect("test-sae", sae_password="secret",
1963                   sae_password_id="pw id",
1964                   key_mgmt="SAE", scan_freq="2412", wait_connect=False)
1965    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
1966                            "CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
1967    if ev is None or "CTRL-EVENT-NETWORK-NOT-FOUND" not in ev:
1968        raise Exception("Connection failure not reported")
1969
1970def test_sae_forced_anti_clogging_pw_id(dev, apdev):
1971    """SAE anti clogging (forced and Password Identifier)"""
1972    check_sae_capab(dev[0])
1973    params = hostapd.wpa2_params(ssid="test-sae")
1974    params['wpa_key_mgmt'] = 'SAE'
1975    params['sae_anti_clogging_threshold'] = '0'
1976    params['sae_password'] = 'secret|id=' + 29*'A'
1977    hostapd.add_ap(apdev[0], params)
1978    for i in range(0, 2):
1979        dev[i].request("SET sae_groups ")
1980        dev[i].connect("test-sae", sae_password="secret",
1981                       sae_password_id=29*'A', key_mgmt="SAE", scan_freq="2412")
1982
1983def test_sae_reauth(dev, apdev):
1984    """SAE reauthentication"""
1985    check_sae_capab(dev[0])
1986    params = hostapd.wpa2_params(ssid="test-sae",
1987                                 passphrase="12345678")
1988    params['wpa_key_mgmt'] = 'SAE'
1989    params["ieee80211w"] = "2"
1990    hapd = hostapd.add_ap(apdev[0], params)
1991
1992    dev[0].request("SET sae_groups ")
1993    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1994                        ieee80211w="2", scan_freq="2412")
1995
1996    hapd.set("ext_mgmt_frame_handling", "1")
1997    dev[0].request("DISCONNECT")
1998    dev[0].wait_disconnected(timeout=10)
1999    hapd.set("ext_mgmt_frame_handling", "0")
2000    dev[0].request("PMKSA_FLUSH")
2001    dev[0].request("REASSOCIATE")
2002    dev[0].wait_connected(timeout=10, error="Timeout on re-connection")
2003
2004def test_sae_anti_clogging_during_attack(dev, apdev):
2005    """SAE anti clogging during an attack"""
2006    try:
2007        run_sae_anti_clogging_during_attack(dev, apdev)
2008    finally:
2009        stop_monitor(apdev[1]["ifname"])
2010
2011def build_sae_commit(bssid, addr, group=21, token=None):
2012    if group == 19:
2013        scalar = binascii.unhexlify("7332d3ebff24804005ccd8c56141e3ed8d84f40638aa31cd2fac11d4d2e89e7b")
2014        element = binascii.unhexlify("954d0f4457066bff3168376a1d7174f4e66620d1792406f613055b98513a7f03a538c13dfbaf2029e2adc6aa96aa0ddcf08ac44887b02f004b7f29b9dbf4b7d9")
2015    elif group == 21:
2016        scalar = binascii.unhexlify("001eec673111b902f5c8a61c8cb4c1c4793031aeea8c8c319410903bc64bcbaea134ab01c4e016d51436f5b5426f7e2af635759a3033fb4031ea79f89a62a3e2f828")
2017        element = binascii.unhexlify("00580eb4b448ea600ea277d5e66e4ed37db82bb04ac90442e9c3727489f366ba4b82f0a472d02caf4cdd142e96baea5915d71374660ee23acbaca38cf3fe8c5fb94b01abbc5278121635d7c06911c5dad8f18d516e1fbe296c179b7c87a1dddfab393337d3d215ed333dd396da6d8f20f798c60d054f1093c24d9c2d98e15c030cc375f0")
2018        pass
2019    frame = binascii.unhexlify("b0003a01")
2020    frame += bssid + addr + bssid
2021    frame += binascii.unhexlify("1000")
2022    auth_alg = 3
2023    transact = 1
2024    status = 0
2025    frame += struct.pack("<HHHH", auth_alg, transact, status, group)
2026    if token:
2027        frame += token
2028    frame += scalar + element
2029    return frame
2030
2031def sae_rx_commit_token_req(sock, radiotap, send_two=False):
2032    try:
2033        msg = sock.recv(1500)
2034    except TimeoutError:
2035        return False
2036    ver, pad, length, present = struct.unpack('<BBHL', msg[0:8])
2037    frame = msg[length:]
2038    if len(frame) < 4:
2039        return False
2040    fc, duration = struct.unpack('<HH', frame[0:4])
2041    if fc != 0xb0:
2042        return False
2043    frame = frame[4:]
2044    da = frame[0:6]
2045    if da[0] != 0xf2:
2046        return False
2047    sa = frame[6:12]
2048    bssid = frame[12:18]
2049    body = frame[20:]
2050
2051    alg, seq, status, group = struct.unpack('<HHHH', body[0:8])
2052    if alg != 3 or seq != 1 or status != 76:
2053        return False
2054    token = body[8:]
2055
2056    frame = build_sae_commit(bssid, da, token=token)
2057    sock.send(radiotap + frame)
2058    if send_two:
2059        sock.send(radiotap + frame)
2060    return True
2061
2062def run_sae_anti_clogging_during_attack(dev, apdev):
2063    check_sae_capab(dev[0])
2064
2065    # Reset apdev[1] into known state before using it as monitor interface.
2066    # Issues were seen when the previous test case used it as a 5 GHz AP.
2067    params = {"ssid": "monitor"}
2068    hapd2 = hostapd.add_ap(apdev[1], params)
2069    hapd2.disable()
2070
2071    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2072    params['wpa_key_mgmt'] = 'SAE'
2073    params['sae_groups'] = '21'
2074    hapd = hostapd.add_ap(apdev[0], params)
2075
2076    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
2077    dev[0].request("SET sae_groups 21")
2078    dev[1].scan_for_bss(hapd.own_addr(), freq=2412)
2079    dev[1].request("SET sae_groups 21")
2080
2081    sock = start_monitor(apdev[1]["ifname"])
2082    radiotap = radiotap_build()
2083
2084    bssid = binascii.unhexlify(hapd.own_addr().replace(':', ''))
2085    for i in range(16):
2086        addr = binascii.unhexlify("f2%010x" % i)
2087        frame = build_sae_commit(bssid, addr)
2088        sock.send(radiotap + frame)
2089        sock.send(radiotap + frame)
2090
2091    count = 0
2092    for i in range(150):
2093        if sae_rx_commit_token_req(sock, radiotap, send_two=True):
2094            count += 1
2095    logger.info("Number of token responses sent: %d" % count)
2096    if count < 10:
2097        raise Exception("Too few token responses seen: %d" % count)
2098
2099    for i in range(16):
2100        addr = binascii.unhexlify("f201%08x" % i)
2101        frame = build_sae_commit(bssid, addr)
2102        sock.send(radiotap + frame)
2103
2104    count = 0
2105    for i in range(150):
2106        if sae_rx_commit_token_req(sock, radiotap):
2107            count += 1
2108            if count == 10:
2109                break
2110    if count < 5:
2111        raise Exception("Too few token responses in second round: %d" % count)
2112
2113    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
2114                   scan_freq="2412", wait_connect=False)
2115    dev[1].connect("test-sae", psk="12345678", key_mgmt="SAE",
2116                   scan_freq="2412", wait_connect=False)
2117
2118    count = 0
2119    connected0 = False
2120    connected1 = False
2121    for i in range(1000):
2122        if sae_rx_commit_token_req(sock, radiotap):
2123            count += 1
2124            addr = binascii.unhexlify("f202%08x" % i)
2125            frame = build_sae_commit(bssid, addr)
2126            sock.send(radiotap + frame)
2127        while dev[0].mon.pending():
2128            ev = dev[0].mon.recv()
2129            logger.debug("EV0: " + ev)
2130            if "CTRL-EVENT-CONNECTED" in ev:
2131                connected0 = True
2132        while dev[1].mon.pending():
2133            ev = dev[1].mon.recv()
2134            logger.debug("EV1: " + ev)
2135            if "CTRL-EVENT-CONNECTED" in ev:
2136                connected1 = True
2137        if connected0 and connected1:
2138            break
2139        time.sleep(0.00000001)
2140    if not connected0:
2141        raise Exception("Real station(0) did not get connected")
2142    if not connected1:
2143        raise Exception("Real station(1) did not get connected")
2144    if count < 1:
2145        raise Exception("Too few token responses in third round: %d" % count)
2146
2147def test_sae_sync(dev, apdev):
2148    """SAE dot11RSNASAESync"""
2149    check_sae_capab(dev[0])
2150    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2151    params['wpa_key_mgmt'] = 'SAE'
2152    params['sae_sync'] = '1'
2153    hostapd.add_ap(apdev[0], params)
2154
2155    # TODO: More complete dot11RSNASAESync testing. For now, this is really only
2156    # checking that sae_sync config parameter is accepted.
2157    dev[0].request("SET sae_groups ")
2158    dev[1].request("SET sae_groups ")
2159    id = {}
2160    for i in range(0, 2):
2161        dev[i].scan(freq="2412")
2162        id[i] = dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
2163                               scan_freq="2412", only_add_network=True)
2164    for i in range(0, 2):
2165        dev[i].select_network(id[i])
2166    for i in range(0, 2):
2167        dev[i].wait_connected(timeout=10)
2168
2169def test_sae_confirm_immediate(dev, apdev):
2170    """SAE and AP sending Confirm message without waiting STA"""
2171    check_sae_capab(dev[0])
2172    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2173    params['wpa_key_mgmt'] = 'SAE'
2174    params['sae_confirm_immediate'] = '1'
2175    hapd = hostapd.add_ap(apdev[0], params)
2176
2177    dev[0].request("SET sae_groups ")
2178    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412")
2179
2180def test_sae_confirm_immediate2(dev, apdev):
2181    """SAE and AP sending Confirm message without waiting STA (2)"""
2182    check_sae_capab(dev[0])
2183    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2184    params['wpa_key_mgmt'] = 'SAE'
2185    params['sae_confirm_immediate'] = '2'
2186    hapd = hostapd.add_ap(apdev[0], params)
2187
2188    dev[0].request("SET sae_groups ")
2189    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412")
2190
2191def test_sae_pwe_group_19(dev, apdev):
2192    """SAE PWE derivation options with group 19"""
2193    run_sae_pwe_group(dev, apdev, 19)
2194
2195def test_sae_pwe_group_20(dev, apdev):
2196    """SAE PWE derivation options with group 20"""
2197    run_sae_pwe_group(dev, apdev, 20)
2198
2199def test_sae_pwe_group_21(dev, apdev):
2200    """SAE PWE derivation options with group 21"""
2201    run_sae_pwe_group(dev, apdev, 21)
2202
2203def test_sae_pwe_group_25(dev, apdev):
2204    """SAE PWE derivation options with group 25"""
2205    run_sae_pwe_group(dev, apdev, 25)
2206
2207def test_sae_pwe_group_28(dev, apdev):
2208    """SAE PWE derivation options with group 28"""
2209    run_sae_pwe_group(dev, apdev, 28)
2210
2211def test_sae_pwe_group_29(dev, apdev):
2212    """SAE PWE derivation options with group 29"""
2213    run_sae_pwe_group(dev, apdev, 29)
2214
2215def test_sae_pwe_group_30(dev, apdev):
2216    """SAE PWE derivation options with group 30"""
2217    run_sae_pwe_group(dev, apdev, 30)
2218
2219def test_sae_pwe_group_1(dev, apdev):
2220    """SAE PWE derivation options with group 1"""
2221    run_sae_pwe_group(dev, apdev, 1)
2222
2223def test_sae_pwe_group_2(dev, apdev):
2224    """SAE PWE derivation options with group 2"""
2225    run_sae_pwe_group(dev, apdev, 2)
2226
2227def test_sae_pwe_group_5(dev, apdev):
2228    """SAE PWE derivation options with group 5"""
2229    run_sae_pwe_group(dev, apdev, 5)
2230
2231def test_sae_pwe_group_14(dev, apdev):
2232    """SAE PWE derivation options with group 14"""
2233    run_sae_pwe_group(dev, apdev, 14)
2234
2235def test_sae_pwe_group_15(dev, apdev):
2236    """SAE PWE derivation options with group 15"""
2237    run_sae_pwe_group(dev, apdev, 15)
2238
2239def test_sae_pwe_group_16(dev, apdev):
2240    """SAE PWE derivation options with group 16"""
2241    run_sae_pwe_group(dev, apdev, 16)
2242
2243def test_sae_pwe_group_22(dev, apdev):
2244    """SAE PWE derivation options with group 22"""
2245    run_sae_pwe_group(dev, apdev, 22)
2246
2247def test_sae_pwe_group_23(dev, apdev):
2248    """SAE PWE derivation options with group 23"""
2249    run_sae_pwe_group(dev, apdev, 23)
2250
2251def test_sae_pwe_group_24(dev, apdev):
2252    """SAE PWE derivation options with group 24"""
2253    run_sae_pwe_group(dev, apdev, 24)
2254
2255def start_sae_pwe_ap(apdev, group, sae_pwe, pmf=False):
2256    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2257    params['wpa_key_mgmt'] = 'SAE'
2258    params['sae_groups'] = str(group)
2259    params['sae_pwe'] = str(sae_pwe)
2260    if pmf:
2261        params['ieee80211w'] = '2'
2262    return hostapd.add_ap(apdev, params)
2263
2264def run_sae_pwe_group(dev, apdev, group):
2265    check_sae_capab(dev[0])
2266    tls = dev[0].request("GET tls_library")
2267    if group == 25 and "run=BoringSSL" in tls:
2268        raise HwsimSkip("Group 15 not supported")
2269    if group in [27, 28, 29, 30]:
2270        if tls.startswith("OpenSSL") and ("run=OpenSSL 1." in tls or "run=OpenSSL 3." in tls):
2271            logger.info("Add Brainpool EC groups since OpenSSL is new enough")
2272        elif tls.startswith("wolfSSL"):
2273            logger.info("Make sure Brainpool EC groups were enabled when compiling wolfSSL")
2274        else:
2275            raise HwsimSkip("Brainpool curve not supported")
2276    start_sae_pwe_ap(apdev[0], group, 2)
2277    try:
2278        check_sae_pwe_group(dev[0], group, 0)
2279        check_sae_pwe_group(dev[0], group, 1)
2280        check_sae_pwe_group(dev[0], group, 2)
2281    finally:
2282        dev[0].set("sae_groups", "")
2283        dev[0].set("sae_pwe", "0")
2284
2285def check_sae_pwe_group(dev, group, sae_pwe, check_ssid=False):
2286    dev.set("sae_groups", str(group))
2287    dev.set("sae_pwe", str(sae_pwe))
2288    dev.connect("sae-pwe", psk="12345678", key_mgmt="SAE", scan_freq="2412")
2289    if check_ssid and dev.get_status_field("ssid_verified") != "1":
2290        raise Exception("ssid_verified=1 not in STATUS")
2291    dev.request("REMOVE_NETWORK all")
2292    dev.wait_disconnected()
2293    dev.dump_monitor()
2294
2295def test_sae_pwe_h2e_only_ap(dev, apdev):
2296    """SAE PWE derivation with H2E-only AP"""
2297    check_sae_capab(dev[0])
2298    start_sae_pwe_ap(apdev[0], 19, 1)
2299    try:
2300        check_sae_pwe_group(dev[0], 19, 1, check_ssid=True)
2301        check_sae_pwe_group(dev[0], 19, 2, check_ssid=True)
2302    finally:
2303        dev[0].set("sae_groups", "")
2304        dev[0].set("sae_pwe", "0")
2305
2306    dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE", scan_freq="2412",
2307                   wait_connect=False)
2308    ev = dev[0].wait_event(["CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
2309    if ev is None:
2310        raise Exception("No indication of mismatching network seen")
2311
2312def test_sae_pwe_h2e_only_ap_sta_forcing_loop(dev, apdev):
2313    """SAE PWE derivation with H2E-only AP and STA forcing loop"""
2314    check_sae_capab(dev[0])
2315    start_sae_pwe_ap(apdev[0], 19, 1)
2316    dev[0].set("ignore_sae_h2e_only", "1")
2317    dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE", scan_freq="2412",
2318                   wait_connect=False)
2319    ev = dev[0].wait_event(["CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=10)
2320    dev[0].request("DISCONNECT")
2321    if ev is None:
2322        raise Exception("No indication of temporary disabled network seen")
2323
2324def test_sae_pwe_loop_only_ap(dev, apdev):
2325    """SAE PWE derivation with loop-only AP"""
2326    check_sae_capab(dev[0])
2327    start_sae_pwe_ap(apdev[0], 19, 0)
2328    try:
2329        check_sae_pwe_group(dev[0], 19, 0)
2330        check_sae_pwe_group(dev[0], 19, 2)
2331        dev[0].set("sae_pwe", "1")
2332        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2333                       scan_freq="2412", wait_connect=False)
2334        ev = dev[0].wait_event(["CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
2335        if ev is None:
2336            raise Exception("No indication of mismatching network seen")
2337    finally:
2338        dev[0].set("sae_groups", "")
2339        dev[0].set("sae_pwe", "0")
2340
2341def test_sae_pwe_both(dev, apdev):
2342    """SAE PWE derivation with both options"""
2343    check_sae_capab(dev[0])
2344    check_sae_capab(dev[1])
2345    hapd = start_sae_pwe_ap(apdev[0], 19, 2, pmf=True)
2346    try:
2347        dev[0].set("sae_groups", "")
2348        dev[0].set("sae_pwe", "1")
2349        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2350                       ieee80211w="2", scan_freq="2412")
2351        dev[1].set("sae_groups", "")
2352        dev[1].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2353                       ieee80211w="2", scan_freq="2412")
2354        if dev[0].get_status_field("sae_h2e") != "1":
2355            raise Exception("SAE H2E was not used on dev[0]")
2356        if dev[1].get_status_field("sae_h2e") != "0":
2357            raise Exception("SAE H2E was used on dev[1]")
2358    finally:
2359        dev[0].set("sae_groups", "")
2360        dev[0].set("sae_pwe", "0")
2361        dev[1].set("sae_groups", "")
2362
2363    dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE", scan_freq="2412",
2364                   wait_connect=False)
2365    ev = dev[0].wait_event(["CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
2366    if ev is None:
2367        raise Exception("No indication of mismatching network seen")
2368
2369def test_sae_h2e_rejected_groups(dev, apdev):
2370    """SAE H2E and rejected groups indication"""
2371    check_sae_capab(dev[0])
2372    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2373    params['wpa_key_mgmt'] = 'SAE'
2374    params['sae_groups'] = "19"
2375    params['sae_pwe'] = "1"
2376    hapd = hostapd.add_ap(apdev[0], params)
2377    try:
2378        dev[0].set("sae_groups", "21 20 19")
2379        dev[0].set("sae_pwe", "1")
2380        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2381                       scan_freq="2412")
2382        addr = dev[0].own_addr()
2383        hapd.wait_sta(addr)
2384        sta = hapd.get_sta(addr)
2385        if 'sae_rejected_groups' not in sta:
2386            raise Exception("No sae_rejected_groups")
2387        val = sta['sae_rejected_groups']
2388        if val != "21 20":
2389            raise Exception("Unexpected sae_rejected_groups value: " + val)
2390    finally:
2391        dev[0].set("sae_groups", "")
2392        dev[0].set("sae_pwe", "0")
2393
2394def test_sae_h2e_rejected_groups_diff_ap(dev, apdev):
2395    """SAE H2E and rejected groups with different APs and different config"""
2396    check_sae_capab(dev[0])
2397
2398    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2399    params['wpa_key_mgmt'] = 'SAE'
2400    params['sae_groups'] = "19"
2401    params['sae_pwe'] = "1"
2402    hapd = hostapd.add_ap(apdev[0], params)
2403
2404    try:
2405        dev[0].set("sae_groups", "21 20 19")
2406        dev[0].set("sae_pwe", "1")
2407        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2408                       scan_freq="2412")
2409        addr = dev[0].own_addr()
2410        hapd.wait_sta(addr)
2411
2412        params['sae_groups'] = "20"
2413        hapd2 = hostapd.add_ap(apdev[1], params)
2414        bssid2 = hapd2.own_addr()
2415
2416        dev[0].scan_for_bss(bssid2, freq=2412)
2417        dev[0].roam(bssid2)
2418        hapd2.wait_sta(addr)
2419        sta = hapd2.get_sta(addr)
2420        if 'sae_rejected_groups' not in sta:
2421            raise Exception("No sae_rejected_groups")
2422        val = sta['sae_rejected_groups']
2423        if val != "21":
2424            raise Exception("Unexpected sae_rejected_groups value: " + val)
2425    finally:
2426        dev[0].set("sae_groups", "")
2427        dev[0].set("sae_pwe", "0")
2428
2429def test_sae_h2e_rejected_groups_unexpected(dev, apdev):
2430    """SAE H2E and rejected groups indication (unexpected group)"""
2431    check_sae_capab(dev[0])
2432    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2433    params['wpa_key_mgmt'] = 'SAE'
2434    params['sae_groups'] = "19 20"
2435    params['sae_pwe'] = "1"
2436    hapd = hostapd.add_ap(apdev[0], params)
2437    try:
2438        dev[0].set("sae_groups", "21 19")
2439        dev[0].set("extra_sae_rejected_groups", "19")
2440        dev[0].set("sae_pwe", "1")
2441        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2442                       scan_freq="2412", wait_connect=False)
2443        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2444                                "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=10)
2445        dev[0].request("DISCONNECT")
2446        if ev is None:
2447            raise Exception("No indication of temporary disabled network seen")
2448        if "CTRL-EVENT-CONNECTED" in ev:
2449            raise Exception("Unexpected connection")
2450    finally:
2451        dev[0].set("sae_groups", "")
2452        dev[0].set("sae_pwe", "0")
2453
2454def test_sae_h2e_rejected_groups_invalid(dev, apdev):
2455    """SAE protocol testing - Invalid Rejected Groups element"""
2456    check_sae_capab(dev[0])
2457    params = hostapd.wpa2_params(ssid="test-sae",
2458                                 passphrase="12345678")
2459    params['wpa_key_mgmt'] = 'SAE'
2460    params['sae_groups'] = "19 20"
2461    params['sae_pwe'] = "1"
2462    hapd = hostapd.add_ap(apdev[0], params)
2463
2464    try:
2465        dev[0].set("sae_groups", "20 19")
2466        dev[0].set("sae_pwe", "1")
2467        run_sae_h2e_rejected_groups_invalid(dev[0], hapd)
2468    finally:
2469        dev[0].set("sae_groups", "")
2470        dev[0].set("sae_pwe", "0")
2471
2472def run_sae_h2e_rejected_groups_invalid(dev, hapd):
2473    addr = dev.own_addr()
2474    bssid = hapd.own_addr()
2475
2476    dev.scan_for_bss(bssid, freq=2412)
2477    hapd.set("ext_mgmt_frame_handling", "1")
2478    dev.connect("test-sae", psk="12345678", key_mgmt="SAE",
2479                scan_freq="2412", wait_connect=False)
2480
2481    logger.info("Commit (group 20)")
2482    for i in range(10):
2483        req = hapd.mgmt_rx()
2484        if req is None:
2485            raise Exception("MGMT RX wait timed out (commit)")
2486        if req['subtype'] == 11:
2487            break
2488        req = None
2489    if not req:
2490        raise Exception("Authentication frame (commit) not received")
2491    group, = struct.unpack('<H', req['payload'][6:8])
2492    if group != 20:
2493        raise Exception("Unexpected group %d in SAE Commit" % group)
2494    hapd.dump_monitor()
2495
2496    # Discard this SAE Commit message without AP processing and instead, send
2497    # an unsupported group indication to the STA.
2498    resp = {}
2499    resp['fc'] = 0xb0
2500    resp['da'] = addr
2501    resp['sa'] = bssid
2502    resp['bssid'] = bssid
2503    resp['payload'] = binascii.unhexlify("030001004d001400")
2504    hapd.mgmt_tx(resp)
2505
2506    logger.info("Commit (group 19)")
2507    for i in range(10):
2508        req = hapd.mgmt_rx()
2509        if req is None:
2510            raise Exception("MGMT RX wait timed out (commit)")
2511        if req['subtype'] == 11:
2512            break
2513        req = None
2514    if not req:
2515        raise Exception("Authentication frame (commit) not received")
2516    group, = struct.unpack('<H', req['payload'][6:8])
2517    if group != 19:
2518        raise Exception("Unexpected group %d in SAE Commit" % group)
2519    hapd.dump_monitor()
2520
2521    # Replace the Rejected Groups element with an invalid one and process the
2522    # modified SAE Commit message in hostapd.
2523    rej_groups = req['frame'][-5:]
2524    if rej_groups != binascii.unhexlify('ff035c1400'):
2525        raise Exception("No Rejected Groups element: " + binascii.hexlify(rej_groups).decode())
2526    frame = req['frame'][:-5] + binascii.unhexlify('ff025c14')
2527    hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(frame).decode())
2528
2529    ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
2530    if ev is None:
2531        raise Exception("Management frame TX status not reported")
2532    if "stype=11 ok=1" not in ev:
2533        raise Exception("Unexpected Management frame TX status: " + ev)
2534    buf = ev.split(' ')[3].split('=')[1]
2535    payload = buf[48:]
2536    if payload != "030001000100":
2537        raise Exception("Unexpected AP response to SAE Commit with invalid Rejected Groups element: " + payload)
2538
2539    # Stop modifying frames and verify that connection is eventually established
2540    # with automatic retries.
2541    hapd.set("ext_mgmt_frame_handling", "0")
2542    dev.wait_connected(timeout=60)
2543
2544def test_sae_h2e_password_id(dev, apdev):
2545    """SAE H2E and password identifier"""
2546    check_sae_capab(dev[0])
2547    params = hostapd.wpa2_params(ssid="test-sae")
2548    params['wpa_key_mgmt'] = 'SAE'
2549    params['sae_pwe'] = '1'
2550    params['sae_password'] = 'secret|id=pw id'
2551    hapd = hostapd.add_ap(apdev[0], params)
2552
2553    try:
2554        dev[0].request("SET sae_groups ")
2555        dev[0].set("sae_pwe", "1")
2556        dev[0].connect("test-sae", sae_password="secret",
2557                       sae_password_id="pw id",
2558                       key_mgmt="SAE", scan_freq="2412")
2559    finally:
2560        dev[0].set("sae_groups", "")
2561        dev[0].set("sae_pwe", "0")
2562
2563def test_sae_pwe_in_psk_ap(dev, apdev):
2564    """sae_pwe parameter in PSK-only-AP"""
2565    params = hostapd.wpa2_params(ssid="test-psk", passphrase="12345678")
2566    params['sae_pwe'] = '1'
2567    hapd = hostapd.add_ap(apdev[0], params)
2568
2569    dev[0].connect("test-psk", psk="12345678", scan_freq="2412")
2570
2571def test_sae_auth_restart(dev, apdev):
2572    """SAE and authentication restarts with H2E/looping"""
2573    check_sae_capab(dev[0])
2574    params = hostapd.wpa2_params(ssid="test-sae")
2575    params['wpa_key_mgmt'] = 'SAE'
2576    params['sae_pwe'] = '2'
2577    params['sae_password'] = 'secret|id=pw id'
2578    hapd = hostapd.add_ap(apdev[0], params)
2579
2580    try:
2581        dev[0].request("SET sae_groups ")
2582        for pwe in [1, 0, 1]:
2583            dev[0].set("sae_pwe", str(pwe))
2584            dev[0].connect("test-sae", sae_password="secret",
2585                           sae_password_id="pw id",
2586                           key_mgmt="SAE", scan_freq="2412")
2587            # Disconnect without hostapd removing the STA entry so that the
2588            # following SAE authentication instance starts with an existing
2589            # STA entry that has maintained some SAE state.
2590            hapd.set("ext_mgmt_frame_handling", "1")
2591            dev[0].request("REMOVE_NETWORK all")
2592            req = hapd.mgmt_rx()
2593            dev[0].wait_disconnected()
2594            dev[0].dump_monitor()
2595            hapd.set("ext_mgmt_frame_handling", "0")
2596    finally:
2597        dev[0].set("sae_groups", "")
2598        dev[0].set("sae_pwe", "0")
2599
2600def test_sae_rsne_mismatch(dev, apdev):
2601    """SAE and RSNE mismatch in EAPOL-Key msg 2/4"""
2602    check_sae_capab(dev[0])
2603    dev[0].set("sae_groups", "")
2604
2605    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2606    params['wpa_key_mgmt'] = 'SAE'
2607    hapd = hostapd.add_ap(apdev[0], params)
2608
2609    # First, test with matching RSNE to confirm testing capability
2610    dev[0].set("rsne_override_eapol",
2611               "30140100000fac040100000fac040100000fac080c00")
2612    dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2613                   scan_freq="2412")
2614    dev[0].request("REMOVE_NETWORK all")
2615    dev[0].wait_disconnected()
2616    dev[0].dump_monitor()
2617
2618    # Then, test with modified RSNE
2619    tests = ["30140100000fac040100000fac040100000fac080c10", "0000"]
2620    for ie in tests:
2621        dev[0].set("rsne_override_eapol", ie)
2622        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2623                       scan_freq="2412", wait_connect=False)
2624        ev = dev[0].wait_event(["Associated with"], timeout=10)
2625        if ev is None:
2626            raise Exception("No indication of association seen")
2627        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2628                                "CTRL-EVENT-DISCONNECTED"], timeout=5)
2629        dev[0].request("REMOVE_NETWORK all")
2630        if ev is None:
2631            raise Exception("No disconnection seen")
2632        if "CTRL-EVENT-DISCONNECTED" not in ev:
2633            raise Exception("Unexpected connection")
2634        dev[0].dump_monitor()
2635
2636def test_sae_h2e_rsnxe_mismatch(dev, apdev):
2637    """SAE H2E and RSNXE mismatch in EAPOL-Key msg 2/4"""
2638    check_sae_capab(dev[0])
2639    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2640    params['wpa_key_mgmt'] = 'SAE'
2641    params['sae_pwe'] = "1"
2642    hapd = hostapd.add_ap(apdev[0], params)
2643    try:
2644        dev[0].set("sae_groups", "19")
2645        dev[0].set("sae_pwe", "1")
2646        for rsnxe in ["F40100", "F400", ""]:
2647            dev[0].set("rsnxe_override_eapol", rsnxe)
2648            dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2649                           scan_freq="2412", wait_connect=False)
2650            ev = dev[0].wait_event(["Associated with"], timeout=10)
2651            if ev is None:
2652                raise Exception("No indication of association seen")
2653            ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2654                                    "CTRL-EVENT-DISCONNECTED"], timeout=5)
2655            dev[0].request("REMOVE_NETWORK all")
2656            if ev is None:
2657                raise Exception("No disconnection seen")
2658            if "CTRL-EVENT-DISCONNECTED" not in ev:
2659                raise Exception("Unexpected connection")
2660            dev[0].dump_monitor()
2661    finally:
2662        dev[0].set("sae_groups", "")
2663        dev[0].set("sae_pwe", "0")
2664
2665def test_sae_h2e_rsnxe_mismatch_retries(dev, apdev):
2666    """SAE H2E and RSNXE mismatch in EAPOL-Key msg 2/4 retries"""
2667    check_sae_capab(dev[0])
2668    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2669    params['wpa_key_mgmt'] = 'SAE'
2670    params['sae_pwe'] = "1"
2671    hapd = hostapd.add_ap(apdev[0], params)
2672    try:
2673        dev[0].set("sae_groups", "19")
2674        dev[0].set("sae_pwe", "1")
2675        rsnxe = "F40100"
2676        dev[0].set("rsnxe_override_eapol", rsnxe)
2677        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2678                       scan_freq="2412", wait_connect=False)
2679        ev = dev[0].wait_event(["Associated with"], timeout=10)
2680        if ev is None:
2681            raise Exception("No indication of association seen")
2682        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2683                                "CTRL-EVENT-DISCONNECTED"], timeout=5)
2684        if ev is None:
2685            raise Exception("No disconnection seen")
2686        if "CTRL-EVENT-DISCONNECTED" not in ev:
2687            raise Exception("Unexpected connection")
2688
2689        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2690                                "CTRL-EVENT-DISCONNECTED"], timeout=10)
2691        if ev is None:
2692            raise Exception("No disconnection seen (2)")
2693        if "CTRL-EVENT-DISCONNECTED" not in ev:
2694            raise Exception("Unexpected connection (2)")
2695
2696        dev[0].dump_monitor()
2697    finally:
2698        dev[0].set("sae_groups", "")
2699        dev[0].set("sae_pwe", "0")
2700
2701def test_sae_h2e_rsnxe_mismatch_assoc(dev, apdev):
2702    """SAE H2E and RSNXE mismatch in EAPOL-Key msg 2/4 (assoc)"""
2703    check_sae_capab(dev[0])
2704    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2705    params['wpa_key_mgmt'] = 'SAE'
2706    params['sae_pwe'] = "1"
2707    hapd = hostapd.add_ap(apdev[0], params)
2708    try:
2709        dev[0].set("sae_groups", "19")
2710        dev[0].set("sae_pwe", "1")
2711        for rsnxe in ["F40100", "F400", ""]:
2712            dev[0].set("rsnxe_override_assoc", rsnxe)
2713            dev[0].set("rsnxe_override_eapol", "F40120")
2714            dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2715                           scan_freq="2412", wait_connect=False)
2716            ev = dev[0].wait_event(["Associated with"], timeout=10)
2717            if ev is None:
2718                raise Exception("No indication of association seen")
2719            ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2720                                    "CTRL-EVENT-DISCONNECTED"], timeout=5)
2721            dev[0].request("REMOVE_NETWORK all")
2722            if ev is None:
2723                raise Exception("No disconnection seen")
2724            if "CTRL-EVENT-DISCONNECTED" not in ev:
2725                raise Exception("Unexpected connection")
2726            dev[0].dump_monitor()
2727    finally:
2728        dev[0].set("sae_groups", "")
2729        dev[0].set("sae_pwe", "0")
2730
2731def test_sae_h2e_rsnxe_mismatch_ap(dev, apdev):
2732    """SAE H2E and RSNXE mismatch in EAPOL-Key msg 3/4"""
2733    run_sae_h2e_rsnxe_mismatch_ap(dev, apdev, "F40100")
2734
2735def test_sae_h2e_rsnxe_mismatch_ap2(dev, apdev):
2736    """SAE H2E and RSNXE mismatch in EAPOL-Key msg 3/4"""
2737    run_sae_h2e_rsnxe_mismatch_ap(dev, apdev, "F400")
2738
2739def test_sae_h2e_rsnxe_mismatch_ap3(dev, apdev):
2740    """SAE H2E and RSNXE mismatch in EAPOL-Key msg 3/4"""
2741    run_sae_h2e_rsnxe_mismatch_ap(dev, apdev, "")
2742
2743def run_sae_h2e_rsnxe_mismatch_ap(dev, apdev, rsnxe):
2744    check_sae_capab(dev[0])
2745    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2746    params['wpa_key_mgmt'] = 'SAE'
2747    params['sae_pwe'] = "1"
2748    params['rsnxe_override_eapol'] = rsnxe
2749    hapd = hostapd.add_ap(apdev[0], params)
2750    try:
2751        dev[0].set("sae_groups", "19")
2752        dev[0].set("sae_pwe", "1")
2753        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2754                       scan_freq="2412", wait_connect=False)
2755        ev = dev[0].wait_event(["Associated with"], timeout=10)
2756        if ev is None:
2757            raise Exception("No indication of association seen")
2758        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2759                                "CTRL-EVENT-DISCONNECTED"], timeout=5)
2760        dev[0].request("REMOVE_NETWORK all")
2761        if ev is None:
2762            raise Exception("No disconnection seen")
2763        if "CTRL-EVENT-DISCONNECTED" not in ev:
2764            raise Exception("Unexpected connection")
2765    finally:
2766        dev[0].set("sae_groups", "")
2767        dev[0].set("sae_pwe", "0")
2768
2769def test_sae_forced_anti_clogging_h2e(dev, apdev):
2770    """SAE anti clogging (forced, H2E)"""
2771    check_sae_capab(dev[0])
2772    check_sae_capab(dev[1])
2773    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2774    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
2775    params['sae_pwe'] = "1"
2776    params['sae_anti_clogging_threshold'] = '0'
2777    hostapd.add_ap(apdev[0], params)
2778    dev[2].connect("test-sae", psk="12345678", scan_freq="2412")
2779    try:
2780        for i in range(2):
2781            dev[i].request("SET sae_groups ")
2782            dev[i].set("sae_pwe", "1")
2783            dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
2784                           scan_freq="2412")
2785    finally:
2786        for i in range(2):
2787            dev[i].set("sae_pwe", "0")
2788
2789def test_sae_forced_anti_clogging_h2e_loop(dev, apdev):
2790    """SAE anti clogging (forced, H2E + loop)"""
2791    check_sae_capab(dev[0])
2792    check_sae_capab(dev[1])
2793    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2794    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
2795    params['sae_pwe'] = "2"
2796    params['sae_anti_clogging_threshold'] = '0'
2797    hostapd.add_ap(apdev[0], params)
2798    dev[2].connect("test-sae", psk="12345678", scan_freq="2412")
2799    try:
2800        for i in range(2):
2801            dev[i].request("SET sae_groups ")
2802            dev[i].set("sae_pwe", "2")
2803            dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
2804                           scan_freq="2412")
2805    finally:
2806        for i in range(2):
2807            dev[i].set("sae_pwe", "0")
2808
2809def test_sae_okc(dev, apdev):
2810    """SAE and opportunistic key caching"""
2811    check_sae_capab(dev[0])
2812    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2813    params['wpa_key_mgmt'] = 'SAE'
2814    params['okc'] = '1'
2815    hapd = hostapd.add_ap(apdev[0], params)
2816    bssid = hapd.own_addr()
2817
2818    dev[0].flush_scan_cache()
2819    dev[0].set("sae_groups", "")
2820    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
2821                        okc=True, scan_freq="2412")
2822    dev[0].dump_monitor()
2823    hapd.wait_sta()
2824    if "sae_group" not in dev[0].get_status():
2825        raise Exception("SAE authentication not used")
2826
2827    hapd2 = hostapd.add_ap(apdev[1], params)
2828    bssid2 = hapd2.own_addr()
2829
2830    dev[0].scan_for_bss(bssid2, freq=2412)
2831    dev[0].roam(bssid2)
2832    dev[0].dump_monitor()
2833    hapd2.wait_sta()
2834    if "sae_group" in dev[0].get_status():
2835        raise Exception("SAE authentication used during roam to AP2")
2836
2837    dev[0].roam(bssid)
2838    dev[0].dump_monitor()
2839    hapd.wait_sta()
2840    if "sae_group" in dev[0].get_status():
2841        raise Exception("SAE authentication used during roam to AP1")
2842
2843def test_sae_okc_sta_only(dev, apdev):
2844    """SAE and opportunistic key caching only on STA"""
2845    check_sae_capab(dev[0])
2846    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2847    params['wpa_key_mgmt'] = 'SAE'
2848    hapd = hostapd.add_ap(apdev[0], params)
2849    bssid = hapd.own_addr()
2850
2851    dev[0].flush_scan_cache()
2852    dev[0].set("sae_groups", "")
2853    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
2854                        okc=True, scan_freq="2412")
2855    dev[0].dump_monitor()
2856    hapd.wait_sta()
2857    if "sae_group" not in dev[0].get_status():
2858        raise Exception("SAE authentication not used")
2859
2860    hapd2 = hostapd.add_ap(apdev[1], params)
2861    bssid2 = hapd2.own_addr()
2862
2863    dev[0].scan_for_bss(bssid2, freq=2412)
2864    dev[0].roam(bssid2, assoc_reject_ok=True)
2865    dev[0].dump_monitor()
2866    hapd2.wait_sta()
2867    if "sae_group" not in dev[0].get_status():
2868        raise Exception("SAE authentication not used during roam to AP2")
2869
2870def test_sae_okc_pmk_lifetime(dev, apdev):
2871    """SAE and opportunistic key caching and PMK lifetime"""
2872    check_sae_capab(dev[0])
2873    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2874    params['wpa_key_mgmt'] = 'SAE'
2875    params['okc'] = '1'
2876    hapd = hostapd.add_ap(apdev[0], params)
2877    bssid = hapd.own_addr()
2878
2879    dev[0].flush_scan_cache()
2880    dev[0].set("sae_groups", "")
2881    dev[0].set("dot11RSNAConfigPMKLifetime", "10")
2882    dev[0].set("dot11RSNAConfigPMKReauthThreshold", "30")
2883    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
2884                        okc=True, scan_freq="2412")
2885    dev[0].dump_monitor()
2886    hapd.wait_sta()
2887    if "sae_group" not in dev[0].get_status():
2888        raise Exception("SAE authentication not used")
2889
2890    hapd2 = hostapd.add_ap(apdev[1], params)
2891    bssid2 = hapd2.own_addr()
2892
2893    time.sleep(5)
2894    dev[0].scan_for_bss(bssid2, freq=2412)
2895    dev[0].roam(bssid2)
2896    dev[0].dump_monitor()
2897    hapd2.wait_sta()
2898    if "sae_group" not in dev[0].get_status():
2899        raise Exception("SAE authentication not used during roam to AP2 after reauth threshold")
2900
2901def test_sae_pmk_lifetime(dev, apdev):
2902    """SAE and PMK lifetime"""
2903    check_sae_capab(dev[0])
2904    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2905    params['wpa_key_mgmt'] = 'SAE'
2906    hapd = hostapd.add_ap(apdev[0], params)
2907    bssid = hapd.own_addr()
2908
2909    dev[0].set("sae_groups", "")
2910    dev[0].set("dot11RSNAConfigPMKLifetime", "10")
2911    dev[0].set("dot11RSNAConfigPMKReauthThreshold", "50")
2912    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
2913                        scan_freq="2412")
2914    dev[0].dump_monitor()
2915    hapd.wait_sta()
2916    if "sae_group" not in dev[0].get_status():
2917        raise Exception("SAE authentication not used")
2918
2919    hapd2 = hostapd.add_ap(apdev[1], params)
2920    bssid2 = hapd2.own_addr()
2921
2922    dev[0].flush_scan_cache()
2923    dev[0].scan_for_bss(bssid2, freq=2412)
2924    dev[0].roam(bssid2)
2925    dev[0].dump_monitor()
2926    hapd2.wait_sta()
2927    if "sae_group" not in dev[0].get_status():
2928        raise Exception("SAE authentication not used during roam to AP2")
2929
2930    dev[0].roam(bssid)
2931    dev[0].dump_monitor()
2932    hapd.wait_sta()
2933    if "sae_group" in dev[0].get_status():
2934        raise Exception("SAE authentication used during roam to AP1")
2935
2936    time.sleep(6)
2937    dev[0].scan_for_bss(bssid2, freq=2412)
2938    dev[0].roam(bssid2)
2939    dev[0].dump_monitor()
2940    hapd2.wait_sta()
2941    if "sae_group" not in dev[0].get_status():
2942        raise Exception("SAE authentication not used during roam to AP2 after reauth threshold")
2943
2944    ev = dev[0].wait_event(["PMKSA-CACHE-REMOVED"], 11)
2945    if ev is None:
2946        raise Exception("PMKSA cache entry did not expire")
2947    if bssid2 in ev:
2948        raise Exception("Unexpected expiration of the current SAE PMKSA cache entry")
2949
2950def test_sae_and_psk_multiple_passwords(dev, apdev, params):
2951    """SAE and PSK with multiple passwords/passphrases"""
2952    check_sae_capab(dev[0])
2953    check_sae_capab(dev[1])
2954    addr0 = dev[0].own_addr()
2955    addr1 = dev[1].own_addr()
2956    psk_file = os.path.join(params['logdir'],
2957                            'sae_and_psk_multiple_passwords.wpa_psk')
2958    with open(psk_file, 'w') as f:
2959        f.write(addr0 + ' passphrase0\n')
2960        f.write(addr1 + ' passphrase1\n')
2961    params = hostapd.wpa2_params(ssid="test-sae")
2962    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
2963    params['sae_password'] = ['passphrase0|mac=' + addr0,
2964                              'passphrase1|mac=' + addr1]
2965    params['wpa_psk_file'] = psk_file
2966    hapd = hostapd.add_ap(apdev[0], params)
2967
2968    dev[0].set("sae_groups", "")
2969    dev[0].connect("test-sae", sae_password="passphrase0",
2970                   key_mgmt="SAE", scan_freq="2412")
2971    dev[0].request("REMOVE_NETWORK all")
2972    dev[0].wait_disconnected()
2973
2974    dev[0].connect("test-sae", psk="passphrase0", scan_freq="2412")
2975    dev[0].request("REMOVE_NETWORK all")
2976    dev[0].wait_disconnected()
2977
2978    dev[1].set("sae_groups", "")
2979    dev[1].connect("test-sae", sae_password="passphrase1",
2980                   key_mgmt="SAE", scan_freq="2412")
2981    dev[1].request("REMOVE_NETWORK all")
2982    dev[1].wait_disconnected()
2983
2984    dev[1].connect("test-sae", psk="passphrase1", scan_freq="2412")
2985    dev[1].request("REMOVE_NETWORK all")
2986    dev[1].wait_disconnected()
2987
2988def test_sae_pmf_roam(dev, apdev):
2989    """SAE/PMF roam"""
2990    check_sae_capab(dev[0])
2991    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2992    params['wpa_key_mgmt'] = 'SAE'
2993    params['ieee80211w'] = '2'
2994    params['skip_prune_assoc'] = '1'
2995    hapd = hostapd.add_ap(apdev[0], params)
2996    bssid = hapd.own_addr()
2997
2998    dev[0].flush_scan_cache()
2999    dev[0].set("sae_groups", "")
3000    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
3001                        ieee80211w="2", scan_freq="2412")
3002    dev[0].dump_monitor()
3003    hapd.wait_sta()
3004
3005    hapd2 = hostapd.add_ap(apdev[1], params)
3006    bssid2 = hapd2.own_addr()
3007
3008    dev[0].scan_for_bss(bssid2, freq=2412)
3009    dev[0].roam(bssid2)
3010    dev[0].dump_monitor()
3011    hapd2.wait_sta()
3012
3013    dev[0].roam(bssid)
3014    dev[0].dump_monitor()
3015
3016def test_sae_ocv_pmk(dev, apdev):
3017    """SAE with OCV and fetching PMK (successful 4-way handshake)"""
3018    check_sae_capab(dev[0])
3019    params = hostapd.wpa2_params(ssid="test-sae",
3020                                 passphrase="12345678")
3021    params['wpa_key_mgmt'] = 'SAE'
3022    params['ieee80211w'] = '2'
3023    params['ocv'] = '1'
3024    hapd = hostapd.add_ap(apdev[0], params)
3025
3026    dev[0].set("sae_groups", "")
3027    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", ocv="1",
3028                        ieee80211w="2", scan_freq="2412")
3029    hapd.wait_sta()
3030
3031    pmk_h = hapd.request("GET_PMK " + dev[0].own_addr())
3032    if "FAIL" in pmk_h or len(pmk_h) == 0:
3033        raise Exception("Failed to fetch PMK from hostapd during a successful authentication")
3034
3035    pmk_w = dev[0].get_pmk(id)
3036    if pmk_h != pmk_w:
3037        raise Exception("Fetched PMK does not match: hostapd %s, wpa_supplicant %s" % (pmk_h, pmk_w))
3038
3039def test_sae_ocv_pmk_failure(dev, apdev):
3040    """SAE with OCV and fetching PMK (failed 4-way handshake)"""
3041    check_sae_capab(dev[0])
3042    params = hostapd.wpa2_params(ssid="test-sae",
3043                                 passphrase="12345678")
3044    params['wpa_key_mgmt'] = 'SAE'
3045    params['ieee80211w'] = '2'
3046    params['ocv'] = '1'
3047    hapd = hostapd.add_ap(apdev[0], params)
3048
3049    dev[0].set("sae_groups", "")
3050    dev[0].set("oci_freq_override_eapol", "2462")
3051    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", ocv="1",
3052                        ieee80211w="2", scan_freq="2412", wait_connect=False)
3053    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
3054                            "CTRL-EVENT-DISCONNECTED"], timeout=15)
3055    if ev is None:
3056        raise Exception("No connection result reported")
3057    if "CTRL-EVENT-CONNECTED" in ev:
3058        raise Exception("Unexpected connection")
3059
3060    pmk_h = hapd.request("GET_PMK " + dev[0].own_addr())
3061    if "FAIL" in pmk_h or len(pmk_h) == 0:
3062        raise Exception("Failed to fetch PMK from hostapd during a successful authentication")
3063
3064    res = dev[0].request("PMKSA_GET %d" % id)
3065    if not res.startswith(hapd.own_addr()):
3066        raise Exception("PMKSA from wpa_supplicant does not have matching BSSID")
3067    pmk_w = res.split(' ')[2]
3068    if pmk_h != pmk_w:
3069        raise Exception("Fetched PMK does not match: hostapd %s, wpa_supplicant %s" % (pmk_h, pmk_w))
3070
3071    dev[0].request("DISCONNECT")
3072    time.sleep(0.1)
3073    pmk_h2 = hapd.request("GET_PMK " + dev[0].own_addr())
3074    res = dev[0].request("PMKSA_GET %d" % id)
3075    pmk_w2 = res.split(' ')[2]
3076    if pmk_h2 != pmk_h:
3077        raise Exception("hostapd did not report correct PMK after disconnection")
3078    if pmk_w2 != pmk_w:
3079        raise Exception("wpa_supplicant did not report correct PMK after disconnection")
3080
3081def test_sae_reject(dev, apdev):
3082    """SAE and AP rejecting connection"""
3083    check_sae_capab(dev[0])
3084    params = hostapd.wpa2_params(ssid="test-sae",
3085                                 passphrase="12345678")
3086    params['wpa_key_mgmt'] = 'SAE'
3087    params['max_num_sta'] = '0'
3088    hapd = hostapd.add_ap(apdev[0], params)
3089    dev[0].set("sae_groups", "")
3090    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
3091                        scan_freq="2412", wait_connect=False)
3092    if not dev[0].wait_event(["CTRL-EVENT-AUTH-REJECT"], timeout=10):
3093        raise Exception("Authentication rejection not reported")
3094    dev[0].request("REMOVE_NETWORK all")
3095    dev[0].dump_monitor()
3096
3097def test_sae_ext_key_19(dev, apdev):
3098    """SAE with extended key AKM (group 19)"""
3099    run_sae_ext_key(dev, apdev, 19)
3100
3101def test_sae_ext_key_20(dev, apdev):
3102    """SAE with extended key AKM (group 20)"""
3103    run_sae_ext_key(dev, apdev, 20)
3104
3105def test_sae_ext_key_21(dev, apdev):
3106    """SAE with extended key AKM (group 21)"""
3107    run_sae_ext_key(dev, apdev, 21)
3108
3109def test_sae_ext_key_19_gcmp256(dev, apdev):
3110    """SAE with extended key AKM (group 19) with GCMP256 pairwise cipher"""
3111    run_sae_ext_key(dev, apdev, 19, cipher="GCMP-256")
3112
3113def test_sae_ext_key_20_gcmp256(dev, apdev):
3114    """SAE with extended key AKM (group 20) with GCMP-256 pairwise cipher"""
3115    run_sae_ext_key(dev, apdev, 20, cipher="GCMP-256")
3116
3117def test_sae_ext_key_21_gcmp256(dev, apdev):
3118    """SAE with extended key AKM (group 21) with GCMP-256 pairwise cipher"""
3119    run_sae_ext_key(dev, apdev, 21, cipher="GCMP-256")
3120
3121def test_sae_ext_key_21_gcmp256_gcmp256(dev, apdev):
3122    """SAE with extended key AKM (group 21) with GCMP-256 pairwise and group cipher"""
3123    run_sae_ext_key(dev, apdev, 21, cipher="GCMP-256", group_cipher="GCMP-256")
3124
3125def run_sae_ext_key(dev, apdev, group, cipher="CCMP", group_cipher="CCMP"):
3126    check_sae_capab(dev[0])
3127
3128    if cipher not in dev[0].get_capability("pairwise"):
3129        raise HwsimSkip("Cipher %s not supported" % cipher)
3130    if group_cipher not in dev[0].get_capability("group"):
3131        raise HwsimSkip("Cipher %s not supported" % group_cipher)
3132
3133    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
3134    params['wpa_key_mgmt'] = 'SAE-EXT-KEY'
3135    params['sae_groups'] = str(group)
3136    params['ieee80211w'] = '2'
3137    params['rsn_pairwise'] = cipher
3138    params['group_cipher'] = group_cipher
3139
3140    hapd = hostapd.add_ap(apdev[0], params)
3141    key_mgmt = hapd.get_config()['key_mgmt']
3142    if key_mgmt.split(' ')[0] != "SAE-EXT-KEY":
3143        raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
3144
3145    dev[0].flush_scan_cache()
3146    dev[0].set("sae_groups", str(group))
3147    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE-EXT-KEY",
3148                        pairwise=cipher, group=group_cipher,
3149                        ieee80211w="2", scan_freq="2412")
3150    hapd.wait_sta()
3151    if dev[0].get_status_field('sae_group') != str(group):
3152            raise Exception("Expected SAE group not used")
3153    bss = dev[0].get_bss(apdev[0]['bssid'])
3154    if 'flags' not in bss:
3155        raise Exception("Could not get BSS flags from BSS table")
3156    if "[WPA2-SAE-EXT-KEY-" + cipher + "]" not in bss['flags']:
3157        raise Exception("Unexpected BSS flags: " + bss['flags'])
3158
3159    res = hapd.request("STA-FIRST")
3160    if ("sae_group=%d" % group) not in res.splitlines():
3161        raise Exception("hostapd STA output did not specify SAE group")
3162
3163    sta0 = hapd.get_sta(dev[0].own_addr())
3164    if sta0['wpa'] != '2' or sta0['AKMSuiteSelector'] != '00-0f-ac-24':
3165        raise Exception("SAE STA(0) AKM suite selector reported incorrectly")
3166
3167    pmk_h = hapd.request("GET_PMK " + dev[0].own_addr())
3168    pmk_w = dev[0].get_pmk(id)
3169    if pmk_h != pmk_w:
3170        raise Exception("Fetched PMK does not match: hostapd %s, wpa_supplicant %s" % (pmk_h, pmk_w))
3171    if group == 19:
3172        pmk_len = 32
3173    elif group == 20:
3174        pmk_len = 48
3175    elif group == 21:
3176        pmk_len = 64
3177    if len(pmk_h) != 2 * pmk_len:
3178        raise Exception("Unexpected SAE PMK length: %d" % (len(pmk_h) / 2))
3179    dev[0].request("DISCONNECT")
3180    dev[0].wait_disconnected()
3181    pmk_h2 = hapd.request("GET_PMK " + dev[0].own_addr())
3182    if pmk_h != pmk_h2:
3183        raise Exception("Fetched PMK from PMKSA cache does not match: %s, %s" % (pmk_h, pmk_h2))
3184
3185    dev[0].request("RECONNECT")
3186    dev[0].wait_connected(timeout=15, error="Reconnect timed out")
3187    val = dev[0].get_status_field('sae_group')
3188    if val is not None:
3189        raise Exception("SAE group claimed to have been used: " + val)
3190    sta0 = hapd.get_sta(dev[0].own_addr())
3191    if sta0['wpa'] != '2' or sta0['AKMSuiteSelector'] != '00-0f-ac-24':
3192        raise Exception("SAE STA(0) AKM suite selector reported incorrectly after PMKSA caching")
3193
3194def test_sae_akms(dev, apdev):
3195    """SAE with both AKMs)"""
3196    check_sae_capab(dev[0])
3197    check_sae_capab(dev[1])
3198    check_sae_capab(dev[2])
3199    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
3200    params['wpa_key_mgmt'] = 'SAE SAE-EXT-KEY'
3201    params['sae_groups'] = "19 20"
3202    params['ieee80211w'] = '2'
3203    hapd = hostapd.add_ap(apdev[0], params)
3204
3205    dev[0].set("sae_groups", "20")
3206    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE-EXT-KEY",
3207                   ieee80211w="2", scan_freq="2412")
3208
3209    dev[1].set("sae_groups", "20")
3210    dev[1].connect("test-sae", psk="12345678", key_mgmt="SAE",
3211                   ieee80211w="2", scan_freq="2412")
3212
3213    dev[2].set("sae_groups", "19")
3214    dev[2].connect("test-sae", psk="12345678", key_mgmt="SAE",
3215                   ieee80211w="2", scan_freq="2412")
3216
3217def test_sae_ext_key_h2e_rejected_group(dev, apdev):
3218    """SAE-EXT-KEY, H2E, and rejected groups indication"""
3219    run_sae_ext_key_h2e_rejected_group(dev, apdev, "19", "20 19", "20")
3220
3221def test_sae_ext_key_h2e_rejected_group2(dev, apdev):
3222    """SAE-EXT-KEY, H2E, and rejected groups indication (2)"""
3223    run_sae_ext_key_h2e_rejected_group(dev, apdev, "20", "19 20", "19")
3224
3225def run_sae_ext_key_h2e_rejected_group(dev, apdev, ap_groups, sta_groups,
3226                                       rejected_groups):
3227    check_sae_capab(dev[0])
3228    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
3229    params['wpa_key_mgmt'] = 'SAE-EXT-KEY'
3230    params['sae_groups'] = ap_groups
3231    params['sae_pwe'] = "1"
3232    params['ieee80211w'] = "2"
3233    hapd = hostapd.add_ap(apdev[0], params)
3234    try:
3235        dev[0].set("sae_groups", sta_groups)
3236        dev[0].set("sae_pwe", "1")
3237        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE-EXT-KEY",
3238                       ieee80211w="2", scan_freq="2412")
3239        addr = dev[0].own_addr()
3240        hapd.wait_sta(addr)
3241        sta = hapd.get_sta(addr)
3242        if 'sae_rejected_groups' not in sta:
3243            raise Exception("No sae_rejected_groups")
3244        val = sta['sae_rejected_groups']
3245        if val != rejected_groups:
3246            raise Exception("Unexpected sae_rejected_groups value: " + val)
3247    finally:
3248        dev[0].set("sae_groups", "")
3249        dev[0].set("sae_pwe", "0")
3250
3251def test_sae_pref_ap_wrong_password(dev, apdev):
3252    """SAE and preferred AP using wrong password"""
3253    check_sae_capab(dev[0])
3254
3255    params = hostapd.wpa3_params(ssid="test-sae", password="correct")
3256    params['ieee80211n'] = '0'
3257    hapd = hostapd.add_ap(apdev[0], params)
3258
3259    params = hostapd.wpa3_params(ssid="test-sae", password="wrong")
3260    hapd2 = hostapd.add_ap(apdev[1], params)
3261
3262    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3263    dev[0].scan_for_bss(hapd2.own_addr(), freq=2412)
3264
3265    dev[0].set("sae_groups", "")
3266    dev[0].connect("test-sae", sae_password="correct", key_mgmt="SAE",
3267                   ieee80211w="2", scan_freq="2412")
3268
3269def test_sae_pref_ap_wrong_password2(dev, apdev):
3270    """SAE and preferred AP using wrong password (2)"""
3271    check_sae_capab(dev[0])
3272
3273    params = hostapd.wpa3_params(ssid="test-sae", password="wrong")
3274    hapd2 = hostapd.add_ap(apdev[1], params)
3275
3276    dev[0].scan_for_bss(hapd2.own_addr(), freq=2412)
3277
3278    dev[0].set("sae_groups", "")
3279    dev[0].connect("test-sae", sae_password="correct", key_mgmt="SAE",
3280                   ieee80211w="2", scan_freq="2412", wait_connect=False)
3281    ev = dev[0].wait_event(["CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=30)
3282    if ev is None:
3283        raise Exception("Temporary disabled of SSID not seen")
3284
3285    params = hostapd.wpa3_params(ssid="test-sae", password="correct")
3286    params['ieee80211n'] = '0'
3287    hapd = hostapd.add_ap(apdev[0], params)
3288
3289    dev[0].wait_connected(timeout=40)
3290
3291def test_sae_password_file(dev, apdev):
3292    """SAE and sae_password_file in hostapd configuration"""
3293    check_sae_capab(dev[0])
3294    check_sae_capab(dev[1])
3295    check_sae_capab(dev[2])
3296    fd, fn = tempfile.mkstemp()
3297    try:
3298        f = os.fdopen(fd, 'w')
3299        f.write("pw1|id=id1\n")
3300        f.write("pw2|id=id2\n")
3301        f.write("pw3|id=id3\n")
3302        f.close()
3303
3304        params = hostapd.wpa2_params(ssid="test-sae", wpa_key_mgmt="SAE")
3305        params['sae_password_file'] = fn
3306        hapd = hostapd.add_ap(apdev[0], params)
3307
3308        dev[0].set("sae_groups", "")
3309        dev[0].connect("test-sae", sae_password="pw1", sae_password_id="id1",
3310                       key_mgmt="SAE", scan_freq="2412")
3311
3312        dev[1].set("sae_groups", "")
3313        dev[1].connect("test-sae", sae_password="pw2", sae_password_id="id2",
3314                       key_mgmt="SAE", scan_freq="2412")
3315
3316        dev[2].set("sae_groups", "")
3317        dev[2].connect("test-sae", sae_password="pw3", sae_password_id="id3",
3318                       key_mgmt="SAE", scan_freq="2412")
3319    finally:
3320        os.unlink(fn)
3321
3322def test_sae_ssid_protection(dev, apdev):
3323    """SAE with SSID protection in 4-way handshake"""
3324    check_sae_capab(dev[0])
3325    params = hostapd.wpa2_params(ssid="test-sae",
3326                                 passphrase="12345678")
3327    params['wpa_key_mgmt'] = 'SAE'
3328    params['ssid_protection'] = '1'
3329    hapd = hostapd.add_ap(apdev[0], params)
3330
3331    dev[0].set("sae_groups", "")
3332    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
3333                   ssid_protection="1",
3334                   scan_freq="2412", wait_connect=False)
3335    ev = dev[0].wait_event(["RSN: SSID matched expected value"], timeout=10)
3336    if ev is None:
3337        raise Exception("SSID protection event not seen")
3338    dev[0].wait_connected()
3339    hapd.wait_sta()
3340
3341    if dev[0].get_status_field("ssid_verified") != "1":
3342        raise Exception("ssid_verified=1 not in STATUS")
3343
3344def test_sae_eapol_key_reserved_random(dev, apdev):
3345    """SAE with EAPOL-Key Reserved field set to random value"""
3346    check_sae_capab(dev[0])
3347    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
3348    params['wpa_key_mgmt'] = 'SAE'
3349    params['eapol_key_reserved_random'] = '1'
3350    hapd = hostapd.add_ap(apdev[0], params)
3351
3352    dev[0].set("sae_groups", "")
3353    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
3354                   scan_freq="2412")
3355
3356def test_sae_eapol_key_2_reserved_key_info(dev, apdev):
3357    """SAE with EAPOL-Key msg 2/4 Key Info field reserved bits set"""
3358    check_sae_capab(dev[0])
3359    params = hostapd.wpa3_params(ssid="test-sae", password="12345678")
3360    hapd = hostapd.add_ap(apdev[0], params)
3361
3362    dev[0].set("eapol_2_key_info_set_mask", "c000")
3363    dev[0].set("sae_groups", "")
3364    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", ieee80211w="2",
3365                   scan_freq="2412")
3366
3367def test_sae_long_rsnxe(dev, apdev):
3368    """RSNXE extensibility"""
3369    check_sae_capab(dev[0])
3370
3371    rsnxe = "F4FF2F0000000000000000000000000000FF" + 239*"EE"
3372
3373    params = hostapd.wpa3_params(ssid="sae-pwe", password="12345678")
3374    params['sae_pwe'] = "1"
3375    params['rsnxe_override'] = rsnxe
3376    hapd = hostapd.add_ap(apdev[0], params)
3377
3378    dev[0].set("sae_groups", "")
3379    dev[0].set("rsnxe_override_assoc", rsnxe)
3380    dev[0].set("rsnxe_override_eapol", rsnxe)
3381    try:
3382        dev[0].set("sae_pwe", "2")
3383        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
3384                       scan_freq="2412", ieee80211w="2")
3385        if dev[0].get_status_field("sae_h2e") != "1":
3386            raise Exception("SAE H2E was not used")
3387    finally:
3388        dev[0].set("sae_groups", "")
3389        dev[0].set("sae_pwe", "0")
3390
3391def test_sae_dump_beacon(dev, apdev):
3392    """SAE and DUMP_BEACON"""
3393    check_sae_capab(dev[0])
3394    params = hostapd.wpa3_params(ssid="test-sae", password="12345678")
3395    hapd = hostapd.add_ap(apdev[0], params)
3396
3397    dev[0].set("sae_groups", "")
3398    dev[0].connect("test-sae", sae_password="12345678", key_mgmt="SAE",
3399                   ieee80211w="2", scan_freq="2412")
3400    hapd.wait_sta()
3401    res = hapd.request("DUMP_BEACON")
3402    if "FAIL" in res:
3403        raise Exception("DUMP_BEACON failed")
3404    logger.info("DUMP_BEACON: " + res)
3405
3406    # Make sure there is enough time to capture at least one Beacon frame
3407    time.sleep(0.2)
3408