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