1 # EAP Re-authentication Protocol (ERP) tests
2 # Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
4 # This software may be distributed under the terms of the BSD license.
5 # See README for more details.
9 logger = logging.getLogger()
14 from utils import HwsimSkip
15 from test_ap_eap import int_eap_server_params
16 from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations
18 def 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")
23 def 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)
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",
36 def 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)
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",
50 def test_erp(dev, apdev):
51 """ERP enabled on server and peer"""
52 check_erp_capa(dev[0])
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)
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")
66 dev[0].request("DISCONNECT")
67 dev[0].wait_disconnected(timeout=15)
68 dev[0].request("RECONNECT")
69 ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
71 raise Exception("EAP success timed out")
72 if "EAP re-authentication completed successfully" not in ev:
73 raise Exception("Did not use ERP")
74 dev[0].wait_connected(timeout=15, error="Reconnection timed out")
76 def test_erp_server_no_match(dev, apdev):
77 """ERP enabled on server and peer, but server has no key match"""
78 check_erp_capa(dev[0])
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)
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")
92 dev[0].wait_disconnected(timeout=15)
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)
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)
105 raise Exception("EAP success timed out")
106 if "EAP re-authentication completed successfully" in ev:
107 raise Exception("Unexpected use of ERP")
108 dev[0].wait_connected(timeout=15, error="Reconnection timed out")
110 def 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',
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)
128 def test_erp_radius(dev, apdev):
129 """ERP enabled on RADIUS server and peer"""
130 check_erp_capa(dev[0])
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)
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")
145 dev[0].request("DISCONNECT")
146 dev[0].wait_disconnected(timeout=15)
147 dev[0].request("RECONNECT")
148 ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
150 raise Exception("EAP success timed out")
151 if "EAP re-authentication completed successfully" not in ev:
152 raise Exception("Did not use ERP")
153 dev[0].wait_connected(timeout=15, error="Reconnection timed out")
155 def erp_test(dev, hapd, **kwargs):
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")
162 dev.wait_disconnected(timeout=15)
164 dev.request("RECONNECT")
165 ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
167 raise Exception("EAP success timed out")
168 if "EAP re-authentication completed successfully" not in ev:
169 raise Exception("Did not use ERP")
170 dev.wait_connected(timeout=15, error="Reconnection timed out")
171 ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
173 raise Exception("No connection event received from hostapd")
174 dev.request("DISCONNECT")
176 def test_erp_radius_eap_methods(dev, apdev):
177 """ERP enabled on RADIUS server and peer"""
178 check_erp_capa(dev[0])
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)
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",
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",
198 phase1="fast_provisioning=2",
199 pac_file="blob://fast_pac_auth_erp")
200 erp_test(dev[0], hapd, eap="GPSK", identity="erp-gpsk@example.com",
201 password="abcdefghijklmnop0123456789abcdef")
202 erp_test(dev[0], hapd, eap="IKEV2", identity="erp-ikev2@example.com",
204 erp_test(dev[0], hapd, eap="PAX", identity="erp-pax@example.com",
205 password_hex="0123456789abcdef0123456789abcdef")
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")
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")
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")
225 def test_erp_key_lifetime_in_memory(dev, apdev, params):
226 """ERP and key lifetime in memory"""
227 check_erp_capa(dev[0])
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"
236 pid = find_wpas_process(dev[0])
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")
245 buf = read_process_memory(pid, password)
247 dev[0].request("DISCONNECT")
248 dev[0].wait_disconnected(timeout=15)
258 with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
259 for l in f.readlines():
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)
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)
281 if not msk or not emsk or not rIK or not rRK or not pmk or not ptk or not gtk:
282 raise Exception("Could not find keys from debug log")
284 raise Exception("Unexpected GTK length")
290 fname = os.path.join(params['logdir'],
291 'erp_key_lifetime_in_memory.memctx-')
293 logger.info("Checking keys in memory while associated")
294 get_key_locations(buf, password, "Password")
295 get_key_locations(buf, pmk, "PMK")
296 get_key_locations(buf, msk, "MSK")
297 get_key_locations(buf, emsk, "EMSK")
298 get_key_locations(buf, rRK, "rRK")
299 get_key_locations(buf, rIK, "rIK")
300 if password not in buf:
301 raise HwsimSkip("Password not found while associated")
303 raise HwsimSkip("PMK not found while associated")
305 raise Exception("KCK not found while associated")
307 raise Exception("KEK not found while associated")
309 raise Exception("TK found from memory")
311 raise Exception("GTK found from memory")
313 logger.info("Checking keys in memory after disassociation")
314 buf = read_process_memory(pid, password)
316 # Note: Password is still present in network configuration
317 # Note: PMK is in EAP fast re-auth data
319 get_key_locations(buf, password, "Password")
320 get_key_locations(buf, pmk, "PMK")
321 get_key_locations(buf, msk, "MSK")
322 get_key_locations(buf, emsk, "EMSK")
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")
330 dev[0].request("RECONNECT")
331 ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
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")
338 dev[0].request("DISCONNECT")
339 dev[0].wait_disconnected(timeout=15)
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")
363 logger.info("Checking keys in memory after ERP and disassociation")
364 buf = read_process_memory(pid, password)
366 # Note: Password is still present in network configuration
368 get_key_locations(buf, password, "Password")
369 get_key_locations(buf, pmk, "PMK")
370 get_key_locations(buf, msk, "MSK")
371 get_key_locations(buf, emsk, "EMSK")
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")
379 dev[0].request("REMOVE_NETWORK all")
381 logger.info("Checking keys in memory after network profile removal")
382 buf = read_process_memory(pid, password)
384 # Note: rRK and rIK are still in memory
386 get_key_locations(buf, password, "Password")
387 get_key_locations(buf, pmk, "PMK")
388 get_key_locations(buf, msk, "MSK")
389 get_key_locations(buf, emsk, "EMSK")
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")
398 verify_not_present(buf, msk, fname, "MSK")
399 verify_not_present(buf, emsk, fname, "EMSK")
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")