]> git.ipfire.org Git - thirdparty/hostap.git/blob - tests/hwsim/test_ap_psk.py
tests: Verify that wpa_supplicant clears keys from memory
[thirdparty/hostap.git] / tests / hwsim / test_ap_psk.py
1 # WPA2-Personal tests
2 # Copyright (c) 2014, Qualcomm Atheros, Inc.
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 hashlib
9 import hmac
10 import logging
11 logger = logging.getLogger()
12 import os
13 import re
14 import struct
15 import subprocess
16 import time
17
18 import hostapd
19 import hwsim_utils
20
21 def check_mib(dev, vals):
22 mib = dev.get_mib()
23 for v in vals:
24 if mib[v[0]] != v[1]:
25 raise Exception("Unexpected {} = {} (expected {})".format(v[0], mib[v[0]], v[1]))
26
27 def test_ap_wpa2_psk(dev, apdev):
28 """WPA2-PSK AP with PSK instead of passphrase"""
29 ssid = "test-wpa2-psk"
30 passphrase = 'qwertyuiop'
31 psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
32 params = hostapd.wpa2_params(ssid=ssid)
33 params['wpa_psk'] = psk
34 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
35 key_mgmt = hapd.get_config()['key_mgmt']
36 if key_mgmt.split(' ')[0] != "WPA-PSK":
37 raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
38 dev[0].connect(ssid, raw_psk=psk, scan_freq="2412")
39 dev[1].connect(ssid, psk=passphrase, scan_freq="2412")
40
41 sig = dev[0].request("SIGNAL_POLL").splitlines()
42 pkt = dev[0].request("PKTCNT_POLL").splitlines()
43 if "FREQUENCY=2412" not in sig:
44 raise Exception("Unexpected SIGNAL_POLL value: " + str(sig))
45 if "TXBAD=0" not in pkt:
46 raise Exception("Unexpected TXBAD value: " + str(pkt))
47
48 def test_ap_wpa2_psk_file(dev, apdev):
49 """WPA2-PSK AP with PSK from a file"""
50 ssid = "test-wpa2-psk"
51 passphrase = 'qwertyuiop'
52 psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
53 params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
54 params['wpa_psk_file'] = 'hostapd.wpa_psk'
55 hostapd.add_ap(apdev[0]['ifname'], params)
56 dev[1].connect(ssid, psk="very secret", scan_freq="2412", wait_connect=False)
57 dev[2].connect(ssid, raw_psk=psk, scan_freq="2412")
58 dev[2].request("REMOVE_NETWORK all")
59 dev[0].connect(ssid, psk="very secret", scan_freq="2412")
60 dev[0].request("REMOVE_NETWORK all")
61 dev[2].connect(ssid, psk="another passphrase for all STAs", scan_freq="2412")
62 dev[0].connect(ssid, psk="another passphrase for all STAs", scan_freq="2412")
63 ev = dev[1].wait_event(["WPA: 4-Way Handshake failed"], timeout=10)
64 if ev is None:
65 raise Exception("Timed out while waiting for failure report")
66 dev[1].request("REMOVE_NETWORK all")
67
68 def test_ap_wpa2_ptk_rekey(dev, apdev):
69 """WPA2-PSK AP and PTK rekey enforced by station"""
70 ssid = "test-wpa2-psk"
71 passphrase = 'qwertyuiop'
72 params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
73 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
74 dev[0].connect(ssid, psk=passphrase, wpa_ptk_rekey="1", scan_freq="2412")
75 ev = dev[0].wait_event(["WPA: Key negotiation completed"])
76 if ev is None:
77 raise Exception("PTK rekey timed out")
78 hwsim_utils.test_connectivity(dev[0], hapd)
79
80 def test_ap_wpa2_ptk_rekey_ap(dev, apdev):
81 """WPA2-PSK AP and PTK rekey enforced by AP"""
82 ssid = "test-wpa2-psk"
83 passphrase = 'qwertyuiop'
84 params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
85 params['wpa_ptk_rekey'] = '2'
86 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
87 dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
88 ev = dev[0].wait_event(["WPA: Key negotiation completed"])
89 if ev is None:
90 raise Exception("PTK rekey timed out")
91 hwsim_utils.test_connectivity(dev[0], hapd)
92
93 def test_ap_wpa2_sha256_ptk_rekey(dev, apdev):
94 """WPA2-PSK/SHA256 AKM AP and PTK rekey enforced by station"""
95 ssid = "test-wpa2-psk"
96 passphrase = 'qwertyuiop'
97 params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
98 params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
99 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
100 dev[0].connect(ssid, psk=passphrase, key_mgmt="WPA-PSK-SHA256",
101 wpa_ptk_rekey="1", scan_freq="2412")
102 ev = dev[0].wait_event(["WPA: Key negotiation completed"])
103 if ev is None:
104 raise Exception("PTK rekey timed out")
105 hwsim_utils.test_connectivity(dev[0], hapd)
106 check_mib(dev[0], [ ("dot11RSNAAuthenticationSuiteRequested", "00-0f-ac-6"),
107 ("dot11RSNAAuthenticationSuiteSelected", "00-0f-ac-6") ])
108
109 def test_ap_wpa2_sha256_ptk_rekey_ap(dev, apdev):
110 """WPA2-PSK/SHA256 AKM AP and PTK rekey enforced by AP"""
111 ssid = "test-wpa2-psk"
112 passphrase = 'qwertyuiop'
113 params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
114 params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
115 params['wpa_ptk_rekey'] = '2'
116 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
117 dev[0].connect(ssid, psk=passphrase, key_mgmt="WPA-PSK-SHA256",
118 scan_freq="2412")
119 ev = dev[0].wait_event(["WPA: Key negotiation completed"])
120 if ev is None:
121 raise Exception("PTK rekey timed out")
122 hwsim_utils.test_connectivity(dev[0], hapd)
123 check_mib(dev[0], [ ("dot11RSNAAuthenticationSuiteRequested", "00-0f-ac-6"),
124 ("dot11RSNAAuthenticationSuiteSelected", "00-0f-ac-6") ])
125
126 def test_ap_wpa_ptk_rekey(dev, apdev):
127 """WPA-PSK/TKIP AP and PTK rekey enforced by station"""
128 ssid = "test-wpa-psk"
129 passphrase = 'qwertyuiop'
130 params = hostapd.wpa_params(ssid=ssid, passphrase=passphrase)
131 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
132 dev[0].connect(ssid, psk=passphrase, wpa_ptk_rekey="1", scan_freq="2412")
133 if "[WPA-PSK-TKIP]" not in dev[0].request("SCAN_RESULTS"):
134 raise Exception("Scan results missing WPA element info")
135 ev = dev[0].wait_event(["WPA: Key negotiation completed"])
136 if ev is None:
137 raise Exception("PTK rekey timed out")
138 hwsim_utils.test_connectivity(dev[0], hapd)
139
140 def test_ap_wpa_ptk_rekey_ap(dev, apdev):
141 """WPA-PSK/TKIP AP and PTK rekey enforced by AP"""
142 ssid = "test-wpa-psk"
143 passphrase = 'qwertyuiop'
144 params = hostapd.wpa_params(ssid=ssid, passphrase=passphrase)
145 params['wpa_ptk_rekey'] = '2'
146 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
147 dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
148 ev = dev[0].wait_event(["WPA: Key negotiation completed"], timeout=10)
149 if ev is None:
150 raise Exception("PTK rekey timed out")
151 hwsim_utils.test_connectivity(dev[0], hapd)
152
153 def test_ap_wpa_ccmp(dev, apdev):
154 """WPA-PSK/CCMP"""
155 ssid = "test-wpa-psk"
156 passphrase = 'qwertyuiop'
157 params = hostapd.wpa_params(ssid=ssid, passphrase=passphrase)
158 params['wpa_pairwise'] = "CCMP"
159 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
160 dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
161 hwsim_utils.test_connectivity(dev[0], hapd)
162 check_mib(dev[0], [ ("dot11RSNAConfigGroupCipherSize", "128"),
163 ("dot11RSNAGroupCipherRequested", "00-50-f2-4"),
164 ("dot11RSNAPairwiseCipherRequested", "00-50-f2-4"),
165 ("dot11RSNAAuthenticationSuiteRequested", "00-50-f2-2"),
166 ("dot11RSNAGroupCipherSelected", "00-50-f2-4"),
167 ("dot11RSNAPairwiseCipherSelected", "00-50-f2-4"),
168 ("dot11RSNAAuthenticationSuiteSelected", "00-50-f2-2"),
169 ("dot1xSuppSuppControlledPortStatus", "Authorized") ])
170
171 def test_ap_wpa2_psk_file(dev, apdev):
172 """WPA2-PSK AP with various PSK file error and success cases"""
173 addr0 = dev[0].p2p_dev_addr()
174 addr1 = dev[1].p2p_dev_addr()
175 addr2 = dev[2].p2p_dev_addr()
176 ssid = "psk"
177 pskfile = "/tmp/ap_wpa2_psk_file_errors.psk_file"
178 try:
179 os.remove(pskfile)
180 except:
181 pass
182
183 params = { "ssid": ssid, "wpa": "2", "wpa_key_mgmt": "WPA-PSK",
184 "rsn_pairwise": "CCMP", "wpa_psk_file": pskfile }
185
186 try:
187 # missing PSK file
188 hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
189 if "FAIL" not in hapd.request("ENABLE"):
190 raise Exception("Unexpected ENABLE success")
191 hapd.request("DISABLE")
192
193 # invalid MAC address
194 with open(pskfile, "w") as f:
195 f.write("\n")
196 f.write("foo\n")
197 if "FAIL" not in hapd.request("ENABLE"):
198 raise Exception("Unexpected ENABLE success")
199 hapd.request("DISABLE")
200
201 # no PSK on line
202 with open(pskfile, "w") as f:
203 f.write("00:11:22:33:44:55\n")
204 if "FAIL" not in hapd.request("ENABLE"):
205 raise Exception("Unexpected ENABLE success")
206 hapd.request("DISABLE")
207
208 # invalid PSK
209 with open(pskfile, "w") as f:
210 f.write("00:11:22:33:44:55 1234567\n")
211 if "FAIL" not in hapd.request("ENABLE"):
212 raise Exception("Unexpected ENABLE success")
213 hapd.request("DISABLE")
214
215 # valid PSK file
216 with open(pskfile, "w") as f:
217 f.write("00:11:22:33:44:55 12345678\n")
218 f.write(addr0 + " 123456789\n")
219 f.write(addr1 + " 123456789a\n")
220 f.write(addr2 + " 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n")
221 if "FAIL" in hapd.request("ENABLE"):
222 raise Exception("Unexpected ENABLE failure")
223
224 dev[0].connect(ssid, psk="123456789", scan_freq="2412")
225 dev[1].connect(ssid, psk="123456789a", scan_freq="2412")
226 dev[2].connect(ssid, raw_psk="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", scan_freq="2412")
227
228 finally:
229 try:
230 os.remove(pskfile)
231 except:
232 pass
233
234 def test_ap_wpa2_psk_wildcard_ssid(dev, apdev):
235 """WPA2-PSK AP and wildcard SSID configuration"""
236 ssid = "test-wpa2-psk"
237 passphrase = 'qwertyuiop'
238 psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
239 params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
240 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
241 dev[0].connect("", bssid=apdev[0]['bssid'], psk=passphrase,
242 scan_freq="2412")
243 dev[1].connect("", bssid=apdev[0]['bssid'], raw_psk=psk, scan_freq="2412")
244
245 def test_ap_wpa2_gtk_rekey(dev, apdev):
246 """WPA2-PSK AP and GTK rekey enforced by AP"""
247 ssid = "test-wpa2-psk"
248 passphrase = 'qwertyuiop'
249 params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
250 params['wpa_group_rekey'] = '1'
251 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
252 dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
253 ev = dev[0].wait_event(["WPA: Group rekeying completed"], timeout=2)
254 if ev is None:
255 raise Exception("GTK rekey timed out")
256 hwsim_utils.test_connectivity(dev[0], hapd)
257
258 def test_ap_wpa_gtk_rekey(dev, apdev):
259 """WPA-PSK/TKIP AP and GTK rekey enforced by AP"""
260 ssid = "test-wpa-psk"
261 passphrase = 'qwertyuiop'
262 params = hostapd.wpa_params(ssid=ssid, passphrase=passphrase)
263 params['wpa_group_rekey'] = '1'
264 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
265 dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
266 ev = dev[0].wait_event(["WPA: Group rekeying completed"], timeout=2)
267 if ev is None:
268 raise Exception("GTK rekey timed out")
269 hwsim_utils.test_connectivity(dev[0], hapd)
270
271 def test_ap_wpa2_gmk_rekey(dev, apdev):
272 """WPA2-PSK AP and GMK and GTK rekey enforced by AP"""
273 ssid = "test-wpa2-psk"
274 passphrase = 'qwertyuiop'
275 params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
276 params['wpa_group_rekey'] = '1'
277 params['wpa_gmk_rekey'] = '2'
278 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
279 dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
280 for i in range(0, 3):
281 ev = dev[0].wait_event(["WPA: Group rekeying completed"], timeout=2)
282 if ev is None:
283 raise Exception("GTK rekey timed out")
284 hwsim_utils.test_connectivity(dev[0], hapd)
285
286 def test_ap_wpa2_strict_rekey(dev, apdev):
287 """WPA2-PSK AP and strict GTK rekey enforced by AP"""
288 ssid = "test-wpa2-psk"
289 passphrase = 'qwertyuiop'
290 params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
291 params['wpa_strict_rekey'] = '1'
292 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
293 dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
294 dev[1].connect(ssid, psk=passphrase, scan_freq="2412")
295 dev[1].request("DISCONNECT")
296 ev = dev[0].wait_event(["WPA: Group rekeying completed"], timeout=2)
297 if ev is None:
298 raise Exception("GTK rekey timed out")
299 hwsim_utils.test_connectivity(dev[0], hapd)
300
301 def test_ap_wpa2_bridge_fdb(dev, apdev):
302 """Bridge FDB entry removal"""
303 try:
304 ssid = "test-wpa2-psk"
305 passphrase = "12345678"
306 params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
307 params['bridge'] = 'ap-br0'
308 hostapd.add_ap(apdev[0]['ifname'], params)
309 subprocess.call(['sudo', 'brctl', 'setfd', 'ap-br0', '0'])
310 subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
311 dev[0].connect(ssid, psk=passphrase, scan_freq="2412",
312 bssid=apdev[0]['bssid'])
313 dev[1].connect(ssid, psk=passphrase, scan_freq="2412",
314 bssid=apdev[0]['bssid'])
315 addr0 = dev[0].p2p_interface_addr()
316 hwsim_utils.test_connectivity_sta(dev[0], dev[1])
317 cmd = subprocess.Popen(['brctl', 'showmacs', 'ap-br0'],
318 stdout=subprocess.PIPE)
319 macs1 = cmd.stdout.read()
320 dev[0].request("DISCONNECT")
321 dev[1].request("DISCONNECT")
322 time.sleep(1)
323 cmd = subprocess.Popen(['brctl', 'showmacs', 'ap-br0'],
324 stdout=subprocess.PIPE)
325 macs2 = cmd.stdout.read()
326
327 addr1 = dev[1].p2p_interface_addr()
328 if addr0 not in macs1 or addr1 not in macs1:
329 raise Exception("Bridge FDB entry missing")
330 if addr0 in macs2 or addr1 in macs2:
331 raise Exception("Bridge FDB entry was not removed")
332 finally:
333 subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
334 subprocess.call(['sudo', 'brctl', 'delbr', 'ap-br0'])
335
336 def test_ap_wpa2_already_in_bridge(dev, apdev):
337 """hostapd behavior with interface already in bridge"""
338 ifname = apdev[0]['ifname']
339 br_ifname = 'ext-ap-br0'
340 try:
341 ssid = "test-wpa2-psk"
342 passphrase = "12345678"
343 subprocess.call(['brctl', 'addbr', br_ifname])
344 subprocess.call(['brctl', 'setfd', br_ifname, '0'])
345 subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'up'])
346 subprocess.call(['iw', ifname, 'set', 'type', '__ap'])
347 subprocess.call(['brctl', 'addif', br_ifname, ifname])
348 params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
349 hapd = hostapd.add_ap(ifname, params)
350 if hapd.get_driver_status_field('brname') != br_ifname:
351 raise Exception("Bridge name not identified correctly")
352 dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
353 finally:
354 subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'down'])
355 subprocess.call(['brctl', 'delif', br_ifname, ifname])
356 subprocess.call(['iw', ifname, 'set', 'type', 'station'])
357 subprocess.call(['brctl', 'delbr', br_ifname])
358
359 def test_ap_wpa2_in_different_bridge(dev, apdev):
360 """hostapd behavior with interface in different bridge"""
361 ifname = apdev[0]['ifname']
362 br_ifname = 'ext-ap-br0'
363 try:
364 ssid = "test-wpa2-psk"
365 passphrase = "12345678"
366 subprocess.call(['brctl', 'addbr', br_ifname])
367 subprocess.call(['brctl', 'setfd', br_ifname, '0'])
368 subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'up'])
369 subprocess.call(['iw', ifname, 'set', 'type', '__ap'])
370 subprocess.call(['brctl', 'addif', br_ifname, ifname])
371 time.sleep(0.5)
372 params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
373 params['bridge'] = 'ap-br0'
374 hapd = hostapd.add_ap(ifname, params)
375 subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
376 subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
377 brname = hapd.get_driver_status_field('brname')
378 if brname != 'ap-br0':
379 raise Exception("Incorrect bridge: " + brname)
380 dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
381 hwsim_utils.test_connectivity_iface(dev[0], hapd, "ap-br0")
382 if hapd.get_driver_status_field("added_bridge") != "1":
383 raise Exception("Unexpected added_bridge value")
384 if hapd.get_driver_status_field("added_if_into_bridge") != "1":
385 raise Exception("Unexpected added_if_into_bridge value")
386 dev[0].request("DISCONNECT")
387 hapd.disable()
388 finally:
389 subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'down'])
390 subprocess.call(['brctl', 'delif', br_ifname, ifname],
391 stderr=open('/dev/null', 'w'))
392 subprocess.call(['brctl', 'delbr', br_ifname])
393
394 def test_ap_wpa2_ext_add_to_bridge(dev, apdev):
395 """hostapd behavior with interface added to bridge externally"""
396 ifname = apdev[0]['ifname']
397 br_ifname = 'ext-ap-br0'
398 try:
399 ssid = "test-wpa2-psk"
400 passphrase = "12345678"
401 params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
402 hapd = hostapd.add_ap(ifname, params)
403
404 subprocess.call(['brctl', 'addbr', br_ifname])
405 subprocess.call(['brctl', 'setfd', br_ifname, '0'])
406 subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'up'])
407 subprocess.call(['brctl', 'addif', br_ifname, ifname])
408 dev[0].connect(ssid, psk=passphrase, scan_freq="2412")
409 if hapd.get_driver_status_field('brname') != br_ifname:
410 raise Exception("Bridge name not identified correctly")
411 finally:
412 subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'down'])
413 subprocess.call(['brctl', 'delif', br_ifname, ifname])
414 subprocess.call(['brctl', 'delbr', br_ifname])
415
416 def test_ap_wpa2_psk_ext(dev, apdev):
417 """WPA2-PSK AP using external EAPOL I/O"""
418 bssid = apdev[0]['bssid']
419 ssid = "test-wpa2-psk"
420 passphrase = 'qwertyuiop'
421 psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
422 params = hostapd.wpa2_params(ssid=ssid)
423 params['wpa_psk'] = psk
424 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
425 hapd.request("SET ext_eapol_frame_io 1")
426 dev[0].request("SET ext_eapol_frame_io 1")
427 dev[0].connect(ssid, psk=passphrase, scan_freq="2412", wait_connect=False)
428 addr = dev[0].p2p_interface_addr()
429 while True:
430 ev = hapd.wait_event(["EAPOL-TX", "AP-STA-CONNECTED"], timeout=15)
431 if ev is None:
432 raise Exception("Timeout on EAPOL-TX from hostapd")
433 if "AP-STA-CONNECTED" in ev:
434 dev[0].wait_connected(timeout=15)
435 break
436 res = dev[0].request("EAPOL_RX " + bssid + " " + ev.split(' ')[2])
437 if "OK" not in res:
438 raise Exception("EAPOL_RX to wpa_supplicant failed")
439 ev = dev[0].wait_event(["EAPOL-TX", "CTRL-EVENT-CONNECTED"], timeout=15)
440 if ev is None:
441 raise Exception("Timeout on EAPOL-TX from wpa_supplicant")
442 if "CTRL-EVENT-CONNECTED" in ev:
443 break
444 res = hapd.request("EAPOL_RX " + addr + " " + ev.split(' ')[2])
445 if "OK" not in res:
446 raise Exception("EAPOL_RX to hostapd failed")
447
448 def parse_eapol(data):
449 (version, type, length) = struct.unpack('>BBH', data[0:4])
450 payload = data[4:]
451 if length > len(payload):
452 raise Exception("Invalid EAPOL length")
453 if length < len(payload):
454 payload = payload[0:length]
455 eapol = {}
456 eapol['version'] = version
457 eapol['type'] = type
458 eapol['length'] = length
459 eapol['payload'] = payload
460 if type == 3:
461 # EAPOL-Key
462 (eapol['descr_type'],) = struct.unpack('B', payload[0:1])
463 payload = payload[1:]
464 if eapol['descr_type'] == 2 or eapol['descr_type'] == 254:
465 # RSN EAPOL-Key
466 (key_info, key_len) = struct.unpack('>HH', payload[0:4])
467 eapol['rsn_key_info'] = key_info
468 eapol['rsn_key_len'] = key_len
469 eapol['rsn_replay_counter'] = payload[4:12]
470 eapol['rsn_key_nonce'] = payload[12:44]
471 eapol['rsn_key_iv'] = payload[44:60]
472 eapol['rsn_key_rsc'] = payload[60:68]
473 eapol['rsn_key_id'] = payload[68:76]
474 eapol['rsn_key_mic'] = payload[76:92]
475 payload = payload[92:]
476 (eapol['rsn_key_data_len'],) = struct.unpack('>H', payload[0:2])
477 payload = payload[2:]
478 eapol['rsn_key_data'] = payload
479 return eapol
480
481 def build_eapol(msg):
482 data = struct.pack(">BBH", msg['version'], msg['type'], msg['length'])
483 if msg['type'] == 3:
484 data += struct.pack('>BHH', msg['descr_type'], msg['rsn_key_info'],
485 msg['rsn_key_len'])
486 data += msg['rsn_replay_counter']
487 data += msg['rsn_key_nonce']
488 data += msg['rsn_key_iv']
489 data += msg['rsn_key_rsc']
490 data += msg['rsn_key_id']
491 data += msg['rsn_key_mic']
492 data += struct.pack('>H', msg['rsn_key_data_len'])
493 data += msg['rsn_key_data']
494 else:
495 data += msg['payload']
496 return data
497
498 def sha1_prf(key, label, data, outlen):
499 res = ''
500 counter = 0
501 while outlen > 0:
502 m = hmac.new(key, label, hashlib.sha1)
503 m.update(struct.pack('B', 0))
504 m.update(data)
505 m.update(struct.pack('B', counter))
506 counter += 1
507 hash = m.digest()
508 if outlen > len(hash):
509 res += hash
510 outlen -= len(hash)
511 else:
512 res += hash[0:outlen]
513 outlen = 0
514 return res
515
516 def pmk_to_ptk(pmk, addr1, addr2, nonce1, nonce2):
517 if addr1 < addr2:
518 data = binascii.unhexlify(addr1.replace(':','')) + binascii.unhexlify(addr2.replace(':',''))
519 else:
520 data = binascii.unhexlify(addr2.replace(':','')) + binascii.unhexlify(addr1.replace(':',''))
521 if nonce1 < nonce2:
522 data += nonce1 + nonce2
523 else:
524 data += nonce2 + nonce1
525 label = "Pairwise key expansion"
526 ptk = sha1_prf(pmk, label, data, 48)
527 kck = ptk[0:16]
528 kek = ptk[16:32]
529 return (ptk, kck, kek)
530
531 def eapol_key_mic(kck, msg):
532 msg['rsn_key_mic'] = binascii.unhexlify('00000000000000000000000000000000')
533 data = build_eapol(msg)
534 m = hmac.new(kck, data, hashlib.sha1)
535 msg['rsn_key_mic'] = m.digest()[0:16]
536
537 def rsn_eapol_key_set(msg, key_info, key_len, nonce, data):
538 msg['rsn_key_info'] = key_info
539 msg['rsn_key_len'] = key_len
540 if nonce:
541 msg['rsn_key_nonce'] = nonce
542 else:
543 msg['rsn_key_nonce'] = binascii.unhexlify('0000000000000000000000000000000000000000000000000000000000000000')
544 if data:
545 msg['rsn_key_data_len'] = len(data)
546 msg['rsn_key_data'] = data
547 msg['length'] = 95 + len(data)
548 else:
549 msg['rsn_key_data_len'] = 0
550 msg['rsn_key_data'] = ''
551 msg['length'] = 95
552
553 def recv_eapol(hapd):
554 ev = hapd.wait_event(["EAPOL-TX"], timeout=15)
555 if ev is None:
556 raise Exception("Timeout on EAPOL-TX from hostapd")
557 eapol = binascii.unhexlify(ev.split(' ')[2])
558 return parse_eapol(eapol)
559
560 def send_eapol(hapd, addr, data):
561 res = hapd.request("EAPOL_RX " + addr + " " + binascii.hexlify(data))
562 if "OK" not in res:
563 raise Exception("EAPOL_RX to hostapd failed")
564
565 def reply_eapol(info, hapd, addr, msg, key_info, nonce, data, kck):
566 logger.info("Send EAPOL-Key msg " + info)
567 rsn_eapol_key_set(msg, key_info, 0, nonce, data)
568 eapol_key_mic(kck, msg)
569 send_eapol(hapd, addr, build_eapol(msg))
570
571 def hapd_connected(hapd):
572 ev = hapd.wait_event(["AP-STA-CONNECTED"], timeout=15)
573 if ev is None:
574 raise Exception("Timeout on AP-STA-CONNECTED from hostapd")
575
576 def eapol_test(apdev, dev, wpa2=True):
577 bssid = apdev['bssid']
578 if wpa2:
579 ssid = "test-wpa2-psk"
580 else:
581 ssid = "test-wpa-psk"
582 psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
583 pmk = binascii.unhexlify(psk)
584 if wpa2:
585 params = hostapd.wpa2_params(ssid=ssid)
586 else:
587 params = hostapd.wpa_params(ssid=ssid)
588 params['wpa_psk'] = psk
589 hapd = hostapd.add_ap(apdev['ifname'], params)
590 hapd.request("SET ext_eapol_frame_io 1")
591 dev.request("SET ext_eapol_frame_io 1")
592 dev.connect(ssid, psk="not used", scan_freq="2412", wait_connect=False)
593 addr = dev.p2p_interface_addr()
594 if wpa2:
595 rsne = binascii.unhexlify('30140100000fac040100000fac040100000fac020000')
596 else:
597 rsne = binascii.unhexlify('dd160050f20101000050f20201000050f20201000050f202')
598 snonce = binascii.unhexlify('1111111111111111111111111111111111111111111111111111111111111111')
599 return (bssid,ssid,hapd,snonce,pmk,addr,rsne)
600
601 def test_ap_wpa2_psk_ext_eapol(dev, apdev):
602 """WPA2-PSK AP using external EAPOL supplicant"""
603 (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
604
605 msg = recv_eapol(hapd)
606 anonce = msg['rsn_key_nonce']
607 logger.info("Replay same data back")
608 send_eapol(hapd, addr, build_eapol(msg))
609
610 (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
611
612 logger.info("Truncated Key Data in EAPOL-Key msg 2/4")
613 rsn_eapol_key_set(msg, 0x0101, 0, snonce, rsne)
614 msg['length'] = 95 + 22 - 1
615 send_eapol(hapd, addr, build_eapol(msg))
616
617 reply_eapol("2/4", hapd, addr, msg, 0x010a, snonce, rsne, kck)
618
619 msg = recv_eapol(hapd)
620 if anonce != msg['rsn_key_nonce']:
621 raise Exception("ANonce changed")
622 logger.info("Replay same data back")
623 send_eapol(hapd, addr, build_eapol(msg))
624
625 reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
626 hapd_connected(hapd)
627
628 def test_ap_wpa2_psk_ext_eapol_retry1(dev, apdev):
629 """WPA2 4-way handshake with EAPOL-Key 1/4 retransmitted"""
630 (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
631
632 msg1 = recv_eapol(hapd)
633 anonce = msg1['rsn_key_nonce']
634
635 msg2 = recv_eapol(hapd)
636 if anonce != msg2['rsn_key_nonce']:
637 raise Exception("ANonce changed")
638
639 (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
640
641 logger.info("Send EAPOL-Key msg 2/4")
642 msg = msg2
643 rsn_eapol_key_set(msg, 0x010a, 0, snonce, rsne)
644 eapol_key_mic(kck, msg)
645 send_eapol(hapd, addr, build_eapol(msg))
646
647 msg = recv_eapol(hapd)
648 if anonce != msg['rsn_key_nonce']:
649 raise Exception("ANonce changed")
650
651 reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
652 hapd_connected(hapd)
653
654 def test_ap_wpa2_psk_ext_eapol_retry1b(dev, apdev):
655 """WPA2 4-way handshake with EAPOL-Key 1/4 and 2/4 retransmitted"""
656 (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
657
658 msg1 = recv_eapol(hapd)
659 anonce = msg1['rsn_key_nonce']
660 msg2 = recv_eapol(hapd)
661 if anonce != msg2['rsn_key_nonce']:
662 raise Exception("ANonce changed")
663
664 (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
665 reply_eapol("2/4 (a)", hapd, addr, msg1, 0x010a, snonce, rsne, kck)
666 reply_eapol("2/4 (b)", hapd, addr, msg2, 0x010a, snonce, rsne, kck)
667
668 msg = recv_eapol(hapd)
669 if anonce != msg['rsn_key_nonce']:
670 raise Exception("ANonce changed")
671
672 reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
673 hapd_connected(hapd)
674
675 def test_ap_wpa2_psk_ext_eapol_retry1c(dev, apdev):
676 """WPA2 4-way handshake with EAPOL-Key 1/4 and 2/4 retransmitted and SNonce changing"""
677 (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
678
679 msg1 = recv_eapol(hapd)
680 anonce = msg1['rsn_key_nonce']
681
682 msg2 = recv_eapol(hapd)
683 if anonce != msg2['rsn_key_nonce']:
684 raise Exception("ANonce changed")
685 (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
686 reply_eapol("2/4 (a)", hapd, addr, msg1, 0x010a, snonce, rsne, kck)
687
688 snonce2 = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
689 (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce2, anonce)
690 reply_eapol("2/4 (b)", hapd, addr, msg2, 0x010a, snonce2, rsne, kck)
691
692 msg = recv_eapol(hapd)
693 if anonce != msg['rsn_key_nonce']:
694 raise Exception("ANonce changed")
695 reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
696 hapd_connected(hapd)
697
698 def test_ap_wpa2_psk_ext_eapol_retry1d(dev, apdev):
699 """WPA2 4-way handshake with EAPOL-Key 1/4 and 2/4 retransmitted and SNonce changing and older used"""
700 (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
701
702 msg1 = recv_eapol(hapd)
703 anonce = msg1['rsn_key_nonce']
704 msg2 = recv_eapol(hapd)
705 if anonce != msg2['rsn_key_nonce']:
706 raise Exception("ANonce changed")
707
708 (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
709 reply_eapol("2/4 (a)", hapd, addr, msg1, 0x010a, snonce, rsne, kck)
710
711 snonce2 = binascii.unhexlify('2222222222222222222222222222222222222222222222222222222222222222')
712 (ptk2, kck2, kek2) = pmk_to_ptk(pmk, addr, bssid, snonce2, anonce)
713
714 reply_eapol("2/4 (b)", hapd, addr, msg2, 0x010a, snonce2, rsne, kck2)
715 msg = recv_eapol(hapd)
716 if anonce != msg['rsn_key_nonce']:
717 raise Exception("ANonce changed")
718 reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
719 hapd_connected(hapd)
720
721 def test_ap_wpa2_psk_ext_eapol_type_diff(dev, apdev):
722 """WPA2 4-way handshake using external EAPOL supplicant"""
723 (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
724
725 msg = recv_eapol(hapd)
726 anonce = msg['rsn_key_nonce']
727
728 (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
729
730 # Incorrect descriptor type (frame dropped)
731 msg['descr_type'] = 253
732 rsn_eapol_key_set(msg, 0x010a, 0, snonce, rsne)
733 eapol_key_mic(kck, msg)
734 send_eapol(hapd, addr, build_eapol(msg))
735
736 # Incorrect descriptor type, but with a workaround (frame processed)
737 msg['descr_type'] = 254
738 rsn_eapol_key_set(msg, 0x010a, 0, snonce, rsne)
739 eapol_key_mic(kck, msg)
740 send_eapol(hapd, addr, build_eapol(msg))
741
742 msg = recv_eapol(hapd)
743 if anonce != msg['rsn_key_nonce']:
744 raise Exception("ANonce changed")
745 logger.info("Replay same data back")
746 send_eapol(hapd, addr, build_eapol(msg))
747
748 reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
749 hapd_connected(hapd)
750
751 def test_ap_wpa_psk_ext_eapol(dev, apdev):
752 """WPA2-PSK AP using external EAPOL supplicant"""
753 (bssid,ssid,hapd,snonce,pmk,addr,wpae) = eapol_test(apdev[0], dev[0],
754 wpa2=False)
755
756 msg = recv_eapol(hapd)
757 anonce = msg['rsn_key_nonce']
758 logger.info("Replay same data back")
759 send_eapol(hapd, addr, build_eapol(msg))
760 logger.info("Too short data")
761 send_eapol(hapd, addr, build_eapol(msg)[0:98])
762
763 (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
764 msg['descr_type'] = 2
765 reply_eapol("2/4(invalid type)", hapd, addr, msg, 0x010a, snonce, wpae, kck)
766 msg['descr_type'] = 254
767 reply_eapol("2/4", hapd, addr, msg, 0x010a, snonce, wpae, kck)
768
769 msg = recv_eapol(hapd)
770 if anonce != msg['rsn_key_nonce']:
771 raise Exception("ANonce changed")
772 logger.info("Replay same data back")
773 send_eapol(hapd, addr, build_eapol(msg))
774
775 reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
776 hapd_connected(hapd)
777
778 def test_ap_wpa2_psk_ext_eapol_key_info(dev, apdev):
779 """WPA2-PSK 4-way handshake with strange key info values"""
780 (bssid,ssid,hapd,snonce,pmk,addr,rsne) = eapol_test(apdev[0], dev[0])
781
782 msg = recv_eapol(hapd)
783 anonce = msg['rsn_key_nonce']
784
785 (ptk, kck, kek) = pmk_to_ptk(pmk, addr, bssid, snonce, anonce)
786 rsn_eapol_key_set(msg, 0x0000, 0, snonce, rsne)
787 send_eapol(hapd, addr, build_eapol(msg))
788 rsn_eapol_key_set(msg, 0xffff, 0, snonce, rsne)
789 send_eapol(hapd, addr, build_eapol(msg))
790 # SMK M1
791 rsn_eapol_key_set(msg, 0x2802, 0, snonce, rsne)
792 send_eapol(hapd, addr, build_eapol(msg))
793 # SMK M3
794 rsn_eapol_key_set(msg, 0x2002, 0, snonce, rsne)
795 send_eapol(hapd, addr, build_eapol(msg))
796 # Request
797 rsn_eapol_key_set(msg, 0x0902, 0, snonce, rsne)
798 send_eapol(hapd, addr, build_eapol(msg))
799 # Request
800 rsn_eapol_key_set(msg, 0x0902, 0, snonce, rsne)
801 tmp_kck = binascii.unhexlify('00000000000000000000000000000000')
802 eapol_key_mic(tmp_kck, msg)
803 send_eapol(hapd, addr, build_eapol(msg))
804
805 reply_eapol("2/4", hapd, addr, msg, 0x010a, snonce, rsne, kck)
806
807 msg = recv_eapol(hapd)
808 if anonce != msg['rsn_key_nonce']:
809 raise Exception("ANonce changed")
810
811 # Request (valic MIC)
812 rsn_eapol_key_set(msg, 0x0902, 0, snonce, rsne)
813 eapol_key_mic(kck, msg)
814 send_eapol(hapd, addr, build_eapol(msg))
815 # Request (valid MIC, replayed counter)
816 rsn_eapol_key_set(msg, 0x0902, 0, snonce, rsne)
817 eapol_key_mic(kck, msg)
818 send_eapol(hapd, addr, build_eapol(msg))
819
820 reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
821 hapd_connected(hapd)
822
823 def find_wpas_process(dev):
824 ifname = dev.ifname
825 cmd = subprocess.Popen(['ps', 'ax'], stdout=subprocess.PIPE)
826 (data,err) = cmd.communicate()
827 for l in data.splitlines():
828 if "wpa_supplicant" not in l:
829 continue
830 if "-i" + ifname not in l:
831 continue
832 return int(l.strip().split(' ')[0])
833 raise Exception("Could not find wpa_supplicant process")
834
835 def read_process_memory(pid, key=None):
836 buf = bytes()
837 with open('/proc/%d/maps' % pid, 'r') as maps, \
838 open('/proc/%d/mem' % pid, 'r') as mem:
839 for l in maps.readlines():
840 m = re.match(r'([0-9a-f]+)-([0-9a-f]+) ([-r][-w][-x][-p])', l)
841 if not m:
842 continue
843 start = int(m.group(1), 16)
844 end = int(m.group(2), 16)
845 perm = m.group(3)
846 if start > 0xffffffffffff:
847 continue
848 if end < start:
849 continue
850 if not perm.startswith('rw'):
851 continue
852 mem.seek(start)
853 data = mem.read(end - start)
854 buf += data
855 if key and key in data:
856 logger.info("Key found in " + l)
857 return buf
858
859 def verify_not_present(buf, key, fname, keyname):
860 pos = buf.find(key)
861 if pos < 0:
862 return
863
864 prefix = 2048 if pos > 2048 else pos
865 with open(fname + keyname, 'w') as f:
866 f.write(buf[pos - prefix:pos + 2048])
867 raise Exception(keyname + " found after disassociation")
868
869 def get_key_locations(buf, key, keyname):
870 count = 0
871 pos = 0
872 while True:
873 pos = buf.find(key, pos)
874 if pos < 0:
875 break
876 logger.info("Found %s at %d" % (keyname, pos))
877 count += 1
878 pos += len(key)
879 return count
880
881 def test_wpa2_psk_key_lifetime_in_memory(dev, apdev, params):
882 """WPA2-PSK and PSK/PTK lifetime in memory"""
883 ssid = "test-wpa2-psk"
884 passphrase = 'qwertyuiop'
885 psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
886 pmk = binascii.unhexlify(psk)
887 p = hostapd.wpa2_params(ssid=ssid)
888 p['wpa_psk'] = psk
889 hapd = hostapd.add_ap(apdev[0]['ifname'], p)
890
891 pid = find_wpas_process(dev[0])
892
893 id = dev[0].connect(ssid, raw_psk=psk, scan_freq="2412",
894 only_add_network=True)
895
896 logger.info("Checking keys in memory after network profile configuration")
897 buf = read_process_memory(pid, pmk)
898 get_key_locations(buf, pmk, "PMK")
899
900 dev[0].request("REMOVE_NETWORK all")
901 logger.info("Checking keys in memory after network profile removal")
902 buf = read_process_memory(pid, pmk)
903 get_key_locations(buf, pmk, "PMK")
904
905 id = dev[0].connect(ssid, psk=passphrase, scan_freq="2412",
906 only_add_network=True)
907
908 logger.info("Checking keys in memory before connection")
909 buf = read_process_memory(pid, pmk)
910 get_key_locations(buf, pmk, "PMK")
911
912 dev[0].connect_network(id, timeout=20)
913 time.sleep(0.1)
914
915 buf = read_process_memory(pid, pmk)
916
917 dev[0].request("DISCONNECT")
918 dev[0].wait_disconnected()
919
920 dev[0].relog()
921 ptk = None
922 gtk = None
923 with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
924 for l in f.readlines():
925 if "WPA: PTK - hexdump" in l:
926 val = l.strip().split(':')[3].replace(' ', '')
927 ptk = binascii.unhexlify(val)
928 if "WPA: Group Key - hexdump" in l:
929 val = l.strip().split(':')[3].replace(' ', '')
930 gtk = binascii.unhexlify(val)
931 if not pmk or not ptk or not gtk:
932 raise Exception("Could not find keys from debug log")
933 if len(gtk) != 16:
934 raise Exception("Unexpected GTK length")
935
936 kck = ptk[0:16]
937 kek = ptk[16:32]
938 tk = ptk[32:48]
939
940 logger.info("Checking keys in memory while associated")
941 get_key_locations(buf, pmk, "PMK")
942 if pmk not in buf:
943 print("PMK not found while associated")
944 return "skip"
945 if kck not in buf:
946 raise Exception("KCK not found while associated")
947 if kek not in buf:
948 raise Exception("KEK not found while associated")
949 if tk in buf:
950 raise Exception("TK found from memory")
951 if gtk in buf:
952 raise Exception("GTK found from memory")
953
954 logger.info("Checking keys in memory after disassociation")
955 buf = read_process_memory(pid, pmk)
956 get_key_locations(buf, pmk, "PMK")
957
958 # Note: PMK/PSK is still present in network configuration
959
960 fname = os.path.join(params['logdir'],
961 'wpa2_psk_key_lifetime_in_memory.memctx-')
962 verify_not_present(buf, kck, fname, "KCK")
963 verify_not_present(buf, kek, fname, "KEK")
964 verify_not_present(buf, tk, fname, "TK")
965 verify_not_present(buf, gtk, fname, "GTK")
966
967 dev[0].request("REMOVE_NETWORK all")
968
969 logger.info("Checking keys in memory after network profile removal")
970 buf = read_process_memory(pid, pmk)
971 get_key_locations(buf, pmk, "PMK")
972
973 verify_not_present(buf, pmk, fname, "PMK")
974 verify_not_present(buf, kck, fname, "KCK")
975 verify_not_present(buf, kek, fname, "KEK")
976 verify_not_present(buf, tk, fname, "TK")
977 verify_not_present(buf, gtk, fname, "GTK")