]> git.ipfire.org Git - thirdparty/hostap.git/blame - tests/hwsim/test_macsec.py
HE: MCS size is always a minimum of 4 bytes
[thirdparty/hostap.git] / tests / hwsim / test_macsec.py
CommitLineData
ead573d8 1# Test cases for MACsec/MKA
b21540e6 2# Copyright (c) 2018-2019, Jouni Malinen <j@w1.fi>
ead573d8
JM
3#
4# This software may be distributed under the terms of the BSD license.
5# See README for more details.
6
7import logging
8logger = logging.getLogger()
e1810300 9import binascii
ead573d8
JM
10import os
11import signal
12import subprocess
13import time
14
41bca926 15import hostapd
ead573d8
JM
16from wpasupplicant import WpaSupplicant
17import hwsim_utils
344929a9 18from utils import HwsimSkip, alloc_fail, fail_test, wait_fail_trigger
ead573d8
JM
19
20def cleanup_macsec():
b21540e6 21 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5', monitor=False)
ead573d8
JM
22 wpas.interface_remove("veth0")
23 wpas.interface_remove("veth1")
b21540e6 24 del wpas
ead573d8
JM
25 subprocess.call(["ip", "link", "del", "veth0"],
26 stderr=open('/dev/null', 'w'))
27
28def test_macsec_psk(dev, apdev, params):
29 """MACsec PSK"""
30 try:
31 run_macsec_psk(dev, apdev, params, "macsec_psk")
32 finally:
33 cleanup_macsec()
34
35def test_macsec_psk_mka_life_time(dev, apdev, params):
36 """MACsec PSK - MKA life time"""
37 try:
38 run_macsec_psk(dev, apdev, params, "macsec_psk_mka_life_time")
b21540e6 39 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5', monitor=False)
ead573d8 40 wpas.interface_remove("veth1")
b21540e6 41 del wpas
ead573d8
JM
42 # Wait for live peer to be removed on veth0
43 time.sleep(6.1)
44 finally:
45 cleanup_macsec()
46
47def test_macsec_psk_integ_only(dev, apdev, params):
48 """MACsec PSK (integrity only)"""
49 try:
50 run_macsec_psk(dev, apdev, params, "macsec_psk_integ_only",
51 integ_only=True)
52 finally:
53 cleanup_macsec()
54
55def test_macsec_psk_port(dev, apdev, params):
56 """MACsec PSK (port)"""
57 try:
58 run_macsec_psk(dev, apdev, params, "macsec_psk_port",
59 port0=65534, port1=65534)
60 finally:
61 cleanup_macsec()
62
63def test_macsec_psk_different_ports(dev, apdev, params):
64 """MACsec PSK (different ports)"""
65 try:
66 run_macsec_psk(dev, apdev, params, "macsec_psk_different_ports",
67 port0=2, port1=3)
68 finally:
69 cleanup_macsec()
70
71def test_macsec_psk_shorter_ckn(dev, apdev, params):
72 """MACsec PSK (shorter CKN)"""
73 try:
74 ckn = "11223344"
75 run_macsec_psk(dev, apdev, params, "macsec_psk_shorter_ckn",
76 ckn0=ckn, ckn1=ckn)
77 finally:
78 cleanup_macsec()
79
80def test_macsec_psk_shorter_ckn2(dev, apdev, params):
81 """MACsec PSK (shorter CKN, unaligned)"""
82 try:
83 ckn = "112233"
84 run_macsec_psk(dev, apdev, params, "macsec_psk_shorter_ckn2",
85 ckn0=ckn, ckn1=ckn)
86 finally:
87 cleanup_macsec()
88
89def test_macsec_psk_ckn_mismatch(dev, apdev, params):
90 """MACsec PSK (CKN mismatch)"""
91 try:
92 ckn0 = "11223344"
93 ckn1 = "1122334455667788"
94 run_macsec_psk(dev, apdev, params, "macsec_psk_ckn_mismatch",
95 ckn0=ckn0, ckn1=ckn1, expect_failure=True)
96 finally:
97 cleanup_macsec()
98
99def test_macsec_psk_cak_mismatch(dev, apdev, params):
100 """MACsec PSK (CAK mismatch)"""
101 try:
102 cak0 = 16*"11"
103 cak1 = 16*"22"
104 run_macsec_psk(dev, apdev, params, "macsec_psk_cak_mismatch",
105 cak0=cak0, cak1=cak1, expect_failure=True)
106 finally:
107 cleanup_macsec()
108
109def test_macsec_psk_256(dev, apdev, params):
110 """MACsec PSK with 256-bit keys"""
111 try:
112 cak = "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
113 run_macsec_psk(dev, apdev, params, "macsec_psk_256", cak0=cak, cak1=cak)
114 finally:
115 cleanup_macsec()
116
117def set_mka_psk_config(dev, mka_priority=None, integ_only=False, port=None,
118 ckn=None, cak=None):
119 dev.set("eapol_version", "3")
120 dev.set("ap_scan", "0")
121 dev.set("fast_reauth", "1")
122
123 id = dev.add_network()
124 dev.set_network(id, "key_mgmt", "NONE")
125 if cak is None:
126 cak = "000102030405060708090a0b0c0d0e0f"
127 dev.set_network(id, "mka_cak", cak)
128 if ckn is None:
129 ckn = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
130 dev.set_network(id, "mka_ckn", ckn)
131 dev.set_network(id, "eapol_flags", "0")
132 dev.set_network(id, "macsec_policy", "1")
133 if integ_only:
134 dev.set_network(id, "macsec_integ_only", "1")
135 if mka_priority is not None:
136 dev.set_network(id, "mka_priority", str(mka_priority))
137 if port is not None:
138 dev.set_network(id, "macsec_port", str(port))
139
140 dev.select_network(id)
141
41bca926
JM
142def set_mka_eap_config(dev, mka_priority=None, integ_only=False, port=None):
143 dev.set("eapol_version", "3")
144 dev.set("ap_scan", "0")
145 dev.set("fast_reauth", "1")
146
147 id = dev.add_network()
148 dev.set_network(id, "key_mgmt", "NONE")
149 dev.set_network(id, "eapol_flags", "0")
150 dev.set_network(id, "macsec_policy", "1")
151 if integ_only:
152 dev.set_network(id, "macsec_integ_only", "1")
153 if mka_priority is not None:
154 dev.set_network(id, "mka_priority", str(mka_priority))
155 if port is not None:
156 dev.set_network(id, "macsec_port", str(port))
157
158 dev.set_network(id, "key_mgmt", "IEEE8021X")
159 dev.set_network(id, "eap", "TTLS")
160 dev.set_network_quoted(id, "ca_cert", "auth_serv/ca.pem")
161 dev.set_network_quoted(id, "phase2", "auth=MSCHAPV2")
162 dev.set_network_quoted(id, "anonymous_identity", "ttls")
163 dev.set_network_quoted(id, "identity", "DOMAIN\mschapv2 user")
164 dev.set_network_quoted(id, "password", "password")
165
166 dev.select_network(id)
167
ead573d8 168def log_ip_macsec():
fab49f61 169 cmd = subprocess.Popen(["ip", "macsec", "show"],
ead573d8
JM
170 stdout=subprocess.PIPE,
171 stderr=open('/dev/null', 'w'))
1c48c9bc 172 res = cmd.stdout.read().decode()
ead573d8
JM
173 cmd.stdout.close()
174 logger.info("ip macsec:\n" + res)
175
176def log_ip_link():
fab49f61 177 cmd = subprocess.Popen(["ip", "link", "show"],
ead573d8 178 stdout=subprocess.PIPE)
1c48c9bc 179 res = cmd.stdout.read().decode()
ead573d8
JM
180 cmd.stdout.close()
181 logger.info("ip link:\n" + res)
182
344929a9 183def add_veth():
ead573d8 184 try:
fab49f61
JM
185 subprocess.check_call(["ip", "link", "add", "veth0", "type", "veth",
186 "peer", "name", "veth1"])
ead573d8
JM
187 except subprocess.CalledProcessError:
188 raise HwsimSkip("veth not supported (kernel CONFIG_VETH)")
189
344929a9
JM
190def add_wpas_interfaces(count=2):
191 wpa = []
192 try:
193 for i in range(count):
194 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
195 wpas.interface_add("veth%d" % i, driver="macsec_linux")
196 wpa.append(wpas)
bab493b9 197 except Exception as e:
344929a9 198 if "Failed to add a dynamic wpa_supplicant interface" in str(e):
3281c159 199 raise HwsimSkip("macsec supported (wpa_supplicant CONFIG_MACSEC, CONFIG_DRIVER_MACSEC_LINUX; kernel CONFIG_MACSEC)")
344929a9
JM
200 raise
201
202 return wpa
203
0d09bd08
JM
204def lower_addr(addr1, addr2):
205 a1 = addr1.split(':')
206 a2 = addr2.split(':')
207 for i in range(6):
e1810300 208 if binascii.unhexlify(a1[i]) < binascii.unhexlify(a2[i]):
0d09bd08 209 return True
e1810300 210 if binascii.unhexlify(a1[i]) > binascii.unhexlify(a2[i]):
0d09bd08
JM
211 return False
212 return False
213
41bca926 214def wait_mka_done(wpa, expect_failure=False, hostapd=False):
344929a9
JM
215 max_iter = 14 if expect_failure else 40
216 for i in range(max_iter):
0d09bd08
JM
217 done = True
218 for w in wpa:
219 secured = w.get_status_field("Secured")
41bca926
JM
220 live_peers = w.get_status_field("live_peers")
221 peers = int(live_peers) if live_peers else 0
0d09bd08
JM
222 if expect_failure and (secured == "Yes" or peers > 0):
223 raise Exception("MKA completed unexpectedly")
41bca926
JM
224 expect_peers = len(wpa) - 1
225 if hostapd:
226 expect_peers += 1
227 if peers != expect_peers or secured != "Yes":
0d09bd08
JM
228 done = False
229 break
230 w.dump_monitor()
231 if done:
232 break
344929a9
JM
233 time.sleep(0.5)
234
235 if expect_failure:
344929a9
JM
236 return
237
0d09bd08
JM
238 if not done:
239 raise Exception("MKA not completed successfully")
240
41bca926
JM
241 if hostapd:
242 # TODO: check that hostapd is the key server
243 return
244
0d09bd08
JM
245 key_server = None
246 ks_prio = 999
247 for w in wpa:
248 logger.info("%s STATUS:\n%s" % (w.ifname, w.request("STATUS")))
249 addr = w.get_status_field("address")
250 prio = int(w.get_status_field("Actor Priority"))
251 if key_server is None or prio < ks_prio or \
252 (prio == ks_prio and lower_addr(addr, ks_addr)):
253 key_server = w
254 ks_addr = addr
255 ks_prio = prio
256
257 logger.info("Expected key server: " + key_server.ifname)
258 if key_server.get_status_field("is_key_server") != "Yes":
259 raise Exception("Expected key server was not elected")
260 for w in wpa:
261 if w != key_server and w.get_status_field("is_key_server") == "Yes":
262 raise Exception("Unexpected key server")
344929a9
JM
263
264def run_macsec_psk(dev, apdev, params, prefix, integ_only=False, port0=None,
265 port1=None, ckn0=None, ckn1=None, cak0=None, cak1=None,
266 expect_failure=False):
267 add_veth()
268
ead573d8
JM
269 cap_veth0 = os.path.join(params['logdir'], prefix + ".veth0.pcap")
270 cap_veth1 = os.path.join(params['logdir'], prefix + ".veth1.pcap")
271 cap_macsec0 = os.path.join(params['logdir'], prefix + ".macsec0.pcap")
272 cap_macsec1 = os.path.join(params['logdir'], prefix + ".macsec1.pcap")
273
274 for i in range(2):
fab49f61 275 subprocess.check_call(["ip", "link", "set", "dev", "veth%d" % i, "up"])
ead573d8
JM
276
277 cmd = {}
278 cmd[0] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', 'veth0',
279 '-w', cap_veth0, '-s', '2000',
280 '--immediate-mode'],
281 stderr=open('/dev/null', 'w'))
282 cmd[1] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', 'veth1',
283 '-w', cap_veth1, '-s', '2000',
284 '--immediate-mode'],
285 stderr=open('/dev/null', 'w'))
286
344929a9
JM
287 wpa = add_wpas_interfaces()
288 wpas0 = wpa[0]
289 wpas1 = wpa[1]
ead573d8
JM
290
291 set_mka_psk_config(wpas0, integ_only=integ_only, port=port0, ckn=ckn0,
292 cak=cak0)
293 set_mka_psk_config(wpas1, mka_priority=100, integ_only=integ_only,
294 port=port1, ckn=ckn1, cak=cak1)
295
296 log_ip_macsec()
297 log_ip_link()
298
299 logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
300 logger.info("wpas1 STATUS:\n" + wpas1.request("STATUS"))
301 logger.info("wpas0 STATUS-DRIVER:\n" + wpas0.request("STATUS-DRIVER"))
302 logger.info("wpas1 STATUS-DRIVER:\n" + wpas1.request("STATUS-DRIVER"))
303 macsec_ifname0 = wpas0.get_driver_status_field("parent_ifname")
304 macsec_ifname1 = wpas1.get_driver_status_field("parent_ifname")
305
0d09bd08 306 wait_mka_done(wpa, expect_failure=expect_failure)
ead573d8
JM
307
308 if expect_failure:
ead573d8
JM
309 for i in range(len(cmd)):
310 cmd[i].terminate()
311 return
312
313 cmd[2] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', macsec_ifname0,
314 '-w', cap_macsec0, '-s', '2000',
315 '--immediate-mode'],
316 stderr=open('/dev/null', 'w'))
317 cmd[3] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', macsec_ifname1,
318 '-w', cap_macsec1, '-s', '2000',
319 '--immediate-mode'],
320 stderr=open('/dev/null', 'w'))
321 time.sleep(0.5)
322
90eb910e
JM
323 mi0 = wpas0.get_status_field("mi")
324 mi1 = wpas1.get_status_field("mi")
325 sci0 = wpas0.get_status_field("actor_sci")
326 sci1 = wpas1.get_status_field("actor_sci")
327 logger.info("wpas0 MIB:\n" + wpas0.request("MIB"))
328 logger.info("wpas1 MIB:\n" + wpas1.request("MIB"))
329 mib0 = wpas0.get_mib()
330 mib1 = wpas1.get_mib()
331
332 if mib0['ieee8021XKayMkaPeerListMI'] != mi1:
333 raise Exception("Unexpected ieee8021XKayMkaPeerListMI value (0)")
334 if mib0['ieee8021XKayMkaPeerListType'] != "1":
335 raise Exception("Unexpected ieee8021XKayMkaPeerListType value (0)")
336 if mib0['ieee8021XKayMkaPeerListSCI'] != sci1:
337 raise Exception("Unexpected ieee8021XKayMkaPeerListSCI value (0)")
338 if mib1['ieee8021XKayMkaPeerListMI'] != mi0:
339 raise Exception("Unexpected ieee8021XKayMkaPeerListMI value (1)")
340 if mib1['ieee8021XKayMkaPeerListType'] != "1":
341 raise Exception("Unexpected ieee8021XKayMkaPeerListType value (1)")
342 if mib1['ieee8021XKayMkaPeerListSCI'] != sci0:
343 raise Exception("Unexpected ieee8021XKayMkaPeerListSCI value (1)")
344
ead573d8
JM
345 logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
346 logger.info("wpas1 STATUS:\n" + wpas1.request("STATUS"))
347 log_ip_macsec()
348 hwsim_utils.test_connectivity(wpas0, wpas1,
349 ifname1=macsec_ifname0,
350 ifname2=macsec_ifname1,
351 send_len=1400)
352 log_ip_macsec()
353
354 time.sleep(1)
355 for i in range(len(cmd)):
356 cmd[i].terminate()
357
a2acadf6 358def cleanup_macsec_br(count):
b21540e6 359 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5', monitor=False)
a2acadf6
JM
360 for i in range(count):
361 wpas.interface_remove("veth%d" % i)
362 subprocess.call(["ip", "link", "del", "veth%d" % i],
363 stderr=open('/dev/null', 'w'))
fe5400dd 364 del wpas
a2acadf6
JM
365 subprocess.call(["ip", "link", "set", "brveth", "down"])
366 subprocess.call(["brctl", "delbr", "brveth"])
367
368def test_macsec_psk_br2(dev, apdev):
369 """MACsec PSK (bridge; 2 devices)"""
370 try:
371 run_macsec_psk_br(dev, apdev, 2, [10, 20])
372 finally:
373 cleanup_macsec_br(count=2)
374
375def test_macsec_psk_br2_same_prio(dev, apdev):
376 """MACsec PSK (bridge; 2 devices, same mka_priority)"""
377 try:
378 run_macsec_psk_br(dev, apdev, 2, [None, None])
379 finally:
380 cleanup_macsec_br(count=2)
381
382def test_macsec_psk_br3(dev, apdev):
383 """MACsec PSK (bridge; 3 devices)"""
384 try:
385 run_macsec_psk_br(dev, apdev, 3, [10, 20, 30])
386 finally:
387 cleanup_macsec_br(count=3)
388
389def test_macsec_psk_br3_same_prio(dev, apdev):
390 """MACsec PSK (bridge; 3 devices, same mka_priority)"""
391 try:
392 run_macsec_psk_br(dev, apdev, 3, [None, None, None])
393 finally:
394 cleanup_macsec_br(count=3)
395
396def run_macsec_psk_br(dev, apdev, count, mka_priority):
397 subprocess.check_call(["brctl", "addbr", "brveth"])
398 subprocess.call(["echo 8 > /sys/devices/virtual/net/brveth/bridge/group_fwd_mask"],
399 shell=True)
400
401 try:
402 for i in range(count):
fab49f61
JM
403 subprocess.check_call(["ip", "link", "add", "veth%d" % i,
404 "type", "veth",
405 "peer", "name", "vethbr%d" % i])
a2acadf6 406 subprocess.check_call(["ip", "link", "set", "vethbr%d" % i, "up"])
fab49f61
JM
407 subprocess.check_call(["brctl", "addif", "brveth",
408 "vethbr%d" % i])
a2acadf6
JM
409 except subprocess.CalledProcessError:
410 raise HwsimSkip("veth not supported (kernel CONFIG_VETH)")
411
412 subprocess.check_call(["ip", "link", "set", "brveth", "up"])
413
414 log_ip_link()
415
416 wpa = add_wpas_interfaces(count=count)
417 for i in range(count):
418 set_mka_psk_config(wpa[i], mka_priority=mka_priority[i])
419 wpa[i].dump_monitor()
420 wait_mka_done(wpa)
421
422 macsec_ifname = []
423 for i in range(count):
424 macsec_ifname.append(wpa[i].get_driver_status_field("parent_ifname"))
425
426 timeout = 2
427 max_tries = 2 if count > 2 else 1
428 success_seen = False
429 failure_seen = False
430 for i in range(1, count):
431 try:
432 hwsim_utils.test_connectivity(wpa[0], wpa[i],
433 ifname1=macsec_ifname[0],
434 ifname2=macsec_ifname[i],
435 send_len=1400,
436 timeout=timeout, max_tries=max_tries)
437 success_seen = True
438 logger.info("Traffic test %d<->%d success" % (0, i))
439 except:
440 failure_seen = True
441 logger.info("Traffic test %d<->%d failure" % (0, i))
442 for i in range(2, count):
443 try:
444 hwsim_utils.test_connectivity(wpa[1], wpa[i],
445 ifname1=macsec_ifname[1],
446 ifname2=macsec_ifname[i],
447 send_len=1400,
448 timeout=timeout, max_tries=max_tries)
449 success_seen = True
450 logger.info("Traffic test %d<->%d success" % (1, i))
451 except:
452 failure_seen = True
453 logger.info("Traffic test %d<->%d failure" % (1, i))
454
455 if not success_seen:
456 raise Exception("None of the data traffic tests succeeded")
457
458 # Something seems to be failing with three device tests semi-regularly, so
459 # do not report this as a failed test case until the real reason behind
460 # those failures have been determined.
461 if failure_seen:
462 if count < 3:
463 raise Exception("Data traffic test failed")
464 else:
465 logger.info("Data traffic test failed - ignore for now for >= 3 device cases")
466
fe5400dd 467 for i in range(count):
b21540e6 468 wpa[i].close_monitor()
fe5400dd 469 for i in range(count):
b21540e6 470 wpa[0].close_control()
fe5400dd
JM
471 del wpa[0]
472
ead573d8
JM
473def test_macsec_psk_ns(dev, apdev, params):
474 """MACsec PSK (netns)"""
475 try:
476 run_macsec_psk_ns(dev, apdev, params)
477 finally:
478 prefix = "macsec_psk_ns"
479 pidfile = os.path.join(params['logdir'], prefix + ".pid")
480 for i in range(2):
481 was_running = False
482 if os.path.exists(pidfile + str(i)):
483 with open(pidfile + str(i), 'r') as f:
484 pid = int(f.read().strip())
485 logger.info("wpa_supplicant for wpas%d still running with pid %d - kill it" % (i, pid))
486 was_running = True
487 os.kill(pid, signal.SIGTERM)
488 if was_running:
489 time.sleep(1)
490
491 subprocess.call(["ip", "netns", "exec", "ns0",
492 "ip", "link", "del", "veth0"],
493 stderr=open('/dev/null', 'w'))
494 subprocess.call(["ip", "link", "del", "veth0"],
495 stderr=open('/dev/null', 'w'))
496 log_ip_link_ns()
497 subprocess.call(["ip", "netns", "delete", "ns0"],
498 stderr=open('/dev/null', 'w'))
499 subprocess.call(["ip", "netns", "delete", "ns1"],
500 stderr=open('/dev/null', 'w'))
501
502def log_ip_macsec_ns():
fab49f61 503 cmd = subprocess.Popen(["ip", "macsec", "show"],
ead573d8
JM
504 stdout=subprocess.PIPE,
505 stderr=open('/dev/null', 'w'))
1c48c9bc 506 res = cmd.stdout.read().decode()
ead573d8
JM
507 cmd.stdout.close()
508 logger.info("ip macsec show:\n" + res)
509
fab49f61
JM
510 cmd = subprocess.Popen(["ip", "netns", "exec", "ns0",
511 "ip", "macsec", "show"],
ead573d8
JM
512 stdout=subprocess.PIPE,
513 stderr=open('/dev/null', 'w'))
1c48c9bc 514 res = cmd.stdout.read().decode()
ead573d8
JM
515 cmd.stdout.close()
516 logger.info("ip macsec show (ns0):\n" + res)
517
fab49f61
JM
518 cmd = subprocess.Popen(["ip", "netns", "exec", "ns1",
519 "ip", "macsec", "show"],
ead573d8
JM
520 stdout=subprocess.PIPE,
521 stderr=open('/dev/null', 'w'))
1c48c9bc 522 res = cmd.stdout.read().decode()
ead573d8
JM
523 cmd.stdout.close()
524 logger.info("ip macsec show (ns1):\n" + res)
525
526def log_ip_link_ns():
fab49f61 527 cmd = subprocess.Popen(["ip", "link", "show"],
ead573d8 528 stdout=subprocess.PIPE)
1c48c9bc 529 res = cmd.stdout.read().decode()
ead573d8
JM
530 cmd.stdout.close()
531 logger.info("ip link:\n" + res)
532
fab49f61
JM
533 cmd = subprocess.Popen(["ip", "netns", "exec", "ns0",
534 "ip", "link", "show"],
ead573d8
JM
535 stdout=subprocess.PIPE,
536 stderr=open('/dev/null', 'w'))
1c48c9bc 537 res = cmd.stdout.read().decode()
ead573d8
JM
538 cmd.stdout.close()
539 logger.info("ip link show (ns0):\n" + res)
540
fab49f61
JM
541 cmd = subprocess.Popen(["ip", "netns", "exec", "ns1",
542 "ip", "link", "show"],
ead573d8
JM
543 stdout=subprocess.PIPE,
544 stderr=open('/dev/null', 'w'))
1c48c9bc 545 res = cmd.stdout.read().decode()
ead573d8
JM
546 cmd.stdout.close()
547 logger.info("ip link show (ns1):\n" + res)
548
549def write_conf(conffile, mka_priority=None):
550 with open(conffile, 'w') as f:
551 f.write("ctrl_interface=DIR=/var/run/wpa_supplicant\n")
552 f.write("eapol_version=3\n")
553 f.write("ap_scan=0\n")
554 f.write("fast_reauth=1\n")
555 f.write("network={\n")
26b0c290
MH
556 f.write(" key_mgmt=NONE\n")
557 f.write(" mka_cak=000102030405060708090a0b0c0d0e0f\n")
558 f.write(" mka_ckn=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\n")
ead573d8
JM
559 if mka_priority is not None:
560 f.write(" mka_priority=%d\n" % mka_priority)
26b0c290
MH
561 f.write(" eapol_flags=0\n")
562 f.write(" macsec_policy=1\n")
ead573d8
JM
563 f.write("}\n")
564
565def run_macsec_psk_ns(dev, apdev, params):
566 try:
fab49f61
JM
567 subprocess.check_call(["ip", "link", "add", "veth0", "type", "veth",
568 "peer", "name", "veth1"])
ead573d8
JM
569 except subprocess.CalledProcessError:
570 raise HwsimSkip("veth not supported (kernel CONFIG_VETH)")
571
572 prefix = "macsec_psk_ns"
573 conffile = os.path.join(params['logdir'], prefix + ".conf")
574 pidfile = os.path.join(params['logdir'], prefix + ".pid")
575 logfile0 = os.path.join(params['logdir'], prefix + ".veth0.log")
576 logfile1 = os.path.join(params['logdir'], prefix + ".veth1.log")
577 cap_veth0 = os.path.join(params['logdir'], prefix + ".veth0.pcap")
578 cap_veth1 = os.path.join(params['logdir'], prefix + ".veth1.pcap")
579 cap_macsec0 = os.path.join(params['logdir'], prefix + ".macsec0.pcap")
580 cap_macsec1 = os.path.join(params['logdir'], prefix + ".macsec1.pcap")
581
582 for i in range(2):
583 try:
fab49f61 584 subprocess.check_call(["ip", "netns", "add", "ns%d" % i])
ead573d8
JM
585 except subprocess.CalledProcessError:
586 raise HwsimSkip("network namespace not supported (kernel CONFIG_NAMESPACES, CONFIG_NET_NS)")
fab49f61
JM
587 subprocess.check_call(["ip", "link", "set", "veth%d" % i,
588 "netns", "ns%d" %i])
589 subprocess.check_call(["ip", "netns", "exec", "ns%d" % i,
590 "ip", "link", "set", "dev", "veth%d" % i,
591 "up"])
ead573d8
JM
592
593 cmd = {}
594 cmd[0] = subprocess.Popen(['ip', 'netns', 'exec', 'ns0',
595 'tcpdump', '-p', '-U', '-i', 'veth0',
596 '-w', cap_veth0, '-s', '2000',
597 '--immediate-mode'],
598 stderr=open('/dev/null', 'w'))
599 cmd[1] = subprocess.Popen(['ip', 'netns', 'exec', 'ns1',
600 'tcpdump', '-p', '-U', '-i', 'veth1',
601 '-w', cap_veth1, '-s', '2000',
602 '--immediate-mode'],
603 stderr=open('/dev/null', 'w'))
604
605 write_conf(conffile + '0')
606 write_conf(conffile + '1', mka_priority=100)
607
608 prg = os.path.join(params['logdir'],
609 'alt-wpa_supplicant/wpa_supplicant/wpa_supplicant')
610 if not os.path.exists(prg):
611 prg = '../../wpa_supplicant/wpa_supplicant'
612
fab49f61
JM
613 arg = ["ip", "netns", "exec", "ns0",
614 prg, '-BdddtKW', '-P', pidfile + '0', '-f', logfile0,
615 '-g', '/tmp/wpas-veth0',
616 '-Dmacsec_linux', '-c', conffile + '0', '-i', "veth0"]
ead573d8
JM
617 logger.info("Start wpa_supplicant: " + str(arg))
618 try:
619 subprocess.check_call(arg)
620 except subprocess.CalledProcessError:
3281c159 621 raise HwsimSkip("macsec supported (wpa_supplicant CONFIG_MACSEC, CONFIG_DRIVER_MACSEC_LINUX; kernel CONFIG_MACSEC)")
ead573d8
JM
622
623 if os.path.exists("wpa_supplicant-macsec2"):
624 logger.info("Use alternative wpa_supplicant binary for one of the macsec devices")
625 prg = "wpa_supplicant-macsec2"
626
fab49f61
JM
627 arg = ["ip", "netns", "exec", "ns1",
628 prg, '-BdddtKW', '-P', pidfile + '1', '-f', logfile1,
629 '-g', '/tmp/wpas-veth1',
630 '-Dmacsec_linux', '-c', conffile + '1', '-i', "veth1"]
ead573d8
JM
631 logger.info("Start wpa_supplicant: " + str(arg))
632 subprocess.check_call(arg)
633
634 wpas0 = WpaSupplicant('veth0', '/tmp/wpas-veth0')
635 wpas1 = WpaSupplicant('veth1', '/tmp/wpas-veth1')
636
637 log_ip_macsec_ns()
638 log_ip_link_ns()
639
640 logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
641 logger.info("wpas1 STATUS:\n" + wpas1.request("STATUS"))
642 logger.info("wpas0 STATUS-DRIVER:\n" + wpas0.request("STATUS-DRIVER"))
643 logger.info("wpas1 STATUS-DRIVER:\n" + wpas1.request("STATUS-DRIVER"))
ead573d8
JM
644
645 for i in range(10):
658ed3ba
JM
646 macsec_ifname0 = wpas0.get_driver_status_field("parent_ifname")
647 macsec_ifname1 = wpas1.get_driver_status_field("parent_ifname")
648 if "Number of Keys" in wpas0.request("STATUS"):
649 key_tx0 = int(wpas0.get_status_field("Number of Keys Distributed"))
650 key_rx0 = int(wpas0.get_status_field("Number of Keys Received"))
651 else:
652 key_tx0 = 0
653 key_rx0 = 0
654 if "Number of Keys" in wpas1.request("STATUS"):
655 key_tx1 = int(wpas1.get_status_field("Number of Keys Distributed"))
656 key_rx1 = int(wpas1.get_status_field("Number of Keys Received"))
657 else:
658 key_tx1 = 0
659 key_rx1 = 0
ead573d8
JM
660 if key_rx0 > 0 and key_tx1 > 0:
661 break
662 time.sleep(1)
663
664 cmd[2] = subprocess.Popen(['ip', 'netns', 'exec', 'ns0',
665 'tcpdump', '-p', '-U', '-i', macsec_ifname0,
666 '-w', cap_macsec0, '-s', '2000',
667 '--immediate-mode'],
668 stderr=open('/dev/null', 'w'))
669 cmd[3] = subprocess.Popen(['ip', 'netns', 'exec', 'ns0',
670 'tcpdump', '-p', '-U', '-i', macsec_ifname1,
671 '-w', cap_macsec1, '-s', '2000',
672 '--immediate-mode'],
673 stderr=open('/dev/null', 'w'))
674 time.sleep(0.5)
675
676 logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
677 logger.info("wpas1 STATUS:\n" + wpas1.request("STATUS"))
678 log_ip_macsec_ns()
679 hwsim_utils.test_connectivity(wpas0, wpas1,
680 ifname1=macsec_ifname0,
681 ifname2=macsec_ifname1,
682 send_len=1400)
683 log_ip_macsec_ns()
684
685 subprocess.check_call(['ip', 'netns', 'exec', 'ns0',
686 'ip', 'addr', 'add', '192.168.248.17/30',
687 'dev', macsec_ifname0])
688 subprocess.check_call(['ip', 'netns', 'exec', 'ns1',
689 'ip', 'addr', 'add', '192.168.248.18/30',
690 'dev', macsec_ifname1])
691 c = subprocess.Popen(['ip', 'netns', 'exec', 'ns0',
692 'ping', '-c', '2', '192.168.248.18'],
693 stdout=subprocess.PIPE)
1c48c9bc 694 res = c.stdout.read().decode()
ead573d8
JM
695 c.stdout.close()
696 logger.info("ping:\n" + res)
697 if "2 packets transmitted, 2 received" not in res:
698 raise Exception("ping did not work")
699
b21540e6 700 wpas0.close_monitor()
ead573d8 701 wpas0.request("TERMINATE")
b21540e6 702 wpas0.close_control()
ead573d8 703 del wpas0
b21540e6 704 wpas1.close_monitor()
ead573d8 705 wpas1.request("TERMINATE")
b21540e6 706 wpas1.close_control()
ead573d8
JM
707 del wpas1
708
709 time.sleep(1)
710 for i in range(len(cmd)):
711 cmd[i].terminate()
344929a9
JM
712
713def test_macsec_psk_fail_cp(dev, apdev):
714 """MACsec PSK local failures in CP state machine"""
715 try:
716 add_veth()
717 wpa = add_wpas_interfaces()
718 set_mka_psk_config(wpa[0])
719 with alloc_fail(wpa[0], 1, "sm_CP_RECEIVE_Enter"):
720 set_mka_psk_config(wpa[1])
721 wait_fail_trigger(wpa[0], "GET_ALLOC_FAIL", max_iter=100)
722
0d09bd08 723 wait_mka_done(wpa)
344929a9
JM
724 finally:
725 cleanup_macsec()
726
727def test_macsec_psk_fail_cp2(dev, apdev):
728 """MACsec PSK local failures in CP state machine (2)"""
729 try:
730 add_veth()
731 wpa = add_wpas_interfaces()
732 set_mka_psk_config(wpa[0])
733 with alloc_fail(wpa[1], 1, "ieee802_1x_cp_sm_init"):
734 set_mka_psk_config(wpa[1])
735 wait_fail_trigger(wpa[1], "GET_ALLOC_FAIL", max_iter=100)
736
0d09bd08 737 wait_mka_done(wpa)
344929a9
JM
738 finally:
739 cleanup_macsec()
41bca926
JM
740
741def cleanup_macsec_hostapd():
742 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5', monitor=False)
743 wpas.interface_remove("veth0")
744 del wpas
745 hapd = hostapd.HostapdGlobal()
746 hapd.remove('veth1')
747 subprocess.call(["ip", "link", "del", "veth0"],
748 stderr=open('/dev/null', 'w'))
749 log_ip_link()
750
751def test_macsec_hostapd_psk(dev, apdev, params):
752 """MACsec PSK with hostapd"""
753 try:
754 run_macsec_hostapd_psk(dev, apdev, params, "macsec_hostapd_psk")
755 finally:
756 cleanup_macsec_hostapd()
757
758def run_macsec_hostapd_psk(dev, apdev, params, prefix, integ_only=False,
759 port0=None, port1=None, ckn0=None, ckn1=None,
760 cak0=None, cak1=None, expect_failure=False):
761 add_veth()
762
763 cap_veth0 = os.path.join(params['logdir'], prefix + ".veth0.pcap")
764 cap_veth1 = os.path.join(params['logdir'], prefix + ".veth1.pcap")
765 cap_macsec0 = os.path.join(params['logdir'], prefix + ".macsec0.pcap")
766 cap_macsec1 = os.path.join(params['logdir'], prefix + ".macsec1.pcap")
767
768 for i in range(2):
769 subprocess.check_call(["ip", "link", "set", "dev", "veth%d" % i, "up"])
770
771 cmd = {}
772 cmd[0] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', 'veth0',
773 '-w', cap_veth0, '-s', '2000',
774 '--immediate-mode'],
775 stderr=open('/dev/null', 'w'))
776 cmd[1] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', 'veth1',
777 '-w', cap_veth1, '-s', '2000',
778 '--immediate-mode'],
779 stderr=open('/dev/null', 'w'))
780
781 wpa = add_wpas_interfaces(count=1)
782 wpas0 = wpa[0]
783
784 set_mka_psk_config(wpas0, integ_only=integ_only, port=port0, ckn=ckn0,
785 cak=cak0, mka_priority=100)
786
787 if cak1 is None:
788 cak1 = "000102030405060708090a0b0c0d0e0f"
789 if ckn1 is None:
790 ckn1 = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
791 params = {"driver": "macsec_linux",
792 "interface": "veth1",
793 "eapol_version": "3",
794 "mka_cak": cak1,
795 "mka_ckn": ckn1,
796 "macsec_policy": "1",
797 "mka_priority": "1"}
798 if integ_only:
799 params["macsec_integ_only"] = "1"
800 if port1 is not None:
801 params["macsec_port"] = str(port1)
802 apdev = {'ifname': 'veth1'}
803 try:
804 hapd = hostapd.add_ap(apdev, params, driver="macsec_linux")
805 except:
806 raise HwsimSkip("No CONFIG_MACSEC=y in hostapd")
807
808 log_ip_macsec()
809 log_ip_link()
810
811 logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
812 logger.info("wpas0 STATUS-DRIVER:\n" + wpas0.request("STATUS-DRIVER"))
813
814 wait_mka_done(wpa, expect_failure=expect_failure, hostapd=True)
815 log_ip_link()
816
817 if expect_failure:
818 for i in range(len(cmd)):
819 cmd[i].terminate()
820 return
821
822 macsec_ifname0 = wpas0.get_driver_status_field("parent_ifname")
823 macsec_ifname1 = hapd.get_driver_status_field("parent_ifname")
824
825 cmd[2] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', macsec_ifname0,
826 '-w', cap_macsec0, '-s', '2000',
827 '--immediate-mode'],
828 stderr=open('/dev/null', 'w'))
829 cmd[3] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', macsec_ifname1,
830 '-w', cap_macsec1, '-s', '2000',
831 '--immediate-mode'],
832 stderr=open('/dev/null', 'w'))
833 time.sleep(0.5)
834
835 logger.info("wpas0 MIB:\n" + wpas0.request("MIB"))
836 logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
837 log_ip_macsec()
838 hwsim_utils.test_connectivity(wpas0, hapd,
839 ifname1=macsec_ifname0,
840 ifname2=macsec_ifname1,
841 send_len=1400)
842 log_ip_macsec()
843
844 time.sleep(1)
845 for i in range(len(cmd)):
846 cmd[i].terminate()
847
848def test_macsec_hostapd_eap(dev, apdev, params):
849 """MACsec EAP with hostapd"""
850 try:
851 run_macsec_hostapd_eap(dev, apdev, params, "macsec_hostapd_eap")
852 finally:
853 cleanup_macsec_hostapd()
854
855def run_macsec_hostapd_eap(dev, apdev, params, prefix, integ_only=False,
856 port0=None, port1=None, expect_failure=False):
857 add_veth()
858
859 cap_veth0 = os.path.join(params['logdir'], prefix + ".veth0.pcap")
860 cap_veth1 = os.path.join(params['logdir'], prefix + ".veth1.pcap")
861 cap_macsec0 = os.path.join(params['logdir'], prefix + ".macsec0.pcap")
862 cap_macsec1 = os.path.join(params['logdir'], prefix + ".macsec1.pcap")
863
864 for i in range(2):
865 subprocess.check_call(["ip", "link", "set", "dev", "veth%d" % i, "up"])
866
867 cmd = {}
868 cmd[0] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', 'veth0',
869 '-w', cap_veth0, '-s', '2000',
870 '--immediate-mode'],
871 stderr=open('/dev/null', 'w'))
872 cmd[1] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', 'veth1',
873 '-w', cap_veth1, '-s', '2000',
874 '--immediate-mode'],
875 stderr=open('/dev/null', 'w'))
876
877 wpa = add_wpas_interfaces(count=1)
878 wpas0 = wpa[0]
879
880 set_mka_eap_config(wpas0, integ_only=integ_only, port=port0,
881 mka_priority=100)
882
883 params = {"driver": "macsec_linux",
884 "interface": "veth1",
885 "eapol_version": "3",
886 "macsec_policy": "1",
887 "mka_priority": "1",
888 "ieee8021x": "1",
889 "auth_server_addr": "127.0.0.1",
890 "auth_server_port": "1812",
891 "auth_server_shared_secret": "radius",
892 "nas_identifier": "nas.w1.fi"}
893 if integ_only:
894 params["macsec_integ_only"] = "1"
895 if port1 is not None:
896 params["macsec_port"] = str(port1)
897 apdev = {'ifname': 'veth1'}
898 try:
899 hapd = hostapd.add_ap(apdev, params, driver="macsec_linux")
900 except:
901 raise HwsimSkip("No CONFIG_MACSEC=y in hostapd")
902
903 log_ip_macsec()
904 log_ip_link()
905
906 logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
907 logger.info("wpas0 STATUS-DRIVER:\n" + wpas0.request("STATUS-DRIVER"))
908
909 wait_mka_done(wpa, expect_failure=expect_failure, hostapd=True)
910 log_ip_link()
911
912 if expect_failure:
913 for i in range(len(cmd)):
914 cmd[i].terminate()
915 return
916
917 macsec_ifname0 = wpas0.get_driver_status_field("parent_ifname")
918 macsec_ifname1 = hapd.get_driver_status_field("parent_ifname")
919
920 cmd[2] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', macsec_ifname0,
921 '-w', cap_macsec0, '-s', '2000',
922 '--immediate-mode'],
923 stderr=open('/dev/null', 'w'))
924 cmd[3] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', macsec_ifname1,
925 '-w', cap_macsec1, '-s', '2000',
926 '--immediate-mode'],
927 stderr=open('/dev/null', 'w'))
928 time.sleep(0.5)
929
930 logger.info("wpas0 MIB:\n" + wpas0.request("MIB"))
931 logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
932 log_ip_macsec()
933 hwsim_utils.test_connectivity(wpas0, hapd,
934 ifname1=macsec_ifname0,
935 ifname2=macsec_ifname1,
936 send_len=1400)
937 log_ip_macsec()
938
939 time.sleep(1)
940 for i in range(len(cmd)):
941 cmd[i].terminate()