Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / tests / hwsim / test_sae.py
1 # Test cases for SAE
2 # Copyright (c) 2013-2015, 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
7 import binascii
8 import os
9 import time
10 import subprocess
11 import logging
12 logger = logging.getLogger()
13
14 import hwsim_utils
15 import hostapd
16 from utils import HwsimSkip, alloc_fail, fail_test
17 from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations
18
19 def test_sae(dev, apdev):
20     """SAE with default group"""
21     if "SAE" not in dev[0].get_capability("auth_alg"):
22         raise HwsimSkip("SAE not supported")
23     params = hostapd.wpa2_params(ssid="test-sae",
24                                  passphrase="12345678")
25     params['wpa_key_mgmt'] = 'SAE'
26     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
27     key_mgmt = hapd.get_config()['key_mgmt']
28     if key_mgmt.split(' ')[0] != "SAE":
29         raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
30
31     dev[0].request("SET sae_groups ")
32     id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
33                         scan_freq="2412")
34     if dev[0].get_status_field('sae_group') != '19':
35             raise Exception("Expected default SAE group not used")
36     bss = dev[0].get_bss(apdev[0]['bssid'])
37     if 'flags' not in bss:
38         raise Exception("Could not get BSS flags from BSS table")
39     if "[WPA2-SAE-CCMP]" not in bss['flags']:
40         raise Exception("Unexpected BSS flags: " + bss['flags'])
41
42 def test_sae_password_ecc(dev, apdev):
43     """SAE with number of different passwords (ECC)"""
44     if "SAE" not in dev[0].get_capability("auth_alg"):
45         raise HwsimSkip("SAE not supported")
46     params = hostapd.wpa2_params(ssid="test-sae",
47                                  passphrase="12345678")
48     params['wpa_key_mgmt'] = 'SAE'
49     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
50
51     dev[0].request("SET sae_groups 19")
52
53     for i in range(10):
54         password = "12345678-" + str(i)
55         hapd.set("wpa_passphrase", password)
56         dev[0].connect("test-sae", psk=password, key_mgmt="SAE",
57                        scan_freq="2412")
58         dev[0].request("REMOVE_NETWORK all")
59         dev[0].wait_disconnected()
60
61 def test_sae_password_ffc(dev, apdev):
62     """SAE with number of different passwords (FFC)"""
63     if "SAE" not in dev[0].get_capability("auth_alg"):
64         raise HwsimSkip("SAE not supported")
65     params = hostapd.wpa2_params(ssid="test-sae",
66                                  passphrase="12345678")
67     params['wpa_key_mgmt'] = 'SAE'
68     params['sae_groups'] = '22'
69     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
70
71     dev[0].request("SET sae_groups 22")
72
73     for i in range(10):
74         password = "12345678-" + str(i)
75         hapd.set("wpa_passphrase", password)
76         dev[0].connect("test-sae", psk=password, key_mgmt="SAE",
77                        scan_freq="2412")
78         dev[0].request("REMOVE_NETWORK all")
79         dev[0].wait_disconnected()
80
81 def test_sae_pmksa_caching(dev, apdev):
82     """SAE and PMKSA caching"""
83     if "SAE" not in dev[0].get_capability("auth_alg"):
84         raise HwsimSkip("SAE not supported")
85     params = hostapd.wpa2_params(ssid="test-sae",
86                                  passphrase="12345678")
87     params['wpa_key_mgmt'] = 'SAE'
88     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
89
90     dev[0].request("SET sae_groups ")
91     dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
92                    scan_freq="2412")
93     ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
94     if ev is None:
95         raise Exception("No connection event received from hostapd")
96     dev[0].request("DISCONNECT")
97     dev[0].wait_disconnected()
98     dev[0].request("RECONNECT")
99     dev[0].wait_connected(timeout=15, error="Reconnect timed out")
100     if dev[0].get_status_field('sae_group') is not None:
101             raise Exception("SAE group claimed to have been used")
102
103 def test_sae_pmksa_caching_disabled(dev, apdev):
104     """SAE and PMKSA caching disabled"""
105     if "SAE" not in dev[0].get_capability("auth_alg"):
106         raise HwsimSkip("SAE not supported")
107     params = hostapd.wpa2_params(ssid="test-sae",
108                                  passphrase="12345678")
109     params['wpa_key_mgmt'] = 'SAE'
110     params['disable_pmksa_caching'] = '1'
111     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
112
113     dev[0].request("SET sae_groups ")
114     dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
115                    scan_freq="2412")
116     ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
117     if ev is None:
118         raise Exception("No connection event received from hostapd")
119     dev[0].request("DISCONNECT")
120     dev[0].wait_disconnected()
121     dev[0].request("RECONNECT")
122     dev[0].wait_connected(timeout=15, error="Reconnect timed out")
123     if dev[0].get_status_field('sae_group') != '19':
124             raise Exception("Expected default SAE group not used")
125
126 def test_sae_groups(dev, apdev):
127     """SAE with all supported groups"""
128     if "SAE" not in dev[0].get_capability("auth_alg"):
129         raise HwsimSkip("SAE not supported")
130     # This is the full list of supported groups, but groups 14-16 (2048-4096 bit
131     # MODP) and group 21 (521-bit random ECP group) are a bit too slow on some
132     # VMs and can result in hitting the mac80211 authentication timeout, so
133     # allow them to fail and just report such failures in the debug log.
134     sae_groups = [ 19, 25, 26, 20, 21, 2, 5, 14, 15, 16, 22, 23, 24 ]
135     tls = dev[0].request("GET tls_library")
136     if tls.startswith("OpenSSL") and "build=OpenSSL 1.0.2" in tls and "run=OpenSSL 1.0.2" in tls:
137         logger.info("Add Brainpool EC groups since OpenSSL is new enough")
138         sae_groups += [ 27, 28, 29, 30 ]
139     heavy_groups = [ 14, 15, 16 ]
140     groups = [str(g) for g in sae_groups]
141     params = hostapd.wpa2_params(ssid="test-sae-groups",
142                                  passphrase="12345678")
143     params['wpa_key_mgmt'] = 'SAE'
144     params['sae_groups'] = ' '.join(groups)
145     hostapd.add_ap(apdev[0]['ifname'], params)
146
147     for g in groups:
148         logger.info("Testing SAE group " + g)
149         dev[0].request("SET sae_groups " + g)
150         id = dev[0].connect("test-sae-groups", psk="12345678", key_mgmt="SAE",
151                             scan_freq="2412", wait_connect=False)
152         if int(g) in heavy_groups:
153             ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=5)
154             if ev is None:
155                 logger.info("No connection with heavy SAE group %s did not connect - likely hitting timeout in mac80211" % g)
156                 dev[0].remove_network(id)
157                 time.sleep(0.1)
158                 dev[0].dump_monitor()
159                 continue
160             logger.info("Connection with heavy SAE group " + g)
161         else:
162             ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=10)
163             if ev is None:
164                 if "BoringSSL" in tls and int(g) in [ 25 ]:
165                     logger.info("Ignore connection failure with group " + g + " with BoringSSL")
166                     dev[0].remove_network(id)
167                     dev[0].dump_monitor()
168                     continue
169                 raise Exception("Connection timed out with group " + g)
170         if dev[0].get_status_field('sae_group') != g:
171             raise Exception("Expected SAE group not used")
172         dev[0].remove_network(id)
173         dev[0].wait_disconnected()
174         dev[0].dump_monitor()
175
176 def test_sae_group_nego(dev, apdev):
177     """SAE group negotiation"""
178     if "SAE" not in dev[0].get_capability("auth_alg"):
179         raise HwsimSkip("SAE not supported")
180     params = hostapd.wpa2_params(ssid="test-sae-group-nego",
181                                  passphrase="12345678")
182     params['wpa_key_mgmt'] = 'SAE'
183     params['sae_groups'] = '19'
184     hostapd.add_ap(apdev[0]['ifname'], params)
185
186     dev[0].request("SET sae_groups 25 26 20 19")
187     dev[0].connect("test-sae-group-nego", psk="12345678", key_mgmt="SAE",
188                    scan_freq="2412")
189     if dev[0].get_status_field('sae_group') != '19':
190         raise Exception("Expected SAE group not used")
191
192 def test_sae_anti_clogging(dev, apdev):
193     """SAE anti clogging"""
194     if "SAE" not in dev[0].get_capability("auth_alg"):
195         raise HwsimSkip("SAE not supported")
196     params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
197     params['wpa_key_mgmt'] = 'SAE'
198     params['sae_anti_clogging_threshold'] = '1'
199     hostapd.add_ap(apdev[0]['ifname'], params)
200
201     dev[0].request("SET sae_groups ")
202     dev[1].request("SET sae_groups ")
203     id = {}
204     for i in range(0, 2):
205         dev[i].scan(freq="2412")
206         id[i] = dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
207                                scan_freq="2412", only_add_network=True)
208     for i in range(0, 2):
209         dev[i].select_network(id[i])
210     for i in range(0, 2):
211         dev[i].wait_connected(timeout=10)
212
213 def test_sae_forced_anti_clogging(dev, apdev):
214     """SAE anti clogging (forced)"""
215     if "SAE" not in dev[0].get_capability("auth_alg"):
216         raise HwsimSkip("SAE not supported")
217     params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
218     params['wpa_key_mgmt'] = 'SAE WPA-PSK'
219     params['sae_anti_clogging_threshold'] = '0'
220     hostapd.add_ap(apdev[0]['ifname'], params)
221     dev[2].connect("test-sae", psk="12345678", scan_freq="2412")
222     for i in range(0, 2):
223         dev[i].request("SET sae_groups ")
224         dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
225                        scan_freq="2412")
226
227 def test_sae_mixed(dev, apdev):
228     """Mixed SAE and non-SAE network"""
229     if "SAE" not in dev[0].get_capability("auth_alg"):
230         raise HwsimSkip("SAE not supported")
231     params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
232     params['wpa_key_mgmt'] = 'SAE WPA-PSK'
233     params['sae_anti_clogging_threshold'] = '0'
234     hostapd.add_ap(apdev[0]['ifname'], params)
235
236     dev[2].connect("test-sae", psk="12345678", scan_freq="2412")
237     for i in range(0, 2):
238         dev[i].request("SET sae_groups ")
239         dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
240                        scan_freq="2412")
241
242 def test_sae_missing_password(dev, apdev):
243     """SAE and missing password"""
244     if "SAE" not in dev[0].get_capability("auth_alg"):
245         raise HwsimSkip("SAE not supported")
246     params = hostapd.wpa2_params(ssid="test-sae",
247                                  passphrase="12345678")
248     params['wpa_key_mgmt'] = 'SAE'
249     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
250
251     dev[0].request("SET sae_groups ")
252     id = dev[0].connect("test-sae",
253                         raw_psk="46b4a73b8a951ad53ebd2e0afdb9c5483257edd4c21d12b7710759da70945858",
254                         key_mgmt="SAE", scan_freq="2412", wait_connect=False)
255     ev = dev[0].wait_event(['CTRL-EVENT-SSID-TEMP-DISABLED'], timeout=10)
256     if ev is None:
257         raise Exception("Invalid network not temporarily disabled")
258
259
260 def test_sae_key_lifetime_in_memory(dev, apdev, params):
261     """SAE and key lifetime in memory"""
262     if "SAE" not in dev[0].get_capability("auth_alg"):
263         raise HwsimSkip("SAE not supported")
264     password = "5ad144a7c1f5a5503baa6fa01dabc15b1843e8c01662d78d16b70b5cd23cf8b"
265     p = hostapd.wpa2_params(ssid="test-sae", passphrase=password)
266     p['wpa_key_mgmt'] = 'SAE'
267     hapd = hostapd.add_ap(apdev[0]['ifname'], p)
268
269     pid = find_wpas_process(dev[0])
270
271     dev[0].request("SET sae_groups ")
272     id = dev[0].connect("test-sae", psk=password, key_mgmt="SAE",
273                         scan_freq="2412")
274
275     time.sleep(1)
276     buf = read_process_memory(pid, password)
277
278     dev[0].request("DISCONNECT")
279     dev[0].wait_disconnected()
280
281     dev[0].relog()
282     sae_k = None
283     sae_keyseed = None
284     sae_kck = None
285     pmk = None
286     ptk = None
287     gtk = None
288     with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
289         for l in f.readlines():
290             if "SAE: k - hexdump" in l:
291                 val = l.strip().split(':')[3].replace(' ', '')
292                 sae_k = binascii.unhexlify(val)
293             if "SAE: keyseed - hexdump" in l:
294                 val = l.strip().split(':')[3].replace(' ', '')
295                 sae_keyseed = binascii.unhexlify(val)
296             if "SAE: KCK - hexdump" in l:
297                 val = l.strip().split(':')[3].replace(' ', '')
298                 sae_kck = binascii.unhexlify(val)
299             if "SAE: PMK - hexdump" in l:
300                 val = l.strip().split(':')[3].replace(' ', '')
301                 pmk = binascii.unhexlify(val)
302             if "WPA: PTK - hexdump" in l:
303                 val = l.strip().split(':')[3].replace(' ', '')
304                 ptk = binascii.unhexlify(val)
305             if "WPA: Group Key - hexdump" in l:
306                 val = l.strip().split(':')[3].replace(' ', '')
307                 gtk = binascii.unhexlify(val)
308     if not sae_k or not sae_keyseed or not sae_kck or not pmk or not ptk or not gtk:
309         raise Exception("Could not find keys from debug log")
310     if len(gtk) != 16:
311         raise Exception("Unexpected GTK length")
312
313     kck = ptk[0:16]
314     kek = ptk[16:32]
315     tk = ptk[32:48]
316
317     fname = os.path.join(params['logdir'],
318                          'sae_key_lifetime_in_memory.memctx-')
319
320     logger.info("Checking keys in memory while associated")
321     get_key_locations(buf, password, "Password")
322     get_key_locations(buf, pmk, "PMK")
323     if password not in buf:
324         raise HwsimSkip("Password not found while associated")
325     if pmk not in buf:
326         raise HwsimSkip("PMK not found while associated")
327     if kck not in buf:
328         raise Exception("KCK not found while associated")
329     if kek not in buf:
330         raise Exception("KEK not found while associated")
331     if tk in buf:
332         raise Exception("TK found from memory")
333     if gtk in buf:
334         raise Exception("GTK found from memory")
335     verify_not_present(buf, sae_k, fname, "SAE(k)")
336     verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
337     verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
338
339     logger.info("Checking keys in memory after disassociation")
340     buf = read_process_memory(pid, password)
341
342     # Note: Password is still present in network configuration
343     # Note: PMK is in PMKSA cache
344
345     get_key_locations(buf, password, "Password")
346     get_key_locations(buf, pmk, "PMK")
347     verify_not_present(buf, kck, fname, "KCK")
348     verify_not_present(buf, kek, fname, "KEK")
349     verify_not_present(buf, tk, fname, "TK")
350     verify_not_present(buf, gtk, fname, "GTK")
351     verify_not_present(buf, sae_k, fname, "SAE(k)")
352     verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
353     verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
354
355     dev[0].request("PMKSA_FLUSH")
356     logger.info("Checking keys in memory after PMKSA cache flush")
357     buf = read_process_memory(pid, password)
358     get_key_locations(buf, password, "Password")
359     get_key_locations(buf, pmk, "PMK")
360     verify_not_present(buf, pmk, fname, "PMK")
361
362     dev[0].request("REMOVE_NETWORK all")
363
364     logger.info("Checking keys in memory after network profile removal")
365     buf = read_process_memory(pid, password)
366
367     get_key_locations(buf, password, "Password")
368     get_key_locations(buf, pmk, "PMK")
369     verify_not_present(buf, password, fname, "password")
370     verify_not_present(buf, pmk, fname, "PMK")
371     verify_not_present(buf, kck, fname, "KCK")
372     verify_not_present(buf, kek, fname, "KEK")
373     verify_not_present(buf, tk, fname, "TK")
374     verify_not_present(buf, gtk, fname, "GTK")
375     verify_not_present(buf, sae_k, fname, "SAE(k)")
376     verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
377     verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
378
379 def test_sae_oom_wpas(dev, apdev):
380     """SAE and OOM in wpa_supplicant"""
381     if "SAE" not in dev[0].get_capability("auth_alg"):
382         raise HwsimSkip("SAE not supported")
383     params = hostapd.wpa2_params(ssid="test-sae",
384                                  passphrase="12345678")
385     params['wpa_key_mgmt'] = 'SAE'
386     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
387
388     dev[0].request("SET sae_groups 25")
389     tls = dev[0].request("GET tls_library")
390     if "BoringSSL" in tls:
391         dev[0].request("SET sae_groups 26")
392     with alloc_fail(dev[0], 1, "sae_set_group"):
393         dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
394                        scan_freq="2412")
395         dev[0].request("REMOVE_NETWORK all")
396
397     dev[0].request("SET sae_groups ")
398     with alloc_fail(dev[0], 2, "sae_set_group"):
399         dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
400                        scan_freq="2412")
401         dev[0].request("REMOVE_NETWORK all")
402
403 def test_sae_proto_ecc(dev, apdev):
404     """SAE protocol testing (ECC)"""
405     if "SAE" not in dev[0].get_capability("auth_alg"):
406         raise HwsimSkip("SAE not supported")
407     params = hostapd.wpa2_params(ssid="test-sae",
408                                  passphrase="12345678")
409     params['wpa_key_mgmt'] = 'SAE'
410     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
411     bssid = apdev[0]['bssid']
412
413     dev[0].request("SET sae_groups 19")
414
415     tests = [ ("Confirm mismatch",
416                "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
417                "0000800edebc3f260dc1fe7e0b20888af2b8a3316252ec37388a8504e25b73dc4240"),
418               ("Commit without even full cyclic group field",
419                "13",
420                None),
421               ("Too short commit",
422                "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02",
423                None),
424               ("Invalid commit scalar (0)",
425                "1300" + "0000000000000000000000000000000000000000000000000000000000000000" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
426                None),
427               ("Invalid commit scalar (1)",
428                "1300" + "0000000000000000000000000000000000000000000000000000000000000001" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
429                None),
430               ("Invalid commit scalar (> r)",
431                "1300" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
432                None),
433               ("Commit element not on curve",
434                "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728d0000000000000000000000000000000000000000000000000000000000000000",
435                None),
436               ("Invalid commit element (y coordinate > P)",
437                "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
438                None),
439               ("Invalid commit element (x coordinate > P)",
440                "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
441                None),
442               ("Different group in commit",
443                "1400" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
444                None),
445               ("Too short confirm",
446                "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
447                "0000800edebc3f260dc1fe7e0b20888af2b8a3316252ec37388a8504e25b73dc42")]
448     for (note, commit, confirm) in tests:
449         logger.info(note)
450         dev[0].scan_for_bss(bssid, freq=2412)
451         hapd.set("ext_mgmt_frame_handling", "1")
452         dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
453                        scan_freq="2412", wait_connect=False)
454
455         logger.info("Commit")
456         for i in range(0, 10):
457             req = hapd.mgmt_rx()
458             if req is None:
459                 raise Exception("MGMT RX wait timed out (commit)")
460             if req['subtype'] == 11:
461                 break
462             req = None
463         if not req:
464             raise Exception("Authentication frame (commit) not received")
465
466         hapd.dump_monitor()
467         resp = {}
468         resp['fc'] = req['fc']
469         resp['da'] = req['sa']
470         resp['sa'] = req['da']
471         resp['bssid'] = req['bssid']
472         resp['payload'] = binascii.unhexlify("030001000000" + commit)
473         hapd.mgmt_tx(resp)
474
475         if confirm:
476             logger.info("Confirm")
477             for i in range(0, 10):
478                 req = hapd.mgmt_rx()
479                 if req is None:
480                     raise Exception("MGMT RX wait timed out (confirm)")
481                 if req['subtype'] == 11:
482                     break
483                 req = None
484             if not req:
485                 raise Exception("Authentication frame (confirm) not received")
486
487             hapd.dump_monitor()
488             resp = {}
489             resp['fc'] = req['fc']
490             resp['da'] = req['sa']
491             resp['sa'] = req['da']
492             resp['bssid'] = req['bssid']
493             resp['payload'] = binascii.unhexlify("030002000000" + confirm)
494             hapd.mgmt_tx(resp)
495
496         time.sleep(0.1)
497         dev[0].request("REMOVE_NETWORK all")
498         hapd.set("ext_mgmt_frame_handling", "0")
499         hapd.dump_monitor()
500
501 def test_sae_proto_ffc(dev, apdev):
502     """SAE protocol testing (FFC)"""
503     if "SAE" not in dev[0].get_capability("auth_alg"):
504         raise HwsimSkip("SAE not supported")
505     params = hostapd.wpa2_params(ssid="test-sae",
506                                  passphrase="12345678")
507     params['wpa_key_mgmt'] = 'SAE'
508     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
509     bssid = apdev[0]['bssid']
510
511     dev[0].request("SET sae_groups 2")
512
513     tests = [ ("Confirm mismatch",
514                "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "a8c00117493cdffa5dd671e934bc9cb1a69f39e25e9dd9cd9afd3aea2441a0f5491211c7ba50a753563f9ce943b043557cb71193b28e86ed9544f4289c471bf91b70af5c018cf4663e004165b0fd0bc1d8f3f78adf42eee92bcbc55246fd3ee9f107ab965dc7d4986f23eb71d616ebfe6bfe0a6c1ac5dc1718acee17c9a17486",
515                "0000f3116a9731f1259622e3eb55d4b3b50ba16f8c5f5565b28e609b180c51460251"),
516               ("Too short commit",
517                "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "a8c00117493cdffa5dd671e934bc9cb1a69f39e25e9dd9cd9afd3aea2441a0f5491211c7ba50a753563f9ce943b043557cb71193b28e86ed9544f4289c471bf91b70af5c018cf4663e004165b0fd0bc1d8f3f78adf42eee92bcbc55246fd3ee9f107ab965dc7d4986f23eb71d616ebfe6bfe0a6c1ac5dc1718acee17c9a174",
518                None),
519               ("Invalid element (0) in commit",
520                "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
521                None),
522               ("Invalid element (1) in commit",
523                "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
524                None),
525               ("Invalid element (> P) in commit",
526                "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
527                None) ]
528     for (note, commit, confirm) in tests:
529         logger.info(note)
530         dev[0].scan_for_bss(bssid, freq=2412)
531         hapd.set("ext_mgmt_frame_handling", "1")
532         dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
533                        scan_freq="2412", wait_connect=False)
534
535         logger.info("Commit")
536         for i in range(0, 10):
537             req = hapd.mgmt_rx()
538             if req is None:
539                 raise Exception("MGMT RX wait timed out (commit)")
540             if req['subtype'] == 11:
541                 break
542             req = None
543         if not req:
544             raise Exception("Authentication frame (commit) not received")
545
546         hapd.dump_monitor()
547         resp = {}
548         resp['fc'] = req['fc']
549         resp['da'] = req['sa']
550         resp['sa'] = req['da']
551         resp['bssid'] = req['bssid']
552         resp['payload'] = binascii.unhexlify("030001000000" + commit)
553         hapd.mgmt_tx(resp)
554
555         if confirm:
556             logger.info("Confirm")
557             for i in range(0, 10):
558                 req = hapd.mgmt_rx()
559                 if req is None:
560                     raise Exception("MGMT RX wait timed out (confirm)")
561                 if req['subtype'] == 11:
562                     break
563                 req = None
564             if not req:
565                 raise Exception("Authentication frame (confirm) not received")
566
567             hapd.dump_monitor()
568             resp = {}
569             resp['fc'] = req['fc']
570             resp['da'] = req['sa']
571             resp['sa'] = req['da']
572             resp['bssid'] = req['bssid']
573             resp['payload'] = binascii.unhexlify("030002000000" + confirm)
574             hapd.mgmt_tx(resp)
575
576         time.sleep(0.1)
577         dev[0].request("REMOVE_NETWORK all")
578         hapd.set("ext_mgmt_frame_handling", "0")
579         hapd.dump_monitor()
580
581 def test_sae_no_ffc_by_default(dev, apdev):
582     """SAE and default groups rejecting FFC"""
583     if "SAE" not in dev[0].get_capability("auth_alg"):
584         raise HwsimSkip("SAE not supported")
585     params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
586     params['wpa_key_mgmt'] = 'SAE'
587     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
588
589     dev[0].request("SET sae_groups 5")
590     dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412",
591                    wait_connect=False)
592     ev = dev[0].wait_event(["SME: Trying to authenticate"], timeout=3)
593     if ev is None:
594         raise Exception("Did not try to authenticate")
595     ev = dev[0].wait_event(["SME: Trying to authenticate"], timeout=3)
596     if ev is None:
597         raise Exception("Did not try to authenticate (2)")
598     dev[0].request("REMOVE_NETWORK all")
599
600 def sae_reflection_attack(apdev, dev, group):
601     if "SAE" not in dev.get_capability("auth_alg"):
602         raise HwsimSkip("SAE not supported")
603     params = hostapd.wpa2_params(ssid="test-sae",
604                                  passphrase="no-knowledge-of-passphrase")
605     params['wpa_key_mgmt'] = 'SAE'
606     hapd = hostapd.add_ap(apdev['ifname'], params)
607     bssid = apdev['bssid']
608
609     dev.scan_for_bss(bssid, freq=2412)
610     hapd.set("ext_mgmt_frame_handling", "1")
611
612     dev.request("SET sae_groups %d" % group)
613     dev.connect("test-sae", psk="reflection-attack", key_mgmt="SAE",
614                 scan_freq="2412", wait_connect=False)
615
616     # Commit
617     for i in range(0, 10):
618         req = hapd.mgmt_rx()
619         if req is None:
620             raise Exception("MGMT RX wait timed out")
621         if req['subtype'] == 11:
622             break
623         req = None
624     if not req:
625         raise Exception("Authentication frame not received")
626
627     resp = {}
628     resp['fc'] = req['fc']
629     resp['da'] = req['sa']
630     resp['sa'] = req['da']
631     resp['bssid'] = req['bssid']
632     resp['payload'] = req['payload']
633     hapd.mgmt_tx(resp)
634
635     # Confirm
636     req = hapd.mgmt_rx(timeout=0.5)
637     if req is not None:
638         if req['subtype'] == 11:
639             raise Exception("Unexpected Authentication frame seen")
640
641 def test_sae_reflection_attack_ecc(dev, apdev):
642     """SAE reflection attack (ECC)"""
643     sae_reflection_attack(apdev[0], dev[0], 19)
644
645 def test_sae_reflection_attack_ffc(dev, apdev):
646     """SAE reflection attack (FFC)"""
647     sae_reflection_attack(apdev[0], dev[0], 5)
648
649 def test_sae_anti_clogging_proto(dev, apdev):
650     """SAE anti clogging protocol testing"""
651     if "SAE" not in dev[0].get_capability("auth_alg"):
652         raise HwsimSkip("SAE not supported")
653     params = hostapd.wpa2_params(ssid="test-sae",
654                                  passphrase="no-knowledge-of-passphrase")
655     params['wpa_key_mgmt'] = 'SAE'
656     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
657     bssid = apdev[0]['bssid']
658
659     dev[0].scan_for_bss(bssid, freq=2412)
660     hapd.set("ext_mgmt_frame_handling", "1")
661
662     dev[0].request("SET sae_groups ")
663     dev[0].connect("test-sae", psk="anti-cloggign", key_mgmt="SAE",
664                    scan_freq="2412", wait_connect=False)
665
666     # Commit
667     for i in range(0, 10):
668         req = hapd.mgmt_rx()
669         if req is None:
670             raise Exception("MGMT RX wait timed out")
671         if req['subtype'] == 11:
672             break
673         req = None
674     if not req:
675         raise Exception("Authentication frame not received")
676
677     resp = {}
678     resp['fc'] = req['fc']
679     resp['da'] = req['sa']
680     resp['sa'] = req['da']
681     resp['bssid'] = req['bssid']
682     resp['payload'] = binascii.unhexlify("030001004c00" + "ffff00")
683     hapd.mgmt_tx(resp)
684
685     # Confirm (not received due to DH group being rejected)
686     req = hapd.mgmt_rx(timeout=0.5)
687     if req is not None:
688         if req['subtype'] == 11:
689             raise Exception("Unexpected Authentication frame seen")
690
691 def test_sae_no_random(dev, apdev):
692     """SAE and no random numbers available"""
693     if "SAE" not in dev[0].get_capability("auth_alg"):
694         raise HwsimSkip("SAE not supported")
695     params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
696     params['wpa_key_mgmt'] = 'SAE'
697     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
698
699     dev[0].request("SET sae_groups ")
700     tests = [ (1, "os_get_random;sae_get_rand"),
701               (1, "os_get_random;get_rand_1_to_p_1"),
702               (1, "os_get_random;get_random_qr_qnr"),
703               (1, "os_get_random;sae_derive_pwe_ecc") ]
704     for count, func in tests:
705         with fail_test(dev[0], count, func):
706             dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
707                            scan_freq="2412")
708             dev[0].request("REMOVE_NETWORK all")
709             dev[0].wait_disconnected()