]> git.ipfire.org Git - thirdparty/hostap.git/blob - tests/hwsim/test_sae.py
tests: Pass full apdev to add_ap() function (1)
[thirdparty/hostap.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 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, wait_fail_trigger
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], 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], 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], 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], 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], 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], 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], 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], 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], 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], 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], 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], 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 # The decrypted copy of GTK is freed only after the CTRL-EVENT-CONNECTED
276 # event has been delivered, so verify that wpa_supplicant has returned to
277 # eloop before reading process memory.
278 time.sleep(1)
279 dev[0].ping()
280 buf = read_process_memory(pid, password)
281
282 dev[0].request("DISCONNECT")
283 dev[0].wait_disconnected()
284
285 dev[0].relog()
286 sae_k = None
287 sae_keyseed = None
288 sae_kck = None
289 pmk = None
290 ptk = None
291 gtk = None
292 with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
293 for l in f.readlines():
294 if "SAE: k - hexdump" in l:
295 val = l.strip().split(':')[3].replace(' ', '')
296 sae_k = binascii.unhexlify(val)
297 if "SAE: keyseed - hexdump" in l:
298 val = l.strip().split(':')[3].replace(' ', '')
299 sae_keyseed = binascii.unhexlify(val)
300 if "SAE: KCK - hexdump" in l:
301 val = l.strip().split(':')[3].replace(' ', '')
302 sae_kck = binascii.unhexlify(val)
303 if "SAE: PMK - hexdump" in l:
304 val = l.strip().split(':')[3].replace(' ', '')
305 pmk = binascii.unhexlify(val)
306 if "WPA: PTK - hexdump" in l:
307 val = l.strip().split(':')[3].replace(' ', '')
308 ptk = binascii.unhexlify(val)
309 if "WPA: Group Key - hexdump" in l:
310 val = l.strip().split(':')[3].replace(' ', '')
311 gtk = binascii.unhexlify(val)
312 if not sae_k or not sae_keyseed or not sae_kck or not pmk or not ptk or not gtk:
313 raise Exception("Could not find keys from debug log")
314 if len(gtk) != 16:
315 raise Exception("Unexpected GTK length")
316
317 kck = ptk[0:16]
318 kek = ptk[16:32]
319 tk = ptk[32:48]
320
321 fname = os.path.join(params['logdir'],
322 'sae_key_lifetime_in_memory.memctx-')
323
324 logger.info("Checking keys in memory while associated")
325 get_key_locations(buf, password, "Password")
326 get_key_locations(buf, pmk, "PMK")
327 if password not in buf:
328 raise HwsimSkip("Password not found while associated")
329 if pmk not in buf:
330 raise HwsimSkip("PMK not found while associated")
331 if kck not in buf:
332 raise Exception("KCK not found while associated")
333 if kek not in buf:
334 raise Exception("KEK not found while associated")
335 if tk in buf:
336 raise Exception("TK found from memory")
337 if gtk in buf:
338 get_key_locations(buf, gtk, "GTK")
339 raise Exception("GTK found from memory")
340 verify_not_present(buf, sae_k, fname, "SAE(k)")
341 verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
342 verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
343
344 logger.info("Checking keys in memory after disassociation")
345 buf = read_process_memory(pid, password)
346
347 # Note: Password is still present in network configuration
348 # Note: PMK is in PMKSA cache
349
350 get_key_locations(buf, password, "Password")
351 get_key_locations(buf, pmk, "PMK")
352 verify_not_present(buf, kck, fname, "KCK")
353 verify_not_present(buf, kek, fname, "KEK")
354 verify_not_present(buf, tk, fname, "TK")
355 verify_not_present(buf, gtk, fname, "GTK")
356 verify_not_present(buf, sae_k, fname, "SAE(k)")
357 verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
358 verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
359
360 dev[0].request("PMKSA_FLUSH")
361 logger.info("Checking keys in memory after PMKSA cache flush")
362 buf = read_process_memory(pid, password)
363 get_key_locations(buf, password, "Password")
364 get_key_locations(buf, pmk, "PMK")
365 verify_not_present(buf, pmk, fname, "PMK")
366
367 dev[0].request("REMOVE_NETWORK all")
368
369 logger.info("Checking keys in memory after network profile removal")
370 buf = read_process_memory(pid, password)
371
372 get_key_locations(buf, password, "Password")
373 get_key_locations(buf, pmk, "PMK")
374 verify_not_present(buf, password, fname, "password")
375 verify_not_present(buf, pmk, fname, "PMK")
376 verify_not_present(buf, kck, fname, "KCK")
377 verify_not_present(buf, kek, fname, "KEK")
378 verify_not_present(buf, tk, fname, "TK")
379 verify_not_present(buf, gtk, fname, "GTK")
380 verify_not_present(buf, sae_k, fname, "SAE(k)")
381 verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
382 verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
383
384 def test_sae_oom_wpas(dev, apdev):
385 """SAE and OOM in wpa_supplicant"""
386 if "SAE" not in dev[0].get_capability("auth_alg"):
387 raise HwsimSkip("SAE not supported")
388 params = hostapd.wpa2_params(ssid="test-sae",
389 passphrase="12345678")
390 params['wpa_key_mgmt'] = 'SAE'
391 hapd = hostapd.add_ap(apdev[0], params)
392
393 dev[0].request("SET sae_groups 25")
394 tls = dev[0].request("GET tls_library")
395 if "BoringSSL" in tls:
396 dev[0].request("SET sae_groups 26")
397 with alloc_fail(dev[0], 1, "sae_set_group"):
398 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
399 scan_freq="2412")
400 dev[0].request("REMOVE_NETWORK all")
401
402 dev[0].request("SET sae_groups ")
403 with alloc_fail(dev[0], 2, "sae_set_group"):
404 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
405 scan_freq="2412")
406 dev[0].request("REMOVE_NETWORK all")
407
408 def test_sae_proto_ecc(dev, apdev):
409 """SAE protocol testing (ECC)"""
410 if "SAE" not in dev[0].get_capability("auth_alg"):
411 raise HwsimSkip("SAE not supported")
412 params = hostapd.wpa2_params(ssid="test-sae",
413 passphrase="12345678")
414 params['wpa_key_mgmt'] = 'SAE'
415 hapd = hostapd.add_ap(apdev[0], params)
416 bssid = apdev[0]['bssid']
417
418 dev[0].request("SET sae_groups 19")
419
420 tests = [ ("Confirm mismatch",
421 "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
422 "0000800edebc3f260dc1fe7e0b20888af2b8a3316252ec37388a8504e25b73dc4240"),
423 ("Commit without even full cyclic group field",
424 "13",
425 None),
426 ("Too short commit",
427 "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02",
428 None),
429 ("Invalid commit scalar (0)",
430 "1300" + "0000000000000000000000000000000000000000000000000000000000000000" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
431 None),
432 ("Invalid commit scalar (1)",
433 "1300" + "0000000000000000000000000000000000000000000000000000000000000001" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
434 None),
435 ("Invalid commit scalar (> r)",
436 "1300" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
437 None),
438 ("Commit element not on curve",
439 "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728d0000000000000000000000000000000000000000000000000000000000000000",
440 None),
441 ("Invalid commit element (y coordinate > P)",
442 "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
443 None),
444 ("Invalid commit element (x coordinate > P)",
445 "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
446 None),
447 ("Different group in commit",
448 "1400" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
449 None),
450 ("Too short confirm",
451 "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
452 "0000800edebc3f260dc1fe7e0b20888af2b8a3316252ec37388a8504e25b73dc42")]
453 for (note, commit, confirm) in tests:
454 logger.info(note)
455 dev[0].scan_for_bss(bssid, freq=2412)
456 hapd.set("ext_mgmt_frame_handling", "1")
457 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
458 scan_freq="2412", wait_connect=False)
459
460 logger.info("Commit")
461 for i in range(0, 10):
462 req = hapd.mgmt_rx()
463 if req is None:
464 raise Exception("MGMT RX wait timed out (commit)")
465 if req['subtype'] == 11:
466 break
467 req = None
468 if not req:
469 raise Exception("Authentication frame (commit) not received")
470
471 hapd.dump_monitor()
472 resp = {}
473 resp['fc'] = req['fc']
474 resp['da'] = req['sa']
475 resp['sa'] = req['da']
476 resp['bssid'] = req['bssid']
477 resp['payload'] = binascii.unhexlify("030001000000" + commit)
478 hapd.mgmt_tx(resp)
479
480 if confirm:
481 logger.info("Confirm")
482 for i in range(0, 10):
483 req = hapd.mgmt_rx()
484 if req is None:
485 raise Exception("MGMT RX wait timed out (confirm)")
486 if req['subtype'] == 11:
487 break
488 req = None
489 if not req:
490 raise Exception("Authentication frame (confirm) not received")
491
492 hapd.dump_monitor()
493 resp = {}
494 resp['fc'] = req['fc']
495 resp['da'] = req['sa']
496 resp['sa'] = req['da']
497 resp['bssid'] = req['bssid']
498 resp['payload'] = binascii.unhexlify("030002000000" + confirm)
499 hapd.mgmt_tx(resp)
500
501 time.sleep(0.1)
502 dev[0].request("REMOVE_NETWORK all")
503 hapd.set("ext_mgmt_frame_handling", "0")
504 hapd.dump_monitor()
505
506 def test_sae_proto_ffc(dev, apdev):
507 """SAE protocol testing (FFC)"""
508 if "SAE" not in dev[0].get_capability("auth_alg"):
509 raise HwsimSkip("SAE not supported")
510 params = hostapd.wpa2_params(ssid="test-sae",
511 passphrase="12345678")
512 params['wpa_key_mgmt'] = 'SAE'
513 hapd = hostapd.add_ap(apdev[0], params)
514 bssid = apdev[0]['bssid']
515
516 dev[0].request("SET sae_groups 2")
517
518 tests = [ ("Confirm mismatch",
519 "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "a8c00117493cdffa5dd671e934bc9cb1a69f39e25e9dd9cd9afd3aea2441a0f5491211c7ba50a753563f9ce943b043557cb71193b28e86ed9544f4289c471bf91b70af5c018cf4663e004165b0fd0bc1d8f3f78adf42eee92bcbc55246fd3ee9f107ab965dc7d4986f23eb71d616ebfe6bfe0a6c1ac5dc1718acee17c9a17486",
520 "0000f3116a9731f1259622e3eb55d4b3b50ba16f8c5f5565b28e609b180c51460251"),
521 ("Too short commit",
522 "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "a8c00117493cdffa5dd671e934bc9cb1a69f39e25e9dd9cd9afd3aea2441a0f5491211c7ba50a753563f9ce943b043557cb71193b28e86ed9544f4289c471bf91b70af5c018cf4663e004165b0fd0bc1d8f3f78adf42eee92bcbc55246fd3ee9f107ab965dc7d4986f23eb71d616ebfe6bfe0a6c1ac5dc1718acee17c9a174",
523 None),
524 ("Invalid element (0) in commit",
525 "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
526 None),
527 ("Invalid element (1) in commit",
528 "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
529 None),
530 ("Invalid element (> P) in commit",
531 "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
532 None) ]
533 for (note, commit, confirm) in tests:
534 logger.info(note)
535 dev[0].scan_for_bss(bssid, freq=2412)
536 hapd.set("ext_mgmt_frame_handling", "1")
537 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
538 scan_freq="2412", wait_connect=False)
539
540 logger.info("Commit")
541 for i in range(0, 10):
542 req = hapd.mgmt_rx()
543 if req is None:
544 raise Exception("MGMT RX wait timed out (commit)")
545 if req['subtype'] == 11:
546 break
547 req = None
548 if not req:
549 raise Exception("Authentication frame (commit) not received")
550
551 hapd.dump_monitor()
552 resp = {}
553 resp['fc'] = req['fc']
554 resp['da'] = req['sa']
555 resp['sa'] = req['da']
556 resp['bssid'] = req['bssid']
557 resp['payload'] = binascii.unhexlify("030001000000" + commit)
558 hapd.mgmt_tx(resp)
559
560 if confirm:
561 logger.info("Confirm")
562 for i in range(0, 10):
563 req = hapd.mgmt_rx()
564 if req is None:
565 raise Exception("MGMT RX wait timed out (confirm)")
566 if req['subtype'] == 11:
567 break
568 req = None
569 if not req:
570 raise Exception("Authentication frame (confirm) not received")
571
572 hapd.dump_monitor()
573 resp = {}
574 resp['fc'] = req['fc']
575 resp['da'] = req['sa']
576 resp['sa'] = req['da']
577 resp['bssid'] = req['bssid']
578 resp['payload'] = binascii.unhexlify("030002000000" + confirm)
579 hapd.mgmt_tx(resp)
580
581 time.sleep(0.1)
582 dev[0].request("REMOVE_NETWORK all")
583 hapd.set("ext_mgmt_frame_handling", "0")
584 hapd.dump_monitor()
585
586 def test_sae_no_ffc_by_default(dev, apdev):
587 """SAE and default groups rejecting FFC"""
588 if "SAE" not in dev[0].get_capability("auth_alg"):
589 raise HwsimSkip("SAE not supported")
590 params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
591 params['wpa_key_mgmt'] = 'SAE'
592 hapd = hostapd.add_ap(apdev[0], params)
593
594 dev[0].request("SET sae_groups 5")
595 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412",
596 wait_connect=False)
597 ev = dev[0].wait_event(["SME: Trying to authenticate"], timeout=3)
598 if ev is None:
599 raise Exception("Did not try to authenticate")
600 ev = dev[0].wait_event(["SME: Trying to authenticate"], timeout=3)
601 if ev is None:
602 raise Exception("Did not try to authenticate (2)")
603 dev[0].request("REMOVE_NETWORK all")
604
605 def sae_reflection_attack(apdev, dev, group):
606 if "SAE" not in dev.get_capability("auth_alg"):
607 raise HwsimSkip("SAE not supported")
608 params = hostapd.wpa2_params(ssid="test-sae",
609 passphrase="no-knowledge-of-passphrase")
610 params['wpa_key_mgmt'] = 'SAE'
611 hapd = hostapd.add_ap(apdev['ifname'], params)
612 bssid = apdev['bssid']
613
614 dev.scan_for_bss(bssid, freq=2412)
615 hapd.set("ext_mgmt_frame_handling", "1")
616
617 dev.request("SET sae_groups %d" % group)
618 dev.connect("test-sae", psk="reflection-attack", key_mgmt="SAE",
619 scan_freq="2412", wait_connect=False)
620
621 # Commit
622 for i in range(0, 10):
623 req = hapd.mgmt_rx()
624 if req is None:
625 raise Exception("MGMT RX wait timed out")
626 if req['subtype'] == 11:
627 break
628 req = None
629 if not req:
630 raise Exception("Authentication frame not received")
631
632 resp = {}
633 resp['fc'] = req['fc']
634 resp['da'] = req['sa']
635 resp['sa'] = req['da']
636 resp['bssid'] = req['bssid']
637 resp['payload'] = req['payload']
638 hapd.mgmt_tx(resp)
639
640 # Confirm
641 req = hapd.mgmt_rx(timeout=0.5)
642 if req is not None:
643 if req['subtype'] == 11:
644 raise Exception("Unexpected Authentication frame seen")
645
646 def test_sae_reflection_attack_ecc(dev, apdev):
647 """SAE reflection attack (ECC)"""
648 sae_reflection_attack(apdev[0], dev[0], 19)
649
650 def test_sae_reflection_attack_ffc(dev, apdev):
651 """SAE reflection attack (FFC)"""
652 sae_reflection_attack(apdev[0], dev[0], 5)
653
654 def test_sae_anti_clogging_proto(dev, apdev):
655 """SAE anti clogging protocol testing"""
656 if "SAE" not in dev[0].get_capability("auth_alg"):
657 raise HwsimSkip("SAE not supported")
658 params = hostapd.wpa2_params(ssid="test-sae",
659 passphrase="no-knowledge-of-passphrase")
660 params['wpa_key_mgmt'] = 'SAE'
661 hapd = hostapd.add_ap(apdev[0], params)
662 bssid = apdev[0]['bssid']
663
664 dev[0].scan_for_bss(bssid, freq=2412)
665 hapd.set("ext_mgmt_frame_handling", "1")
666
667 dev[0].request("SET sae_groups ")
668 dev[0].connect("test-sae", psk="anti-cloggign", key_mgmt="SAE",
669 scan_freq="2412", wait_connect=False)
670
671 # Commit
672 for i in range(0, 10):
673 req = hapd.mgmt_rx()
674 if req is None:
675 raise Exception("MGMT RX wait timed out")
676 if req['subtype'] == 11:
677 break
678 req = None
679 if not req:
680 raise Exception("Authentication frame not received")
681
682 resp = {}
683 resp['fc'] = req['fc']
684 resp['da'] = req['sa']
685 resp['sa'] = req['da']
686 resp['bssid'] = req['bssid']
687 resp['payload'] = binascii.unhexlify("030001004c00" + "ffff00")
688 hapd.mgmt_tx(resp)
689
690 # Confirm (not received due to DH group being rejected)
691 req = hapd.mgmt_rx(timeout=0.5)
692 if req is not None:
693 if req['subtype'] == 11:
694 raise Exception("Unexpected Authentication frame seen")
695
696 def test_sae_no_random(dev, apdev):
697 """SAE and no random numbers available"""
698 if "SAE" not in dev[0].get_capability("auth_alg"):
699 raise HwsimSkip("SAE not supported")
700 params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
701 params['wpa_key_mgmt'] = 'SAE'
702 hapd = hostapd.add_ap(apdev[0], params)
703
704 dev[0].request("SET sae_groups ")
705 tests = [ (1, "os_get_random;sae_get_rand"),
706 (1, "os_get_random;get_rand_1_to_p_1"),
707 (1, "os_get_random;get_random_qr_qnr"),
708 (1, "os_get_random;sae_derive_pwe_ecc") ]
709 for count, func in tests:
710 with fail_test(dev[0], count, func):
711 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
712 scan_freq="2412")
713 dev[0].request("REMOVE_NETWORK all")
714 dev[0].wait_disconnected()
715
716 def test_sae_pwe_failure(dev, apdev):
717 """SAE and pwe failure"""
718 if "SAE" not in dev[0].get_capability("auth_alg"):
719 raise HwsimSkip("SAE not supported")
720 params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
721 params['wpa_key_mgmt'] = 'SAE'
722 params['sae_groups'] = '19 5'
723 hapd = hostapd.add_ap(apdev[0], params)
724
725 dev[0].request("SET sae_groups 19")
726 with fail_test(dev[0], 1, "hmac_sha256_vector;sae_derive_pwe_ecc"):
727 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
728 scan_freq="2412")
729 dev[0].request("REMOVE_NETWORK all")
730 dev[0].wait_disconnected()
731 with fail_test(dev[0], 1, "sae_test_pwd_seed_ecc"):
732 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
733 scan_freq="2412")
734 dev[0].request("REMOVE_NETWORK all")
735 dev[0].wait_disconnected()
736
737 dev[0].request("SET sae_groups 5")
738 with fail_test(dev[0], 1, "hmac_sha256_vector;sae_derive_pwe_ffc"):
739 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
740 scan_freq="2412")
741 dev[0].request("REMOVE_NETWORK all")
742 dev[0].wait_disconnected()
743
744 dev[0].request("SET sae_groups 5")
745 with fail_test(dev[0], 1, "sae_test_pwd_seed_ffc"):
746 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
747 scan_freq="2412")
748 dev[0].request("REMOVE_NETWORK all")
749 dev[0].wait_disconnected()
750 with fail_test(dev[0], 2, "sae_test_pwd_seed_ffc"):
751 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
752 scan_freq="2412")
753 dev[0].request("REMOVE_NETWORK all")
754 dev[0].wait_disconnected()
755
756 def test_sae_bignum_failure(dev, apdev):
757 """SAE and bignum failure"""
758 if "SAE" not in dev[0].get_capability("auth_alg"):
759 raise HwsimSkip("SAE not supported")
760 params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
761 params['wpa_key_mgmt'] = 'SAE'
762 params['sae_groups'] = '19 5 22'
763 hapd = hostapd.add_ap(apdev[0], params)
764
765 dev[0].request("SET sae_groups 19")
766 tests = [ (1, "crypto_bignum_init_set;get_rand_1_to_p_1"),
767 (1, "crypto_bignum_init;is_quadratic_residue_blind"),
768 (1, "crypto_bignum_mulmod;is_quadratic_residue_blind"),
769 (2, "crypto_bignum_mulmod;is_quadratic_residue_blind"),
770 (3, "crypto_bignum_mulmod;is_quadratic_residue_blind"),
771 (1, "crypto_bignum_legendre;is_quadratic_residue_blind"),
772 (1, "crypto_bignum_init_set;sae_test_pwd_seed_ecc"),
773 (1, "crypto_ec_point_compute_y_sqr;sae_test_pwd_seed_ecc"),
774 (1, "crypto_bignum_init_set;get_random_qr_qnr"),
775 (1, "crypto_bignum_to_bin;sae_derive_pwe_ecc"),
776 (1, "crypto_ec_point_init;sae_derive_pwe_ecc"),
777 (1, "crypto_ec_point_solve_y_coord;sae_derive_pwe_ecc"),
778 (1, "crypto_ec_point_init;sae_derive_commit_element_ecc"),
779 (1, "crypto_ec_point_mul;sae_derive_commit_element_ecc"),
780 (1, "crypto_ec_point_invert;sae_derive_commit_element_ecc"),
781 (1, "crypto_bignum_init;=sae_derive_commit"),
782 (1, "crypto_ec_point_init;sae_derive_k_ecc"),
783 (1, "crypto_ec_point_mul;sae_derive_k_ecc"),
784 (1, "crypto_ec_point_add;sae_derive_k_ecc"),
785 (2, "crypto_ec_point_mul;sae_derive_k_ecc"),
786 (1, "crypto_ec_point_to_bin;sae_derive_k_ecc"),
787 (1, "crypto_bignum_legendre;get_random_qr_qnr"),
788 (1, "sha256_prf;sae_derive_keys"),
789 (1, "crypto_bignum_init;sae_derive_keys"),
790 (1, "crypto_bignum_init_set;sae_parse_commit_scalar"),
791 (1, "crypto_bignum_to_bin;sae_parse_commit_element_ecc"),
792 (1, "crypto_ec_point_from_bin;sae_parse_commit_element_ecc") ]
793 for count, func in tests:
794 with fail_test(dev[0], count, func):
795 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
796 scan_freq="2412", wait_connect=False)
797 wait_fail_trigger(dev[0], "GET_FAIL")
798 dev[0].request("REMOVE_NETWORK all")
799
800 dev[0].request("SET sae_groups 5")
801 tests = [ (1, "crypto_bignum_init_set;sae_set_group"),
802 (2, "crypto_bignum_init_set;sae_set_group"),
803 (1, "crypto_bignum_init_set;sae_get_rand"),
804 (1, "crypto_bignum_init_set;sae_test_pwd_seed_ffc"),
805 (1, "crypto_bignum_exptmod;sae_test_pwd_seed_ffc"),
806 (1, "crypto_bignum_init;sae_derive_pwe_ffc"),
807 (1, "crypto_bignum_init;sae_derive_commit_element_ffc"),
808 (1, "crypto_bignum_exptmod;sae_derive_commit_element_ffc"),
809 (1, "crypto_bignum_inverse;sae_derive_commit_element_ffc"),
810 (1, "crypto_bignum_init;sae_derive_k_ffc"),
811 (1, "crypto_bignum_exptmod;sae_derive_k_ffc"),
812 (1, "crypto_bignum_mulmod;sae_derive_k_ffc"),
813 (2, "crypto_bignum_exptmod;sae_derive_k_ffc"),
814 (1, "crypto_bignum_to_bin;sae_derive_k_ffc"),
815 (1, "crypto_bignum_init_set;sae_parse_commit_element_ffc"),
816 (1, "crypto_bignum_init;sae_parse_commit_element_ffc"),
817 (2, "crypto_bignum_init_set;sae_parse_commit_element_ffc"),
818 (1, "crypto_bignum_exptmod;sae_parse_commit_element_ffc") ]
819 for count, func in tests:
820 with fail_test(dev[0], count, func):
821 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
822 scan_freq="2412", wait_connect=False)
823 wait_fail_trigger(dev[0], "GET_FAIL")
824 dev[0].request("REMOVE_NETWORK all")
825
826 dev[0].request("SET sae_groups 22")
827 tests = [ (1, "crypto_bignum_init_set;sae_test_pwd_seed_ffc"),
828 (1, "crypto_bignum_sub;sae_test_pwd_seed_ffc"),
829 (1, "crypto_bignum_div;sae_test_pwd_seed_ffc") ]
830 for count, func in tests:
831 with fail_test(dev[0], count, func):
832 dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
833 scan_freq="2412", wait_connect=False)
834 wait_fail_trigger(dev[0], "GET_FAIL")
835 dev[0].request("REMOVE_NETWORK all")