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