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