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