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 test_macsec_gcm_aes_256(dev, apdev, params):
119    """MACsec PSK with GCM-AES-256"""
120    try:
121        cak = "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
122        run_macsec_psk(dev, apdev, params, "macsec_gcm_aes_256",
123                       cak0=cak, cak1=cak, csindex=1)
124    finally:
125        cleanup_macsec()
126
127def set_mka_psk_config(dev, mka_priority=None, integ_only=False, port=None,
128                       ckn=None, cak=None, csindex=None):
129    dev.set("eapol_version", "3")
130    dev.set("ap_scan", "0")
131    dev.set("fast_reauth", "1")
132
133    id = dev.add_network()
134    dev.set_network(id, "key_mgmt", "NONE")
135    if cak is None:
136        cak = "000102030405060708090a0b0c0d0e0f"
137    dev.set_network(id, "mka_cak", cak)
138    if ckn is None:
139        ckn = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
140    dev.set_network(id, "mka_ckn", ckn)
141    dev.set_network(id, "eapol_flags", "0")
142    dev.set_network(id, "macsec_policy", "1")
143    if integ_only:
144        dev.set_network(id, "macsec_integ_only", "1")
145    if mka_priority is not None:
146        dev.set_network(id, "mka_priority", str(mka_priority))
147    if port is not None:
148        dev.set_network(id, "macsec_port", str(port))
149    if csindex is not None:
150        dev.set_network(id, "macsec_csindex", str(csindex))
151
152    dev.select_network(id)
153
154def set_mka_eap_config(dev, mka_priority=None, integ_only=False, port=None):
155    dev.set("eapol_version", "3")
156    dev.set("ap_scan", "0")
157    dev.set("fast_reauth", "1")
158
159    id = dev.add_network()
160    dev.set_network(id, "key_mgmt", "NONE")
161    dev.set_network(id, "eapol_flags", "0")
162    dev.set_network(id, "macsec_policy", "1")
163    if integ_only:
164        dev.set_network(id, "macsec_integ_only", "1")
165    if mka_priority is not None:
166        dev.set_network(id, "mka_priority", str(mka_priority))
167    if port is not None:
168        dev.set_network(id, "macsec_port", str(port))
169
170    dev.set_network(id, "key_mgmt", "IEEE8021X")
171    dev.set_network(id, "eap", "TTLS")
172    dev.set_network_quoted(id, "ca_cert", "auth_serv/ca.pem")
173    dev.set_network_quoted(id, "phase2", "auth=MSCHAPV2")
174    dev.set_network_quoted(id, "anonymous_identity", "ttls")
175    dev.set_network_quoted(id, "identity", "DOMAIN\mschapv2 user")
176    dev.set_network_quoted(id, "password", "password")
177
178    dev.select_network(id)
179
180def log_ip_macsec():
181    cmd = subprocess.Popen(["ip", "macsec", "show"],
182                           stdout=subprocess.PIPE,
183                           stderr=open('/dev/null', 'w'))
184    res = cmd.stdout.read().decode()
185    cmd.stdout.close()
186    logger.info("ip macsec:\n" + res)
187
188def log_ip_link():
189    cmd = subprocess.Popen(["ip", "link", "show"],
190                           stdout=subprocess.PIPE)
191    res = cmd.stdout.read().decode()
192    cmd.stdout.close()
193    logger.info("ip link:\n" + res)
194
195def add_veth():
196    try:
197        subprocess.check_call(["ip", "link", "add", "veth0", "type", "veth",
198                               "peer", "name", "veth1"])
199    except subprocess.CalledProcessError:
200        raise HwsimSkip("veth not supported (kernel CONFIG_VETH)")
201
202def add_wpas_interfaces(count=2):
203    wpa = []
204    try:
205        for i in range(count):
206            wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
207            wpas.interface_add("veth%d" % i, driver="macsec_linux")
208            wpa.append(wpas)
209    except Exception as e:
210        if "Failed to add a dynamic wpa_supplicant interface" in str(e):
211            raise HwsimSkip("macsec supported (wpa_supplicant CONFIG_MACSEC, CONFIG_DRIVER_MACSEC_LINUX; kernel CONFIG_MACSEC)")
212        raise
213
214    return wpa
215
216def lower_addr(addr1, addr2):
217    a1 = addr1.split(':')
218    a2 = addr2.split(':')
219    for i in range(6):
220        if binascii.unhexlify(a1[i]) < binascii.unhexlify(a2[i]):
221            return True
222        if binascii.unhexlify(a1[i]) > binascii.unhexlify(a2[i]):
223            return False
224    return False
225
226def wait_mka_done(wpa, expect_failure=False, hostapd=False):
227    max_iter = 14 if expect_failure else 40
228    for i in range(max_iter):
229        done = True
230        for w in wpa:
231            secured = w.get_status_field("Secured")
232            live_peers = w.get_status_field("live_peers")
233            peers = int(live_peers) if live_peers else 0
234            if expect_failure and (secured == "Yes" or peers > 0):
235                raise Exception("MKA completed unexpectedly")
236            expect_peers = len(wpa) - 1
237            if hostapd:
238                expect_peers += 1
239            if peers != expect_peers or secured != "Yes":
240                done = False
241                break
242            w.dump_monitor()
243        if done:
244            break
245        time.sleep(0.5)
246
247    if expect_failure:
248        return
249
250    if not done:
251        raise Exception("MKA not completed successfully")
252
253    if hostapd:
254        # TODO: check that hostapd is the key server
255        return
256
257    key_server = None
258    ks_prio = 999
259    for w in wpa:
260        logger.info("%s STATUS:\n%s" % (w.ifname, w.request("STATUS")))
261        addr = w.get_status_field("address")
262        prio = int(w.get_status_field("Actor Priority"))
263        if key_server is None or prio < ks_prio or \
264           (prio == ks_prio and lower_addr(addr, ks_addr)):
265            key_server = w
266            ks_addr = addr
267            ks_prio = prio
268
269    logger.info("Expected key server: " + key_server.ifname)
270    if key_server.get_status_field("is_key_server") != "Yes":
271        raise Exception("Expected key server was not elected")
272    for w in wpa:
273        if w != key_server and w.get_status_field("is_key_server") == "Yes":
274            raise Exception("Unexpected key server")
275
276def run_macsec_psk(dev, apdev, params, prefix, integ_only=False, port0=None,
277                   port1=None, ckn0=None, ckn1=None, cak0=None, cak1=None,
278                   csindex=None, expect_failure=False):
279    add_veth()
280
281    cap_veth0 = os.path.join(params['logdir'], prefix + ".veth0.pcap")
282    cap_veth1 = os.path.join(params['logdir'], prefix + ".veth1.pcap")
283    cap_macsec0 = os.path.join(params['logdir'], prefix + ".macsec0.pcap")
284    cap_macsec1 = os.path.join(params['logdir'], prefix + ".macsec1.pcap")
285
286    for i in range(2):
287        subprocess.check_call(["ip", "link", "set", "dev", "veth%d" % i, "up"])
288
289    cmd = {}
290    cmd[0] = WlantestCapture('veth0', cap_veth0)
291    cmd[1] = WlantestCapture('veth1', cap_veth1)
292
293    wpa = add_wpas_interfaces()
294    wpas0 = wpa[0]
295    wpas1 = wpa[1]
296
297    set_mka_psk_config(wpas0, integ_only=integ_only, port=port0, ckn=ckn0,
298                       cak=cak0, csindex=csindex)
299    set_mka_psk_config(wpas1, mka_priority=100, integ_only=integ_only,
300                       port=port1, ckn=ckn1, cak=cak1, csindex=csindex)
301
302    log_ip_macsec()
303    log_ip_link()
304
305    logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
306    logger.info("wpas1 STATUS:\n" + wpas1.request("STATUS"))
307    logger.info("wpas0 STATUS-DRIVER:\n" + wpas0.request("STATUS-DRIVER"))
308    logger.info("wpas1 STATUS-DRIVER:\n" + wpas1.request("STATUS-DRIVER"))
309    macsec_ifname0 = wpas0.get_driver_status_field("parent_ifname")
310    macsec_ifname1 = wpas1.get_driver_status_field("parent_ifname")
311
312    wait_mka_done(wpa, expect_failure=expect_failure)
313
314    if expect_failure:
315        for i in range(len(cmd)):
316            cmd[i].close()
317        return
318
319    cmd[2] = WlantestCapture(macsec_ifname0, cap_macsec0)
320    cmd[3] = WlantestCapture(macsec_ifname1, cap_macsec1)
321    time.sleep(0.5)
322
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
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].close()
357
358def cleanup_macsec_br(count):
359    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5', monitor=False)
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'))
364    del wpas
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):
403            subprocess.check_call(["ip", "link", "add", "veth%d" % i,
404                                   "type", "veth",
405                                   "peer", "name", "vethbr%d" % i])
406            subprocess.check_call(["ip", "link", "set", "vethbr%d" % i, "up"])
407            subprocess.check_call(["brctl", "addif", "brveth",
408                                   "vethbr%d" % i])
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
467    for i in range(count):
468        wpa[i].close_monitor()
469    for i in range(count):
470        wpa[0].close_control()
471        del wpa[0]
472
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():
503    cmd = subprocess.Popen(["ip", "macsec", "show"],
504                           stdout=subprocess.PIPE,
505                           stderr=open('/dev/null', 'w'))
506    res = cmd.stdout.read().decode()
507    cmd.stdout.close()
508    logger.info("ip macsec show:\n" + res)
509
510    cmd = subprocess.Popen(["ip", "netns", "exec", "ns0",
511                            "ip", "macsec", "show"],
512                           stdout=subprocess.PIPE,
513                           stderr=open('/dev/null', 'w'))
514    res = cmd.stdout.read().decode()
515    cmd.stdout.close()
516    logger.info("ip macsec show (ns0):\n" + res)
517
518    cmd = subprocess.Popen(["ip", "netns", "exec", "ns1",
519                            "ip", "macsec", "show"],
520                           stdout=subprocess.PIPE,
521                           stderr=open('/dev/null', 'w'))
522    res = cmd.stdout.read().decode()
523    cmd.stdout.close()
524    logger.info("ip macsec show (ns1):\n" + res)
525
526def log_ip_link_ns():
527    cmd = subprocess.Popen(["ip", "link", "show"],
528                           stdout=subprocess.PIPE)
529    res = cmd.stdout.read().decode()
530    cmd.stdout.close()
531    logger.info("ip link:\n" + res)
532
533    cmd = subprocess.Popen(["ip", "netns", "exec", "ns0",
534                            "ip", "link", "show"],
535                           stdout=subprocess.PIPE,
536                           stderr=open('/dev/null', 'w'))
537    res = cmd.stdout.read().decode()
538    cmd.stdout.close()
539    logger.info("ip link show (ns0):\n" + res)
540
541    cmd = subprocess.Popen(["ip", "netns", "exec", "ns1",
542                            "ip", "link", "show"],
543                           stdout=subprocess.PIPE,
544                           stderr=open('/dev/null', 'w'))
545    res = cmd.stdout.read().decode()
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")
556        f.write("   key_mgmt=NONE\n")
557        f.write("   mka_cak=000102030405060708090a0b0c0d0e0f\n")
558        f.write("   mka_ckn=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\n")
559        if mka_priority is not None:
560            f.write("   mka_priority=%d\n" % mka_priority)
561        f.write("   eapol_flags=0\n")
562        f.write("   macsec_policy=1\n")
563        f.write("}\n")
564
565def run_macsec_psk_ns(dev, apdev, params):
566    try:
567        subprocess.check_call(["ip", "link", "add", "veth0", "type", "veth",
568                               "peer", "name", "veth1"])
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:
584            subprocess.check_call(["ip", "netns", "add", "ns%d" % i])
585        except subprocess.CalledProcessError:
586            raise HwsimSkip("network namespace not supported (kernel CONFIG_NAMESPACES, CONFIG_NET_NS)")
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"])
592
593    cmd = {}
594    cmd[0] = WlantestCapture('veth0', cap_veth0, netns='ns0')
595    cmd[1] = WlantestCapture('veth1', cap_veth1, netns='ns1')
596
597    write_conf(conffile + '0')
598    write_conf(conffile + '1', mka_priority=100)
599
600    prg = os.path.join(params['logdir'],
601                       'alt-wpa_supplicant/wpa_supplicant/wpa_supplicant')
602    if not os.path.exists(prg):
603        prg = '../../wpa_supplicant/wpa_supplicant'
604
605    arg = ["ip", "netns", "exec", "ns0",
606           prg, '-BdddtKW', '-P', pidfile + '0', '-f', logfile0,
607           '-g', '/tmp/wpas-veth0',
608           '-Dmacsec_linux', '-c', conffile + '0', '-i', "veth0"]
609    logger.info("Start wpa_supplicant: " + str(arg))
610    try:
611        subprocess.check_call(arg)
612    except subprocess.CalledProcessError:
613        raise HwsimSkip("macsec supported (wpa_supplicant CONFIG_MACSEC, CONFIG_DRIVER_MACSEC_LINUX; kernel CONFIG_MACSEC)")
614
615    if os.path.exists("wpa_supplicant-macsec2"):
616        logger.info("Use alternative wpa_supplicant binary for one of the macsec devices")
617        prg = "wpa_supplicant-macsec2"
618
619    arg = ["ip", "netns", "exec", "ns1",
620           prg, '-BdddtKW', '-P', pidfile + '1', '-f', logfile1,
621           '-g', '/tmp/wpas-veth1',
622           '-Dmacsec_linux', '-c', conffile + '1', '-i', "veth1"]
623    logger.info("Start wpa_supplicant: " + str(arg))
624    subprocess.check_call(arg)
625
626    wpas0 = WpaSupplicant('veth0', '/tmp/wpas-veth0')
627    wpas1 = WpaSupplicant('veth1', '/tmp/wpas-veth1')
628
629    log_ip_macsec_ns()
630    log_ip_link_ns()
631
632    logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
633    logger.info("wpas1 STATUS:\n" + wpas1.request("STATUS"))
634    logger.info("wpas0 STATUS-DRIVER:\n" + wpas0.request("STATUS-DRIVER"))
635    logger.info("wpas1 STATUS-DRIVER:\n" + wpas1.request("STATUS-DRIVER"))
636
637    for i in range(10):
638        macsec_ifname0 = wpas0.get_driver_status_field("parent_ifname")
639        macsec_ifname1 = wpas1.get_driver_status_field("parent_ifname")
640        if "Number of Keys" in wpas0.request("STATUS"):
641            key_tx0 = int(wpas0.get_status_field("Number of Keys Distributed"))
642            key_rx0 = int(wpas0.get_status_field("Number of Keys Received"))
643        else:
644            key_tx0 = 0
645            key_rx0 = 0
646        if "Number of Keys" in wpas1.request("STATUS"):
647            key_tx1 = int(wpas1.get_status_field("Number of Keys Distributed"))
648            key_rx1 = int(wpas1.get_status_field("Number of Keys Received"))
649        else:
650            key_tx1 = 0
651            key_rx1 = 0
652        if key_rx0 > 0 and key_tx1 > 0:
653            break
654        time.sleep(1)
655
656    cmd[2] = WlantestCapture(macsec_ifname0, cap_macsec0, netns='ns0')
657    cmd[3] = WlantestCapture(macsec_ifname1, cap_macsec1, netns='ns0')
658    time.sleep(0.5)
659
660    logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
661    logger.info("wpas1 STATUS:\n" + wpas1.request("STATUS"))
662    log_ip_macsec_ns()
663    hwsim_utils.test_connectivity(wpas0, wpas1,
664                                  ifname1=macsec_ifname0,
665                                  ifname2=macsec_ifname1,
666                                  send_len=1400)
667    log_ip_macsec_ns()
668
669    subprocess.check_call(['ip', 'netns', 'exec', 'ns0',
670                           'ip', 'addr', 'add', '192.168.248.17/30',
671                           'dev', macsec_ifname0])
672    subprocess.check_call(['ip', 'netns', 'exec', 'ns1',
673                           'ip', 'addr', 'add', '192.168.248.18/30',
674                           'dev', macsec_ifname1])
675    c = subprocess.Popen(['ip', 'netns', 'exec', 'ns0',
676                          'ping', '-c', '2', '192.168.248.18'],
677                         stdout=subprocess.PIPE)
678    res = c.stdout.read().decode()
679    c.stdout.close()
680    logger.info("ping:\n" + res)
681    if "2 packets transmitted, 2 received" not in res:
682        raise Exception("ping did not work")
683
684    wpas0.close_monitor()
685    wpas0.request("TERMINATE")
686    wpas0.close_control()
687    del wpas0
688    wpas1.close_monitor()
689    wpas1.request("TERMINATE")
690    wpas1.close_control()
691    del wpas1
692
693    time.sleep(1)
694    for i in range(len(cmd)):
695        cmd[i].close()
696
697def test_macsec_psk_fail_cp(dev, apdev):
698    """MACsec PSK local failures in CP state machine"""
699    try:
700        add_veth()
701        wpa = add_wpas_interfaces()
702        set_mka_psk_config(wpa[0])
703        with alloc_fail(wpa[0], 1, "sm_CP_RECEIVE_Enter"):
704            set_mka_psk_config(wpa[1])
705            wait_fail_trigger(wpa[0], "GET_ALLOC_FAIL", max_iter=100)
706
707        wait_mka_done(wpa)
708    finally:
709        cleanup_macsec()
710
711def test_macsec_psk_fail_cp2(dev, apdev):
712    """MACsec PSK local failures in CP state machine (2)"""
713    try:
714        add_veth()
715        wpa = add_wpas_interfaces()
716        set_mka_psk_config(wpa[0])
717        with alloc_fail(wpa[1], 1, "ieee802_1x_cp_sm_init"):
718            set_mka_psk_config(wpa[1])
719            wait_fail_trigger(wpa[1], "GET_ALLOC_FAIL", max_iter=100)
720
721        wait_mka_done(wpa)
722    finally:
723        cleanup_macsec()
724
725def cleanup_macsec_hostapd():
726    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5', monitor=False)
727    wpas.interface_remove("veth0")
728    del wpas
729    hapd = hostapd.HostapdGlobal()
730    hapd.remove('veth1')
731    subprocess.call(["ip", "link", "del", "veth0"],
732                    stderr=open('/dev/null', 'w'))
733    log_ip_link()
734
735def test_macsec_hostapd_psk(dev, apdev, params):
736    """MACsec PSK with hostapd"""
737    try:
738        run_macsec_hostapd_psk(dev, apdev, params, "macsec_hostapd_psk")
739    finally:
740        cleanup_macsec_hostapd()
741
742def run_macsec_hostapd_psk(dev, apdev, params, prefix, integ_only=False,
743                           port0=None, port1=None, ckn0=None, ckn1=None,
744                           cak0=None, cak1=None, expect_failure=False):
745    add_veth()
746
747    cap_veth0 = os.path.join(params['logdir'], prefix + ".veth0.pcap")
748    cap_veth1 = os.path.join(params['logdir'], prefix + ".veth1.pcap")
749    cap_macsec0 = os.path.join(params['logdir'], prefix + ".macsec0.pcap")
750    cap_macsec1 = os.path.join(params['logdir'], prefix + ".macsec1.pcap")
751
752    for i in range(2):
753        subprocess.check_call(["ip", "link", "set", "dev", "veth%d" % i, "up"])
754
755    cmd = {}
756    cmd[0] = WlantestCapture('veth0', cap_veth0)
757    cmd[1] = WlantestCapture('veth1', cap_veth1)
758
759    wpa = add_wpas_interfaces(count=1)
760    wpas0 = wpa[0]
761
762    set_mka_psk_config(wpas0, integ_only=integ_only, port=port0, ckn=ckn0,
763                       cak=cak0, mka_priority=100)
764
765    if cak1 is None:
766        cak1 = "000102030405060708090a0b0c0d0e0f"
767    if ckn1 is None:
768        ckn1 = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
769    params = {"driver": "macsec_linux",
770              "interface": "veth1",
771              "eapol_version": "3",
772              "mka_cak": cak1,
773              "mka_ckn": ckn1,
774              "macsec_policy": "1",
775              "mka_priority": "1"}
776    if integ_only:
777        params["macsec_integ_only"] = "1"
778    if port1 is not None:
779        params["macsec_port"] = str(port1)
780    apdev = {'ifname': 'veth1'}
781    try:
782        hapd = hostapd.add_ap(apdev, params, driver="macsec_linux")
783    except:
784        raise HwsimSkip("No CONFIG_MACSEC=y in hostapd")
785
786    log_ip_macsec()
787    log_ip_link()
788
789    logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
790    logger.info("wpas0 STATUS-DRIVER:\n" + wpas0.request("STATUS-DRIVER"))
791
792    wait_mka_done(wpa, expect_failure=expect_failure, hostapd=True)
793    log_ip_link()
794
795    if expect_failure:
796        for i in range(len(cmd)):
797            cmd[i].close()
798        return
799
800    macsec_ifname0 = wpas0.get_driver_status_field("parent_ifname")
801    macsec_ifname1 = hapd.get_driver_status_field("parent_ifname")
802
803    cmd[2] = WlantestCapture(macsec_ifname0, cap_macsec0)
804    cmd[3] = WlantestCapture(macsec_ifname1, cap_macsec1)
805    time.sleep(0.5)
806
807    logger.info("wpas0 MIB:\n" +  wpas0.request("MIB"))
808    logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
809    log_ip_macsec()
810    hwsim_utils.test_connectivity(wpas0, hapd,
811                                  ifname1=macsec_ifname0,
812                                  ifname2=macsec_ifname1,
813                                  send_len=1400)
814    log_ip_macsec()
815
816    time.sleep(1)
817    for i in range(len(cmd)):
818        cmd[i].close()
819
820def test_macsec_hostapd_eap(dev, apdev, params):
821    """MACsec EAP with hostapd"""
822    try:
823        run_macsec_hostapd_eap(dev, apdev, params, "macsec_hostapd_eap")
824    finally:
825        cleanup_macsec_hostapd()
826
827def run_macsec_hostapd_eap(dev, apdev, params, prefix, integ_only=False,
828                           port0=None, port1=None, expect_failure=False):
829    add_veth()
830
831    cap_veth0 = os.path.join(params['logdir'], prefix + ".veth0.pcap")
832    cap_veth1 = os.path.join(params['logdir'], prefix + ".veth1.pcap")
833    cap_macsec0 = os.path.join(params['logdir'], prefix + ".macsec0.pcap")
834    cap_macsec1 = os.path.join(params['logdir'], prefix + ".macsec1.pcap")
835
836    for i in range(2):
837        subprocess.check_call(["ip", "link", "set", "dev", "veth%d" % i, "up"])
838
839    cmd = {}
840    cmd[0] = WlantestCapture('veth0', cap_veth0)
841    cmd[1] = WlantestCapture('veth1', cap_veth1)
842
843    wpa = add_wpas_interfaces(count=1)
844    wpas0 = wpa[0]
845
846    set_mka_eap_config(wpas0, integ_only=integ_only, port=port0,
847                       mka_priority=100)
848
849    params = {"driver": "macsec_linux",
850              "interface": "veth1",
851              "eapol_version": "3",
852              "macsec_policy": "1",
853              "mka_priority": "1",
854              "ieee8021x": "1",
855              "auth_server_addr": "127.0.0.1",
856              "auth_server_port": "1812",
857              "auth_server_shared_secret": "radius",
858              "nas_identifier": "nas.w1.fi"}
859    if integ_only:
860        params["macsec_integ_only"] = "1"
861    if port1 is not None:
862        params["macsec_port"] = str(port1)
863    apdev = {'ifname': 'veth1'}
864    try:
865        hapd = hostapd.add_ap(apdev, params, driver="macsec_linux")
866    except:
867        raise HwsimSkip("No CONFIG_MACSEC=y in hostapd")
868
869    log_ip_macsec()
870    log_ip_link()
871
872    logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
873    logger.info("wpas0 STATUS-DRIVER:\n" + wpas0.request("STATUS-DRIVER"))
874
875    wait_mka_done(wpa, expect_failure=expect_failure, hostapd=True)
876    log_ip_link()
877
878    if expect_failure:
879        for i in range(len(cmd)):
880            cmd[i].close()
881        return
882
883    macsec_ifname0 = wpas0.get_driver_status_field("parent_ifname")
884    macsec_ifname1 = hapd.get_driver_status_field("parent_ifname")
885
886    cmd[2] = WlantestCapture(macsec_ifname0, cap_macsec0)
887    cmd[3] = WlantestCapture(macsec_ifname1, cap_macsec1)
888    time.sleep(0.5)
889
890    logger.info("wpas0 MIB:\n" +  wpas0.request("MIB"))
891    logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS"))
892    log_ip_macsec()
893    hwsim_utils.test_connectivity(wpas0, hapd,
894                                  ifname1=macsec_ifname0,
895                                  ifname2=macsec_ifname1,
896                                  send_len=1400)
897    log_ip_macsec()
898
899    time.sleep(1)
900    for i in range(len(cmd)):
901        cmd[i].close()
902