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