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 26 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_init;sae_derive_pwe_ecc"),
1494             (1, "crypto_ec_point_solve_y_coord;sae_derive_pwe_ecc"),
1495             (1, "crypto_ec_point_init;sae_derive_commit_element_ecc"),
1496             (1, "crypto_ec_point_mul;sae_derive_commit_element_ecc"),
1497             (1, "crypto_ec_point_invert;sae_derive_commit_element_ecc"),
1498             (1, "crypto_bignum_init;=sae_derive_commit"),
1499             (1, "crypto_ec_point_init;sae_derive_k_ecc"),
1500             (1, "crypto_ec_point_mul;sae_derive_k_ecc"),
1501             (1, "crypto_ec_point_add;sae_derive_k_ecc"),
1502             (2, "crypto_ec_point_mul;sae_derive_k_ecc"),
1503             (1, "crypto_ec_point_to_bin;sae_derive_k_ecc"),
1504             (1, "crypto_bignum_legendre;dragonfly_get_random_qr_qnr"),
1505             (1, "sha256_prf;sae_derive_keys"),
1506             (1, "crypto_bignum_init;sae_derive_keys"),
1507             (1, "crypto_bignum_init_set;sae_parse_commit_scalar"),
1508             (1, "crypto_bignum_to_bin;sae_parse_commit_element_ecc"),
1509             (1, "crypto_ec_point_from_bin;sae_parse_commit_element_ecc")]
1510    for count, func in tests:
1511        with fail_test(dev[0], count, func):
1512            hapd.request("NOTE STA failure testing %d:%s" % (count, func))
1513            dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1514                           scan_freq="2412", wait_connect=False)
1515            wait_fail_trigger(dev[0], "GET_FAIL", timeout=0.1)
1516            dev[0].request("REMOVE_NETWORK all")
1517            dev[0].dump_monitor()
1518            hapd.dump_monitor()
1519
1520    dev[0].request("SET sae_groups 15")
1521    tests = [(1, "crypto_bignum_init_set;sae_set_group"),
1522             (2, "crypto_bignum_init_set;sae_set_group"),
1523             (1, "crypto_bignum_init;sae_derive_commit"),
1524             (2, "crypto_bignum_init;sae_derive_commit"),
1525             (1, "crypto_bignum_init_set;sae_test_pwd_seed_ffc"),
1526             (1, "crypto_bignum_exptmod;sae_test_pwd_seed_ffc"),
1527             (1, "crypto_bignum_init;sae_derive_pwe_ffc"),
1528             (1, "crypto_bignum_init;sae_derive_commit_element_ffc"),
1529             (1, "crypto_bignum_exptmod;sae_derive_commit_element_ffc"),
1530             (1, "crypto_bignum_inverse;sae_derive_commit_element_ffc"),
1531             (1, "crypto_bignum_init;sae_derive_k_ffc"),
1532             (1, "crypto_bignum_exptmod;sae_derive_k_ffc"),
1533             (1, "crypto_bignum_mulmod;sae_derive_k_ffc"),
1534             (2, "crypto_bignum_exptmod;sae_derive_k_ffc"),
1535             (1, "crypto_bignum_to_bin;sae_derive_k_ffc"),
1536             (1, "crypto_bignum_init_set;sae_parse_commit_element_ffc"),
1537             (1, "crypto_bignum_init;sae_parse_commit_element_ffc"),
1538             (2, "crypto_bignum_init_set;sae_parse_commit_element_ffc"),
1539             (1, "crypto_bignum_exptmod;sae_parse_commit_element_ffc")]
1540    for count, func in tests:
1541        with fail_test(dev[0], count, func):
1542            hapd.request("NOTE STA failure testing %d:%s" % (count, func))
1543            dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1544                           scan_freq="2412", wait_connect=False)
1545            wait_fail_trigger(dev[0], "GET_FAIL", timeout=0.1)
1546            dev[0].request("REMOVE_NETWORK all")
1547            dev[0].dump_monitor()
1548            hapd.dump_monitor()
1549
1550def test_sae_bignum_failure_unsafe_group(dev, apdev):
1551    """SAE and bignum failure unsafe group"""
1552    check_sae_capab(dev[0])
1553    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
1554    params['wpa_key_mgmt'] = 'SAE'
1555    params['sae_groups'] = '22'
1556    hapd = hostapd.add_ap(apdev[0], params)
1557
1558    dev[0].request("SET sae_groups 22")
1559    tests = [(1, "crypto_bignum_init_set;sae_test_pwd_seed_ffc"),
1560             (1, "crypto_bignum_sub;sae_test_pwd_seed_ffc"),
1561             (1, "crypto_bignum_div;sae_test_pwd_seed_ffc")]
1562    for count, func in tests:
1563        with fail_test(dev[0], count, func):
1564            hapd.request("NOTE STA failure testing %d:%s" % (count, func))
1565            dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1566                           scan_freq="2412", wait_connect=False)
1567            wait_fail_trigger(dev[0], "GET_FAIL")
1568            dev[0].request("REMOVE_NETWORK all")
1569            dev[0].dump_monitor()
1570            hapd.dump_monitor()
1571
1572def test_sae_invalid_anti_clogging_token_req(dev, apdev):
1573    """SAE and invalid anti-clogging token request"""
1574    check_sae_capab(dev[0])
1575    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
1576    params['wpa_key_mgmt'] = 'SAE'
1577    # Beacon more frequently since Probe Request frames are practically ignored
1578    # in this test setup (ext_mgmt_frame_handled=1 on hostapd side) and
1579    # wpa_supplicant scans may end up getting ignored if no new results are
1580    # available due to the missing Probe Response frames.
1581    params['beacon_int'] = '20'
1582    hapd = hostapd.add_ap(apdev[0], params)
1583    bssid = apdev[0]['bssid']
1584
1585    dev[0].request("SET sae_groups 19")
1586    dev[0].scan_for_bss(bssid, freq=2412)
1587    hapd.set("ext_mgmt_frame_handling", "1")
1588    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1589                   scan_freq="2412", wait_connect=False)
1590    ev = dev[0].wait_event(["SME: Trying to authenticate"])
1591    if ev is None:
1592        raise Exception("No authentication attempt seen (1)")
1593    dev[0].dump_monitor()
1594
1595    for i in range(0, 10):
1596        req = hapd.mgmt_rx()
1597        if req is None:
1598            raise Exception("MGMT RX wait timed out (commit)")
1599        if req['subtype'] == 11:
1600            break
1601        req = None
1602    if not req:
1603        raise Exception("Authentication frame (commit) not received")
1604
1605    hapd.dump_monitor()
1606    resp = {}
1607    resp['fc'] = req['fc']
1608    resp['da'] = req['sa']
1609    resp['sa'] = req['da']
1610    resp['bssid'] = req['bssid']
1611    resp['payload'] = binascii.unhexlify("030001004c0013")
1612    hapd.mgmt_tx(resp)
1613    ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
1614    if ev is None:
1615        raise Exception("Management frame TX status not reported (1)")
1616    if "stype=11 ok=1" not in ev:
1617        raise Exception("Unexpected management frame TX status (1): " + ev)
1618
1619    ev = dev[0].wait_event(["SME: Trying to authenticate"])
1620    if ev is None:
1621        raise Exception("No authentication attempt seen (2)")
1622    dev[0].dump_monitor()
1623
1624    for i in range(0, 10):
1625        req = hapd.mgmt_rx()
1626        if req is None:
1627            raise Exception("MGMT RX wait timed out (commit) (2)")
1628        if req['subtype'] == 11:
1629            break
1630        req = None
1631    if not req:
1632        raise Exception("Authentication frame (commit) not received (2)")
1633
1634    hapd.dump_monitor()
1635    resp = {}
1636    resp['fc'] = req['fc']
1637    resp['da'] = req['sa']
1638    resp['sa'] = req['da']
1639    resp['bssid'] = req['bssid']
1640    resp['payload'] = binascii.unhexlify("030001000100")
1641    hapd.mgmt_tx(resp)
1642    ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
1643    if ev is None:
1644        raise Exception("Management frame TX status not reported (1)")
1645    if "stype=11 ok=1" not in ev:
1646        raise Exception("Unexpected management frame TX status (1): " + ev)
1647
1648    ev = dev[0].wait_event(["SME: Trying to authenticate"])
1649    if ev is None:
1650        raise Exception("No authentication attempt seen (3)")
1651    dev[0].dump_monitor()
1652
1653    dev[0].request("DISCONNECT")
1654
1655def test_sae_password(dev, apdev):
1656    """SAE and sae_password in hostapd configuration"""
1657    check_sae_capab(dev[0])
1658    params = hostapd.wpa2_params(ssid="test-sae",
1659                                 passphrase="12345678")
1660    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
1661    params['sae_password'] = "sae-password"
1662    hapd = hostapd.add_ap(apdev[0], params)
1663
1664    dev[0].request("SET sae_groups ")
1665    dev[0].connect("test-sae", psk="sae-password", key_mgmt="SAE",
1666                   scan_freq="2412")
1667    dev[1].connect("test-sae", psk="12345678", scan_freq="2412")
1668    dev[2].request("SET sae_groups ")
1669    dev[2].connect("test-sae", sae_password="sae-password", key_mgmt="SAE",
1670                   scan_freq="2412")
1671
1672def test_sae_password_short(dev, apdev):
1673    """SAE and short password"""
1674    check_sae_capab(dev[0])
1675    params = hostapd.wpa2_params(ssid="test-sae")
1676    params['wpa_key_mgmt'] = 'SAE'
1677    params['sae_password'] = "secret"
1678    hapd = hostapd.add_ap(apdev[0], params)
1679
1680    dev[0].request("SET sae_groups ")
1681    dev[0].connect("test-sae", sae_password="secret", key_mgmt="SAE",
1682                   scan_freq="2412")
1683
1684def test_sae_password_long(dev, apdev):
1685    """SAE and long password"""
1686    check_sae_capab(dev[0])
1687    params = hostapd.wpa2_params(ssid="test-sae")
1688    params['wpa_key_mgmt'] = 'SAE'
1689    params['sae_password'] = 100*"A"
1690    hapd = hostapd.add_ap(apdev[0], params)
1691
1692    dev[0].request("SET sae_groups ")
1693    dev[0].connect("test-sae", sae_password=100*"A", key_mgmt="SAE",
1694                   scan_freq="2412")
1695
1696def test_sae_connect_cmd(dev, apdev):
1697    """SAE with connect command"""
1698    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
1699    wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
1700    check_sae_capab(wpas)
1701    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
1702    params['wpa_key_mgmt'] = 'SAE'
1703    hapd = hostapd.add_ap(apdev[0], params)
1704
1705    wpas.request("SET sae_groups ")
1706    wpas.connect("test-sae", psk="12345678", key_mgmt="SAE",
1707                 scan_freq="2412", wait_connect=False)
1708    # mac80211_hwsim does not support SAE offload, so accept both a successful
1709    # connection and association rejection.
1710    ev = wpas.wait_event(["CTRL-EVENT-CONNECTED", "CTRL-EVENT-ASSOC-REJECT",
1711                          "Association request to the driver failed"],
1712                         timeout=15)
1713    if ev is None:
1714        raise Exception("No connection result reported")
1715
1716def run_sae_password_id(dev, apdev, groups=None):
1717    check_sae_capab(dev[0])
1718    params = hostapd.wpa2_params(ssid="test-sae")
1719    params['wpa_key_mgmt'] = 'SAE'
1720    if groups:
1721        params['sae_groups'] = groups
1722    else:
1723        groups = ""
1724    params['sae_password'] = ['secret|mac=ff:ff:ff:ff:ff:ff|id=pw id',
1725                              'foo|mac=02:02:02:02:02:02',
1726                              'another secret|mac=ff:ff:ff:ff:ff:ff|id=' + 29*'A']
1727    hapd = hostapd.add_ap(apdev[0], params)
1728
1729    dev[0].request("SET sae_groups " + groups)
1730    dev[0].connect("test-sae", sae_password="secret", sae_password_id="pw id",
1731                   key_mgmt="SAE", scan_freq="2412")
1732    dev[0].request("REMOVE_NETWORK all")
1733    dev[0].wait_disconnected()
1734
1735    # SAE Password Identifier element with the exact same length as the
1736    # optional Anti-Clogging Token field
1737    dev[0].connect("test-sae", sae_password="another secret",
1738                   sae_password_id=29*'A',
1739                   key_mgmt="SAE", scan_freq="2412")
1740    dev[0].request("REMOVE_NETWORK all")
1741    dev[0].wait_disconnected()
1742
1743    dev[0].connect("test-sae", sae_password="secret", sae_password_id="unknown",
1744                   key_mgmt="SAE", scan_freq="2412", wait_connect=False)
1745
1746    ev = dev[0].wait_event(["CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER"],
1747                           timeout=10)
1748    if ev is None:
1749        raise Exception("Unknown password identifier not reported")
1750    dev[0].request("REMOVE_NETWORK all")
1751
1752def test_sae_password_id(dev, apdev):
1753    """SAE and password identifier"""
1754    run_sae_password_id(dev, apdev, "")
1755
1756def test_sae_password_id_ecc(dev, apdev):
1757    """SAE and password identifier (ECC)"""
1758    run_sae_password_id(dev, apdev, "19")
1759
1760def test_sae_password_id_ffc(dev, apdev):
1761    """SAE and password identifier (FFC)"""
1762    run_sae_password_id(dev, apdev, "15")
1763
1764def test_sae_password_id_only(dev, apdev):
1765    """SAE and password identifier (exclusively)"""
1766    check_sae_capab(dev[0])
1767    params = hostapd.wpa2_params(ssid="test-sae")
1768    params['wpa_key_mgmt'] = 'SAE'
1769    params['sae_password'] = 'secret|id=pw id'
1770    hapd = hostapd.add_ap(apdev[0], params)
1771
1772    dev[0].request("SET sae_groups ")
1773    dev[0].connect("test-sae", sae_password="secret", sae_password_id="pw id",
1774                   key_mgmt="SAE", scan_freq="2412")
1775
1776def test_sae_password_id_pwe_looping(dev, apdev):
1777    """SAE and password identifier with forced PWE looping"""
1778    check_sae_capab(dev[0])
1779    params = hostapd.wpa2_params(ssid="test-sae")
1780    params['wpa_key_mgmt'] = 'SAE'
1781    params['sae_password'] = 'secret|id=pw id'
1782    params['sae_pwe'] = "3"
1783    hapd = hostapd.add_ap(apdev[0], params)
1784
1785    dev[0].request("SET sae_groups ")
1786    try:
1787        dev[0].set("sae_pwe", "3")
1788        dev[0].connect("test-sae", sae_password="secret",
1789                       sae_password_id="pw id",
1790                       key_mgmt="SAE", scan_freq="2412")
1791    finally:
1792        dev[0].set("sae_pwe", "0")
1793
1794def test_sae_password_id_pwe_check_ap(dev, apdev):
1795    """SAE and password identifier with STA using unexpected PWE derivation"""
1796    check_sae_capab(dev[0])
1797    params = hostapd.wpa2_params(ssid="test-sae")
1798    params['wpa_key_mgmt'] = 'SAE'
1799    params['sae_password'] = 'secret|id=pw id'
1800    hapd = hostapd.add_ap(apdev[0], params)
1801
1802    dev[0].request("SET sae_groups ")
1803    try:
1804        dev[0].set("sae_pwe", "3")
1805        dev[0].connect("test-sae", sae_password="secret",
1806                       sae_password_id="pw id",
1807                       key_mgmt="SAE", scan_freq="2412", wait_connect=False)
1808        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
1809                                "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=10)
1810        if ev is None or "CTRL-EVENT-SSID-TEMP-DISABLED" not in ev:
1811            raise Exception("Connection failure not reported")
1812    finally:
1813        dev[0].set("sae_pwe", "0")
1814
1815def test_sae_password_id_pwe_check_sta(dev, apdev):
1816    """SAE and password identifier with AP using unexpected PWE derivation"""
1817    check_sae_capab(dev[0])
1818    params = hostapd.wpa2_params(ssid="test-sae")
1819    params['wpa_key_mgmt'] = 'SAE'
1820    params['sae_pwe'] = "3"
1821    params['sae_password'] = 'secret|id=pw id'
1822    hapd = hostapd.add_ap(apdev[0], params)
1823
1824    dev[0].request("SET sae_groups ")
1825    dev[0].connect("test-sae", sae_password="secret",
1826                   sae_password_id="pw id",
1827                   key_mgmt="SAE", scan_freq="2412", wait_connect=False)
1828    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
1829                            "CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
1830    if ev is None or "CTRL-EVENT-NETWORK-NOT-FOUND" not in ev:
1831        raise Exception("Connection failure not reported")
1832
1833def test_sae_forced_anti_clogging_pw_id(dev, apdev):
1834    """SAE anti clogging (forced and Password Identifier)"""
1835    check_sae_capab(dev[0])
1836    params = hostapd.wpa2_params(ssid="test-sae")
1837    params['wpa_key_mgmt'] = 'SAE'
1838    params['sae_anti_clogging_threshold'] = '0'
1839    params['sae_password'] = 'secret|id=' + 29*'A'
1840    hostapd.add_ap(apdev[0], params)
1841    for i in range(0, 2):
1842        dev[i].request("SET sae_groups ")
1843        dev[i].connect("test-sae", sae_password="secret",
1844                       sae_password_id=29*'A', key_mgmt="SAE", scan_freq="2412")
1845
1846def test_sae_reauth(dev, apdev):
1847    """SAE reauthentication"""
1848    check_sae_capab(dev[0])
1849    params = hostapd.wpa2_params(ssid="test-sae",
1850                                 passphrase="12345678")
1851    params['wpa_key_mgmt'] = 'SAE'
1852    params["ieee80211w"] = "2"
1853    hapd = hostapd.add_ap(apdev[0], params)
1854
1855    dev[0].request("SET sae_groups ")
1856    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1857                        ieee80211w="2", scan_freq="2412")
1858
1859    hapd.set("ext_mgmt_frame_handling", "1")
1860    dev[0].request("DISCONNECT")
1861    dev[0].wait_disconnected(timeout=10)
1862    hapd.set("ext_mgmt_frame_handling", "0")
1863    dev[0].request("PMKSA_FLUSH")
1864    dev[0].request("REASSOCIATE")
1865    dev[0].wait_connected(timeout=10, error="Timeout on re-connection")
1866
1867def test_sae_anti_clogging_during_attack(dev, apdev):
1868    """SAE anti clogging during an attack"""
1869    try:
1870        run_sae_anti_clogging_during_attack(dev, apdev)
1871    finally:
1872        stop_monitor(apdev[1]["ifname"])
1873
1874def build_sae_commit(bssid, addr, group=21, token=None):
1875    if group == 19:
1876        scalar = binascii.unhexlify("7332d3ebff24804005ccd8c56141e3ed8d84f40638aa31cd2fac11d4d2e89e7b")
1877        element = binascii.unhexlify("954d0f4457066bff3168376a1d7174f4e66620d1792406f613055b98513a7f03a538c13dfbaf2029e2adc6aa96aa0ddcf08ac44887b02f004b7f29b9dbf4b7d9")
1878    elif group == 21:
1879        scalar = binascii.unhexlify("001eec673111b902f5c8a61c8cb4c1c4793031aeea8c8c319410903bc64bcbaea134ab01c4e016d51436f5b5426f7e2af635759a3033fb4031ea79f89a62a3e2f828")
1880        element = binascii.unhexlify("00580eb4b448ea600ea277d5e66e4ed37db82bb04ac90442e9c3727489f366ba4b82f0a472d02caf4cdd142e96baea5915d71374660ee23acbaca38cf3fe8c5fb94b01abbc5278121635d7c06911c5dad8f18d516e1fbe296c179b7c87a1dddfab393337d3d215ed333dd396da6d8f20f798c60d054f1093c24d9c2d98e15c030cc375f0")
1881        pass
1882    frame = binascii.unhexlify("b0003a01")
1883    frame += bssid + addr + bssid
1884    frame += binascii.unhexlify("1000")
1885    auth_alg = 3
1886    transact = 1
1887    status = 0
1888    frame += struct.pack("<HHHH", auth_alg, transact, status, group)
1889    if token:
1890        frame += token
1891    frame += scalar + element
1892    return frame
1893
1894def sae_rx_commit_token_req(sock, radiotap, send_two=False):
1895    msg = sock.recv(1500)
1896    ver, pad, length, present = struct.unpack('<BBHL', msg[0:8])
1897    frame = msg[length:]
1898    if len(frame) < 4:
1899        return False
1900    fc, duration = struct.unpack('<HH', frame[0:4])
1901    if fc != 0xb0:
1902        return False
1903    frame = frame[4:]
1904    da = frame[0:6]
1905    if da[0] != 0xf2:
1906        return False
1907    sa = frame[6:12]
1908    bssid = frame[12:18]
1909    body = frame[20:]
1910
1911    alg, seq, status, group = struct.unpack('<HHHH', body[0:8])
1912    if alg != 3 or seq != 1 or status != 76:
1913        return False
1914    token = body[8:]
1915
1916    frame = build_sae_commit(bssid, da, token=token)
1917    sock.send(radiotap + frame)
1918    if send_two:
1919        sock.send(radiotap + frame)
1920    return True
1921
1922def run_sae_anti_clogging_during_attack(dev, apdev):
1923    check_sae_capab(dev[0])
1924    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
1925    params['wpa_key_mgmt'] = 'SAE'
1926    params['sae_groups'] = '21'
1927    hapd = hostapd.add_ap(apdev[0], params)
1928
1929    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1930    dev[0].request("SET sae_groups 21")
1931    dev[1].scan_for_bss(hapd.own_addr(), freq=2412)
1932    dev[1].request("SET sae_groups 21")
1933
1934    sock = start_monitor(apdev[1]["ifname"])
1935    radiotap = radiotap_build()
1936
1937    bssid = binascii.unhexlify(hapd.own_addr().replace(':', ''))
1938    for i in range(16):
1939        addr = binascii.unhexlify("f2%010x" % i)
1940        frame = build_sae_commit(bssid, addr)
1941        sock.send(radiotap + frame)
1942        sock.send(radiotap + frame)
1943
1944    count = 0
1945    for i in range(150):
1946        if sae_rx_commit_token_req(sock, radiotap, send_two=True):
1947            count += 1
1948    logger.info("Number of token responses sent: %d" % count)
1949    if count < 10:
1950        raise Exception("Too few token responses seen: %d" % count)
1951
1952    for i in range(16):
1953        addr = binascii.unhexlify("f201%08x" % i)
1954        frame = build_sae_commit(bssid, addr)
1955        sock.send(radiotap + frame)
1956
1957    count = 0
1958    for i in range(150):
1959        if sae_rx_commit_token_req(sock, radiotap):
1960            count += 1
1961            if count == 10:
1962                break
1963    if count < 5:
1964        raise Exception("Too few token responses in second round: %d" % count)
1965
1966    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
1967                   scan_freq="2412", wait_connect=False)
1968    dev[1].connect("test-sae", psk="12345678", key_mgmt="SAE",
1969                   scan_freq="2412", wait_connect=False)
1970
1971    count = 0
1972    connected0 = False
1973    connected1 = False
1974    for i in range(1000):
1975        if sae_rx_commit_token_req(sock, radiotap):
1976            count += 1
1977            addr = binascii.unhexlify("f202%08x" % i)
1978            frame = build_sae_commit(bssid, addr)
1979            sock.send(radiotap + frame)
1980        while dev[0].mon.pending():
1981            ev = dev[0].mon.recv()
1982            logger.debug("EV0: " + ev)
1983            if "CTRL-EVENT-CONNECTED" in ev:
1984                connected0 = True
1985        while dev[1].mon.pending():
1986            ev = dev[1].mon.recv()
1987            logger.debug("EV1: " + ev)
1988            if "CTRL-EVENT-CONNECTED" in ev:
1989                connected1 = True
1990        if connected0 and connected1:
1991            break
1992        time.sleep(0.00000001)
1993    if not connected0:
1994        raise Exception("Real station(0) did not get connected")
1995    if not connected1:
1996        raise Exception("Real station(1) did not get connected")
1997    if count < 1:
1998        raise Exception("Too few token responses in third round: %d" % count)
1999
2000def test_sae_sync(dev, apdev):
2001    """SAE dot11RSNASAESync"""
2002    check_sae_capab(dev[0])
2003    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2004    params['wpa_key_mgmt'] = 'SAE'
2005    params['sae_sync'] = '1'
2006    hostapd.add_ap(apdev[0], params)
2007
2008    # TODO: More complete dot11RSNASAESync testing. For now, this is really only
2009    # checking that sae_sync config parameter is accepted.
2010    dev[0].request("SET sae_groups ")
2011    dev[1].request("SET sae_groups ")
2012    id = {}
2013    for i in range(0, 2):
2014        dev[i].scan(freq="2412")
2015        id[i] = dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
2016                               scan_freq="2412", only_add_network=True)
2017    for i in range(0, 2):
2018        dev[i].select_network(id[i])
2019    for i in range(0, 2):
2020        dev[i].wait_connected(timeout=10)
2021
2022def test_sae_confirm_immediate(dev, apdev):
2023    """SAE and AP sending Confirm message without waiting STA"""
2024    check_sae_capab(dev[0])
2025    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2026    params['wpa_key_mgmt'] = 'SAE'
2027    params['sae_confirm_immediate'] = '1'
2028    hapd = hostapd.add_ap(apdev[0], params)
2029
2030    dev[0].request("SET sae_groups ")
2031    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412")
2032
2033def test_sae_confirm_immediate2(dev, apdev):
2034    """SAE and AP sending Confirm message without waiting STA (2)"""
2035    check_sae_capab(dev[0])
2036    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2037    params['wpa_key_mgmt'] = 'SAE'
2038    params['sae_confirm_immediate'] = '2'
2039    hapd = hostapd.add_ap(apdev[0], params)
2040
2041    dev[0].request("SET sae_groups ")
2042    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412")
2043
2044def test_sae_pwe_group_19(dev, apdev):
2045    """SAE PWE derivation options with group 19"""
2046    run_sae_pwe_group(dev, apdev, 19)
2047
2048def test_sae_pwe_group_20(dev, apdev):
2049    """SAE PWE derivation options with group 20"""
2050    run_sae_pwe_group(dev, apdev, 20)
2051
2052def test_sae_pwe_group_21(dev, apdev):
2053    """SAE PWE derivation options with group 21"""
2054    run_sae_pwe_group(dev, apdev, 21)
2055
2056def test_sae_pwe_group_25(dev, apdev):
2057    """SAE PWE derivation options with group 25"""
2058    run_sae_pwe_group(dev, apdev, 25)
2059
2060def test_sae_pwe_group_28(dev, apdev):
2061    """SAE PWE derivation options with group 28"""
2062    run_sae_pwe_group(dev, apdev, 28)
2063
2064def test_sae_pwe_group_29(dev, apdev):
2065    """SAE PWE derivation options with group 29"""
2066    run_sae_pwe_group(dev, apdev, 29)
2067
2068def test_sae_pwe_group_30(dev, apdev):
2069    """SAE PWE derivation options with group 30"""
2070    run_sae_pwe_group(dev, apdev, 30)
2071
2072def test_sae_pwe_group_1(dev, apdev):
2073    """SAE PWE derivation options with group 1"""
2074    run_sae_pwe_group(dev, apdev, 1)
2075
2076def test_sae_pwe_group_2(dev, apdev):
2077    """SAE PWE derivation options with group 2"""
2078    run_sae_pwe_group(dev, apdev, 2)
2079
2080def test_sae_pwe_group_5(dev, apdev):
2081    """SAE PWE derivation options with group 5"""
2082    run_sae_pwe_group(dev, apdev, 5)
2083
2084def test_sae_pwe_group_14(dev, apdev):
2085    """SAE PWE derivation options with group 14"""
2086    run_sae_pwe_group(dev, apdev, 14)
2087
2088def test_sae_pwe_group_15(dev, apdev):
2089    """SAE PWE derivation options with group 15"""
2090    run_sae_pwe_group(dev, apdev, 15)
2091
2092def test_sae_pwe_group_16(dev, apdev):
2093    """SAE PWE derivation options with group 16"""
2094    run_sae_pwe_group(dev, apdev, 16)
2095
2096def test_sae_pwe_group_22(dev, apdev):
2097    """SAE PWE derivation options with group 22"""
2098    run_sae_pwe_group(dev, apdev, 22)
2099
2100def test_sae_pwe_group_23(dev, apdev):
2101    """SAE PWE derivation options with group 23"""
2102    run_sae_pwe_group(dev, apdev, 23)
2103
2104def test_sae_pwe_group_24(dev, apdev):
2105    """SAE PWE derivation options with group 24"""
2106    run_sae_pwe_group(dev, apdev, 24)
2107
2108def start_sae_pwe_ap(apdev, group, sae_pwe):
2109    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2110    params['wpa_key_mgmt'] = 'SAE'
2111    params['sae_groups'] = str(group)
2112    params['sae_pwe'] = str(sae_pwe)
2113    return hostapd.add_ap(apdev, params)
2114
2115def run_sae_pwe_group(dev, apdev, group):
2116    check_sae_capab(dev[0])
2117    tls = dev[0].request("GET tls_library")
2118    if group in [27, 28, 29, 30]:
2119        if tls.startswith("OpenSSL") and "run=OpenSSL 1." in tls:
2120            logger.info("Add Brainpool EC groups since OpenSSL is new enough")
2121        else:
2122            raise HwsimSkip("Brainpool curve not supported")
2123    start_sae_pwe_ap(apdev[0], group, 2)
2124    try:
2125        check_sae_pwe_group(dev[0], group, 0)
2126        check_sae_pwe_group(dev[0], group, 1)
2127        check_sae_pwe_group(dev[0], group, 2)
2128    finally:
2129        dev[0].set("sae_groups", "")
2130        dev[0].set("sae_pwe", "0")
2131
2132def check_sae_pwe_group(dev, group, sae_pwe):
2133    dev.set("sae_groups", str(group))
2134    dev.set("sae_pwe", str(sae_pwe))
2135    dev.connect("sae-pwe", psk="12345678", key_mgmt="SAE", scan_freq="2412")
2136    dev.request("REMOVE_NETWORK all")
2137    dev.wait_disconnected()
2138    dev.dump_monitor()
2139
2140def test_sae_pwe_h2e_only_ap(dev, apdev):
2141    """SAE PWE derivation with H2E-only AP"""
2142    check_sae_capab(dev[0])
2143    start_sae_pwe_ap(apdev[0], 19, 1)
2144    try:
2145        check_sae_pwe_group(dev[0], 19, 1)
2146        check_sae_pwe_group(dev[0], 19, 2)
2147    finally:
2148        dev[0].set("sae_groups", "")
2149        dev[0].set("sae_pwe", "0")
2150
2151    dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE", scan_freq="2412",
2152                   wait_connect=False)
2153    ev = dev[0].wait_event(["CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
2154    if ev is None:
2155        raise Exception("No indication of mismatching network seen")
2156
2157def test_sae_pwe_h2e_only_ap_sta_forcing_loop(dev, apdev):
2158    """SAE PWE derivation with H2E-only AP and STA forcing loop"""
2159    check_sae_capab(dev[0])
2160    start_sae_pwe_ap(apdev[0], 19, 1)
2161    dev[0].set("ignore_sae_h2e_only", "1")
2162    dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE", scan_freq="2412",
2163                   wait_connect=False)
2164    ev = dev[0].wait_event(["CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=10)
2165    dev[0].request("DISCONNECT")
2166    if ev is None:
2167        raise Exception("No indication of temporary disabled network seen")
2168
2169def test_sae_pwe_loop_only_ap(dev, apdev):
2170    """SAE PWE derivation with loop-only AP"""
2171    check_sae_capab(dev[0])
2172    start_sae_pwe_ap(apdev[0], 19, 0)
2173    try:
2174        check_sae_pwe_group(dev[0], 19, 0)
2175        check_sae_pwe_group(dev[0], 19, 2)
2176        dev[0].set("sae_pwe", "1")
2177        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2178                       scan_freq="2412", wait_connect=False)
2179        ev = dev[0].wait_event(["CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
2180        if ev is None:
2181            raise Exception("No indication of mismatching network seen")
2182    finally:
2183        dev[0].set("sae_groups", "")
2184        dev[0].set("sae_pwe", "0")
2185
2186def test_sae_h2e_rejected_groups(dev, apdev):
2187    """SAE H2E and rejected groups indication"""
2188    check_sae_capab(dev[0])
2189    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2190    params['wpa_key_mgmt'] = 'SAE'
2191    params['sae_groups'] = "19"
2192    params['sae_pwe'] = "1"
2193    hapd = hostapd.add_ap(apdev[0], params)
2194    try:
2195        dev[0].set("sae_groups", "21 20 19")
2196        dev[0].set("sae_pwe", "1")
2197        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2198                       scan_freq="2412")
2199        addr = dev[0].own_addr()
2200        hapd.wait_sta(addr)
2201        sta = hapd.get_sta(addr)
2202        if 'sae_rejected_groups' not in sta:
2203            raise Exception("No sae_rejected_groups")
2204        val = sta['sae_rejected_groups']
2205        if val != "21 20":
2206            raise Exception("Unexpected sae_rejected_groups value: " + val)
2207    finally:
2208        dev[0].set("sae_groups", "")
2209        dev[0].set("sae_pwe", "0")
2210
2211def test_sae_h2e_rejected_groups_unexpected(dev, apdev):
2212    """SAE H2E and rejected groups indication (unexpected group)"""
2213    check_sae_capab(dev[0])
2214    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2215    params['wpa_key_mgmt'] = 'SAE'
2216    params['sae_groups'] = "19 20"
2217    params['sae_pwe'] = "1"
2218    hapd = hostapd.add_ap(apdev[0], params)
2219    try:
2220        dev[0].set("sae_groups", "21 19")
2221        dev[0].set("extra_sae_rejected_groups", "19")
2222        dev[0].set("sae_pwe", "1")
2223        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2224                       scan_freq="2412", wait_connect=False)
2225        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2226                                "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=10)
2227        dev[0].request("DISCONNECT")
2228        if ev is None:
2229            raise Exception("No indication of temporary disabled network seen")
2230        if "CTRL-EVENT-CONNECTED" in ev:
2231            raise Exception("Unexpected connection")
2232    finally:
2233        dev[0].set("sae_groups", "")
2234        dev[0].set("sae_pwe", "0")
2235
2236def test_sae_h2e_password_id(dev, apdev):
2237    """SAE H2E and password identifier"""
2238    check_sae_capab(dev[0])
2239    params = hostapd.wpa2_params(ssid="test-sae")
2240    params['wpa_key_mgmt'] = 'SAE'
2241    params['sae_pwe'] = '1'
2242    params['sae_password'] = 'secret|id=pw id'
2243    hapd = hostapd.add_ap(apdev[0], params)
2244
2245    try:
2246        dev[0].request("SET sae_groups ")
2247        dev[0].set("sae_pwe", "1")
2248        dev[0].connect("test-sae", sae_password="secret",
2249                       sae_password_id="pw id",
2250                       key_mgmt="SAE", scan_freq="2412")
2251    finally:
2252        dev[0].set("sae_groups", "")
2253        dev[0].set("sae_pwe", "0")
2254
2255def test_sae_pwe_in_psk_ap(dev, apdev):
2256    """sae_pwe parameter in PSK-only-AP"""
2257    params = hostapd.wpa2_params(ssid="test-psk", passphrase="12345678")
2258    params['sae_pwe'] = '1'
2259    hapd = hostapd.add_ap(apdev[0], params)
2260
2261    dev[0].connect("test-psk", psk="12345678", scan_freq="2412")
2262
2263def test_sae_auth_restart(dev, apdev):
2264    """SAE and authentication restarts with H2E/looping"""
2265    check_sae_capab(dev[0])
2266    params = hostapd.wpa2_params(ssid="test-sae")
2267    params['wpa_key_mgmt'] = 'SAE'
2268    params['sae_pwe'] = '2'
2269    params['sae_password'] = 'secret|id=pw id'
2270    hapd = hostapd.add_ap(apdev[0], params)
2271
2272    try:
2273        dev[0].request("SET sae_groups ")
2274        for pwe in [1, 0, 1]:
2275            dev[0].set("sae_pwe", str(pwe))
2276            dev[0].connect("test-sae", sae_password="secret",
2277                           sae_password_id="pw id",
2278                           key_mgmt="SAE", scan_freq="2412")
2279            # Disconnect without hostapd removing the STA entry so that the
2280            # following SAE authentication instance starts with an existing
2281            # STA entry that has maintained some SAE state.
2282            hapd.set("ext_mgmt_frame_handling", "1")
2283            dev[0].request("REMOVE_NETWORK all")
2284            req = hapd.mgmt_rx()
2285            dev[0].wait_disconnected()
2286            dev[0].dump_monitor()
2287            hapd.set("ext_mgmt_frame_handling", "0")
2288    finally:
2289        dev[0].set("sae_groups", "")
2290        dev[0].set("sae_pwe", "0")
2291
2292def test_sae_rsne_mismatch(dev, apdev):
2293    """SAE and RSNE mismatch in EAPOL-Key msg 2/4"""
2294    check_sae_capab(dev[0])
2295    dev[0].set("sae_groups", "")
2296
2297    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2298    params['wpa_key_mgmt'] = 'SAE'
2299    hapd = hostapd.add_ap(apdev[0], params)
2300
2301    # First, test with matching RSNE to confirm testing capability
2302    dev[0].set("rsne_override_eapol",
2303               "30140100000fac040100000fac040100000fac080000")
2304    dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2305                   scan_freq="2412")
2306    dev[0].request("REMOVE_NETWORK all")
2307    dev[0].wait_disconnected()
2308    dev[0].dump_monitor()
2309
2310    # Then, test with modified RSNE
2311    tests = ["30140100000fac040100000fac040100000fac080010", "0000"]
2312    for ie in tests:
2313        dev[0].set("rsne_override_eapol", ie)
2314        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2315                       scan_freq="2412", wait_connect=False)
2316        ev = dev[0].wait_event(["Associated with"], timeout=10)
2317        if ev is None:
2318            raise Exception("No indication of association seen")
2319        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2320                                "CTRL-EVENT-DISCONNECTED"], timeout=5)
2321        dev[0].request("REMOVE_NETWORK all")
2322        if ev is None:
2323            raise Exception("No disconnection seen")
2324        if "CTRL-EVENT-DISCONNECTED" not in ev:
2325            raise Exception("Unexpected connection")
2326        dev[0].dump_monitor()
2327
2328def test_sae_h2e_rsnxe_mismatch(dev, apdev):
2329    """SAE H2E and RSNXE mismatch in EAPOL-Key msg 2/4"""
2330    check_sae_capab(dev[0])
2331    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2332    params['wpa_key_mgmt'] = 'SAE'
2333    params['sae_pwe'] = "1"
2334    hapd = hostapd.add_ap(apdev[0], params)
2335    try:
2336        dev[0].set("sae_groups", "19")
2337        dev[0].set("sae_pwe", "1")
2338        for rsnxe in ["F40100", "F400", ""]:
2339            dev[0].set("rsnxe_override_eapol", rsnxe)
2340            dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2341                           scan_freq="2412", wait_connect=False)
2342            ev = dev[0].wait_event(["Associated with"], timeout=10)
2343            if ev is None:
2344                raise Exception("No indication of association seen")
2345            ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2346                                    "CTRL-EVENT-DISCONNECTED"], timeout=5)
2347            dev[0].request("REMOVE_NETWORK all")
2348            if ev is None:
2349                raise Exception("No disconnection seen")
2350            if "CTRL-EVENT-DISCONNECTED" not in ev:
2351                raise Exception("Unexpected connection")
2352            dev[0].dump_monitor()
2353    finally:
2354        dev[0].set("sae_groups", "")
2355        dev[0].set("sae_pwe", "0")
2356
2357def test_sae_h2e_rsnxe_mismatch_retries(dev, apdev):
2358    """SAE H2E and RSNXE mismatch in EAPOL-Key msg 2/4 retries"""
2359    check_sae_capab(dev[0])
2360    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2361    params['wpa_key_mgmt'] = 'SAE'
2362    params['sae_pwe'] = "1"
2363    hapd = hostapd.add_ap(apdev[0], params)
2364    try:
2365        dev[0].set("sae_groups", "19")
2366        dev[0].set("sae_pwe", "1")
2367        rsnxe = "F40100"
2368        dev[0].set("rsnxe_override_eapol", rsnxe)
2369        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2370                       scan_freq="2412", wait_connect=False)
2371        ev = dev[0].wait_event(["Associated with"], timeout=10)
2372        if ev is None:
2373            raise Exception("No indication of association seen")
2374        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2375                                "CTRL-EVENT-DISCONNECTED"], timeout=5)
2376        if ev is None:
2377            raise Exception("No disconnection seen")
2378        if "CTRL-EVENT-DISCONNECTED" not in ev:
2379            raise Exception("Unexpected connection")
2380
2381        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2382                                "CTRL-EVENT-DISCONNECTED"], timeout=10)
2383        if ev is None:
2384            raise Exception("No disconnection seen (2)")
2385        if "CTRL-EVENT-DISCONNECTED" not in ev:
2386            raise Exception("Unexpected connection (2)")
2387
2388        dev[0].dump_monitor()
2389    finally:
2390        dev[0].set("sae_groups", "")
2391        dev[0].set("sae_pwe", "0")
2392
2393def test_sae_h2e_rsnxe_mismatch_assoc(dev, apdev):
2394    """SAE H2E and RSNXE mismatch in EAPOL-Key msg 2/4 (assoc)"""
2395    check_sae_capab(dev[0])
2396    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2397    params['wpa_key_mgmt'] = 'SAE'
2398    params['sae_pwe'] = "1"
2399    hapd = hostapd.add_ap(apdev[0], params)
2400    try:
2401        dev[0].set("sae_groups", "19")
2402        dev[0].set("sae_pwe", "1")
2403        for rsnxe in ["F40100", "F400", ""]:
2404            dev[0].set("rsnxe_override_assoc", rsnxe)
2405            dev[0].set("rsnxe_override_eapol", "F40120")
2406            dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2407                           scan_freq="2412", wait_connect=False)
2408            ev = dev[0].wait_event(["Associated with"], timeout=10)
2409            if ev is None:
2410                raise Exception("No indication of association seen")
2411            ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2412                                    "CTRL-EVENT-DISCONNECTED"], timeout=5)
2413            dev[0].request("REMOVE_NETWORK all")
2414            if ev is None:
2415                raise Exception("No disconnection seen")
2416            if "CTRL-EVENT-DISCONNECTED" not in ev:
2417                raise Exception("Unexpected connection")
2418            dev[0].dump_monitor()
2419    finally:
2420        dev[0].set("sae_groups", "")
2421        dev[0].set("sae_pwe", "0")
2422
2423def test_sae_h2e_rsnxe_mismatch_ap(dev, apdev):
2424    """SAE H2E and RSNXE mismatch in EAPOL-Key msg 3/4"""
2425    run_sae_h2e_rsnxe_mismatch_ap(dev, apdev, "F40100")
2426
2427def test_sae_h2e_rsnxe_mismatch_ap2(dev, apdev):
2428    """SAE H2E and RSNXE mismatch in EAPOL-Key msg 3/4"""
2429    run_sae_h2e_rsnxe_mismatch_ap(dev, apdev, "F400")
2430
2431def test_sae_h2e_rsnxe_mismatch_ap3(dev, apdev):
2432    """SAE H2E and RSNXE mismatch in EAPOL-Key msg 3/4"""
2433    run_sae_h2e_rsnxe_mismatch_ap(dev, apdev, "")
2434
2435def run_sae_h2e_rsnxe_mismatch_ap(dev, apdev, rsnxe):
2436    check_sae_capab(dev[0])
2437    params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
2438    params['wpa_key_mgmt'] = 'SAE'
2439    params['sae_pwe'] = "1"
2440    params['rsnxe_override_eapol'] = rsnxe
2441    hapd = hostapd.add_ap(apdev[0], params)
2442    try:
2443        dev[0].set("sae_groups", "19")
2444        dev[0].set("sae_pwe", "1")
2445        dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
2446                       scan_freq="2412", wait_connect=False)
2447        ev = dev[0].wait_event(["Associated with"], timeout=10)
2448        if ev is None:
2449            raise Exception("No indication of association seen")
2450        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2451                                "CTRL-EVENT-DISCONNECTED"], timeout=5)
2452        dev[0].request("REMOVE_NETWORK all")
2453        if ev is None:
2454            raise Exception("No disconnection seen")
2455        if "CTRL-EVENT-DISCONNECTED" not in ev:
2456            raise Exception("Unexpected connection")
2457    finally:
2458        dev[0].set("sae_groups", "")
2459        dev[0].set("sae_pwe", "0")
2460
2461def test_sae_forced_anti_clogging_h2e(dev, apdev):
2462    """SAE anti clogging (forced, H2E)"""
2463    check_sae_capab(dev[0])
2464    check_sae_capab(dev[1])
2465    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2466    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
2467    params['sae_pwe'] = "1"
2468    params['sae_anti_clogging_threshold'] = '0'
2469    hostapd.add_ap(apdev[0], params)
2470    dev[2].connect("test-sae", psk="12345678", scan_freq="2412")
2471    try:
2472        for i in range(2):
2473            dev[i].request("SET sae_groups ")
2474            dev[i].set("sae_pwe", "1")
2475            dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
2476                           scan_freq="2412")
2477    finally:
2478        for i in range(2):
2479            dev[i].set("sae_pwe", "0")
2480
2481def test_sae_forced_anti_clogging_h2e_loop(dev, apdev):
2482    """SAE anti clogging (forced, H2E + loop)"""
2483    check_sae_capab(dev[0])
2484    check_sae_capab(dev[1])
2485    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2486    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
2487    params['sae_pwe'] = "2"
2488    params['sae_anti_clogging_threshold'] = '0'
2489    hostapd.add_ap(apdev[0], params)
2490    dev[2].connect("test-sae", psk="12345678", scan_freq="2412")
2491    try:
2492        for i in range(2):
2493            dev[i].request("SET sae_groups ")
2494            dev[i].set("sae_pwe", "2")
2495            dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
2496                           scan_freq="2412")
2497    finally:
2498        for i in range(2):
2499            dev[i].set("sae_pwe", "0")
2500
2501def test_sae_okc(dev, apdev):
2502    """SAE and opportunistic key caching"""
2503    check_sae_capab(dev[0])
2504    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2505    params['wpa_key_mgmt'] = 'SAE'
2506    params['okc'] = '1'
2507    hapd = hostapd.add_ap(apdev[0], params)
2508    bssid = hapd.own_addr()
2509
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].set("sae_groups", "")
2543    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
2544                        okc=True, scan_freq="2412")
2545    dev[0].dump_monitor()
2546    hapd.wait_sta()
2547    if "sae_group" not in dev[0].get_status():
2548        raise Exception("SAE authentication not used")
2549
2550    hapd2 = hostapd.add_ap(apdev[1], params)
2551    bssid2 = hapd2.own_addr()
2552
2553    dev[0].scan_for_bss(bssid2, freq=2412)
2554    dev[0].roam(bssid2, assoc_reject_ok=True)
2555    dev[0].dump_monitor()
2556    hapd2.wait_sta()
2557    if "sae_group" not in dev[0].get_status():
2558        raise Exception("SAE authentication not used during roam to AP2")
2559
2560def test_sae_okc_pmk_lifetime(dev, apdev):
2561    """SAE and opportunistic key caching and PMK lifetime"""
2562    check_sae_capab(dev[0])
2563    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2564    params['wpa_key_mgmt'] = 'SAE'
2565    params['okc'] = '1'
2566    hapd = hostapd.add_ap(apdev[0], params)
2567    bssid = hapd.own_addr()
2568
2569    dev[0].set("sae_groups", "")
2570    dev[0].set("dot11RSNAConfigPMKLifetime", "10")
2571    dev[0].set("dot11RSNAConfigPMKReauthThreshold", "30")
2572    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
2573                        okc=True, scan_freq="2412")
2574    dev[0].dump_monitor()
2575    hapd.wait_sta()
2576    if "sae_group" not in dev[0].get_status():
2577        raise Exception("SAE authentication not used")
2578
2579    hapd2 = hostapd.add_ap(apdev[1], params)
2580    bssid2 = hapd2.own_addr()
2581
2582    time.sleep(5)
2583    dev[0].scan_for_bss(bssid2, freq=2412)
2584    dev[0].roam(bssid2)
2585    dev[0].dump_monitor()
2586    hapd2.wait_sta()
2587    if "sae_group" not in dev[0].get_status():
2588        raise Exception("SAE authentication not used during roam to AP2 after reauth threshold")
2589
2590def test_sae_pmk_lifetime(dev, apdev):
2591    """SAE and PMK lifetime"""
2592    check_sae_capab(dev[0])
2593    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2594    params['wpa_key_mgmt'] = 'SAE'
2595    hapd = hostapd.add_ap(apdev[0], params)
2596    bssid = hapd.own_addr()
2597
2598    dev[0].set("sae_groups", "")
2599    dev[0].set("dot11RSNAConfigPMKLifetime", "10")
2600    dev[0].set("dot11RSNAConfigPMKReauthThreshold", "50")
2601    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
2602                        scan_freq="2412")
2603    dev[0].dump_monitor()
2604    hapd.wait_sta()
2605    if "sae_group" not in dev[0].get_status():
2606        raise Exception("SAE authentication not used")
2607
2608    hapd2 = hostapd.add_ap(apdev[1], params)
2609    bssid2 = hapd2.own_addr()
2610
2611    dev[0].scan_for_bss(bssid2, freq=2412)
2612    dev[0].roam(bssid2)
2613    dev[0].dump_monitor()
2614    hapd2.wait_sta()
2615    if "sae_group" not in dev[0].get_status():
2616        raise Exception("SAE authentication not used during roam to AP2")
2617
2618    dev[0].roam(bssid)
2619    dev[0].dump_monitor()
2620    hapd.wait_sta()
2621    if "sae_group" in dev[0].get_status():
2622        raise Exception("SAE authentication used during roam to AP1")
2623
2624    time.sleep(6)
2625    dev[0].scan_for_bss(bssid2, freq=2412)
2626    dev[0].roam(bssid2)
2627    dev[0].dump_monitor()
2628    hapd2.wait_sta()
2629    if "sae_group" not in dev[0].get_status():
2630        raise Exception("SAE authentication not used during roam to AP2 after reauth threshold")
2631
2632    ev = dev[0].wait_event(["PMKSA-CACHE-REMOVED"], 11)
2633    if ev is None:
2634        raise Exception("PMKSA cache entry did not expire")
2635    if bssid2 in ev:
2636        raise Exception("Unexpected expiration of the current SAE PMKSA cache entry")
2637
2638def test_sae_and_psk_multiple_passwords(dev, apdev, params):
2639    """SAE and PSK with multiple passwords/passphrases"""
2640    check_sae_capab(dev[0])
2641    check_sae_capab(dev[1])
2642    addr0 = dev[0].own_addr()
2643    addr1 = dev[1].own_addr()
2644    psk_file = os.path.join(params['logdir'],
2645                            'sae_and_psk_multiple_passwords.wpa_psk')
2646    with open(psk_file, 'w') as f:
2647        f.write(addr0 + ' passphrase0\n')
2648        f.write(addr1 + ' passphrase1\n')
2649    params = hostapd.wpa2_params(ssid="test-sae")
2650    params['wpa_key_mgmt'] = 'SAE WPA-PSK'
2651    params['sae_password'] = ['passphrase0|mac=' + addr0,
2652                              'passphrase1|mac=' + addr1]
2653    params['wpa_psk_file'] = psk_file
2654    hapd = hostapd.add_ap(apdev[0], params)
2655
2656    dev[0].set("sae_groups", "")
2657    dev[0].connect("test-sae", sae_password="passphrase0",
2658                   key_mgmt="SAE", scan_freq="2412")
2659    dev[0].request("REMOVE_NETWORK all")
2660    dev[0].wait_disconnected()
2661
2662    dev[0].connect("test-sae", psk="passphrase0", scan_freq="2412")
2663    dev[0].request("REMOVE_NETWORK all")
2664    dev[0].wait_disconnected()
2665
2666    dev[1].set("sae_groups", "")
2667    dev[1].connect("test-sae", sae_password="passphrase1",
2668                   key_mgmt="SAE", scan_freq="2412")
2669    dev[1].request("REMOVE_NETWORK all")
2670    dev[1].wait_disconnected()
2671
2672    dev[1].connect("test-sae", psk="passphrase1", scan_freq="2412")
2673    dev[1].request("REMOVE_NETWORK all")
2674    dev[1].wait_disconnected()
2675
2676def test_sae_pmf_roam(dev, apdev):
2677    """SAE/PMF roam"""
2678    check_sae_capab(dev[0])
2679    params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
2680    params['wpa_key_mgmt'] = 'SAE'
2681    params['ieee80211w'] = '2'
2682    params['skip_prune_assoc'] = '1'
2683    hapd = hostapd.add_ap(apdev[0], params)
2684    bssid = hapd.own_addr()
2685
2686    dev[0].set("sae_groups", "")
2687    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
2688                        ieee80211w="2", scan_freq="2412")
2689    dev[0].dump_monitor()
2690    hapd.wait_sta()
2691
2692    hapd2 = hostapd.add_ap(apdev[1], params)
2693    bssid2 = hapd2.own_addr()
2694
2695    dev[0].scan_for_bss(bssid2, freq=2412)
2696    dev[0].roam(bssid2)
2697    dev[0].dump_monitor()
2698    hapd2.wait_sta()
2699
2700    dev[0].roam(bssid)
2701    dev[0].dump_monitor()
2702
2703def test_sae_ocv_pmk(dev, apdev):
2704    """SAE with OCV and fetching PMK (successful 4-way handshake)"""
2705    check_sae_capab(dev[0])
2706    params = hostapd.wpa2_params(ssid="test-sae",
2707                                 passphrase="12345678")
2708    params['wpa_key_mgmt'] = 'SAE'
2709    params['ieee80211w'] = '2'
2710    params['ocv'] = '1'
2711    hapd = hostapd.add_ap(apdev[0], params)
2712
2713    dev[0].set("sae_groups", "")
2714    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", ocv="1",
2715                        ieee80211w="2", scan_freq="2412")
2716    hapd.wait_sta()
2717
2718    pmk_h = hapd.request("GET_PMK " + dev[0].own_addr())
2719    if "FAIL" in pmk_h or len(pmk_h) == 0:
2720        raise Exception("Failed to fetch PMK from hostapd during a successful authentication")
2721
2722    pmk_w = dev[0].get_pmk(id)
2723    if pmk_h != pmk_w:
2724        raise Exception("Fetched PMK does not match: hostapd %s, wpa_supplicant %s" % (pmk_h, pmk_w))
2725
2726def test_sae_ocv_pmk_failure(dev, apdev):
2727    """SAE with OCV and fetching PMK (failed 4-way handshake)"""
2728    check_sae_capab(dev[0])
2729    params = hostapd.wpa2_params(ssid="test-sae",
2730                                 passphrase="12345678")
2731    params['wpa_key_mgmt'] = 'SAE'
2732    params['ieee80211w'] = '2'
2733    params['ocv'] = '1'
2734    hapd = hostapd.add_ap(apdev[0], params)
2735
2736    dev[0].set("sae_groups", "")
2737    dev[0].set("oci_freq_override_eapol", "2462")
2738    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", ocv="1",
2739                        ieee80211w="2", scan_freq="2412", wait_connect=False)
2740    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2741                            "CTRL-EVENT-DISCONNECTED"], timeout=15)
2742    if ev is None:
2743        raise Exception("No connection result reported")
2744    if "CTRL-EVENT-CONNECTED" in ev:
2745        raise Exception("Unexpected connection")
2746
2747    pmk_h = hapd.request("GET_PMK " + dev[0].own_addr())
2748    if "FAIL" in pmk_h or len(pmk_h) == 0:
2749        raise Exception("Failed to fetch PMK from hostapd during a successful authentication")
2750
2751    res = dev[0].request("PMKSA_GET %d" % id)
2752    if not res.startswith(hapd.own_addr()):
2753        raise Exception("PMKSA from wpa_supplicant does not have matching BSSID")
2754    pmk_w = res.split(' ')[2]
2755    if pmk_h != pmk_w:
2756        raise Exception("Fetched PMK does not match: hostapd %s, wpa_supplicant %s" % (pmk_h, pmk_w))
2757
2758    dev[0].request("DISCONNECT")
2759    time.sleep(0.1)
2760    pmk_h2 = hapd.request("GET_PMK " + dev[0].own_addr())
2761    res = dev[0].request("PMKSA_GET %d" % id)
2762    pmk_w2 = res.split(' ')[2]
2763    if pmk_h2 != pmk_h:
2764        raise Exception("hostapd did not report correct PMK after disconnection")
2765    if pmk_w2 != pmk_w:
2766        raise Exception("wpa_supplicant did not report correct PMK after disconnection")
2767
2768def test_sae_reject(dev, apdev):
2769    """SAE and AP rejecting connection"""
2770    check_sae_capab(dev[0])
2771    params = hostapd.wpa2_params(ssid="test-sae",
2772                                 passphrase="12345678")
2773    params['wpa_key_mgmt'] = 'SAE'
2774    params['max_num_sta'] = '0'
2775    hapd = hostapd.add_ap(apdev[0], params)
2776    dev[0].set("sae_groups", "")
2777    id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
2778                        scan_freq="2412", wait_connect=False)
2779    if not dev[0].wait_event(["CTRL-EVENT-AUTH-REJECT"], timeout=10):
2780        raise Exception("Authentication rejection not reported")
2781    dev[0].request("REMOVE_NETWORK all")
2782    dev[0].dump_monitor()
2783