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