]>
Commit | Line | Data |
---|---|---|
20e5c283 | 1 | # IEEE 802.1X tests |
348bc4e0 | 2 | # Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi> |
20e5c283 JM |
3 | # |
4 | # This software may be distributed under the terms of the BSD license. | |
5 | # See README for more details. | |
6 | ||
348bc4e0 JM |
7 | import binascii |
8 | import hmac | |
20e5c283 JM |
9 | import logging |
10 | import time | |
11 | ||
12 | import hostapd | |
13 | import hwsim_utils | |
24072e17 | 14 | from utils import skip_with_fips |
20e5c283 JM |
15 | |
16 | logger = logging.getLogger() | |
17 | ||
18 | def test_ieee8021x_wep104(dev, apdev): | |
19 | """IEEE 802.1X connection using dynamic WEP104""" | |
24072e17 | 20 | skip_with_fips(dev[0]) |
20e5c283 JM |
21 | params = hostapd.radius_params() |
22 | params["ssid"] = "ieee8021x-wep" | |
23 | params["ieee8021x"] = "1" | |
24 | params["wep_key_len_broadcast"] = "13" | |
25 | params["wep_key_len_unicast"] = "13" | |
8b8a1864 | 26 | hapd = hostapd.add_ap(apdev[0], params) |
20e5c283 JM |
27 | |
28 | dev[0].connect("ieee8021x-wep", key_mgmt="IEEE8021X", eap="PSK", | |
29 | identity="psk.user@example.com", | |
a08fdb17 JM |
30 | password_hex="0123456789abcdef0123456789abcdef", |
31 | scan_freq="2412") | |
a8375c94 | 32 | hwsim_utils.test_connectivity(dev[0], hapd) |
20e5c283 JM |
33 | |
34 | def test_ieee8021x_wep40(dev, apdev): | |
35 | """IEEE 802.1X connection using dynamic WEP40""" | |
24072e17 | 36 | skip_with_fips(dev[0]) |
20e5c283 JM |
37 | params = hostapd.radius_params() |
38 | params["ssid"] = "ieee8021x-wep" | |
39 | params["ieee8021x"] = "1" | |
40 | params["wep_key_len_broadcast"] = "5" | |
41 | params["wep_key_len_unicast"] = "5" | |
8b8a1864 | 42 | hapd = hostapd.add_ap(apdev[0], params) |
20e5c283 JM |
43 | |
44 | dev[0].connect("ieee8021x-wep", key_mgmt="IEEE8021X", eap="PSK", | |
45 | identity="psk.user@example.com", | |
a08fdb17 JM |
46 | password_hex="0123456789abcdef0123456789abcdef", |
47 | scan_freq="2412") | |
a8375c94 | 48 | hwsim_utils.test_connectivity(dev[0], hapd) |
20e5c283 JM |
49 | |
50 | def test_ieee8021x_open(dev, apdev): | |
51 | """IEEE 802.1X connection using open network""" | |
52 | params = hostapd.radius_params() | |
53 | params["ssid"] = "ieee8021x-open" | |
54 | params["ieee8021x"] = "1" | |
8b8a1864 | 55 | hapd = hostapd.add_ap(apdev[0], params) |
20e5c283 JM |
56 | |
57 | id = dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0", | |
58 | eap="PSK", identity="psk.user@example.com", | |
a08fdb17 JM |
59 | password_hex="0123456789abcdef0123456789abcdef", |
60 | scan_freq="2412") | |
a8375c94 | 61 | hwsim_utils.test_connectivity(dev[0], hapd) |
20e5c283 JM |
62 | |
63 | logger.info("Test EAPOL-Logoff") | |
64 | dev[0].request("LOGOFF") | |
65 | ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"]) | |
66 | if ev is None: | |
67 | raise Exception("Did not get disconnected") | |
68 | if "reason=23" not in ev: | |
69 | raise Exception("Unexpected disconnection reason") | |
70 | ||
71 | dev[0].request("LOGON") | |
72 | dev[0].connect_network(id) | |
a8375c94 | 73 | hwsim_utils.test_connectivity(dev[0], hapd) |
598555c7 JM |
74 | |
75 | def test_ieee8021x_static_wep40(dev, apdev): | |
76 | """IEEE 802.1X connection using static WEP40""" | |
77 | params = hostapd.radius_params() | |
78 | params["ssid"] = "ieee8021x-wep" | |
79 | params["ieee8021x"] = "1" | |
80 | params["wep_key0"] = '"hello"' | |
8b8a1864 | 81 | hapd = hostapd.add_ap(apdev[0], params) |
598555c7 JM |
82 | |
83 | dev[0].connect("ieee8021x-wep", key_mgmt="IEEE8021X", eap="PSK", | |
84 | identity="psk.user@example.com", | |
85 | password_hex="0123456789abcdef0123456789abcdef", | |
a08fdb17 JM |
86 | wep_key0='"hello"', eapol_flags="0", |
87 | scan_freq="2412") | |
598555c7 | 88 | hwsim_utils.test_connectivity(dev[0], hapd) |
a08fdb17 JM |
89 | |
90 | def test_ieee8021x_proto(dev, apdev): | |
91 | """IEEE 802.1X and EAPOL supplicant protocol testing""" | |
92 | params = hostapd.radius_params() | |
93 | params["ssid"] = "ieee8021x-open" | |
94 | params["ieee8021x"] = "1" | |
8b8a1864 | 95 | hapd = hostapd.add_ap(apdev[0], params) |
a08fdb17 JM |
96 | bssid = apdev[0]['bssid'] |
97 | ||
98 | dev[1].request("SET ext_eapol_frame_io 1") | |
99 | dev[1].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0", | |
100 | eap="PSK", identity="psk.user@example.com", | |
101 | password_hex="0123456789abcdef0123456789abcdef", | |
102 | scan_freq="2412", wait_connect=False) | |
103 | id = dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0", | |
104 | eap="PSK", identity="psk.user@example.com", | |
105 | password_hex="0123456789abcdef0123456789abcdef", | |
106 | scan_freq="2412") | |
107 | ev = dev[1].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5) | |
108 | ||
109 | start = dev[0].get_mib() | |
110 | ||
111 | tests = [ "11", | |
112 | "11223344", | |
113 | "020000050a93000501", | |
114 | "020300050a93000501", | |
115 | "0203002c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", | |
116 | "0203002c0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000", | |
117 | "0203002c0100050000000000000000000000000000000000000000000000000000000000000000000000000000000000", | |
118 | "02aa00050a93000501" ] | |
119 | for frame in tests: | |
120 | res = dev[0].request("EAPOL_RX " + bssid + " " + frame) | |
121 | if "OK" not in res: | |
122 | raise Exception("EAPOL_RX to wpa_supplicant failed") | |
123 | dev[1].request("EAPOL_RX " + bssid + " " + frame) | |
124 | ||
125 | stop = dev[0].get_mib() | |
126 | ||
127 | logger.info("MIB before test frames: " + str(start)) | |
128 | logger.info("MIB after test frames: " + str(stop)) | |
129 | ||
130 | vals = [ 'dot1xSuppInvalidEapolFramesRx', | |
131 | 'dot1xSuppEapLengthErrorFramesRx' ] | |
132 | for val in vals: | |
133 | if int(stop[val]) <= int(start[val]): | |
134 | raise Exception(val + " did not increase") | |
2ff49289 JM |
135 | |
136 | def test_ieee8021x_eapol_start(dev, apdev): | |
137 | """IEEE 802.1X and EAPOL-Start retransmissions""" | |
138 | params = hostapd.radius_params() | |
139 | params["ssid"] = "ieee8021x-open" | |
140 | params["ieee8021x"] = "1" | |
8b8a1864 | 141 | hapd = hostapd.add_ap(apdev[0], params) |
2ff49289 | 142 | bssid = apdev[0]['bssid'] |
77832550 | 143 | addr0 = dev[0].own_addr() |
2ff49289 JM |
144 | |
145 | hapd.set("ext_eapol_frame_io", "1") | |
146 | try: | |
147 | dev[0].request("SET EAPOL::startPeriod 1") | |
148 | dev[0].request("SET EAPOL::maxStart 1") | |
149 | dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0", | |
150 | eap="PSK", identity="psk.user@example.com", | |
151 | password_hex="0123456789abcdef0123456789abcdef", | |
152 | scan_freq="2412", wait_connect=False) | |
153 | held = False | |
154 | for i in range(30): | |
155 | pae = dev[0].get_status_field('Supplicant PAE state') | |
156 | if pae == "HELD": | |
77832550 JM |
157 | mib = hapd.get_sta(addr0, info="eapol") |
158 | if mib['auth_pae_state'] != 'AUTHENTICATING': | |
159 | raise Exception("Unexpected Auth PAE state: " + mib['auth_pae_state']) | |
2ff49289 JM |
160 | held = True |
161 | break | |
162 | time.sleep(0.25) | |
163 | if not held: | |
164 | raise Exception("PAE state HELD not reached") | |
165 | dev[0].wait_disconnected() | |
166 | finally: | |
167 | dev[0].request("SET EAPOL::startPeriod 30") | |
168 | dev[0].request("SET EAPOL::maxStart 3") | |
348bc4e0 | 169 | |
e0236b15 JM |
170 | def test_ieee8021x_held(dev, apdev): |
171 | """IEEE 802.1X and HELD state""" | |
172 | params = hostapd.radius_params() | |
173 | params["ssid"] = "ieee8021x-open" | |
174 | params["ieee8021x"] = "1" | |
8b8a1864 | 175 | hapd = hostapd.add_ap(apdev[0], params) |
e0236b15 JM |
176 | bssid = apdev[0]['bssid'] |
177 | ||
178 | hapd.set("ext_eapol_frame_io", "1") | |
179 | try: | |
180 | dev[0].request("SET EAPOL::startPeriod 1") | |
181 | dev[0].request("SET EAPOL::maxStart 0") | |
182 | dev[0].request("SET EAPOL::heldPeriod 1") | |
183 | dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0", | |
184 | eap="PSK", identity="psk.user@example.com", | |
185 | password_hex="0123456789abcdef0123456789abcdef", | |
186 | scan_freq="2412", wait_connect=False) | |
187 | held = False | |
188 | for i in range(30): | |
189 | pae = dev[0].get_status_field('Supplicant PAE state') | |
190 | if pae == "HELD": | |
191 | held = True | |
192 | break | |
193 | time.sleep(0.25) | |
194 | if not held: | |
195 | raise Exception("PAE state HELD not reached") | |
196 | ||
197 | hapd.set("ext_eapol_frame_io", "0") | |
198 | for i in range(30): | |
199 | pae = dev[0].get_status_field('Supplicant PAE state') | |
200 | if pae != "HELD": | |
201 | held = False | |
202 | break | |
203 | time.sleep(0.25) | |
204 | if held: | |
205 | raise Exception("PAE state HELD not left") | |
206 | ev = dev[0].wait_event([ "CTRL-EVENT-CONNECTED", | |
207 | "CTRL-EVENT-DISCONNECTED" ], timeout=10) | |
208 | if ev is None: | |
209 | raise Exception("Connection timed out") | |
210 | if "CTRL-EVENT-DISCONNECTED" in ev: | |
211 | raise Exception("Unexpected disconnection") | |
212 | finally: | |
213 | dev[0].request("SET EAPOL::startPeriod 30") | |
214 | dev[0].request("SET EAPOL::maxStart 3") | |
215 | dev[0].request("SET EAPOL::heldPeriod 60") | |
216 | ||
348bc4e0 JM |
217 | def send_eapol_key(dev, bssid, signkey, frame_start, frame_end): |
218 | zero_sign = "00000000000000000000000000000000" | |
219 | frame = frame_start + zero_sign + frame_end | |
220 | hmac_obj = hmac.new(binascii.unhexlify(signkey)) | |
221 | hmac_obj.update(binascii.unhexlify(frame)) | |
222 | sign = hmac_obj.digest() | |
223 | frame = frame_start + binascii.hexlify(sign) + frame_end | |
224 | dev.request("EAPOL_RX " + bssid + " " + frame) | |
225 | ||
226 | def test_ieee8021x_eapol_key(dev, apdev): | |
227 | """IEEE 802.1X connection and EAPOL-Key protocol tests""" | |
24072e17 | 228 | skip_with_fips(dev[0]) |
348bc4e0 JM |
229 | params = hostapd.radius_params() |
230 | params["ssid"] = "ieee8021x-wep" | |
231 | params["ieee8021x"] = "1" | |
232 | params["wep_key_len_broadcast"] = "5" | |
233 | params["wep_key_len_unicast"] = "5" | |
8b8a1864 | 234 | hapd = hostapd.add_ap(apdev[0], params) |
348bc4e0 JM |
235 | bssid = apdev[0]['bssid'] |
236 | ||
237 | dev[0].connect("ieee8021x-wep", key_mgmt="IEEE8021X", eap="VENDOR-TEST", | |
238 | identity="vendor-test", scan_freq="2412") | |
239 | ||
240 | # Hardcoded MSK from VENDOR-TEST | |
241 | encrkey = "1111111111111111111111111111111111111111111111111111111111111111" | |
242 | signkey = "2222222222222222222222222222222222222222222222222222222222222222" | |
243 | ||
244 | # EAPOL-Key replay counter does not increase | |
245 | send_eapol_key(dev[0], bssid, signkey, | |
246 | "02030031" + "010005" + "0000000000000000" + "056c22d109f29d4d9fb9b9ccbad33283" + "02", | |
247 | "1c636a30a4") | |
248 | ||
249 | # EAPOL-Key too large Key Length field value | |
250 | send_eapol_key(dev[0], bssid, signkey, | |
251 | "02030031" + "010021" + "ffffffffffffffff" + "056c22d109f29d4d9fb9b9ccbad33283" + "02", | |
252 | "1c636a30a4") | |
253 | ||
254 | # EAPOL-Key too much key data | |
255 | send_eapol_key(dev[0], bssid, signkey, | |
256 | "0203004d" + "010005" + "ffffffffffffffff" + "056c22d109f29d4d9fb9b9ccbad33283" + "02", | |
257 | 33*"ff") | |
258 | ||
259 | # EAPOL-Key too little key data | |
260 | send_eapol_key(dev[0], bssid, signkey, | |
261 | "02030030" + "010005" + "ffffffffffffffff" + "056c22d109f29d4d9fb9b9ccbad33283" + "02", | |
262 | "1c636a30") | |
263 | ||
264 | # EAPOL-Key with no key data and too long WEP key length | |
265 | send_eapol_key(dev[0], bssid, signkey, | |
266 | "0203002c" + "010020" + "ffffffffffffffff" + "056c22d109f29d4d9fb9b9ccbad33283" + "02", | |
267 | "") | |
a32a6d2c JM |
268 | |
269 | def test_ieee8021x_reauth(dev, apdev): | |
270 | """IEEE 802.1X and EAPOL_REAUTH request""" | |
271 | params = hostapd.radius_params() | |
272 | params["ssid"] = "ieee8021x-open" | |
273 | params["ieee8021x"] = "1" | |
8b8a1864 | 274 | hapd = hostapd.add_ap(apdev[0], params) |
a32a6d2c JM |
275 | |
276 | dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0", | |
277 | eap="PSK", identity="psk.user@example.com", | |
278 | password_hex="0123456789abcdef0123456789abcdef", | |
279 | scan_freq="2412") | |
280 | ||
281 | hapd.request("EAPOL_REAUTH " + dev[0].own_addr()) | |
282 | ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5) | |
283 | if ev is None: | |
284 | raise Exception("EAP authentication did not start") | |
285 | ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=5) | |
286 | if ev is None: | |
287 | raise Exception("EAP authentication did not succeed") | |
288 | time.sleep(0.1) | |
289 | hwsim_utils.test_connectivity(dev[0], hapd) | |
b7bdfb68 JM |
290 | |
291 | def test_ieee8021x_set_conf(dev, apdev): | |
292 | """IEEE 802.1X and EAPOL_SET command""" | |
293 | params = hostapd.radius_params() | |
294 | params["ssid"] = "ieee8021x-open" | |
295 | params["ieee8021x"] = "1" | |
8b8a1864 | 296 | hapd = hostapd.add_ap(apdev[0], params) |
b7bdfb68 JM |
297 | |
298 | dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0", | |
299 | eap="PSK", identity="psk.user@example.com", | |
300 | password_hex="0123456789abcdef0123456789abcdef", | |
301 | scan_freq="2412") | |
302 | ||
303 | addr0 = dev[0].own_addr() | |
304 | tests = [ "EAPOL_SET 1", | |
305 | "EAPOL_SET %sfoo bar" % addr0, | |
306 | "EAPOL_SET %s foo" % addr0, | |
307 | "EAPOL_SET %s foo bar" % addr0, | |
308 | "EAPOL_SET %s AdminControlledDirections bar" % addr0, | |
309 | "EAPOL_SET %s AdminControlledPortControl bar" % addr0, | |
310 | "EAPOL_SET %s reAuthEnabled bar" % addr0, | |
311 | "EAPOL_SET %s KeyTransmissionEnabled bar" % addr0, | |
312 | "EAPOL_SET 11:22:33:44:55:66 AdminControlledDirections Both" ] | |
313 | for t in tests: | |
314 | if "FAIL" not in hapd.request(t): | |
315 | raise Exception("Invalid EAPOL_SET command accepted: " + t) | |
316 | ||
317 | tests = [ ("AdminControlledDirections", "adminControlledDirections", "In"), | |
318 | ("AdminControlledDirections", "adminControlledDirections", | |
319 | "Both"), | |
320 | ("quietPeriod", "quietPeriod", "13"), | |
321 | ("serverTimeout", "serverTimeout", "7"), | |
322 | ("reAuthPeriod", "reAuthPeriod", "1234"), | |
323 | ("reAuthEnabled", "reAuthEnabled", "FALSE"), | |
324 | ("reAuthEnabled", "reAuthEnabled", "TRUE"), | |
325 | ("KeyTransmissionEnabled", "keyTxEnabled", "TRUE"), | |
326 | ("KeyTransmissionEnabled", "keyTxEnabled", "FALSE"), | |
327 | ("AdminControlledPortControl", "portControl", "ForceAuthorized"), | |
328 | ("AdminControlledPortControl", "portControl", | |
329 | "ForceUnauthorized"), | |
330 | ("AdminControlledPortControl", "portControl", "Auto") ] | |
331 | for param,mibparam,val in tests: | |
332 | if "OK" not in hapd.request("EAPOL_SET %s %s %s" % (addr0, param, val)): | |
333 | raise Exception("Failed to set %s %s" % (param, val)) | |
334 | mib = hapd.get_sta(addr0, info="eapol") | |
335 | if mib[mibparam] != val: | |
336 | raise Exception("Unexpected %s value: %s (expected %s)" % (param, mib[mibparam], val)) | |
337 | ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=5) | |
338 | if ev is None: | |
339 | raise Exception("EAP authentication did not succeed") | |
340 | time.sleep(0.1) | |
341 | hwsim_utils.test_connectivity(dev[0], hapd) | |
2496adf0 JM |
342 | |
343 | def test_ieee8021x_auth_awhile(dev, apdev): | |
344 | """IEEE 802.1X and EAPOL Authenticator aWhile handling""" | |
345 | params = hostapd.radius_params() | |
346 | params["ssid"] = "ieee8021x-open" | |
347 | params["ieee8021x"] = "1" | |
348 | params['auth_server_port'] = "18129" | |
8b8a1864 | 349 | hapd = hostapd.add_ap(apdev[0], params) |
2496adf0 JM |
350 | bssid = apdev[0]['bssid'] |
351 | addr0 = dev[0].own_addr() | |
352 | ||
353 | params = {} | |
354 | params['ssid'] = 'as' | |
355 | params['beacon_int'] = '2000' | |
356 | params['radius_server_clients'] = 'auth_serv/radius_clients.conf' | |
357 | params['radius_server_auth_port'] = '18129' | |
358 | params['eap_server'] = '1' | |
359 | params['eap_user_file'] = 'auth_serv/eap_user.conf' | |
360 | params['ca_cert'] = 'auth_serv/ca.pem' | |
361 | params['server_cert'] = 'auth_serv/server.pem' | |
362 | params['private_key'] = 'auth_serv/server.key' | |
8b8a1864 | 363 | hapd1 = hostapd.add_ap(apdev[1], params) |
2496adf0 JM |
364 | |
365 | dev[0].connect("ieee8021x-open", key_mgmt="IEEE8021X", eapol_flags="0", | |
366 | eap="PSK", identity="psk.user@example.com", | |
367 | password_hex="0123456789abcdef0123456789abcdef", | |
368 | scan_freq="2412") | |
369 | hapd1.disable() | |
370 | if "OK" not in hapd.request("EAPOL_SET %s serverTimeout 1" % addr0): | |
371 | raise Exception("Failed to set serverTimeout") | |
372 | hapd.request("EAPOL_REAUTH " + dev[0].own_addr()) | |
373 | ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5) | |
374 | ||
375 | for i in range(40): | |
376 | mib = hapd.get_sta(addr0, info="eapol") | |
377 | val = int(mib['aWhile']) | |
378 | if val > 0: | |
379 | break | |
380 | time.sleep(1) | |
381 | if val == 0: | |
382 | raise Exception("aWhile did not increase") | |
383 | ||
384 | hapd.dump_monitor() | |
385 | for i in range(40): | |
386 | mib = hapd.get_sta(addr0, info="eapol") | |
387 | val = int(mib['aWhile']) | |
388 | if val < 5: | |
389 | break | |
390 | time.sleep(1) | |
391 | ev = hapd.wait_event(["CTRL-EVENT-EAP-PROPOSED"], timeout=10) | |
392 | if ev is None: | |
393 | raise Exception("Authentication restart not seen") |