]>
Commit | Line | Data |
---|---|---|
1640a2e4 | 1 | # Test cases for SAE |
10ba4ae4 | 2 | # Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi> |
1640a2e4 JM |
3 | # |
4 | # This software may be distributed under the terms of the BSD license. | |
5 | # See README for more details. | |
6 | ||
5b3c40a6 JM |
7 | import binascii |
8 | import os | |
1640a2e4 JM |
9 | import time |
10 | import subprocess | |
11 | import logging | |
12 | logger = logging.getLogger() | |
13 | ||
14 | import hwsim_utils | |
15 | import hostapd | |
10ba4ae4 | 16 | from utils import HwsimSkip, alloc_fail, fail_test |
5b3c40a6 | 17 | from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations |
1640a2e4 JM |
18 | |
19 | def test_sae(dev, apdev): | |
20 | """SAE with default group""" | |
b9749b6a JM |
21 | if "SAE" not in dev[0].get_capability("auth_alg"): |
22 | raise HwsimSkip("SAE not supported") | |
1640a2e4 JM |
23 | params = hostapd.wpa2_params(ssid="test-sae", |
24 | passphrase="12345678") | |
25 | params['wpa_key_mgmt'] = 'SAE' | |
65038313 JM |
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) | |
1640a2e4 JM |
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") | |
d463c556 JM |
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']) | |
1640a2e4 | 41 | |
33dcced5 JM |
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 | ||
19d3a6e3 JM |
81 | def test_sae_pmksa_caching(dev, apdev): |
82 | """SAE and PMKSA caching""" | |
b9749b6a JM |
83 | if "SAE" not in dev[0].get_capability("auth_alg"): |
84 | raise HwsimSkip("SAE not supported") | |
19d3a6e3 JM |
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") | |
7cc9a81f JM |
93 | ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5) |
94 | if ev is None: | |
95 | raise Exception("No connection event received from hostapd") | |
19d3a6e3 | 96 | dev[0].request("DISCONNECT") |
7cc9a81f | 97 | dev[0].wait_disconnected() |
19d3a6e3 | 98 | dev[0].request("RECONNECT") |
5f35a5e2 | 99 | dev[0].wait_connected(timeout=15, error="Reconnect timed out") |
19d3a6e3 JM |
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""" | |
b9749b6a JM |
105 | if "SAE" not in dev[0].get_capability("auth_alg"): |
106 | raise HwsimSkip("SAE not supported") | |
19d3a6e3 JM |
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") | |
7cc9a81f JM |
116 | ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5) |
117 | if ev is None: | |
118 | raise Exception("No connection event received from hostapd") | |
19d3a6e3 | 119 | dev[0].request("DISCONNECT") |
7cc9a81f | 120 | dev[0].wait_disconnected() |
19d3a6e3 | 121 | dev[0].request("RECONNECT") |
5f35a5e2 | 122 | dev[0].wait_connected(timeout=15, error="Reconnect timed out") |
19d3a6e3 JM |
123 | if dev[0].get_status_field('sae_group') != '19': |
124 | raise Exception("Expected default SAE group not used") | |
125 | ||
1640a2e4 JM |
126 | def test_sae_groups(dev, apdev): |
127 | """SAE with all supported groups""" | |
b9749b6a JM |
128 | if "SAE" not in dev[0].get_capability("auth_alg"): |
129 | raise HwsimSkip("SAE not supported") | |
b1f487cb JM |
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 ] | |
9e286d5e JM |
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 ] | |
b1f487cb | 139 | heavy_groups = [ 14, 15, 16 ] |
1640a2e4 JM |
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", | |
b1f487cb JM |
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: | |
a68d1792 JM |
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) | |
1640a2e4 JM |
170 | if dev[0].get_status_field('sae_group') != g: |
171 | raise Exception("Expected SAE group not used") | |
172 | dev[0].remove_network(id) | |
b1f487cb JM |
173 | dev[0].wait_disconnected() |
174 | dev[0].dump_monitor() | |
1640a2e4 JM |
175 | |
176 | def test_sae_group_nego(dev, apdev): | |
177 | """SAE group negotiation""" | |
b9749b6a JM |
178 | if "SAE" not in dev[0].get_capability("auth_alg"): |
179 | raise HwsimSkip("SAE not supported") | |
1640a2e4 JM |
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") | |
a6cf5cd6 JM |
191 | |
192 | def test_sae_anti_clogging(dev, apdev): | |
193 | """SAE anti clogging""" | |
b9749b6a JM |
194 | if "SAE" not in dev[0].get_capability("auth_alg"): |
195 | raise HwsimSkip("SAE not supported") | |
a6cf5cd6 JM |
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): | |
5f35a5e2 | 211 | dev[i].wait_connected(timeout=10) |
d05ff960 JM |
212 | |
213 | def test_sae_forced_anti_clogging(dev, apdev): | |
214 | """SAE anti clogging (forced)""" | |
b9749b6a JM |
215 | if "SAE" not in dev[0].get_capability("auth_alg"): |
216 | raise HwsimSkip("SAE not supported") | |
d05ff960 | 217 | params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678") |
fd4709ff | 218 | params['wpa_key_mgmt'] = 'SAE WPA-PSK' |
d05ff960 JM |
219 | params['sae_anti_clogging_threshold'] = '0' |
220 | hostapd.add_ap(apdev[0]['ifname'], params) | |
fd4709ff | 221 | dev[2].connect("test-sae", psk="12345678", scan_freq="2412") |
d05ff960 JM |
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""" | |
b9749b6a JM |
229 | if "SAE" not in dev[0].get_capability("auth_alg"): |
230 | raise HwsimSkip("SAE not supported") | |
d05ff960 JM |
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") | |
acb63c75 JM |
241 | |
242 | def test_sae_missing_password(dev, apdev): | |
243 | """SAE and missing password""" | |
b9749b6a JM |
244 | if "SAE" not in dev[0].get_capability("auth_alg"): |
245 | raise HwsimSkip("SAE not supported") | |
acb63c75 JM |
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") | |
5b3c40a6 JM |
258 | |
259 | ||
260 | def test_sae_key_lifetime_in_memory(dev, apdev, params): | |
261 | """SAE and key lifetime in memory""" | |
b9749b6a JM |
262 | if "SAE" not in dev[0].get_capability("auth_alg"): |
263 | raise HwsimSkip("SAE not supported") | |
5b3c40a6 JM |
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 | ||
54f2cae2 | 275 | time.sleep(1) |
5b3c40a6 JM |
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: | |
81e787b7 | 324 | raise HwsimSkip("Password not found while associated") |
5b3c40a6 | 325 | if pmk not in buf: |
81e787b7 | 326 | raise HwsimSkip("PMK not found while associated") |
5b3c40a6 JM |
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: | |
8eb45bde | 334 | get_key_locations(buf, gtk, "GTK") |
5b3c40a6 JM |
335 | raise Exception("GTK found from memory") |
336 | verify_not_present(buf, sae_k, fname, "SAE(k)") | |
337 | verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)") | |
338 | verify_not_present(buf, sae_kck, fname, "SAE(KCK)") | |
339 | ||
340 | logger.info("Checking keys in memory after disassociation") | |
341 | buf = read_process_memory(pid, password) | |
342 | ||
343 | # Note: Password is still present in network configuration | |
344 | # Note: PMK is in PMKSA cache | |
345 | ||
346 | get_key_locations(buf, password, "Password") | |
347 | get_key_locations(buf, pmk, "PMK") | |
348 | verify_not_present(buf, kck, fname, "KCK") | |
349 | verify_not_present(buf, kek, fname, "KEK") | |
350 | verify_not_present(buf, tk, fname, "TK") | |
351 | verify_not_present(buf, gtk, fname, "GTK") | |
352 | verify_not_present(buf, sae_k, fname, "SAE(k)") | |
353 | verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)") | |
354 | verify_not_present(buf, sae_kck, fname, "SAE(KCK)") | |
355 | ||
356 | dev[0].request("PMKSA_FLUSH") | |
357 | logger.info("Checking keys in memory after PMKSA cache flush") | |
358 | buf = read_process_memory(pid, password) | |
359 | get_key_locations(buf, password, "Password") | |
360 | get_key_locations(buf, pmk, "PMK") | |
361 | verify_not_present(buf, pmk, fname, "PMK") | |
362 | ||
363 | dev[0].request("REMOVE_NETWORK all") | |
364 | ||
365 | logger.info("Checking keys in memory after network profile removal") | |
366 | buf = read_process_memory(pid, password) | |
367 | ||
368 | get_key_locations(buf, password, "Password") | |
369 | get_key_locations(buf, pmk, "PMK") | |
370 | verify_not_present(buf, password, fname, "password") | |
371 | verify_not_present(buf, pmk, fname, "PMK") | |
372 | verify_not_present(buf, kck, fname, "KCK") | |
373 | verify_not_present(buf, kek, fname, "KEK") | |
374 | verify_not_present(buf, tk, fname, "TK") | |
375 | verify_not_present(buf, gtk, fname, "GTK") | |
376 | verify_not_present(buf, sae_k, fname, "SAE(k)") | |
377 | verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)") | |
378 | verify_not_present(buf, sae_kck, fname, "SAE(KCK)") | |
eb6d3532 JM |
379 | |
380 | def test_sae_oom_wpas(dev, apdev): | |
381 | """SAE and OOM in wpa_supplicant""" | |
382 | if "SAE" not in dev[0].get_capability("auth_alg"): | |
383 | raise HwsimSkip("SAE not supported") | |
384 | params = hostapd.wpa2_params(ssid="test-sae", | |
385 | passphrase="12345678") | |
386 | params['wpa_key_mgmt'] = 'SAE' | |
387 | hapd = hostapd.add_ap(apdev[0]['ifname'], params) | |
388 | ||
389 | dev[0].request("SET sae_groups 25") | |
db036ed5 JM |
390 | tls = dev[0].request("GET tls_library") |
391 | if "BoringSSL" in tls: | |
392 | dev[0].request("SET sae_groups 26") | |
eb6d3532 JM |
393 | with alloc_fail(dev[0], 1, "sae_set_group"): |
394 | dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", | |
395 | scan_freq="2412") | |
396 | dev[0].request("REMOVE_NETWORK all") | |
397 | ||
398 | dev[0].request("SET sae_groups ") | |
399 | with alloc_fail(dev[0], 2, "sae_set_group"): | |
400 | dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", | |
401 | scan_freq="2412") | |
402 | dev[0].request("REMOVE_NETWORK all") | |
5527a391 JM |
403 | |
404 | def test_sae_proto_ecc(dev, apdev): | |
405 | """SAE protocol testing (ECC)""" | |
406 | if "SAE" not in dev[0].get_capability("auth_alg"): | |
407 | raise HwsimSkip("SAE not supported") | |
408 | params = hostapd.wpa2_params(ssid="test-sae", | |
409 | passphrase="12345678") | |
410 | params['wpa_key_mgmt'] = 'SAE' | |
411 | hapd = hostapd.add_ap(apdev[0]['ifname'], params) | |
412 | bssid = apdev[0]['bssid'] | |
413 | ||
414 | dev[0].request("SET sae_groups 19") | |
415 | ||
416 | tests = [ ("Confirm mismatch", | |
417 | "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8", | |
418 | "0000800edebc3f260dc1fe7e0b20888af2b8a3316252ec37388a8504e25b73dc4240"), | |
419 | ("Commit without even full cyclic group field", | |
420 | "13", | |
421 | None), | |
422 | ("Too short commit", | |
423 | "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02", | |
424 | None), | |
425 | ("Invalid commit scalar (0)", | |
426 | "1300" + "0000000000000000000000000000000000000000000000000000000000000000" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8", | |
427 | None), | |
17ce7bb9 JM |
428 | ("Invalid commit scalar (1)", |
429 | "1300" + "0000000000000000000000000000000000000000000000000000000000000001" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8", | |
430 | None), | |
5527a391 JM |
431 | ("Invalid commit scalar (> r)", |
432 | "1300" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8", | |
433 | None), | |
434 | ("Commit element not on curve", | |
435 | "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728d0000000000000000000000000000000000000000000000000000000000000000", | |
436 | None), | |
437 | ("Invalid commit element (y coordinate > P)", | |
438 | "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", | |
439 | None), | |
440 | ("Invalid commit element (x coordinate > P)", | |
441 | "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8", | |
442 | None), | |
443 | ("Different group in commit", | |
444 | "1400" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8", | |
445 | None), | |
446 | ("Too short confirm", | |
447 | "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8", | |
448 | "0000800edebc3f260dc1fe7e0b20888af2b8a3316252ec37388a8504e25b73dc42")] | |
449 | for (note, commit, confirm) in tests: | |
450 | logger.info(note) | |
451 | dev[0].scan_for_bss(bssid, freq=2412) | |
452 | hapd.set("ext_mgmt_frame_handling", "1") | |
453 | dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", | |
454 | scan_freq="2412", wait_connect=False) | |
455 | ||
456 | logger.info("Commit") | |
457 | for i in range(0, 10): | |
458 | req = hapd.mgmt_rx() | |
459 | if req is None: | |
460 | raise Exception("MGMT RX wait timed out (commit)") | |
461 | if req['subtype'] == 11: | |
462 | break | |
463 | req = None | |
464 | if not req: | |
465 | raise Exception("Authentication frame (commit) not received") | |
466 | ||
467 | hapd.dump_monitor() | |
468 | resp = {} | |
469 | resp['fc'] = req['fc'] | |
470 | resp['da'] = req['sa'] | |
471 | resp['sa'] = req['da'] | |
472 | resp['bssid'] = req['bssid'] | |
473 | resp['payload'] = binascii.unhexlify("030001000000" + commit) | |
474 | hapd.mgmt_tx(resp) | |
475 | ||
476 | if confirm: | |
477 | logger.info("Confirm") | |
478 | for i in range(0, 10): | |
479 | req = hapd.mgmt_rx() | |
480 | if req is None: | |
481 | raise Exception("MGMT RX wait timed out (confirm)") | |
482 | if req['subtype'] == 11: | |
483 | break | |
484 | req = None | |
485 | if not req: | |
486 | raise Exception("Authentication frame (confirm) not received") | |
487 | ||
488 | hapd.dump_monitor() | |
489 | resp = {} | |
490 | resp['fc'] = req['fc'] | |
491 | resp['da'] = req['sa'] | |
492 | resp['sa'] = req['da'] | |
493 | resp['bssid'] = req['bssid'] | |
494 | resp['payload'] = binascii.unhexlify("030002000000" + confirm) | |
495 | hapd.mgmt_tx(resp) | |
496 | ||
497 | time.sleep(0.1) | |
498 | dev[0].request("REMOVE_NETWORK all") | |
499 | hapd.set("ext_mgmt_frame_handling", "0") | |
500 | hapd.dump_monitor() | |
501 | ||
502 | def test_sae_proto_ffc(dev, apdev): | |
503 | """SAE protocol testing (FFC)""" | |
504 | if "SAE" not in dev[0].get_capability("auth_alg"): | |
505 | raise HwsimSkip("SAE not supported") | |
506 | params = hostapd.wpa2_params(ssid="test-sae", | |
507 | passphrase="12345678") | |
508 | params['wpa_key_mgmt'] = 'SAE' | |
509 | hapd = hostapd.add_ap(apdev[0]['ifname'], params) | |
510 | bssid = apdev[0]['bssid'] | |
511 | ||
512 | dev[0].request("SET sae_groups 2") | |
513 | ||
514 | tests = [ ("Confirm mismatch", | |
515 | "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "a8c00117493cdffa5dd671e934bc9cb1a69f39e25e9dd9cd9afd3aea2441a0f5491211c7ba50a753563f9ce943b043557cb71193b28e86ed9544f4289c471bf91b70af5c018cf4663e004165b0fd0bc1d8f3f78adf42eee92bcbc55246fd3ee9f107ab965dc7d4986f23eb71d616ebfe6bfe0a6c1ac5dc1718acee17c9a17486", | |
516 | "0000f3116a9731f1259622e3eb55d4b3b50ba16f8c5f5565b28e609b180c51460251"), | |
517 | ("Too short commit", | |
518 | "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "a8c00117493cdffa5dd671e934bc9cb1a69f39e25e9dd9cd9afd3aea2441a0f5491211c7ba50a753563f9ce943b043557cb71193b28e86ed9544f4289c471bf91b70af5c018cf4663e004165b0fd0bc1d8f3f78adf42eee92bcbc55246fd3ee9f107ab965dc7d4986f23eb71d616ebfe6bfe0a6c1ac5dc1718acee17c9a174", | |
519 | None), | |
520 | ("Invalid element (0) in commit", | |
521 | "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", | |
522 | None), | |
523 | ("Invalid element (1) in commit", | |
524 | "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", | |
525 | None), | |
526 | ("Invalid element (> P) in commit", | |
527 | "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", | |
528 | None) ] | |
529 | for (note, commit, confirm) in tests: | |
530 | logger.info(note) | |
531 | dev[0].scan_for_bss(bssid, freq=2412) | |
532 | hapd.set("ext_mgmt_frame_handling", "1") | |
533 | dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", | |
534 | scan_freq="2412", wait_connect=False) | |
535 | ||
536 | logger.info("Commit") | |
537 | for i in range(0, 10): | |
538 | req = hapd.mgmt_rx() | |
539 | if req is None: | |
540 | raise Exception("MGMT RX wait timed out (commit)") | |
541 | if req['subtype'] == 11: | |
542 | break | |
543 | req = None | |
544 | if not req: | |
545 | raise Exception("Authentication frame (commit) not received") | |
546 | ||
547 | hapd.dump_monitor() | |
548 | resp = {} | |
549 | resp['fc'] = req['fc'] | |
550 | resp['da'] = req['sa'] | |
551 | resp['sa'] = req['da'] | |
552 | resp['bssid'] = req['bssid'] | |
553 | resp['payload'] = binascii.unhexlify("030001000000" + commit) | |
554 | hapd.mgmt_tx(resp) | |
555 | ||
556 | if confirm: | |
557 | logger.info("Confirm") | |
558 | for i in range(0, 10): | |
559 | req = hapd.mgmt_rx() | |
560 | if req is None: | |
561 | raise Exception("MGMT RX wait timed out (confirm)") | |
562 | if req['subtype'] == 11: | |
563 | break | |
564 | req = None | |
565 | if not req: | |
566 | raise Exception("Authentication frame (confirm) not received") | |
567 | ||
568 | hapd.dump_monitor() | |
569 | resp = {} | |
570 | resp['fc'] = req['fc'] | |
571 | resp['da'] = req['sa'] | |
572 | resp['sa'] = req['da'] | |
573 | resp['bssid'] = req['bssid'] | |
574 | resp['payload'] = binascii.unhexlify("030002000000" + confirm) | |
575 | hapd.mgmt_tx(resp) | |
576 | ||
577 | time.sleep(0.1) | |
578 | dev[0].request("REMOVE_NETWORK all") | |
579 | hapd.set("ext_mgmt_frame_handling", "0") | |
580 | hapd.dump_monitor() | |
581 | ||
582 | def test_sae_no_ffc_by_default(dev, apdev): | |
583 | """SAE and default groups rejecting FFC""" | |
584 | if "SAE" not in dev[0].get_capability("auth_alg"): | |
585 | raise HwsimSkip("SAE not supported") | |
586 | params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678") | |
587 | params['wpa_key_mgmt'] = 'SAE' | |
588 | hapd = hostapd.add_ap(apdev[0]['ifname'], params) | |
589 | ||
590 | dev[0].request("SET sae_groups 5") | |
591 | dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412", | |
592 | wait_connect=False) | |
593 | ev = dev[0].wait_event(["SME: Trying to authenticate"], timeout=3) | |
594 | if ev is None: | |
595 | raise Exception("Did not try to authenticate") | |
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 (2)") | |
599 | dev[0].request("REMOVE_NETWORK all") | |
939527b5 JM |
600 | |
601 | def sae_reflection_attack(apdev, dev, group): | |
602 | if "SAE" not in dev.get_capability("auth_alg"): | |
603 | raise HwsimSkip("SAE not supported") | |
604 | params = hostapd.wpa2_params(ssid="test-sae", | |
605 | passphrase="no-knowledge-of-passphrase") | |
606 | params['wpa_key_mgmt'] = 'SAE' | |
607 | hapd = hostapd.add_ap(apdev['ifname'], params) | |
608 | bssid = apdev['bssid'] | |
609 | ||
610 | dev.scan_for_bss(bssid, freq=2412) | |
611 | hapd.set("ext_mgmt_frame_handling", "1") | |
612 | ||
613 | dev.request("SET sae_groups %d" % group) | |
614 | dev.connect("test-sae", psk="reflection-attack", key_mgmt="SAE", | |
615 | scan_freq="2412", wait_connect=False) | |
616 | ||
617 | # Commit | |
618 | for i in range(0, 10): | |
619 | req = hapd.mgmt_rx() | |
620 | if req is None: | |
621 | raise Exception("MGMT RX wait timed out") | |
622 | if req['subtype'] == 11: | |
623 | break | |
624 | req = None | |
625 | if not req: | |
626 | raise Exception("Authentication frame not received") | |
627 | ||
628 | resp = {} | |
629 | resp['fc'] = req['fc'] | |
630 | resp['da'] = req['sa'] | |
631 | resp['sa'] = req['da'] | |
632 | resp['bssid'] = req['bssid'] | |
633 | resp['payload'] = req['payload'] | |
634 | hapd.mgmt_tx(resp) | |
635 | ||
636 | # Confirm | |
637 | req = hapd.mgmt_rx(timeout=0.5) | |
638 | if req is not None: | |
639 | if req['subtype'] == 11: | |
640 | raise Exception("Unexpected Authentication frame seen") | |
641 | ||
642 | def test_sae_reflection_attack_ecc(dev, apdev): | |
643 | """SAE reflection attack (ECC)""" | |
644 | sae_reflection_attack(apdev[0], dev[0], 19) | |
645 | ||
646 | def test_sae_reflection_attack_ffc(dev, apdev): | |
647 | """SAE reflection attack (FFC)""" | |
648 | sae_reflection_attack(apdev[0], dev[0], 5) | |
1965e196 JM |
649 | |
650 | def test_sae_anti_clogging_proto(dev, apdev): | |
651 | """SAE anti clogging protocol testing""" | |
652 | if "SAE" not in dev[0].get_capability("auth_alg"): | |
653 | raise HwsimSkip("SAE not supported") | |
654 | params = hostapd.wpa2_params(ssid="test-sae", | |
655 | passphrase="no-knowledge-of-passphrase") | |
656 | params['wpa_key_mgmt'] = 'SAE' | |
657 | hapd = hostapd.add_ap(apdev[0]['ifname'], params) | |
658 | bssid = apdev[0]['bssid'] | |
659 | ||
660 | dev[0].scan_for_bss(bssid, freq=2412) | |
661 | hapd.set("ext_mgmt_frame_handling", "1") | |
662 | ||
663 | dev[0].request("SET sae_groups ") | |
664 | dev[0].connect("test-sae", psk="anti-cloggign", key_mgmt="SAE", | |
665 | scan_freq="2412", wait_connect=False) | |
666 | ||
667 | # Commit | |
668 | for i in range(0, 10): | |
669 | req = hapd.mgmt_rx() | |
670 | if req is None: | |
671 | raise Exception("MGMT RX wait timed out") | |
672 | if req['subtype'] == 11: | |
673 | break | |
674 | req = None | |
675 | if not req: | |
676 | raise Exception("Authentication frame not received") | |
677 | ||
678 | resp = {} | |
679 | resp['fc'] = req['fc'] | |
680 | resp['da'] = req['sa'] | |
681 | resp['sa'] = req['da'] | |
682 | resp['bssid'] = req['bssid'] | |
683 | resp['payload'] = binascii.unhexlify("030001004c00" + "ffff00") | |
684 | hapd.mgmt_tx(resp) | |
685 | ||
686 | # Confirm (not received due to DH group being rejected) | |
687 | req = hapd.mgmt_rx(timeout=0.5) | |
688 | if req is not None: | |
689 | if req['subtype'] == 11: | |
690 | raise Exception("Unexpected Authentication frame seen") | |
10ba4ae4 JM |
691 | |
692 | def test_sae_no_random(dev, apdev): | |
693 | """SAE and no random numbers available""" | |
694 | if "SAE" not in dev[0].get_capability("auth_alg"): | |
695 | raise HwsimSkip("SAE not supported") | |
696 | params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678") | |
697 | params['wpa_key_mgmt'] = 'SAE' | |
698 | hapd = hostapd.add_ap(apdev[0]['ifname'], params) | |
699 | ||
700 | dev[0].request("SET sae_groups ") | |
701 | tests = [ (1, "os_get_random;sae_get_rand"), | |
702 | (1, "os_get_random;get_rand_1_to_p_1"), | |
703 | (1, "os_get_random;get_random_qr_qnr"), | |
704 | (1, "os_get_random;sae_derive_pwe_ecc") ] | |
705 | for count, func in tests: | |
706 | with fail_test(dev[0], count, func): | |
707 | dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", | |
708 | scan_freq="2412") | |
709 | dev[0].request("REMOVE_NETWORK all") | |
710 | dev[0].wait_disconnected() |