]> git.ipfire.org Git - thirdparty/hostap.git/blame - tests/hwsim/test_erp.py
tests: Make *_key_lifetime_in_memory more robust
[thirdparty/hostap.git] / tests / hwsim / test_erp.py
CommitLineData
acc9a635 1# EAP Re-authentication Protocol (ERP) tests
3b51cc63 2# Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
acc9a635
JM
3#
4# This software may be distributed under the terms of the BSD license.
5# See README for more details.
6
5b3c40a6 7import binascii
acc9a635
JM
8import logging
9logger = logging.getLogger()
5b3c40a6
JM
10import os
11import time
acc9a635
JM
12
13import hostapd
81e787b7 14from utils import HwsimSkip
acc9a635 15from test_ap_eap import int_eap_server_params
5b3c40a6 16from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations
acc9a635 17
81e787b7
JM
18def check_erp_capa(dev):
19 capab = dev.get_capability("erp")
20 if not capab or 'ERP' not in capab:
21 raise HwsimSkip("ERP not supported in the build")
22
acc9a635
JM
23def test_erp_initiate_reauth_start(dev, apdev):
24 """Authenticator sending EAP-Initiate/Re-auth-Start, but ERP disabled on peer"""
25 params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
26 params['erp_send_reauth_start'] = '1'
27 params['erp_domain'] = 'example.com'
28 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
29
30 dev[0].request("ERP_FLUSH")
31 dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
32 eap="PAX", identity="pax.user@example.com",
33 password_hex="0123456789abcdef0123456789abcdef",
34 scan_freq="2412")
35
36def test_erp_enabled_on_server(dev, apdev):
37 """ERP enabled on internal EAP server, but disabled on peer"""
38 params = int_eap_server_params()
39 params['erp_send_reauth_start'] = '1'
40 params['erp_domain'] = 'example.com'
41 params['eap_server_erp'] = '1'
42 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
43
44 dev[0].request("ERP_FLUSH")
45 dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
46 eap="PAX", identity="pax.user@example.com",
47 password_hex="0123456789abcdef0123456789abcdef",
48 scan_freq="2412")
49
50def test_erp(dev, apdev):
51 """ERP enabled on server and peer"""
81e787b7 52 check_erp_capa(dev[0])
acc9a635
JM
53 params = int_eap_server_params()
54 params['erp_send_reauth_start'] = '1'
55 params['erp_domain'] = 'example.com'
56 params['eap_server_erp'] = '1'
57 params['disable_pmksa_caching'] = '1'
58 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
59
60 dev[0].request("ERP_FLUSH")
61 dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
62 eap="PSK", identity="psk.user@example.com",
63 password_hex="0123456789abcdef0123456789abcdef",
64 erp="1", scan_freq="2412")
65 for i in range(3):
66 dev[0].request("DISCONNECT")
5f35a5e2 67 dev[0].wait_disconnected(timeout=15)
acc9a635
JM
68 dev[0].request("RECONNECT")
69 ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
70 if ev is None:
71 raise Exception("EAP success timed out")
72 if "EAP re-authentication completed successfully" not in ev:
73 raise Exception("Did not use ERP")
5f35a5e2 74 dev[0].wait_connected(timeout=15, error="Reconnection timed out")
acc9a635 75
0e40d7da
JM
76def test_erp_server_no_match(dev, apdev):
77 """ERP enabled on server and peer, but server has no key match"""
81e787b7 78 check_erp_capa(dev[0])
0e40d7da
JM
79 params = int_eap_server_params()
80 params['erp_send_reauth_start'] = '1'
81 params['erp_domain'] = 'example.com'
82 params['eap_server_erp'] = '1'
83 params['disable_pmksa_caching'] = '1'
84 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
85
86 dev[0].request("ERP_FLUSH")
87 id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
88 eap="PSK", identity="psk.user@example.com",
89 password_hex="0123456789abcdef0123456789abcdef",
90 erp="1", scan_freq="2412")
91 dev[0].request("DISCONNECT")
5f35a5e2 92 dev[0].wait_disconnected(timeout=15)
0e40d7da
JM
93 hapd.request("ERP_FLUSH")
94 dev[0].request("RECONNECT")
95 ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS",
96 "CTRL-EVENT-EAP-FAILURE"], timeout=15)
97 if ev is None:
98 raise Exception("EAP result timed out")
99 if "CTRL-EVENT-EAP-SUCCESS" in ev:
100 raise Exception("Unexpected EAP success")
101 dev[0].request("DISCONNECT")
102 dev[0].select_network(id)
103 ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
104 if ev is None:
105 raise Exception("EAP success timed out")
106 if "EAP re-authentication completed successfully" in ev:
107 raise Exception("Unexpected use of ERP")
5f35a5e2 108 dev[0].wait_connected(timeout=15, error="Reconnection timed out")
0e40d7da 109
acc9a635
JM
110def start_erp_as(apdev):
111 params = { "ssid": "as", "beacon_int": "2000",
112 "radius_server_clients": "auth_serv/radius_clients.conf",
113 "radius_server_auth_port": '18128',
114 "eap_server": "1",
115 "eap_user_file": "auth_serv/eap_user.conf",
116 "ca_cert": "auth_serv/ca.pem",
117 "server_cert": "auth_serv/server.pem",
118 "private_key": "auth_serv/server.key",
119 "eap_sim_db": "unix:/tmp/hlr_auc_gw.sock",
120 "dh_file": "auth_serv/dh.conf",
121 "pac_opaque_encr_key": "000102030405060708090a0b0c0d0e0f",
122 "eap_fast_a_id": "101112131415161718191a1b1c1d1e1f",
123 "eap_fast_a_id_info": "test server",
124 "eap_server_erp": "1",
125 "erp_domain": "example.com" }
126 hostapd.add_ap(apdev['ifname'], params)
127
128def test_erp_radius(dev, apdev):
129 """ERP enabled on RADIUS server and peer"""
81e787b7 130 check_erp_capa(dev[0])
acc9a635
JM
131 start_erp_as(apdev[1])
132 params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
133 params['auth_server_port'] = "18128"
134 params['erp_send_reauth_start'] = '1'
135 params['erp_domain'] = 'example.com'
136 params['disable_pmksa_caching'] = '1'
137 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
138
139 dev[0].request("ERP_FLUSH")
140 dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
141 eap="PSK", identity="psk.user@example.com",
142 password_hex="0123456789abcdef0123456789abcdef",
143 erp="1", scan_freq="2412")
144 for i in range(3):
145 dev[0].request("DISCONNECT")
5f35a5e2 146 dev[0].wait_disconnected(timeout=15)
acc9a635
JM
147 dev[0].request("RECONNECT")
148 ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
149 if ev is None:
150 raise Exception("EAP success timed out")
151 if "EAP re-authentication completed successfully" not in ev:
152 raise Exception("Did not use ERP")
5f35a5e2 153 dev[0].wait_connected(timeout=15, error="Reconnection timed out")
acc9a635
JM
154
155def erp_test(dev, hapd, **kwargs):
156 hapd.dump_monitor()
157 dev.dump_monitor()
158 dev.request("ERP_FLUSH")
159 id = dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", erp="1",
160 scan_freq="2412", **kwargs)
161 dev.request("DISCONNECT")
5f35a5e2 162 dev.wait_disconnected(timeout=15)
acc9a635
JM
163 hapd.dump_monitor()
164 dev.request("RECONNECT")
165 ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
166 if ev is None:
167 raise Exception("EAP success timed out")
168 if "EAP re-authentication completed successfully" not in ev:
169 raise Exception("Did not use ERP")
5f35a5e2 170 dev.wait_connected(timeout=15, error="Reconnection timed out")
acc9a635
JM
171 ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
172 if ev is None:
173 raise Exception("No connection event received from hostapd")
174 dev.request("DISCONNECT")
175
176def test_erp_radius_eap_methods(dev, apdev):
177 """ERP enabled on RADIUS server and peer"""
81e787b7 178 check_erp_capa(dev[0])
acc9a635
JM
179 start_erp_as(apdev[1])
180 params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
181 params['auth_server_port'] = "18128"
182 params['erp_send_reauth_start'] = '1'
183 params['erp_domain'] = 'example.com'
184 params['disable_pmksa_caching'] = '1'
185 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
186
187 erp_test(dev[0], hapd, eap="AKA", identity="0232010000000000@example.com",
188 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
189 erp_test(dev[0], hapd, eap="AKA'", identity="6555444333222111@example.com",
190 password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
191 # TODO: EKE getSession
192 #erp_test(dev[0], hapd, eap="EKE", identity="erp-eke@example.com",
193 # password="hello")
3b51cc63
JM
194 if "FAST" in dev[0].get_capability("eap"):
195 erp_test(dev[0], hapd, eap="FAST", identity="erp-fast@example.com",
196 password="password", ca_cert="auth_serv/ca.pem",
197 phase2="auth=GTC",
198 phase1="fast_provisioning=2",
199 pac_file="blob://fast_pac_auth_erp")
acc9a635
JM
200 erp_test(dev[0], hapd, eap="GPSK", identity="erp-gpsk@example.com",
201 password="abcdefghijklmnop0123456789abcdef")
f41f670e
JM
202 erp_test(dev[0], hapd, eap="IKEV2", identity="erp-ikev2@example.com",
203 password="password")
acc9a635
JM
204 erp_test(dev[0], hapd, eap="PAX", identity="erp-pax@example.com",
205 password_hex="0123456789abcdef0123456789abcdef")
206 # TODO: PEAP (EMSK)
207 #erp_test(dev[0], hapd, eap="PEAP", identity="erp-peap@example.com",
208 # password="password", ca_cert="auth_serv/ca.pem",
209 # phase2="auth=MSCHAPV2")
210 erp_test(dev[0], hapd, eap="PSK", identity="erp-psk@example.com",
211 password_hex="0123456789abcdef0123456789abcdef")
3b51cc63
JM
212 if "PWD" in dev[0].get_capability("eap"):
213 erp_test(dev[0], hapd, eap="PWD", identity="erp-pwd@example.com",
214 password="secret password")
acc9a635
JM
215 erp_test(dev[0], hapd, eap="SAKE", identity="erp-sake@example.com",
216 password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
217 erp_test(dev[0], hapd, eap="SIM", identity="1232010000000000@example.com",
218 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
219 erp_test(dev[0], hapd, eap="TLS", identity="erp-tls@example.com",
220 ca_cert="auth_serv/ca.pem", client_cert="auth_serv/user.pem",
221 private_key="auth_serv/user.key")
222 erp_test(dev[0], hapd, eap="TTLS", identity="erp-ttls@example.com",
223 password="password", ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
5b3c40a6
JM
224
225def test_erp_key_lifetime_in_memory(dev, apdev, params):
226 """ERP and key lifetime in memory"""
81e787b7 227 check_erp_capa(dev[0])
5b3c40a6
JM
228 p = int_eap_server_params()
229 p['erp_send_reauth_start'] = '1'
230 p['erp_domain'] = 'example.com'
231 p['eap_server_erp'] = '1'
232 p['disable_pmksa_caching'] = '1'
233 hapd = hostapd.add_ap(apdev[0]['ifname'], p)
234 password = "63d2d21ac3c09ed567ee004a34490f1d16e7fa5835edf17ddba70a63f1a90a25"
235
236 pid = find_wpas_process(dev[0])
237
238 dev[0].request("ERP_FLUSH")
239 dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
240 identity="pap-secret@example.com", password=password,
241 ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
242 erp="1", scan_freq="2412")
243
54f2cae2 244 time.sleep(1)
5b3c40a6
JM
245 buf = read_process_memory(pid, password)
246
247 dev[0].request("DISCONNECT")
248 dev[0].wait_disconnected(timeout=15)
249
250 dev[0].relog()
750904dd
JM
251 msk = None
252 emsk = None
5b3c40a6
JM
253 rRK = None
254 rIK = None
255 pmk = None
256 ptk = None
257 gtk = None
258 with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
259 for l in f.readlines():
750904dd
JM
260 if "EAP-TTLS: Derived key - hexdump" in l:
261 val = l.strip().split(':')[3].replace(' ', '')
262 msk = binascii.unhexlify(val)
263 if "EAP-TTLS: Derived EMSK - hexdump" in l:
264 val = l.strip().split(':')[3].replace(' ', '')
265 emsk = binascii.unhexlify(val)
5b3c40a6
JM
266 if "EAP: ERP rRK - hexdump" in l:
267 val = l.strip().split(':')[3].replace(' ', '')
268 rRK = binascii.unhexlify(val)
269 if "EAP: ERP rIK - hexdump" in l:
270 val = l.strip().split(':')[3].replace(' ', '')
271 rIK = binascii.unhexlify(val)
272 if "WPA: PMK - hexdump" in l:
273 val = l.strip().split(':')[3].replace(' ', '')
274 pmk = binascii.unhexlify(val)
275 if "WPA: PTK - hexdump" in l:
276 val = l.strip().split(':')[3].replace(' ', '')
277 ptk = binascii.unhexlify(val)
278 if "WPA: Group Key - hexdump" in l:
279 val = l.strip().split(':')[3].replace(' ', '')
280 gtk = binascii.unhexlify(val)
750904dd 281 if not msk or not emsk or not rIK or not rRK or not pmk or not ptk or not gtk:
5b3c40a6
JM
282 raise Exception("Could not find keys from debug log")
283 if len(gtk) != 16:
284 raise Exception("Unexpected GTK length")
285
286 kck = ptk[0:16]
287 kek = ptk[16:32]
288 tk = ptk[32:48]
289
290 fname = os.path.join(params['logdir'],
291 'erp_key_lifetime_in_memory.memctx-')
292
293 logger.info("Checking keys in memory while associated")
294 get_key_locations(buf, password, "Password")
295 get_key_locations(buf, pmk, "PMK")
750904dd
JM
296 get_key_locations(buf, msk, "MSK")
297 get_key_locations(buf, emsk, "EMSK")
5b3c40a6
JM
298 get_key_locations(buf, rRK, "rRK")
299 get_key_locations(buf, rIK, "rIK")
300 if password not in buf:
81e787b7 301 raise HwsimSkip("Password not found while associated")
5b3c40a6 302 if pmk not in buf:
81e787b7 303 raise HwsimSkip("PMK not found while associated")
5b3c40a6
JM
304 if kck not in buf:
305 raise Exception("KCK not found while associated")
306 if kek not in buf:
307 raise Exception("KEK not found while associated")
308 if tk in buf:
309 raise Exception("TK found from memory")
310 if gtk in buf:
311 raise Exception("GTK found from memory")
312
313 logger.info("Checking keys in memory after disassociation")
314 buf = read_process_memory(pid, password)
315
316 # Note: Password is still present in network configuration
317 # Note: PMK is in EAP fast re-auth data
318
319 get_key_locations(buf, password, "Password")
320 get_key_locations(buf, pmk, "PMK")
750904dd
JM
321 get_key_locations(buf, msk, "MSK")
322 get_key_locations(buf, emsk, "EMSK")
5b3c40a6
JM
323 get_key_locations(buf, rRK, "rRK")
324 get_key_locations(buf, rIK, "rIK")
325 verify_not_present(buf, kck, fname, "KCK")
326 verify_not_present(buf, kek, fname, "KEK")
327 verify_not_present(buf, tk, fname, "TK")
328 verify_not_present(buf, gtk, fname, "GTK")
329
330 dev[0].request("RECONNECT")
331 ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
332 if ev is None:
333 raise Exception("EAP success timed out")
334 if "EAP re-authentication completed successfully" not in ev:
335 raise Exception("Did not use ERP")
336 dev[0].wait_connected(timeout=15, error="Reconnection timed out")
337
338 dev[0].request("DISCONNECT")
339 dev[0].wait_disconnected(timeout=15)
340
341 dev[0].relog()
342 pmk = None
343 ptk = None
344 gtk = None
345 with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
346 for l in f.readlines():
347 if "WPA: PMK - hexdump" in l:
348 val = l.strip().split(':')[3].replace(' ', '')
349 pmk = binascii.unhexlify(val)
350 if "WPA: PTK - hexdump" in l:
351 val = l.strip().split(':')[3].replace(' ', '')
352 ptk = binascii.unhexlify(val)
353 if "WPA: GTK in EAPOL-Key - hexdump" in l:
354 val = l.strip().split(':')[3].replace(' ', '')
355 gtk = binascii.unhexlify(val)
356 if not pmk or not ptk or not gtk:
357 raise Exception("Could not find keys from debug log")
358
359 kck = ptk[0:16]
360 kek = ptk[16:32]
361 tk = ptk[32:48]
362
363 logger.info("Checking keys in memory after ERP and disassociation")
364 buf = read_process_memory(pid, password)
365
366 # Note: Password is still present in network configuration
367
368 get_key_locations(buf, password, "Password")
369 get_key_locations(buf, pmk, "PMK")
750904dd
JM
370 get_key_locations(buf, msk, "MSK")
371 get_key_locations(buf, emsk, "EMSK")
5b3c40a6
JM
372 get_key_locations(buf, rRK, "rRK")
373 get_key_locations(buf, rIK, "rIK")
374 verify_not_present(buf, kck, fname, "KCK")
375 verify_not_present(buf, kek, fname, "KEK")
376 verify_not_present(buf, tk, fname, "TK")
377 verify_not_present(buf, gtk, fname, "GTK")
378
379 dev[0].request("REMOVE_NETWORK all")
380
381 logger.info("Checking keys in memory after network profile removal")
382 buf = read_process_memory(pid, password)
383
384 # Note: rRK and rIK are still in memory
385
386 get_key_locations(buf, password, "Password")
387 get_key_locations(buf, pmk, "PMK")
750904dd
JM
388 get_key_locations(buf, msk, "MSK")
389 get_key_locations(buf, emsk, "EMSK")
5b3c40a6
JM
390 get_key_locations(buf, rRK, "rRK")
391 get_key_locations(buf, rIK, "rIK")
392 verify_not_present(buf, password, fname, "password")
393 verify_not_present(buf, pmk, fname, "PMK")
394 verify_not_present(buf, kck, fname, "KCK")
395 verify_not_present(buf, kek, fname, "KEK")
396 verify_not_present(buf, tk, fname, "TK")
397 verify_not_present(buf, gtk, fname, "GTK")
750904dd
JM
398 verify_not_present(buf, msk, fname, "MSK")
399 verify_not_present(buf, emsk, fname, "EMSK")
5b3c40a6
JM
400
401 dev[0].request("ERP_FLUSH")
402 logger.info("Checking keys in memory after ERP_FLUSH")
403 buf = read_process_memory(pid, password)
404 get_key_locations(buf, rRK, "rRK")
405 get_key_locations(buf, rIK, "rIK")
406 verify_not_present(buf, rRK, fname, "rRK")
407 verify_not_present(buf, rIK, fname, "rIK")