]> git.ipfire.org Git - thirdparty/hostap.git/blame - tests/hwsim/test_erp.py
doc: Disable Doxygen autolink support
[thirdparty/hostap.git] / tests / hwsim / test_erp.py
CommitLineData
acc9a635
JM
1# EAP Re-authentication Protocol (ERP) tests
2# Copyright (c) 2014, 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
5b3c40a6 7import binascii
acc9a635
JM
8import logging
9logger = logging.getLogger()
5b3c40a6
JM
10import os
11import time
acc9a635
JM
12
13import hostapd
14from test_ap_eap import int_eap_server_params
5b3c40a6 15from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations
acc9a635
JM
16
17def test_erp_initiate_reauth_start(dev, apdev):
18 """Authenticator sending EAP-Initiate/Re-auth-Start, but ERP disabled on peer"""
19 params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
20 params['erp_send_reauth_start'] = '1'
21 params['erp_domain'] = 'example.com'
22 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
23
24 dev[0].request("ERP_FLUSH")
25 dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
26 eap="PAX", identity="pax.user@example.com",
27 password_hex="0123456789abcdef0123456789abcdef",
28 scan_freq="2412")
29
30def test_erp_enabled_on_server(dev, apdev):
31 """ERP enabled on internal EAP server, but disabled on peer"""
32 params = int_eap_server_params()
33 params['erp_send_reauth_start'] = '1'
34 params['erp_domain'] = 'example.com'
35 params['eap_server_erp'] = '1'
36 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
37
38 dev[0].request("ERP_FLUSH")
39 dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
40 eap="PAX", identity="pax.user@example.com",
41 password_hex="0123456789abcdef0123456789abcdef",
42 scan_freq="2412")
43
44def test_erp(dev, apdev):
45 """ERP enabled on server and peer"""
46 capab = dev[0].get_capability("erp")
47 if not capab or 'ERP' not in capab:
48 return "skip"
49 params = int_eap_server_params()
50 params['erp_send_reauth_start'] = '1'
51 params['erp_domain'] = 'example.com'
52 params['eap_server_erp'] = '1'
53 params['disable_pmksa_caching'] = '1'
54 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
55
56 dev[0].request("ERP_FLUSH")
57 dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
58 eap="PSK", identity="psk.user@example.com",
59 password_hex="0123456789abcdef0123456789abcdef",
60 erp="1", scan_freq="2412")
61 for i in range(3):
62 dev[0].request("DISCONNECT")
5f35a5e2 63 dev[0].wait_disconnected(timeout=15)
acc9a635
JM
64 dev[0].request("RECONNECT")
65 ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
66 if ev is None:
67 raise Exception("EAP success timed out")
68 if "EAP re-authentication completed successfully" not in ev:
69 raise Exception("Did not use ERP")
5f35a5e2 70 dev[0].wait_connected(timeout=15, error="Reconnection timed out")
acc9a635 71
0e40d7da
JM
72def test_erp_server_no_match(dev, apdev):
73 """ERP enabled on server and peer, but server has no key match"""
74 capab = dev[0].get_capability("erp")
75 if not capab or 'ERP' not in capab:
76 return "skip"
77 params = int_eap_server_params()
78 params['erp_send_reauth_start'] = '1'
79 params['erp_domain'] = 'example.com'
80 params['eap_server_erp'] = '1'
81 params['disable_pmksa_caching'] = '1'
82 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
83
84 dev[0].request("ERP_FLUSH")
85 id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
86 eap="PSK", identity="psk.user@example.com",
87 password_hex="0123456789abcdef0123456789abcdef",
88 erp="1", scan_freq="2412")
89 dev[0].request("DISCONNECT")
5f35a5e2 90 dev[0].wait_disconnected(timeout=15)
0e40d7da
JM
91 hapd.request("ERP_FLUSH")
92 dev[0].request("RECONNECT")
93 ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS",
94 "CTRL-EVENT-EAP-FAILURE"], timeout=15)
95 if ev is None:
96 raise Exception("EAP result timed out")
97 if "CTRL-EVENT-EAP-SUCCESS" in ev:
98 raise Exception("Unexpected EAP success")
99 dev[0].request("DISCONNECT")
100 dev[0].select_network(id)
101 ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
102 if ev is None:
103 raise Exception("EAP success timed out")
104 if "EAP re-authentication completed successfully" in ev:
105 raise Exception("Unexpected use of ERP")
5f35a5e2 106 dev[0].wait_connected(timeout=15, error="Reconnection timed out")
0e40d7da 107
acc9a635
JM
108def start_erp_as(apdev):
109 params = { "ssid": "as", "beacon_int": "2000",
110 "radius_server_clients": "auth_serv/radius_clients.conf",
111 "radius_server_auth_port": '18128',
112 "eap_server": "1",
113 "eap_user_file": "auth_serv/eap_user.conf",
114 "ca_cert": "auth_serv/ca.pem",
115 "server_cert": "auth_serv/server.pem",
116 "private_key": "auth_serv/server.key",
117 "eap_sim_db": "unix:/tmp/hlr_auc_gw.sock",
118 "dh_file": "auth_serv/dh.conf",
119 "pac_opaque_encr_key": "000102030405060708090a0b0c0d0e0f",
120 "eap_fast_a_id": "101112131415161718191a1b1c1d1e1f",
121 "eap_fast_a_id_info": "test server",
122 "eap_server_erp": "1",
123 "erp_domain": "example.com" }
124 hostapd.add_ap(apdev['ifname'], params)
125
126def test_erp_radius(dev, apdev):
127 """ERP enabled on RADIUS server and peer"""
128 capab = dev[0].get_capability("erp")
129 if not capab or 'ERP' not in capab:
130 return "skip"
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"""
178 capab = dev[0].get_capability("erp")
179 if not capab or 'ERP' not in capab:
180 return "skip"
181 start_erp_as(apdev[1])
182 params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
183 params['auth_server_port'] = "18128"
184 params['erp_send_reauth_start'] = '1'
185 params['erp_domain'] = 'example.com'
186 params['disable_pmksa_caching'] = '1'
187 hapd = hostapd.add_ap(apdev[0]['ifname'], params)
188
189 erp_test(dev[0], hapd, eap="AKA", identity="0232010000000000@example.com",
190 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
191 erp_test(dev[0], hapd, eap="AKA'", identity="6555444333222111@example.com",
192 password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
193 # TODO: EKE getSession
194 #erp_test(dev[0], hapd, eap="EKE", identity="erp-eke@example.com",
195 # password="hello")
196 erp_test(dev[0], hapd, eap="FAST", identity="erp-fast@example.com",
197 password="password", ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
198 phase1="fast_provisioning=2", pac_file="blob://fast_pac_auth_erp")
199 erp_test(dev[0], hapd, eap="GPSK", identity="erp-gpsk@example.com",
200 password="abcdefghijklmnop0123456789abcdef")
f41f670e
JM
201 erp_test(dev[0], hapd, eap="IKEV2", identity="erp-ikev2@example.com",
202 password="password")
acc9a635
JM
203 erp_test(dev[0], hapd, eap="PAX", identity="erp-pax@example.com",
204 password_hex="0123456789abcdef0123456789abcdef")
205 # TODO: PEAP (EMSK)
206 #erp_test(dev[0], hapd, eap="PEAP", identity="erp-peap@example.com",
207 # password="password", ca_cert="auth_serv/ca.pem",
208 # phase2="auth=MSCHAPV2")
209 erp_test(dev[0], hapd, eap="PSK", identity="erp-psk@example.com",
210 password_hex="0123456789abcdef0123456789abcdef")
211 erp_test(dev[0], hapd, eap="PWD", identity="erp-pwd@example.com",
212 password="secret password")
213 erp_test(dev[0], hapd, eap="SAKE", identity="erp-sake@example.com",
214 password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
215 erp_test(dev[0], hapd, eap="SIM", identity="1232010000000000@example.com",
216 password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
217 erp_test(dev[0], hapd, eap="TLS", identity="erp-tls@example.com",
218 ca_cert="auth_serv/ca.pem", client_cert="auth_serv/user.pem",
219 private_key="auth_serv/user.key")
220 erp_test(dev[0], hapd, eap="TTLS", identity="erp-ttls@example.com",
221 password="password", ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
5b3c40a6
JM
222
223def test_erp_key_lifetime_in_memory(dev, apdev, params):
224 """ERP and key lifetime in memory"""
225 capab = dev[0].get_capability("erp")
226 if not capab or 'ERP' not in capab:
227 return "skip"
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
244 time.sleep(0.1)
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()
251 rRK = None
252 rIK = None
253 pmk = None
254 ptk = None
255 gtk = None
256 with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
257 for l in f.readlines():
258 if "EAP: ERP rRK - hexdump" in l:
259 val = l.strip().split(':')[3].replace(' ', '')
260 rRK = binascii.unhexlify(val)
261 if "EAP: ERP rIK - hexdump" in l:
262 val = l.strip().split(':')[3].replace(' ', '')
263 rIK = binascii.unhexlify(val)
264 if "WPA: PMK - hexdump" in l:
265 val = l.strip().split(':')[3].replace(' ', '')
266 pmk = binascii.unhexlify(val)
267 if "WPA: PTK - hexdump" in l:
268 val = l.strip().split(':')[3].replace(' ', '')
269 ptk = binascii.unhexlify(val)
270 if "WPA: Group Key - hexdump" in l:
271 val = l.strip().split(':')[3].replace(' ', '')
272 gtk = binascii.unhexlify(val)
273 if not rIK or not rRK or not pmk or not ptk or not gtk:
274 raise Exception("Could not find keys from debug log")
275 if len(gtk) != 16:
276 raise Exception("Unexpected GTK length")
277
278 kck = ptk[0:16]
279 kek = ptk[16:32]
280 tk = ptk[32:48]
281
282 fname = os.path.join(params['logdir'],
283 'erp_key_lifetime_in_memory.memctx-')
284
285 logger.info("Checking keys in memory while associated")
286 get_key_locations(buf, password, "Password")
287 get_key_locations(buf, pmk, "PMK")
288 get_key_locations(buf, rRK, "rRK")
289 get_key_locations(buf, rIK, "rIK")
290 if password not in buf:
291 print("Password not found while associated")
292 return "skip"
293 if pmk not in buf:
294 print("PMK not found while associated")
295 return "skip"
296 if kck not in buf:
297 raise Exception("KCK not found while associated")
298 if kek not in buf:
299 raise Exception("KEK not found while associated")
300 if tk in buf:
301 raise Exception("TK found from memory")
302 if gtk in buf:
303 raise Exception("GTK found from memory")
304
305 logger.info("Checking keys in memory after disassociation")
306 buf = read_process_memory(pid, password)
307
308 # Note: Password is still present in network configuration
309 # Note: PMK is in EAP fast re-auth data
310
311 get_key_locations(buf, password, "Password")
312 get_key_locations(buf, pmk, "PMK")
313 get_key_locations(buf, rRK, "rRK")
314 get_key_locations(buf, rIK, "rIK")
315 verify_not_present(buf, kck, fname, "KCK")
316 verify_not_present(buf, kek, fname, "KEK")
317 verify_not_present(buf, tk, fname, "TK")
318 verify_not_present(buf, gtk, fname, "GTK")
319
320 dev[0].request("RECONNECT")
321 ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
322 if ev is None:
323 raise Exception("EAP success timed out")
324 if "EAP re-authentication completed successfully" not in ev:
325 raise Exception("Did not use ERP")
326 dev[0].wait_connected(timeout=15, error="Reconnection timed out")
327
328 dev[0].request("DISCONNECT")
329 dev[0].wait_disconnected(timeout=15)
330
331 dev[0].relog()
332 pmk = None
333 ptk = None
334 gtk = None
335 with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
336 for l in f.readlines():
337 if "WPA: PMK - hexdump" in l:
338 val = l.strip().split(':')[3].replace(' ', '')
339 pmk = binascii.unhexlify(val)
340 if "WPA: PTK - hexdump" in l:
341 val = l.strip().split(':')[3].replace(' ', '')
342 ptk = binascii.unhexlify(val)
343 if "WPA: GTK in EAPOL-Key - hexdump" in l:
344 val = l.strip().split(':')[3].replace(' ', '')
345 gtk = binascii.unhexlify(val)
346 if not pmk or not ptk or not gtk:
347 raise Exception("Could not find keys from debug log")
348
349 kck = ptk[0:16]
350 kek = ptk[16:32]
351 tk = ptk[32:48]
352
353 logger.info("Checking keys in memory after ERP and disassociation")
354 buf = read_process_memory(pid, password)
355
356 # Note: Password is still present in network configuration
357
358 get_key_locations(buf, password, "Password")
359 get_key_locations(buf, pmk, "PMK")
360 get_key_locations(buf, rRK, "rRK")
361 get_key_locations(buf, rIK, "rIK")
362 verify_not_present(buf, kck, fname, "KCK")
363 verify_not_present(buf, kek, fname, "KEK")
364 verify_not_present(buf, tk, fname, "TK")
365 verify_not_present(buf, gtk, fname, "GTK")
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 # Note: rRK and rIK are still in memory
373
374 get_key_locations(buf, password, "Password")
375 get_key_locations(buf, pmk, "PMK")
376 get_key_locations(buf, rRK, "rRK")
377 get_key_locations(buf, rIK, "rIK")
378 verify_not_present(buf, password, fname, "password")
379 verify_not_present(buf, pmk, fname, "PMK")
380 verify_not_present(buf, kck, fname, "KCK")
381 verify_not_present(buf, kek, fname, "KEK")
382 verify_not_present(buf, tk, fname, "TK")
383 verify_not_present(buf, gtk, fname, "GTK")
384
385 dev[0].request("ERP_FLUSH")
386 logger.info("Checking keys in memory after ERP_FLUSH")
387 buf = read_process_memory(pid, password)
388 get_key_locations(buf, rRK, "rRK")
389 get_key_locations(buf, rIK, "rIK")
390 verify_not_present(buf, rRK, fname, "rRK")
391 verify_not_present(buf, rIK, fname, "rIK")