1d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#!/usr/bin/env python2
2d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#
3d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt# eapol_test controller
4d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt# Copyright (c) 2015, Jouni Malinen <j@w1.fi>
5d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#
6d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt# This software may be distributed under the terms of the BSD license.
7d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt# See README for more details.
8d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
9d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtimport argparse
10d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtimport logging
11d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtimport os
12d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtimport Queue
13d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtimport sys
14d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtimport threading
15d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
16d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtlogger = logging.getLogger()
17d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__))
18d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtsys.path.append(os.path.join(dir, '..', 'wpaspy'))
19d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtimport wpaspy
20d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtwpas_ctrl = '/tmp/eapol_test'
21d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
22d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtclass eapol_test:
23d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    def __init__(self, ifname):
24d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        self.ifname = ifname
25d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        self.ctrl = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname))
26d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        if "PONG" not in self.ctrl.request("PING"):
27d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            raise Exception("Failed to connect to eapol_test (%s)" % ifname)
28d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        self.mon = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname))
29d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        self.mon.attach()
30d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
31d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    def add_network(self):
32d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        id = self.request("ADD_NETWORK")
33d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        if "FAIL" in id:
34d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            raise Exception("ADD_NETWORK failed")
35d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        return int(id)
36d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
37d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    def remove_network(self, id):
38d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        id = self.request("REMOVE_NETWORK " + str(id))
39d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        if "FAIL" in id:
40d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            raise Exception("REMOVE_NETWORK failed")
41d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        return None
42d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
43d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    def set_network(self, id, field, value):
44d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        res = self.request("SET_NETWORK " + str(id) + " " + field + " " + value)
45d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        if "FAIL" in res:
46d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            raise Exception("SET_NETWORK failed")
47d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        return None
48d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
49d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    def set_network_quoted(self, id, field, value):
50d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        res = self.request("SET_NETWORK " + str(id) + " " + field + ' "' + value + '"')
51d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        if "FAIL" in res:
52d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            raise Exception("SET_NETWORK failed")
53d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        return None
54d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
55d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    def request(self, cmd, timeout=10):
56d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        return self.ctrl.request(cmd, timeout=timeout)
57d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
58d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    def wait_event(self, events, timeout=10):
59d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        start = os.times()[4]
60d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        while True:
61d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            while self.mon.pending():
62d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt                ev = self.mon.recv()
63d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt                logger.debug(self.ifname + ": " + ev)
64d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt                for event in events:
65d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt                    if event in ev:
66d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt                        return ev
67d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            now = os.times()[4]
68d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            remaining = start + timeout - now
69d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            if remaining <= 0:
70d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt                break
71d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            if not self.mon.pending(timeout=remaining):
72d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt                break
73d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        return None
74d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
75d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtdef run(ifname, count, no_fast_reauth, res):
76d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    et = eapol_test(ifname)
77d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
78d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    et.request("AP_SCAN 0")
79d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    if no_fast_reauth:
80d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        et.request("SET fast_reauth 0")
81d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    else:
82d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        et.request("SET fast_reauth 1")
83d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    id = et.add_network()
84d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    et.set_network(id, "key_mgmt", "IEEE8021X")
85d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    et.set_network(id, "eapol_flags", "0")
86d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    et.set_network(id, "eap", "TLS")
87d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    et.set_network_quoted(id, "identity", "user")
88d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    et.set_network_quoted(id, "ca_cert", 'ca.pem')
89d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    et.set_network_quoted(id, "client_cert", 'client.pem')
90d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    et.set_network_quoted(id, "private_key", 'client.key')
91d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    et.set_network_quoted(id, "private_key_passwd", 'whatever')
92d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    et.set_network(id, "disabled", "0")
93d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
94d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    fail = False
95d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    for i in range(count):
96d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        et.request("REASSOCIATE")
97d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        ev = et.wait_event(["CTRL-EVENT-CONNECTED", "CTRL-EVENT-EAP-FAILURE"])
98d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        if ev is None or "CTRL-EVENT-CONNECTED" not in ev:
99d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            fail = True
100d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            break
101d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
102d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    et.remove_network(id)
103d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
104d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    if fail:
105d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        res.put("FAIL (%d OK)" % i)
106d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    else:
107d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        res.put("PASS %d" % (i + 1))
108d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
109d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtdef main():
110d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    parser = argparse.ArgumentParser(description='eapol_test controller')
111d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    parser.add_argument('--ctrl', help='control interface directory')
112d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    parser.add_argument('--num', help='number of processes')
113d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    parser.add_argument('--iter', help='number of iterations')
114d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    parser.add_argument('--no-fast-reauth', action='store_true',
115d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt                        dest='no_fast_reauth',
116d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt                        help='disable TLS session resumption')
117d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    args = parser.parse_args()
118d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
119d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    num = int(args.num)
120d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    iter = int(args.iter)
121d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    if args.ctrl:
122d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        global wpas_ctrl
123d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        wpas_ctrl = args.ctrl
124d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
125d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    t = {}
126d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    res = {}
127d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    for i in range(num):
128d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        res[i] = Queue.Queue()
129d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        t[i] = threading.Thread(target=run, args=(str(i), iter,
130d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt                                                  args.no_fast_reauth, res[i]))
131d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    for i in range(num):
132d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        t[i].start()
133d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    for i in range(num):
134d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        t[i].join()
135d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        try:
136d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            results = res[i].get(False)
137d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        except:
138d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt            results = "N/A"
139d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt        print "%d: %s" % (i, results)
140d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
141d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtif __name__ == "__main__":
142d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt    main()
143