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