1# EAP protocol tests
2# Copyright (c) 2014-2015, 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 binascii
8import hashlib
9import hmac
10import logging
11logger = logging.getLogger()
12import os
13import select
14import struct
15import threading
16import time
17
18import hostapd
19from utils import *
20from test_ap_eap import check_eap_capa, check_hlr_auc_gw_support, int_eap_server_params
21
22try:
23    import OpenSSL
24    openssl_imported = True
25except ImportError:
26    openssl_imported = False
27
28EAP_CODE_REQUEST = 1
29EAP_CODE_RESPONSE = 2
30EAP_CODE_SUCCESS = 3
31EAP_CODE_FAILURE = 4
32EAP_CODE_INITIATE = 5
33EAP_CODE_FINISH = 6
34
35EAP_TYPE_IDENTITY = 1
36EAP_TYPE_NOTIFICATION = 2
37EAP_TYPE_NAK = 3
38EAP_TYPE_MD5 = 4
39EAP_TYPE_OTP = 5
40EAP_TYPE_GTC = 6
41EAP_TYPE_TLS = 13
42EAP_TYPE_LEAP = 17
43EAP_TYPE_SIM = 18
44EAP_TYPE_TTLS = 21
45EAP_TYPE_AKA = 23
46EAP_TYPE_PEAP = 25
47EAP_TYPE_MSCHAPV2 = 26
48EAP_TYPE_TLV = 33
49EAP_TYPE_TNC = 38
50EAP_TYPE_FAST = 43
51EAP_TYPE_PAX = 46
52EAP_TYPE_PSK = 47
53EAP_TYPE_SAKE = 48
54EAP_TYPE_IKEV2 = 49
55EAP_TYPE_AKA_PRIME = 50
56EAP_TYPE_GPSK = 51
57EAP_TYPE_PWD = 52
58EAP_TYPE_EKE = 53
59EAP_TYPE_EXPANDED = 254
60
61# Type field in EAP-Initiate and EAP-Finish messages
62EAP_ERP_TYPE_REAUTH_START = 1
63EAP_ERP_TYPE_REAUTH = 2
64
65EAP_ERP_TLV_KEYNAME_NAI = 1
66EAP_ERP_TV_RRK_LIFETIME = 2
67EAP_ERP_TV_RMSK_LIFETIME = 3
68EAP_ERP_TLV_DOMAIN_NAME = 4
69EAP_ERP_TLV_CRYPTOSUITES = 5
70EAP_ERP_TLV_AUTHORIZATION_INDICATION = 6
71EAP_ERP_TLV_CALLED_STATION_ID = 128
72EAP_ERP_TLV_CALLING_STATION_ID = 129
73EAP_ERP_TLV_NAS_IDENTIFIER = 130
74EAP_ERP_TLV_NAS_IP_ADDRESS = 131
75EAP_ERP_TLV_NAS_IPV6_ADDRESS = 132
76
77def add_message_authenticator_attr(reply, digest):
78    if digest.startswith(b'0x'):
79        # Work around pyrad tools.py EncodeOctets() functionality that
80        # assumes a binary value that happens to start with "0x" to be
81        # a hex string.
82        digest = b"0x" + binascii.hexlify(digest)
83    reply.AddAttribute("Message-Authenticator", digest)
84
85def build_message_auth(pkt, reply, secret=None):
86    if secret is None:
87        secret = reply.secret
88    hmac_obj = hmac.new(secret, digestmod=hashlib.md5)
89    hmac_obj.update(struct.pack("B", reply.code))
90    hmac_obj.update(struct.pack("B", reply.id))
91
92    reply.AddAttribute("Message-Authenticator", 16*b'\x00')
93    attrs = reply._PktEncodeAttributes()
94
95    # Length
96    flen = 4 + 16 + len(attrs)
97    hmac_obj.update(struct.pack(">H", flen))
98    hmac_obj.update(pkt.authenticator)
99    hmac_obj.update(attrs)
100    del reply[80]
101    add_message_authenticator_attr(reply, hmac_obj.digest())
102
103def run_pyrad_server(srv, t_stop, eap_handler):
104    srv.RunWithStop(t_stop, eap_handler)
105
106def start_radius_server(eap_handler):
107    try:
108        import pyrad.server
109        import pyrad.packet
110        import pyrad.dictionary
111    except ImportError:
112        raise HwsimSkip("No pyrad modules available")
113
114    class TestServer(pyrad.server.Server):
115        def _HandleAuthPacket(self, pkt):
116            pyrad.server.Server._HandleAuthPacket(self, pkt)
117            eap = b''
118            for p in pkt[79]:
119                eap += p
120            eap_req = self.eap_handler(self.ctx, eap)
121            reply = self.CreateReplyPacket(pkt)
122            if eap_req:
123                while True:
124                    if len(eap_req) > 253:
125                        reply.AddAttribute("EAP-Message", eap_req[0:253])
126                        eap_req = eap_req[253:]
127                    else:
128                        reply.AddAttribute("EAP-Message", eap_req)
129                        break
130            else:
131                logger.info("No EAP request available")
132            reply.code = pyrad.packet.AccessChallenge
133
134            # reply attributes
135            build_message_auth(pkt, reply)
136
137            self.SendReplyPacket(pkt.fd, reply)
138
139        def RunWithStop(self, t_stop, eap_handler):
140            self._poll = select.poll()
141            self._fdmap = {}
142            self._PrepareSockets()
143            self.t_stop = t_stop
144            self.eap_handler = eap_handler
145            self.ctx = {}
146
147            while not t_stop.is_set():
148                for (fd, event) in self._poll.poll(200):
149                    if event == select.POLLIN:
150                        try:
151                            fdo = self._fdmap[fd]
152                            self._ProcessInput(fdo)
153                        except pyrad.server.ServerPacketError as err:
154                            logger.info("pyrad server dropping packet: " + str(err))
155                        except pyrad.packet.PacketError as err:
156                            logger.info("pyrad server received invalid packet: " + str(err))
157                    else:
158                        logger.error("Unexpected event in pyrad server main loop")
159
160            for fd in self.authfds + self.acctfds:
161                fd.close()
162
163    srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"),
164                     authport=18138, acctport=18139)
165    srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1",
166                                                     b"radius",
167                                                     "localhost")
168    srv.BindToAddress("127.0.0.1")
169    t_stop = threading.Event()
170    t = threading.Thread(target=run_pyrad_server, args=(srv, t_stop, eap_handler))
171    t.start()
172
173    return {'srv': srv, 'stop': t_stop, 'thread': t}
174
175def stop_radius_server(srv):
176    srv['stop'].set()
177    srv['thread'].join()
178
179def start_ap(ap):
180    params = hostapd.wpa2_eap_params(ssid="eap-test")
181    params['auth_server_port'] = "18138"
182    hapd = hostapd.add_ap(ap, params)
183    return hapd
184
185def test_eap_proto(dev, apdev):
186    """EAP protocol tests"""
187    check_eap_capa(dev[0], "MD5")
188    def eap_handler(ctx, req):
189        logger.info("eap_handler - RX " + binascii.hexlify(req).decode())
190        if 'num' not in ctx:
191            ctx['num'] = 0
192        ctx['num'] = ctx['num'] + 1
193        if 'id' not in ctx:
194            ctx['id'] = 1
195        ctx['id'] = (ctx['id'] + 1) % 256
196        idx = 0
197
198        idx += 1
199        if ctx['num'] == idx:
200            logger.info("Test: MD5 challenge")
201            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
202                               4 + 1 + 3,
203                               EAP_TYPE_MD5,
204                               1, 0xaa, ord('n'))
205        idx += 1
206        if ctx['num'] == idx:
207            logger.info("Test: EAP-Success - id off by 2")
208            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'] + 1, 4)
209
210        idx += 1
211        if ctx['num'] == idx:
212            logger.info("Test: MD5 challenge")
213            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
214                               4 + 1 + 3,
215                               EAP_TYPE_MD5,
216                               1, 0xaa, ord('n'))
217        idx += 1
218        if ctx['num'] == idx:
219            logger.info("Test: EAP-Success - id off by 3")
220            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'] + 2, 4)
221
222        idx += 1
223        if ctx['num'] == idx:
224            logger.info("Test: MD5 challenge")
225            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
226                               4 + 1 + 3,
227                               EAP_TYPE_MD5,
228                               1, 0xaa, ord('n'))
229        idx += 1
230        if ctx['num'] == idx:
231            logger.info("Test: EAP-Notification/Request")
232            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
233                               4 + 1 + 1,
234                               EAP_TYPE_NOTIFICATION,
235                               ord('A'))
236        idx += 1
237        if ctx['num'] == idx:
238            logger.info("Test: EAP-Success")
239            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'] - 1, 4)
240
241        idx += 1
242        if ctx['num'] == idx:
243            logger.info("Test: EAP-Notification/Request")
244            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
245                               4 + 1 + 1,
246                               EAP_TYPE_NOTIFICATION,
247                               ord('B'))
248        idx += 1
249        if ctx['num'] == idx:
250            logger.info("Test: MD5 challenge")
251            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
252                               4 + 1 + 3,
253                               EAP_TYPE_MD5,
254                               1, 0xaa, ord('n'))
255        idx += 1
256        if ctx['num'] == idx:
257            logger.info("Test: EAP-Success")
258            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'] - 1, 4)
259
260        idx += 1
261        if ctx['num'] == idx:
262            logger.info("Test: EAP-Notification/Request")
263            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
264                               4 + 1 + 1,
265                               EAP_TYPE_NOTIFICATION,
266                               ord('C'))
267        idx += 1
268        if ctx['num'] == idx:
269            logger.info("Test: MD5 challenge")
270            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
271                               4 + 1 + 3,
272                               EAP_TYPE_MD5,
273                               1, 0xaa, ord('n'))
274        idx += 1
275        if ctx['num'] == idx:
276            logger.info("Test: EAP-Notification/Request")
277            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
278                               4 + 1 + 1,
279                               EAP_TYPE_NOTIFICATION,
280                               ord('D'))
281        idx += 1
282        if ctx['num'] == idx:
283            logger.info("Test: EAP-Success")
284            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'] - 1, 4)
285
286        idx += 1
287        if ctx['num'] == idx:
288            logger.info("Test: EAP-Notification/Request")
289            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
290                               4 + 1 + 1,
291                               EAP_TYPE_NOTIFICATION,
292                               ord('E'))
293        idx += 1
294        if ctx['num'] == idx:
295            logger.info("Test: EAP-Notification/Request (same id)")
296            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'] - 1,
297                               4 + 1 + 1,
298                               EAP_TYPE_NOTIFICATION,
299                               ord('F'))
300        idx += 1
301        if ctx['num'] == idx:
302            logger.info("Test: Unexpected EAP-Success")
303            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'] - 2, 4)
304
305        return None
306
307    srv = start_radius_server(eap_handler)
308
309    try:
310        hapd = start_ap(apdev[0])
311        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
312
313        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
314                       eap="MD5", identity="user", password="password",
315                       wait_connect=False)
316        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
317        if ev is None:
318            raise Exception("Timeout on EAP start")
319        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
320        if ev is None:
321            raise Exception("Timeout on EAP success")
322        dev[0].request("REMOVE_NETWORK all")
323
324        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
325                       eap="MD5", identity="user", password="password",
326                       wait_connect=False)
327        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
328        if ev is None:
329            raise Exception("Timeout on EAP start")
330        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=1)
331        if ev is not None:
332            raise Exception("Unexpected EAP success")
333        dev[0].request("REMOVE_NETWORK all")
334
335        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
336                       eap="MD5", identity="user", password="password",
337                       wait_connect=False)
338        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
339        if ev is None:
340            raise Exception("Timeout on EAP start")
341        ev = dev[0].wait_event(["CTRL-EVENT-EAP-NOTIFICATION"], timeout=10)
342        if ev is None:
343            raise Exception("Timeout on EAP notification")
344        if ev != "<3>CTRL-EVENT-EAP-NOTIFICATION A":
345            raise Exception("Unexpected notification contents: " + ev)
346        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
347        if ev is None:
348            raise Exception("Timeout on EAP success")
349        dev[0].request("REMOVE_NETWORK all")
350
351        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
352                       eap="MD5", identity="user", password="password",
353                       wait_connect=False)
354        ev = dev[0].wait_event(["CTRL-EVENT-EAP-NOTIFICATION"], timeout=10)
355        if ev is None:
356            raise Exception("Timeout on EAP notification")
357        if ev != "<3>CTRL-EVENT-EAP-NOTIFICATION B":
358            raise Exception("Unexpected notification contents: " + ev)
359        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
360        if ev is None:
361            raise Exception("Timeout on EAP start")
362        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
363        if ev is None:
364            raise Exception("Timeout on EAP success")
365        dev[0].request("REMOVE_NETWORK all")
366
367        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
368                       eap="MD5", identity="user", password="password",
369                       wait_connect=False)
370        ev = dev[0].wait_event(["CTRL-EVENT-EAP-NOTIFICATION"], timeout=10)
371        if ev is None:
372            raise Exception("Timeout on EAP notification")
373        if ev != "<3>CTRL-EVENT-EAP-NOTIFICATION C":
374            raise Exception("Unexpected notification contents: " + ev)
375        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
376        if ev is None:
377            raise Exception("Timeout on EAP start")
378        ev = dev[0].wait_event(["CTRL-EVENT-EAP-NOTIFICATION"], timeout=10)
379        if ev is None:
380            raise Exception("Timeout on EAP notification")
381        if ev != "<3>CTRL-EVENT-EAP-NOTIFICATION D":
382            raise Exception("Unexpected notification contents: " + ev)
383        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
384        if ev is None:
385            raise Exception("Timeout on EAP success")
386        dev[0].request("REMOVE_NETWORK all")
387
388        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
389                       eap="MD5", identity="user", password="password",
390                       wait_connect=False)
391        ev = dev[0].wait_event(["CTRL-EVENT-EAP-NOTIFICATION"], timeout=10)
392        if ev is None:
393            raise Exception("Timeout on EAP notification")
394        if ev != "<3>CTRL-EVENT-EAP-NOTIFICATION E":
395            raise Exception("Unexpected notification contents: " + ev)
396        ev = dev[0].wait_event(["CTRL-EVENT-EAP-NOTIFICATION"], timeout=10)
397        if ev is None:
398            raise Exception("Timeout on EAP notification")
399        if ev != "<3>CTRL-EVENT-EAP-NOTIFICATION F":
400            raise Exception("Unexpected notification contents: " + ev)
401        ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=15)
402        if ev is None:
403            raise Exception("Timeout on EAP failure")
404        dev[0].request("REMOVE_NETWORK all")
405    finally:
406        stop_radius_server(srv)
407
408def test_eap_proto_notification_errors(dev, apdev):
409    """EAP Notification errors"""
410    def eap_handler(ctx, req):
411        logger.info("eap_handler - RX " + binascii.hexlify(req).decode())
412        if 'num' not in ctx:
413            ctx['num'] = 0
414        ctx['num'] = ctx['num'] + 1
415        if 'id' not in ctx:
416            ctx['id'] = 1
417        ctx['id'] = (ctx['id'] + 1) % 256
418        idx = 0
419
420        idx += 1
421        if ctx['num'] == idx:
422            logger.info("Test: MD5 challenge")
423            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
424                               4 + 1 + 3,
425                               EAP_TYPE_MD5,
426                               1, 0xaa, ord('n'))
427        idx += 1
428        if ctx['num'] == idx:
429            logger.info("Test: EAP-Notification/Request")
430            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
431                               4 + 1 + 1,
432                               EAP_TYPE_NOTIFICATION,
433                               ord('A'))
434
435        idx += 1
436        if ctx['num'] == idx:
437            logger.info("Test: MD5 challenge")
438            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
439                               4 + 1 + 3,
440                               EAP_TYPE_MD5,
441                               1, 0xaa, ord('n'))
442        idx += 1
443        if ctx['num'] == idx:
444            logger.info("Test: EAP-Notification/Request")
445            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
446                               4 + 1 + 1,
447                               EAP_TYPE_NOTIFICATION,
448                               ord('A'))
449
450        return None
451
452    srv = start_radius_server(eap_handler)
453
454    try:
455        hapd = start_ap(apdev[0])
456        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
457
458        with alloc_fail(dev[0], 1, "eap_sm_processNotify"):
459            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
460                           eap="MD5", identity="user", password="password",
461                           wait_connect=False)
462            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
463            dev[0].request("REMOVE_NETWORK all")
464            dev[0].wait_disconnected()
465
466        with alloc_fail(dev[0], 1, "eap_msg_alloc;sm_EAP_NOTIFICATION_Enter"):
467            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
468                           eap="MD5", identity="user", password="password",
469                           wait_connect=False)
470            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
471            dev[0].request("REMOVE_NETWORK all")
472            dev[0].wait_disconnected()
473    finally:
474        stop_radius_server(srv)
475
476EAP_SAKE_VERSION = 2
477
478EAP_SAKE_SUBTYPE_CHALLENGE = 1
479EAP_SAKE_SUBTYPE_CONFIRM = 2
480EAP_SAKE_SUBTYPE_AUTH_REJECT = 3
481EAP_SAKE_SUBTYPE_IDENTITY = 4
482
483EAP_SAKE_AT_RAND_S = 1
484EAP_SAKE_AT_RAND_P = 2
485EAP_SAKE_AT_MIC_S = 3
486EAP_SAKE_AT_MIC_P = 4
487EAP_SAKE_AT_SERVERID = 5
488EAP_SAKE_AT_PEERID = 6
489EAP_SAKE_AT_SPI_S = 7
490EAP_SAKE_AT_SPI_P = 8
491EAP_SAKE_AT_ANY_ID_REQ = 9
492EAP_SAKE_AT_PERM_ID_REQ = 10
493EAP_SAKE_AT_ENCR_DATA = 128
494EAP_SAKE_AT_IV = 129
495EAP_SAKE_AT_PADDING = 130
496EAP_SAKE_AT_NEXT_TMPID = 131
497EAP_SAKE_AT_MSK_LIFE = 132
498
499def test_eap_proto_sake(dev, apdev):
500    """EAP-SAKE protocol tests"""
501    global eap_proto_sake_test_done
502    eap_proto_sake_test_done = False
503
504    def sake_challenge(ctx):
505        logger.info("Test: Challenge subtype")
506        return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
507                           4 + 1 + 3 + 18,
508                           EAP_TYPE_SAKE,
509                           EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE,
510                           EAP_SAKE_AT_RAND_S, 18, 0, 0, 0, 0)
511
512    def sake_handler(ctx, req):
513        logger.info("sake_handler - RX " + binascii.hexlify(req).decode())
514        if 'num' not in ctx:
515            ctx['num'] = 0
516        ctx['num'] += 1
517        if 'id' not in ctx:
518            ctx['id'] = 1
519        ctx['id'] = (ctx['id'] + 1) % 256
520        idx = 0
521
522        idx += 1
523        if ctx['num'] == idx:
524            logger.info("Test: Missing payload")
525            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'], 4 + 1,
526                               EAP_TYPE_SAKE)
527
528        idx += 1
529        if ctx['num'] == idx:
530            logger.info("Test: Identity subtype without any attributes")
531            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
532                               4 + 1 + 3,
533                               EAP_TYPE_SAKE,
534                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY)
535
536        idx += 1
537        if ctx['num'] == idx:
538            logger.info("Test: Identity subtype")
539            return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
540                               4 + 1 + 3 + 4,
541                               EAP_TYPE_SAKE,
542                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
543                               EAP_SAKE_AT_ANY_ID_REQ, 4, 0)
544        idx += 1
545        if ctx['num'] == idx:
546            logger.info("Test: Identity subtype (different session id)")
547            return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
548                               4 + 1 + 3 + 4,
549                               EAP_TYPE_SAKE,
550                               EAP_SAKE_VERSION, 1, EAP_SAKE_SUBTYPE_IDENTITY,
551                               EAP_SAKE_AT_PERM_ID_REQ, 4, 0)
552
553        idx += 1
554        if ctx['num'] == idx:
555            logger.info("Test: Identity subtype with too short attribute")
556            return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
557                               4 + 1 + 3 + 2,
558                               EAP_TYPE_SAKE,
559                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
560                               EAP_SAKE_AT_ANY_ID_REQ, 2)
561
562        idx += 1
563        if ctx['num'] == idx:
564            logger.info("Test: Identity subtype with truncated attribute")
565            return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
566                               4 + 1 + 3 + 2,
567                               EAP_TYPE_SAKE,
568                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
569                               EAP_SAKE_AT_ANY_ID_REQ, 4)
570
571        idx += 1
572        if ctx['num'] == idx:
573            logger.info("Test: Identity subtype with too short attribute header")
574            payload = struct.pack("B", EAP_SAKE_AT_ANY_ID_REQ)
575            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
576                               4 + 1 + 3 + len(payload),
577                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
578                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
579
580        idx += 1
581        if ctx['num'] == idx:
582            logger.info("Test: Identity subtype with AT_IV but not AT_ENCR_DATA")
583            payload = struct.pack("BB", EAP_SAKE_AT_IV, 2)
584            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
585                               4 + 1 + 3 + len(payload),
586                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
587                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
588
589        idx += 1
590        if ctx['num'] == idx:
591            logger.info("Test: Identity subtype with skippable and non-skippable unknown attribute")
592            payload = struct.pack("BBBB", 255, 2, 127, 2)
593            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
594                               4 + 1 + 3 + len(payload),
595                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
596                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
597
598        idx += 1
599        if ctx['num'] == idx:
600            logger.info("Test: Identity subtype: AT_RAND_P with invalid payload length")
601            payload = struct.pack("BB", EAP_SAKE_AT_RAND_P, 2)
602            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
603                               4 + 1 + 3 + len(payload),
604                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
605                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
606
607        idx += 1
608        if ctx['num'] == idx:
609            logger.info("Test: Identity subtype: AT_MIC_P with invalid payload length")
610            payload = struct.pack("BB", EAP_SAKE_AT_MIC_P, 2)
611            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
612                               4 + 1 + 3 + len(payload),
613                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
614                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
615
616        idx += 1
617        if ctx['num'] == idx:
618            logger.info("Test: Identity subtype: AT_PERM_ID_REQ with invalid payload length")
619            payload = struct.pack("BBBBBBBBBBBBBB",
620                                  EAP_SAKE_AT_SPI_S, 2,
621                                  EAP_SAKE_AT_SPI_P, 2,
622                                  EAP_SAKE_AT_ENCR_DATA, 2,
623                                  EAP_SAKE_AT_NEXT_TMPID, 2,
624                                  EAP_SAKE_AT_PERM_ID_REQ, 4, 0, 0,
625                                  EAP_SAKE_AT_PERM_ID_REQ, 2)
626            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
627                               4 + 1 + 3 + len(payload),
628                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
629                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
630
631        idx += 1
632        if ctx['num'] == idx:
633            logger.info("Test: Identity subtype: AT_PADDING")
634            payload = struct.pack("BBBBBB",
635                                  EAP_SAKE_AT_PADDING, 3, 0,
636                                  EAP_SAKE_AT_PADDING, 3, 1)
637            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
638                               4 + 1 + 3 + len(payload),
639                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
640                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
641
642        idx += 1
643        if ctx['num'] == idx:
644            logger.info("Test: Identity subtype: AT_MSK_LIFE")
645            payload = struct.pack(">BBLBBH",
646                                  EAP_SAKE_AT_MSK_LIFE, 6, 0,
647                                  EAP_SAKE_AT_MSK_LIFE, 4, 0)
648            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
649                               4 + 1 + 3 + len(payload),
650                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
651                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
652
653        idx += 1
654        if ctx['num'] == idx:
655            logger.info("Test: Identity subtype with invalid attribute length")
656            payload = struct.pack("BB", EAP_SAKE_AT_ANY_ID_REQ, 0)
657            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
658                               4 + 1 + 3 + len(payload),
659                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
660                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
661
662        idx += 1
663        if ctx['num'] == idx:
664            logger.info("Test: Unknown subtype")
665            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
666                               4 + 1 + 3,
667                               EAP_TYPE_SAKE,
668                               EAP_SAKE_VERSION, 0, 123)
669
670        idx += 1
671        if ctx['num'] == idx:
672            logger.info("Test: Challenge subtype without any attributes")
673            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
674                               4 + 1 + 3,
675                               EAP_TYPE_SAKE,
676                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE)
677
678        idx += 1
679        if ctx['num'] == idx:
680            logger.info("Test: Challenge subtype with too short AT_RAND_S")
681            return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
682                               4 + 1 + 3 + 2,
683                               EAP_TYPE_SAKE,
684                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE,
685                               EAP_SAKE_AT_RAND_S, 2)
686
687        idx += 1
688        if ctx['num'] == idx:
689            return sake_challenge(ctx)
690        idx += 1
691        if ctx['num'] == idx:
692            logger.info("Test: Unexpected Identity subtype")
693            return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
694                               4 + 1 + 3 + 4,
695                               EAP_TYPE_SAKE,
696                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
697                               EAP_SAKE_AT_ANY_ID_REQ, 4, 0)
698
699        idx += 1
700        if ctx['num'] == idx:
701            return sake_challenge(ctx)
702        idx += 1
703        if ctx['num'] == idx:
704            logger.info("Test: Unexpected Challenge subtype")
705            return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
706                               4 + 1 + 3 + 18,
707                               EAP_TYPE_SAKE,
708                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE,
709                               EAP_SAKE_AT_RAND_S, 18, 0, 0, 0, 0)
710
711        idx += 1
712        if ctx['num'] == idx:
713            return sake_challenge(ctx)
714        idx += 1
715        if ctx['num'] == idx:
716            logger.info("Test: Confirm subtype without any attributes")
717            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
718                               4 + 1 + 3,
719                               EAP_TYPE_SAKE,
720                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM)
721
722        idx += 1
723        if ctx['num'] == idx:
724            return sake_challenge(ctx)
725        idx += 1
726        if ctx['num'] == idx:
727            logger.info("Test: Confirm subtype with too short AT_MIC_S")
728            return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
729                               4 + 1 + 3 + 2,
730                               EAP_TYPE_SAKE,
731                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM,
732                               EAP_SAKE_AT_MIC_S, 2)
733
734        idx += 1
735        if ctx['num'] == idx:
736            logger.info("Test: Unexpected Confirm subtype")
737            return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
738                               4 + 1 + 3 + 18,
739                               EAP_TYPE_SAKE,
740                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM,
741                               EAP_SAKE_AT_MIC_S, 18, 0, 0, 0, 0)
742
743        idx += 1
744        if ctx['num'] == idx:
745            return sake_challenge(ctx)
746        idx += 1
747        if ctx['num'] == idx:
748            logger.info("Test: Confirm subtype with incorrect AT_MIC_S")
749            return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
750                               4 + 1 + 3 + 18,
751                               EAP_TYPE_SAKE,
752                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM,
753                               EAP_SAKE_AT_MIC_S, 18, 0, 0, 0, 0)
754
755        global eap_proto_sake_test_done
756        if eap_proto_sake_test_done:
757            return sake_challenge(ctx)
758
759        logger.info("No more test responses available - test case completed")
760        eap_proto_sake_test_done = True
761        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
762
763    srv = start_radius_server(sake_handler)
764
765    try:
766        hapd = start_ap(apdev[0])
767        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
768
769        while not eap_proto_sake_test_done:
770            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
771                           eap="SAKE", identity="sake user",
772                           password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
773                           wait_connect=False)
774            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
775            if ev is None:
776                raise Exception("Timeout on EAP start")
777            time.sleep(0.1)
778            dev[0].request("REMOVE_NETWORK all")
779            dev[0].dump_monitor()
780
781        logger.info("Too short password")
782        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
783                       eap="SAKE", identity="sake user",
784                       password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd",
785                       wait_connect=False)
786        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
787        if ev is None:
788            raise Exception("Timeout on EAP start")
789        start = os.times()[4]
790        while True:
791            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
792                                   timeout=0.1)
793            if ev is None:
794                break
795            now = os.times()[4]
796            if now - start > 0.1:
797                break
798            dev[0].dump_monitor()
799
800        dev[0].request("REMOVE_NETWORK all")
801        time.sleep(0.1)
802        dev[0].dump_monitor()
803    finally:
804        stop_radius_server(srv)
805
806def test_eap_proto_sake_errors(dev, apdev):
807    """EAP-SAKE local error cases"""
808    check_eap_capa(dev[0], "SAKE")
809    params = hostapd.wpa2_eap_params(ssid="eap-test")
810    hapd = hostapd.add_ap(apdev[0], params)
811    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
812
813    for i in range(1, 3):
814        with alloc_fail(dev[0], i, "eap_sake_init"):
815            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
816                           eap="SAKE", identity="sake user",
817                           password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
818                           wait_connect=False)
819            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
820                                   timeout=15)
821            if ev is None:
822                raise Exception("Timeout on EAP start")
823            dev[0].request("REMOVE_NETWORK all")
824            dev[0].wait_disconnected()
825            dev[0].dump_monitor()
826
827    tests = [(1, "eap_msg_alloc;eap_sake_build_msg;eap_sake_process_challenge"),
828             (1, "=eap_sake_process_challenge"),
829             (1, "eap_sake_compute_mic;eap_sake_process_challenge"),
830             (1, "eap_sake_build_msg;eap_sake_process_confirm"),
831             (1, "eap_sake_compute_mic;eap_sake_process_confirm"),
832             (2, "eap_sake_compute_mic"),
833             (3, "eap_sake_compute_mic"),
834             (1, "eap_sake_getKey"),
835             (1, "eap_sake_get_emsk"),
836             (1, "eap_sake_get_session_id")]
837    for count, func in tests:
838        with alloc_fail(dev[0], count, func):
839            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
840                           eap="SAKE", identity="sake user@domain",
841                           password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
842                           erp="1",
843                           wait_connect=False)
844            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
845                                   timeout=15)
846            if ev is None:
847                raise Exception("Timeout on EAP start")
848            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
849            dev[0].request("REMOVE_NETWORK all")
850            dev[0].wait_disconnected()
851            dev[0].dump_monitor()
852
853    tests = [(1, "os_get_random;eap_sake_process_challenge"),
854             (1, "eap_sake_derive_keys;eap_sake_process_challenge"),
855             (2, "eap_sake_derive_keys;eap_sake_process_challenge"),
856             (3, "eap_sake_derive_keys;eap_sake_process_challenge"),
857             (4, "eap_sake_derive_keys;eap_sake_process_challenge"),
858             (5, "eap_sake_derive_keys;eap_sake_process_challenge"),
859             (6, "eap_sake_derive_keys;eap_sake_process_challenge")]
860    for count, func in tests:
861        with fail_test(dev[0], count, func):
862            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
863                           eap="SAKE", identity="sake user",
864                           password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
865                           wait_connect=False)
866            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
867            if ev is None:
868                raise Exception("Timeout on EAP start")
869            wait_fail_trigger(dev[0], "GET_FAIL")
870            dev[0].request("REMOVE_NETWORK all")
871            dev[0].wait_disconnected()
872            dev[0].dump_monitor()
873
874def test_eap_proto_sake_errors2(dev, apdev):
875    """EAP-SAKE protocol tests (2)"""
876    def sake_handler(ctx, req):
877        logger.info("sake_handler - RX " + binascii.hexlify(req).decode())
878        if 'num' not in ctx:
879            ctx['num'] = 0
880        ctx['num'] += 1
881        if 'id' not in ctx:
882            ctx['id'] = 1
883        ctx['id'] = (ctx['id'] + 1) % 256
884        idx = 0
885
886        idx += 1
887        if ctx['num'] == idx:
888            logger.info("Test: Identity subtype")
889            return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
890                               4 + 1 + 3 + 4,
891                               EAP_TYPE_SAKE,
892                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
893                               EAP_SAKE_AT_ANY_ID_REQ, 4, 0)
894
895    srv = start_radius_server(sake_handler)
896
897    try:
898        hapd = start_ap(apdev[0])
899        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
900
901        with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_sake_build_msg;eap_sake_process_identity"):
902            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
903                           eap="SAKE", identity="sake user",
904                           password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
905                           wait_connect=False)
906            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
907                                   timeout=15)
908            if ev is None:
909                raise Exception("Timeout on EAP start")
910                dev[0].request("REMOVE_NETWORK all")
911                dev[0].wait_disconnected()
912
913    finally:
914        stop_radius_server(srv)
915
916def run_eap_sake_connect(dev):
917    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
918                eap="SAKE", identity="sake user",
919                password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
920                wait_connect=False)
921    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
922                         "CTRL-EVENT-DISCONNECTED"],
923                        timeout=1)
924    dev.request("REMOVE_NETWORK all")
925    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
926        dev.wait_disconnected()
927    dev.dump_monitor()
928
929def test_eap_proto_sake_errors_server(dev, apdev):
930    """EAP-SAKE local error cases on server"""
931    check_eap_capa(dev[0], "SAKE")
932    params = int_eap_server_params()
933    params['erp_domain'] = 'example.com'
934    params['eap_server_erp'] = '1'
935    hapd = hostapd.add_ap(apdev[0], params)
936    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
937
938    tests = [(1, "eap_sake_init"),
939             (1, "eap_sake_build_msg;eap_sake_build_challenge"),
940             (1, "eap_sake_build_msg;eap_sake_build_confirm"),
941             (1, "eap_sake_compute_mic;eap_sake_build_confirm"),
942             (1, "eap_sake_process_challenge"),
943             (1, "eap_sake_getKey"),
944             (1, "eap_sake_get_emsk"),
945             (1, "eap_sake_get_session_id")]
946    for count, func in tests:
947        with alloc_fail(hapd, count, func):
948            run_eap_sake_connect(dev[0])
949
950    tests = [(1, "eap_sake_init"),
951             (1, "eap_sake_build_challenge"),
952             (1, "eap_sake_build_confirm"),
953             (1, "eap_sake_derive_keys;eap_sake_process_challenge"),
954             (1, "eap_sake_compute_mic;eap_sake_process_challenge"),
955             (1, "eap_sake_compute_mic;eap_sake_process_confirm"),
956             (1, "eap_sake_compute_mic;eap_sake_build_confirm"),
957             (1, "eap_sake_process_confirm")]
958    for count, func in tests:
959        with fail_test(hapd, count, func):
960            run_eap_sake_connect(dev[0])
961
962def start_sake_assoc(dev, hapd):
963    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
964                eap="SAKE", identity="sake user",
965                password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
966                wait_connect=False)
967    proxy_msg(hapd, dev) # EAP-Identity/Request
968    proxy_msg(dev, hapd) # EAP-Identity/Response
969    proxy_msg(hapd, dev) # SAKE/Challenge/Request
970
971def stop_sake_assoc(dev, hapd):
972    dev.request("REMOVE_NETWORK all")
973    dev.wait_disconnected()
974    dev.dump_monitor()
975    hapd.dump_monitor()
976
977def test_eap_proto_sake_server(dev, apdev):
978    """EAP-SAKE protocol testing for the server"""
979    check_eap_capa(dev[0], "SAKE")
980    params = int_eap_server_params()
981    params['erp_domain'] = 'example.com'
982    params['eap_server_erp'] = '1'
983    hapd = hostapd.add_ap(apdev[0], params)
984    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
985    hapd.request("SET ext_eapol_frame_io 1")
986    dev[0].request("SET ext_eapol_frame_io 1")
987
988    # Successful exchange to verify proxying mechanism
989    start_sake_assoc(dev[0], hapd)
990    proxy_msg(dev[0], hapd) # SAKE/Challenge/Response
991    proxy_msg(hapd, dev[0]) # SAKE/Confirm/Request
992    proxy_msg(dev[0], hapd) # SAKE/Confirm/Response
993    proxy_msg(hapd, dev[0]) # EAP-Success
994    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 1/4
995    proxy_msg(dev[0], hapd) # EAPOL-Key msg 2/4
996    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 3/4
997    proxy_msg(dev[0], hapd) # EAPOL-Key msg 4/4
998    dev[0].wait_connected()
999    stop_sake_assoc(dev[0], hapd)
1000
1001    start_sake_assoc(dev[0], hapd)
1002    resp = rx_msg(dev[0])
1003    # Too short EAP-SAKE header
1004    # --> EAP-SAKE: Invalid frame
1005    msg = resp[0:4] + "0007" + resp[8:12] + "0007" + "300200"
1006    tx_msg(dev[0], hapd, msg)
1007    # Unknown version
1008    # --> EAP-SAKE: Unknown version 1
1009    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "30010000"
1010    tx_msg(dev[0], hapd, msg)
1011    # Unknown session
1012    # --> EAP-SAKE: Session ID mismatch
1013    sess, = struct.unpack('B', binascii.unhexlify(resp[20:22]))
1014    sess = binascii.hexlify(struct.pack('B', (sess + 1) % 256)).decode()
1015    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "3002" + sess + "00"
1016    tx_msg(dev[0], hapd, msg)
1017    # Unknown subtype
1018    # --> EAP-SAKE: Unexpected subtype=5 in state=1
1019    msg = resp[0:22] + "05" + resp[24:]
1020    tx_msg(dev[0], hapd, msg)
1021    # Empty challenge
1022    # --> EAP-SAKE: Response/Challenge did not include AT_RAND_P or AT_MIC_P
1023    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + resp[16:24]
1024    tx_msg(dev[0], hapd, msg)
1025    rx_msg(hapd)
1026    stop_sake_assoc(dev[0], hapd)
1027
1028    start_sake_assoc(dev[0], hapd)
1029    resp = rx_msg(dev[0])
1030    # Invalid attribute in challenge
1031    # --> EAP-SAKE: Too short attribute
1032    msg = resp[0:4] + "0009" + resp[8:12] + "0009" + resp[16:26]
1033    tx_msg(dev[0], hapd, msg)
1034    rx_msg(hapd)
1035    stop_sake_assoc(dev[0], hapd)
1036
1037    start_sake_assoc(dev[0], hapd)
1038    proxy_msg(dev[0], hapd) # SAKE/Challenge/Response
1039    proxy_msg(hapd, dev[0]) # SAKE/Confirm/Request
1040    resp = rx_msg(dev[0])
1041    # Empty confirm
1042    # --> EAP-SAKE: Response/Confirm did not include AT_MIC_P
1043    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + resp[16:26]
1044    tx_msg(dev[0], hapd, msg)
1045    rx_msg(hapd)
1046    stop_sake_assoc(dev[0], hapd)
1047
1048    start_sake_assoc(dev[0], hapd)
1049    proxy_msg(dev[0], hapd) # SAKE/Challenge/Response
1050    proxy_msg(hapd, dev[0]) # SAKE/Confirm/Request
1051    resp = rx_msg(dev[0])
1052    # Invalid attribute in confirm
1053    # --> EAP-SAKE: Too short attribute
1054    msg = resp[0:4] + "0009" + resp[8:12] + "0009" + resp[16:26]
1055    tx_msg(dev[0], hapd, msg)
1056    rx_msg(hapd)
1057    stop_sake_assoc(dev[0], hapd)
1058
1059    start_sake_assoc(dev[0], hapd)
1060    proxy_msg(dev[0], hapd) # SAKE/Challenge/Response
1061    proxy_msg(hapd, dev[0]) # SAKE/Confirm/Request
1062    resp = rx_msg(dev[0])
1063    # Corrupted AT_MIC_P value
1064    # --> EAP-SAKE: Incorrect AT_MIC_P
1065    msg = resp[0:30] + "000000000000" + resp[42:]
1066    tx_msg(dev[0], hapd, msg)
1067    rx_msg(hapd)
1068    stop_sake_assoc(dev[0], hapd)
1069
1070def test_eap_proto_leap(dev, apdev):
1071    """EAP-LEAP protocol tests"""
1072    check_eap_capa(dev[0], "LEAP")
1073    def leap_handler(ctx, req):
1074        logger.info("leap_handler - RX " + binascii.hexlify(req).decode())
1075        if 'num' not in ctx:
1076            ctx['num'] = 0
1077        ctx['num'] = ctx['num'] + 1
1078        if 'id' not in ctx:
1079            ctx['id'] = 1
1080        ctx['id'] = (ctx['id'] + 1) % 256
1081
1082        if ctx['num'] == 1:
1083            logger.info("Test: Missing payload")
1084            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
1085                               4 + 1,
1086                               EAP_TYPE_LEAP)
1087
1088        if ctx['num'] == 2:
1089            logger.info("Test: Unexpected version")
1090            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
1091                               4 + 1 + 3,
1092                               EAP_TYPE_LEAP,
1093                               0, 0, 0)
1094
1095        if ctx['num'] == 3:
1096            logger.info("Test: Invalid challenge length")
1097            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
1098                               4 + 1 + 3,
1099                               EAP_TYPE_LEAP,
1100                               1, 0, 0)
1101
1102        if ctx['num'] == 4:
1103            logger.info("Test: Truncated challenge")
1104            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
1105                               4 + 1 + 3,
1106                               EAP_TYPE_LEAP,
1107                               1, 0, 8)
1108
1109        if ctx['num'] == 5:
1110            logger.info("Test: Valid challenge")
1111            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1112                               4 + 1 + 3 + 8,
1113                               EAP_TYPE_LEAP,
1114                               1, 0, 8, 0, 0)
1115        if ctx['num'] == 6:
1116            logger.info("Test: Missing payload in Response")
1117            return struct.pack(">BBHB", EAP_CODE_RESPONSE, ctx['id'],
1118                               4 + 1,
1119                               EAP_TYPE_LEAP)
1120
1121        if ctx['num'] == 7:
1122            logger.info("Test: Valid challenge")
1123            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1124                               4 + 1 + 3 + 8,
1125                               EAP_TYPE_LEAP,
1126                               1, 0, 8, 0, 0)
1127        if ctx['num'] == 8:
1128            logger.info("Test: Unexpected version in Response")
1129            return struct.pack(">BBHBBBB", EAP_CODE_RESPONSE, ctx['id'],
1130                               4 + 1 + 3,
1131                               EAP_TYPE_LEAP,
1132                               0, 0, 8)
1133
1134        if ctx['num'] == 9:
1135            logger.info("Test: Valid challenge")
1136            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1137                               4 + 1 + 3 + 8,
1138                               EAP_TYPE_LEAP,
1139                               1, 0, 8, 0, 0)
1140        if ctx['num'] == 10:
1141            logger.info("Test: Invalid challenge length in Response")
1142            return struct.pack(">BBHBBBB", EAP_CODE_RESPONSE, ctx['id'],
1143                               4 + 1 + 3,
1144                               EAP_TYPE_LEAP,
1145                               1, 0, 0)
1146
1147        if ctx['num'] == 11:
1148            logger.info("Test: Valid challenge")
1149            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1150                               4 + 1 + 3 + 8,
1151                               EAP_TYPE_LEAP,
1152                               1, 0, 8, 0, 0)
1153        if ctx['num'] == 12:
1154            logger.info("Test: Truncated challenge in Response")
1155            return struct.pack(">BBHBBBB", EAP_CODE_RESPONSE, ctx['id'],
1156                               4 + 1 + 3,
1157                               EAP_TYPE_LEAP,
1158                               1, 0, 24)
1159
1160        if ctx['num'] == 13:
1161            logger.info("Test: Valid challenge")
1162            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1163                               4 + 1 + 3 + 8,
1164                               EAP_TYPE_LEAP,
1165                               1, 0, 8, 0, 0)
1166        if ctx['num'] == 14:
1167            logger.info("Test: Invalid challange value in Response")
1168            return struct.pack(">BBHBBBB6L", EAP_CODE_RESPONSE, ctx['id'],
1169                               4 + 1 + 3 + 24,
1170                               EAP_TYPE_LEAP,
1171                               1, 0, 24,
1172                               0, 0, 0, 0, 0, 0)
1173
1174        if ctx['num'] == 15:
1175            logger.info("Test: Valid challenge")
1176            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1177                               4 + 1 + 3 + 8,
1178                               EAP_TYPE_LEAP,
1179                               1, 0, 8, 0, 0)
1180        if ctx['num'] == 16:
1181            logger.info("Test: Valid challange value in Response")
1182            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1183                               4 + 1 + 3 + 24,
1184                               EAP_TYPE_LEAP,
1185                               1, 0, 24,
1186                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1187                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1188                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1189
1190        if ctx['num'] == 17:
1191            logger.info("Test: Valid challenge")
1192            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1193                               4 + 1 + 3 + 8,
1194                               EAP_TYPE_LEAP,
1195                               1, 0, 8, 0, 0)
1196        if ctx['num'] == 18:
1197            logger.info("Test: Success")
1198            return struct.pack(">BBHB", EAP_CODE_SUCCESS, ctx['id'],
1199                               4 + 1,
1200                               EAP_TYPE_LEAP)
1201        # hostapd will drop the next frame in the sequence
1202
1203        if ctx['num'] == 19:
1204            logger.info("Test: Valid challenge")
1205            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1206                               4 + 1 + 3 + 8,
1207                               EAP_TYPE_LEAP,
1208                               1, 0, 8, 0, 0)
1209        if ctx['num'] == 20:
1210            logger.info("Test: Failure")
1211            return struct.pack(">BBHB", EAP_CODE_FAILURE, ctx['id'],
1212                               4 + 1,
1213                               EAP_TYPE_LEAP)
1214
1215        return None
1216
1217    srv = start_radius_server(leap_handler)
1218
1219    try:
1220        hapd = start_ap(apdev[0])
1221        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1222
1223        for i in range(0, 12):
1224            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1225                           eap="LEAP", identity="user", password="password",
1226                           wait_connect=False)
1227            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
1228            if ev is None:
1229                raise Exception("Timeout on EAP start")
1230            time.sleep(0.1)
1231            if i == 10:
1232                logger.info("Wait for additional roundtrip")
1233                time.sleep(1)
1234            dev[0].request("REMOVE_NETWORK all")
1235    finally:
1236        stop_radius_server(srv)
1237
1238def test_eap_proto_leap_errors(dev, apdev):
1239    """EAP-LEAP protocol tests (error paths)"""
1240    check_eap_capa(dev[0], "LEAP")
1241
1242    def leap_handler2(ctx, req):
1243        logger.info("leap_handler2 - RX " + binascii.hexlify(req).decode())
1244        if 'num' not in ctx:
1245            ctx['num'] = 0
1246        ctx['num'] = ctx['num'] + 1
1247        if 'id' not in ctx:
1248            ctx['id'] = 1
1249        ctx['id'] = (ctx['id'] + 1) % 256
1250        idx = 0
1251
1252        idx += 1
1253        if ctx['num'] == idx:
1254            logger.info("Test: Valid challenge")
1255            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1256                               4 + 1 + 3 + 8,
1257                               EAP_TYPE_LEAP,
1258                               1, 0, 8, 0, 0)
1259        idx += 1
1260        if ctx['num'] == idx:
1261            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
1262
1263        idx += 1
1264        if ctx['num'] == idx:
1265            logger.info("Test: Valid challenge")
1266            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1267                               4 + 1 + 3 + 8,
1268                               EAP_TYPE_LEAP,
1269                               1, 0, 8, 0, 0)
1270
1271        idx += 1
1272        if ctx['num'] == idx:
1273            logger.info("Test: Valid challenge")
1274            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1275                               4 + 1 + 3 + 8,
1276                               EAP_TYPE_LEAP,
1277                               1, 0, 8, 0, 0)
1278        idx += 1
1279        if ctx['num'] == idx:
1280            logger.info("Test: Success")
1281            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
1282
1283        idx += 1
1284        if ctx['num'] == idx:
1285            logger.info("Test: Valid challenge")
1286            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1287                               4 + 1 + 3 + 8,
1288                               EAP_TYPE_LEAP,
1289                               1, 0, 8, 0, 0)
1290        idx += 1
1291        if ctx['num'] == idx:
1292            logger.info("Test: Success")
1293            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
1294
1295        idx += 1
1296        if ctx['num'] == idx:
1297            logger.info("Test: Valid challenge")
1298            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1299                               4 + 1 + 3 + 8,
1300                               EAP_TYPE_LEAP,
1301                               1, 0, 8, 0, 0)
1302        idx += 1
1303        if ctx['num'] == idx:
1304            logger.info("Test: Valid challange value in Response")
1305            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1306                               4 + 1 + 3 + 24,
1307                               EAP_TYPE_LEAP,
1308                               1, 0, 24,
1309                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1310                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1311                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1312
1313        idx += 1
1314        if ctx['num'] == idx:
1315            logger.info("Test: Valid challenge")
1316            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1317                               4 + 1 + 3 + 8,
1318                               EAP_TYPE_LEAP,
1319                               1, 0, 8, 0, 0)
1320        idx += 1
1321        if ctx['num'] == idx:
1322            logger.info("Test: Valid challange value in Response")
1323            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1324                               4 + 1 + 3 + 24,
1325                               EAP_TYPE_LEAP,
1326                               1, 0, 24,
1327                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1328                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1329                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1330
1331        idx += 1
1332        if ctx['num'] == idx:
1333            logger.info("Test: Valid challenge")
1334            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1335                               4 + 1 + 3 + 8,
1336                               EAP_TYPE_LEAP,
1337                               1, 0, 8, 0, 0)
1338        idx += 1
1339        if ctx['num'] == idx:
1340            logger.info("Test: Valid challange value in Response")
1341            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1342                               4 + 1 + 3 + 24,
1343                               EAP_TYPE_LEAP,
1344                               1, 0, 24,
1345                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1346                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1347                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1348
1349        idx += 1
1350        if ctx['num'] == idx:
1351            logger.info("Test: Valid challenge")
1352            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1353                               4 + 1 + 3 + 8,
1354                               EAP_TYPE_LEAP,
1355                               1, 0, 8, 0, 0)
1356        idx += 1
1357        if ctx['num'] == idx:
1358            logger.info("Test: Valid challange value in Response")
1359            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1360                               4 + 1 + 3 + 24,
1361                               EAP_TYPE_LEAP,
1362                               1, 0, 24,
1363                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1364                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1365                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1366
1367        idx += 1
1368        if ctx['num'] == idx:
1369            logger.info("Test: Valid challenge")
1370            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1371                               4 + 1 + 3 + 8,
1372                               EAP_TYPE_LEAP,
1373                               1, 0, 8, 0, 0)
1374        idx += 1
1375        if ctx['num'] == idx:
1376            logger.info("Test: Valid challange value in Response")
1377            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1378                               4 + 1 + 3 + 24,
1379                               EAP_TYPE_LEAP,
1380                               1, 0, 24,
1381                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1382                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1383                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1384
1385        idx += 1
1386        if ctx['num'] == idx:
1387            logger.info("Test: Valid challenge")
1388            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1389                               4 + 1 + 3 + 8,
1390                               EAP_TYPE_LEAP,
1391                               1, 0, 8, 0, 0)
1392        idx += 1
1393        if ctx['num'] == idx:
1394            logger.info("Test: Valid challange value in Response")
1395            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1396                               4 + 1 + 3 + 24,
1397                               EAP_TYPE_LEAP,
1398                               1, 0, 24,
1399                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1400                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1401                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1402
1403        idx += 1
1404        if ctx['num'] == idx:
1405            logger.info("Test: Valid challenge")
1406            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1407                               4 + 1 + 3 + 8,
1408                               EAP_TYPE_LEAP,
1409                               1, 0, 8, 0, 0)
1410        idx += 1
1411        if ctx['num'] == idx:
1412            logger.info("Test: Valid challange value in Response")
1413            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1414                               4 + 1 + 3 + 24,
1415                               EAP_TYPE_LEAP,
1416                               1, 0, 24,
1417                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1418                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1419                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1420
1421        idx += 1
1422        if ctx['num'] == idx:
1423            logger.info("Test: Valid challenge")
1424            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1425                               4 + 1 + 3 + 8,
1426                               EAP_TYPE_LEAP,
1427                               1, 0, 8, 0, 0)
1428
1429        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
1430
1431    srv = start_radius_server(leap_handler2)
1432
1433    try:
1434        hapd = start_ap(apdev[0])
1435        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1436
1437        with alloc_fail(dev[0], 1, "eap_leap_init"):
1438            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1439                           eap="LEAP", identity="user", password="password",
1440                           wait_connect=False)
1441            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1442            dev[0].request("REMOVE_NETWORK all")
1443            dev[0].wait_disconnected()
1444
1445        with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_leap_process_request"):
1446            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1447                           eap="LEAP", identity="user",
1448                           password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
1449                           wait_connect=False)
1450            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1451            dev[0].request("REMOVE_NETWORK all")
1452            dev[0].wait_disconnected()
1453
1454        with alloc_fail(dev[0], 1, "eap_leap_process_success"):
1455            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1456                           eap="LEAP", identity="user", password="password",
1457                           wait_connect=False)
1458            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1459            dev[0].request("REMOVE_NETWORK all")
1460            dev[0].wait_disconnected()
1461
1462        with fail_test(dev[0], 1, "os_get_random;eap_leap_process_success"):
1463            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1464                           eap="LEAP", identity="user", password="password",
1465                           wait_connect=False)
1466            wait_fail_trigger(dev[0], "GET_FAIL")
1467            dev[0].request("REMOVE_NETWORK all")
1468            dev[0].wait_disconnected()
1469
1470        with fail_test(dev[0], 1, "eap_leap_process_response"):
1471            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1472                           eap="LEAP", identity="user",
1473                           password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
1474                           wait_connect=False)
1475            wait_fail_trigger(dev[0], "GET_FAIL")
1476            dev[0].request("REMOVE_NETWORK all")
1477            dev[0].wait_disconnected()
1478
1479        with fail_test(dev[0], 1, "nt_password_hash;eap_leap_process_response"):
1480            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1481                           eap="LEAP", identity="user", password="password",
1482                           wait_connect=False)
1483            wait_fail_trigger(dev[0], "GET_FAIL")
1484            dev[0].request("REMOVE_NETWORK all")
1485            dev[0].wait_disconnected()
1486
1487        with fail_test(dev[0], 1, "hash_nt_password_hash;eap_leap_process_response"):
1488            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1489                           eap="LEAP", identity="user", password="password",
1490                           wait_connect=False)
1491            wait_fail_trigger(dev[0], "GET_FAIL")
1492            dev[0].request("REMOVE_NETWORK all")
1493            dev[0].wait_disconnected()
1494
1495        with alloc_fail(dev[0], 1, "eap_leap_getKey"):
1496            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1497                           eap="LEAP", identity="user",
1498                           password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
1499                           wait_connect=False)
1500            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1501            dev[0].request("REMOVE_NETWORK all")
1502            dev[0].wait_disconnected()
1503
1504        with fail_test(dev[0], 1, "eap_leap_getKey"):
1505            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1506                           eap="LEAP", identity="user",
1507                           password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
1508                           wait_connect=False)
1509            wait_fail_trigger(dev[0], "GET_FAIL")
1510            dev[0].request("REMOVE_NETWORK all")
1511            dev[0].wait_disconnected()
1512
1513        with fail_test(dev[0], 1, "nt_password_hash;eap_leap_getKey"):
1514            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1515                           eap="LEAP", identity="user", password="password",
1516                           wait_connect=False)
1517            wait_fail_trigger(dev[0], "GET_FAIL")
1518            dev[0].request("REMOVE_NETWORK all")
1519            dev[0].wait_disconnected()
1520
1521        with fail_test(dev[0], 1, "hash_nt_password_hash;eap_leap_getKey"):
1522            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1523                           eap="LEAP", identity="user", password="password",
1524                           wait_connect=False)
1525            wait_fail_trigger(dev[0], "GET_FAIL")
1526            dev[0].request("REMOVE_NETWORK all")
1527            dev[0].wait_disconnected()
1528
1529        with fail_test(dev[0], 1,
1530                       "nt_challenge_response;eap_leap_process_request"):
1531            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1532                           eap="LEAP", identity="user", password="password",
1533                           wait_connect=False)
1534            wait_fail_trigger(dev[0], "GET_FAIL")
1535            dev[0].request("REMOVE_NETWORK all")
1536            dev[0].wait_disconnected()
1537    finally:
1538        stop_radius_server(srv)
1539
1540def test_eap_proto_md5(dev, apdev):
1541    """EAP-MD5 protocol tests"""
1542    check_eap_capa(dev[0], "MD5")
1543
1544    def md5_handler(ctx, req):
1545        logger.info("md5_handler - RX " + binascii.hexlify(req).decode())
1546        if 'num' not in ctx:
1547            ctx['num'] = 0
1548        ctx['num'] = ctx['num'] + 1
1549        if 'id' not in ctx:
1550            ctx['id'] = 1
1551        ctx['id'] = (ctx['id'] + 1) % 256
1552
1553        if ctx['num'] == 1:
1554            logger.info("Test: Missing payload")
1555            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
1556                               4 + 1,
1557                               EAP_TYPE_MD5)
1558
1559        if ctx['num'] == 2:
1560            logger.info("Test: Zero-length challenge")
1561            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1562                               4 + 1 + 1,
1563                               EAP_TYPE_MD5,
1564                               0)
1565
1566        if ctx['num'] == 3:
1567            logger.info("Test: Truncated challenge")
1568            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1569                               4 + 1 + 1,
1570                               EAP_TYPE_MD5,
1571                               1)
1572
1573        if ctx['num'] == 4:
1574            logger.info("Test: Shortest possible challenge and name")
1575            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
1576                               4 + 1 + 3,
1577                               EAP_TYPE_MD5,
1578                               1, 0xaa, ord('n'))
1579
1580        return None
1581
1582    srv = start_radius_server(md5_handler)
1583
1584    try:
1585        hapd = start_ap(apdev[0])
1586        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1587
1588        for i in range(0, 4):
1589            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1590                           eap="MD5", identity="user", password="password",
1591                           wait_connect=False)
1592            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
1593            if ev is None:
1594                raise Exception("Timeout on EAP start")
1595            time.sleep(0.1)
1596            dev[0].request("REMOVE_NETWORK all")
1597    finally:
1598        stop_radius_server(srv)
1599
1600def test_eap_proto_md5_errors(dev, apdev):
1601    """EAP-MD5 local error cases"""
1602    check_eap_capa(dev[0], "MD5")
1603    params = hostapd.wpa2_eap_params(ssid="eap-test")
1604    hapd = hostapd.add_ap(apdev[0], params)
1605    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1606
1607    with fail_test(dev[0], 1, "chap_md5"):
1608        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1609                       eap="MD5", identity="phase1-user", password="password",
1610                       wait_connect=False)
1611        ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
1612        if ev is None:
1613            raise Exception("Timeout on EAP start")
1614        dev[0].request("REMOVE_NETWORK all")
1615        dev[0].wait_disconnected()
1616
1617    with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_md5_process"):
1618        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1619                       eap="MD5", identity="phase1-user", password="password",
1620                       wait_connect=False)
1621        ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
1622        if ev is None:
1623            raise Exception("Timeout on EAP start")
1624        time.sleep(0.1)
1625        dev[0].request("REMOVE_NETWORK all")
1626
1627def run_eap_md5_connect(dev):
1628    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
1629                eap="MD5", identity="phase1-user", password="password",
1630                wait_connect=False)
1631    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
1632                         "CTRL-EVENT-DISCONNECTED"],
1633                        timeout=1)
1634    dev.request("REMOVE_NETWORK all")
1635    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
1636        dev.wait_disconnected()
1637    dev.dump_monitor()
1638
1639def test_eap_proto_md5_errors_server(dev, apdev):
1640    """EAP-MD5 local error cases on server"""
1641    check_eap_capa(dev[0], "MD5")
1642    params = int_eap_server_params()
1643    params['erp_domain'] = 'example.com'
1644    params['eap_server_erp'] = '1'
1645    hapd = hostapd.add_ap(apdev[0], params)
1646    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1647
1648    tests = [(1, "eap_md5_init")]
1649    for count, func in tests:
1650        with alloc_fail(hapd, count, func):
1651            run_eap_md5_connect(dev[0])
1652
1653    tests = [(1, "os_get_random;eap_md5_buildReq"),
1654             (1, "chap_md5;eap_md5_process")]
1655    for count, func in tests:
1656        with fail_test(hapd, count, func):
1657            run_eap_md5_connect(dev[0])
1658
1659def start_md5_assoc(dev, hapd):
1660    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
1661                eap="MD5", identity="phase1-user", password="password",
1662                wait_connect=False)
1663    proxy_msg(hapd, dev) # EAP-Identity/Request
1664    proxy_msg(dev, hapd) # EAP-Identity/Response
1665    proxy_msg(hapd, dev) # MSCHAPV2/Request
1666    proxy_msg(dev, hapd) # NAK
1667    proxy_msg(hapd, dev) # MD5 Request
1668
1669def stop_md5_assoc(dev, hapd, wait=True):
1670    dev.request("REMOVE_NETWORK all")
1671    if wait:
1672        dev.wait_disconnected()
1673    dev.dump_monitor()
1674    hapd.dump_monitor()
1675
1676def test_eap_proto_md5_server(dev, apdev):
1677    """EAP-MD5 protocol testing for the server"""
1678    check_eap_capa(dev[0], "MD5")
1679    params = int_eap_server_params()
1680    params['erp_domain'] = 'example.com'
1681    params['eap_server_erp'] = '1'
1682    hapd = hostapd.add_ap(apdev[0], params)
1683    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1684    hapd.request("SET ext_eapol_frame_io 1")
1685    dev[0].request("SET ext_eapol_frame_io 1")
1686
1687    # Successful exchange to verify proxying mechanism
1688    start_md5_assoc(dev[0], hapd)
1689    proxy_msg(dev[0], hapd) # MD5 Response
1690    proxy_msg(hapd, dev[0]) # EAP-Success
1691    # Accept both EAP-Success and disconnection indication since it is possible
1692    # for disconnection from the AP (due to EAP-MD5 not deriving keys) to be
1693    # processed more quickly.
1694    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS",
1695                            "CTRL-EVENT-DISCONNECTED"], timeout=5)
1696    if ev is None:
1697        raise Exception("No EAP-Success reported")
1698    stop_md5_assoc(dev[0], hapd, wait="CTRL-EVENT-EAP-SUCCESS" in ev)
1699
1700    start_md5_assoc(dev[0], hapd)
1701    resp = rx_msg(dev[0])
1702    # Too short EAP-MD5 header (no length field)
1703    hapd.note("EAP-MD5: Invalid frame")
1704    msg = resp[0:4] + "0005" + resp[8:12] + "0005" + "04"
1705    tx_msg(dev[0], hapd, msg)
1706    # Too short EAP-MD5 header (no length field)
1707    hapd.note("EAP-MD5: Invalid response (response_len=0 payload_len=1")
1708    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "0400"
1709    tx_msg(dev[0], hapd, msg)
1710    stop_md5_assoc(dev[0], hapd)
1711
1712def test_eap_proto_otp(dev, apdev):
1713    """EAP-OTP protocol tests"""
1714    def otp_handler(ctx, req):
1715        logger.info("otp_handler - RX " + binascii.hexlify(req).decode())
1716        if 'num' not in ctx:
1717            ctx['num'] = 0
1718        ctx['num'] = ctx['num'] + 1
1719        if 'id' not in ctx:
1720            ctx['id'] = 1
1721        ctx['id'] = (ctx['id'] + 1) % 256
1722
1723        if ctx['num'] == 1:
1724            logger.info("Test: Empty payload")
1725            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
1726                               4 + 1,
1727                               EAP_TYPE_OTP)
1728        if ctx['num'] == 2:
1729            logger.info("Test: Success")
1730            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'],
1731                               4)
1732
1733        if ctx['num'] == 3:
1734            logger.info("Test: Challenge included")
1735            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1736                               4 + 1 + 1,
1737                               EAP_TYPE_OTP,
1738                               ord('A'))
1739        if ctx['num'] == 4:
1740            logger.info("Test: Success")
1741            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'],
1742                               4)
1743
1744        return None
1745
1746    srv = start_radius_server(otp_handler)
1747
1748    try:
1749        hapd = start_ap(apdev[0])
1750        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1751
1752        for i in range(0, 1):
1753            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1754                           eap="OTP", identity="user", password="password",
1755                           wait_connect=False)
1756            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
1757                                   timeout=15)
1758            if ev is None:
1759                raise Exception("Timeout on EAP start")
1760            time.sleep(0.1)
1761            dev[0].request("REMOVE_NETWORK all")
1762
1763        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1764                       eap="OTP", identity="user", wait_connect=False)
1765        ev = dev[0].wait_event(["CTRL-REQ-OTP"])
1766        if ev is None:
1767            raise Exception("Request for password timed out")
1768        id = ev.split(':')[0].split('-')[-1]
1769        dev[0].request("CTRL-RSP-OTP-" + id + ":password")
1770        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"])
1771        if ev is None:
1772            raise Exception("Success not reported")
1773    finally:
1774        stop_radius_server(srv)
1775
1776def test_eap_proto_otp_errors(dev, apdev):
1777    """EAP-OTP local error cases"""
1778    def otp_handler2(ctx, req):
1779        logger.info("otp_handler2 - RX " + binascii.hexlify(req).decode())
1780        if 'num' not in ctx:
1781            ctx['num'] = 0
1782        ctx['num'] = ctx['num'] + 1
1783        if 'id' not in ctx:
1784            ctx['id'] = 1
1785        ctx['id'] = (ctx['id'] + 1) % 256
1786        idx = 0
1787
1788        idx += 1
1789        if ctx['num'] == idx:
1790            logger.info("Test: Challenge included")
1791            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1792                               4 + 1 + 1,
1793                               EAP_TYPE_OTP,
1794                               ord('A'))
1795
1796        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
1797
1798    srv = start_radius_server(otp_handler2)
1799
1800    try:
1801        hapd = start_ap(apdev[0])
1802        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1803
1804        with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_otp_process"):
1805            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1806                           eap="OTP", identity="user", password="password",
1807                           wait_connect=False)
1808            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1809            dev[0].request("REMOVE_NETWORK all")
1810            dev[0].wait_disconnected()
1811    finally:
1812        stop_radius_server(srv)
1813
1814EAP_GPSK_OPCODE_GPSK_1 = 1
1815EAP_GPSK_OPCODE_GPSK_2 = 2
1816EAP_GPSK_OPCODE_GPSK_3 = 3
1817EAP_GPSK_OPCODE_GPSK_4 = 4
1818EAP_GPSK_OPCODE_FAIL = 5
1819EAP_GPSK_OPCODE_PROTECTED_FAIL = 6
1820
1821def test_eap_proto_gpsk(dev, apdev):
1822    """EAP-GPSK protocol tests"""
1823    def gpsk_handler(ctx, req):
1824        logger.info("gpsk_handler - RX " + binascii.hexlify(req).decode())
1825        if 'num' not in ctx:
1826            ctx['num'] = 0
1827        ctx['num'] = ctx['num'] + 1
1828        if 'id' not in ctx:
1829            ctx['id'] = 1
1830        ctx['id'] = (ctx['id'] + 1) % 256
1831
1832        idx = 0
1833
1834        idx += 1
1835        if ctx['num'] == idx:
1836            logger.info("Test: Missing payload")
1837            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
1838                               4 + 1,
1839                               EAP_TYPE_GPSK)
1840
1841        idx += 1
1842        if ctx['num'] == idx:
1843            logger.info("Test: Unknown opcode")
1844            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1845                               4 + 1 + 1,
1846                               EAP_TYPE_GPSK,
1847                               255)
1848
1849        idx += 1
1850        if ctx['num'] == idx:
1851            logger.info("Test: Unexpected GPSK-3")
1852            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1853                               4 + 1 + 1,
1854                               EAP_TYPE_GPSK,
1855                               EAP_GPSK_OPCODE_GPSK_3)
1856
1857        idx += 1
1858        if ctx['num'] == idx:
1859            logger.info("Test: GPSK-1 Too short GPSK-1")
1860            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1861                               4 + 1 + 1,
1862                               EAP_TYPE_GPSK,
1863                               EAP_GPSK_OPCODE_GPSK_1)
1864
1865        idx += 1
1866        if ctx['num'] == idx:
1867            logger.info("Test: GPSK-1 Truncated ID_Server")
1868            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
1869                               4 + 1 + 1 + 2,
1870                               EAP_TYPE_GPSK,
1871                               EAP_GPSK_OPCODE_GPSK_1, 1)
1872
1873        idx += 1
1874        if ctx['num'] == idx:
1875            logger.info("Test: GPSK-1 Missing RAND_Server")
1876            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
1877                               4 + 1 + 1 + 2,
1878                               EAP_TYPE_GPSK,
1879                               EAP_GPSK_OPCODE_GPSK_1, 0)
1880
1881        idx += 1
1882        if ctx['num'] == idx:
1883            logger.info("Test: GPSK-1 Missing CSuite_List")
1884            return struct.pack(">BBHBBH8L", EAP_CODE_REQUEST, ctx['id'],
1885                               4 + 1 + 1 + 2 + 32,
1886                               EAP_TYPE_GPSK,
1887                               EAP_GPSK_OPCODE_GPSK_1, 0,
1888                               0, 0, 0, 0, 0, 0, 0, 0)
1889
1890        idx += 1
1891        if ctx['num'] == idx:
1892            logger.info("Test: GPSK-1 Truncated CSuite_List")
1893            return struct.pack(">BBHBBH8LH", EAP_CODE_REQUEST, ctx['id'],
1894                               4 + 1 + 1 + 2 + 32 + 2,
1895                               EAP_TYPE_GPSK,
1896                               EAP_GPSK_OPCODE_GPSK_1, 0,
1897                               0, 0, 0, 0, 0, 0, 0, 0,
1898                               1)
1899
1900        idx += 1
1901        if ctx['num'] == idx:
1902            logger.info("Test: GPSK-1 Empty CSuite_List")
1903            return struct.pack(">BBHBBH8LH", EAP_CODE_REQUEST, ctx['id'],
1904                               4 + 1 + 1 + 2 + 32 + 2,
1905                               EAP_TYPE_GPSK,
1906                               EAP_GPSK_OPCODE_GPSK_1, 0,
1907                               0, 0, 0, 0, 0, 0, 0, 0,
1908                               0)
1909
1910        idx += 1
1911        if ctx['num'] == idx:
1912            logger.info("Test: GPSK-1 Invalid CSuite_List")
1913            return struct.pack(">BBHBBH8LHB", EAP_CODE_REQUEST, ctx['id'],
1914                               4 + 1 + 1 + 2 + 32 + 2 + 1,
1915                               EAP_TYPE_GPSK,
1916                               EAP_GPSK_OPCODE_GPSK_1, 0,
1917                               0, 0, 0, 0, 0, 0, 0, 0,
1918                               1, 0)
1919
1920        idx += 1
1921        if ctx['num'] == idx:
1922            logger.info("Test: GPSK-1 No supported CSuite")
1923            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1924                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1925                               EAP_TYPE_GPSK,
1926                               EAP_GPSK_OPCODE_GPSK_1, 0,
1927                               0, 0, 0, 0, 0, 0, 0, 0,
1928                               6, 0, 0)
1929
1930        idx += 1
1931        if ctx['num'] == idx:
1932            logger.info("Test: GPSK-1 Supported CSuite")
1933            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1934                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1935                               EAP_TYPE_GPSK,
1936                               EAP_GPSK_OPCODE_GPSK_1, 0,
1937                               0, 0, 0, 0, 0, 0, 0, 0,
1938                               6, 0, 1)
1939        idx += 1
1940        if ctx['num'] == idx:
1941            logger.info("Test: Unexpected GPSK-1")
1942            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1943                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1944                               EAP_TYPE_GPSK,
1945                               EAP_GPSK_OPCODE_GPSK_1, 0,
1946                               0, 0, 0, 0, 0, 0, 0, 0,
1947                               6, 0, 1)
1948
1949        idx += 1
1950        if ctx['num'] == idx:
1951            logger.info("Test: GPSK-1 Supported CSuite but too short key")
1952            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1953                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1954                               EAP_TYPE_GPSK,
1955                               EAP_GPSK_OPCODE_GPSK_1, 0,
1956                               0, 0, 0, 0, 0, 0, 0, 0,
1957                               6, 0, 1)
1958
1959        idx += 1
1960        if ctx['num'] == idx:
1961            logger.info("Test: GPSK-1 Supported CSuite")
1962            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1963                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1964                               EAP_TYPE_GPSK,
1965                               EAP_GPSK_OPCODE_GPSK_1, 0,
1966                               0, 0, 0, 0, 0, 0, 0, 0,
1967                               6, 0, 1)
1968        idx += 1
1969        if ctx['num'] == idx:
1970            logger.info("Test: Too short GPSK-3")
1971            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1972                               4 + 1 + 1,
1973                               EAP_TYPE_GPSK,
1974                               EAP_GPSK_OPCODE_GPSK_3)
1975
1976        idx += 1
1977        if ctx['num'] == idx:
1978            logger.info("Test: GPSK-1 Supported CSuite")
1979            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1980                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1981                               EAP_TYPE_GPSK,
1982                               EAP_GPSK_OPCODE_GPSK_1, 0,
1983                               0, 0, 0, 0, 0, 0, 0, 0,
1984                               6, 0, 1)
1985        idx += 1
1986        if ctx['num'] == idx:
1987            logger.info("Test: GPSK-3 Mismatch in RAND_Peer")
1988            return struct.pack(">BBHBB8L", EAP_CODE_REQUEST, ctx['id'],
1989                               4 + 1 + 1 + 32,
1990                               EAP_TYPE_GPSK,
1991                               EAP_GPSK_OPCODE_GPSK_3,
1992                               0, 0, 0, 0, 0, 0, 0, 0)
1993
1994        idx += 1
1995        if ctx['num'] == idx:
1996            logger.info("Test: GPSK-1 Supported CSuite")
1997            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1998                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1999                               EAP_TYPE_GPSK,
2000                               EAP_GPSK_OPCODE_GPSK_1, 0,
2001                               0, 0, 0, 0, 0, 0, 0, 0,
2002                               6, 0, 1)
2003        idx += 1
2004        if ctx['num'] == idx:
2005            logger.info("Test: GPSK-3 Missing RAND_Server")
2006            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2007                              4 + 1 + 1 + 32,
2008                              EAP_TYPE_GPSK,
2009                              EAP_GPSK_OPCODE_GPSK_3)
2010            msg += req[14:46]
2011            return msg
2012
2013        idx += 1
2014        if ctx['num'] == idx:
2015            logger.info("Test: GPSK-1 Supported CSuite")
2016            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2017                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2018                               EAP_TYPE_GPSK,
2019                               EAP_GPSK_OPCODE_GPSK_1, 0,
2020                               0, 0, 0, 0, 0, 0, 0, 0,
2021                               6, 0, 1)
2022        idx += 1
2023        if ctx['num'] == idx:
2024            logger.info("Test: GPSK-3 Mismatch in RAND_Server")
2025            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2026                              4 + 1 + 1 + 32 + 32,
2027                              EAP_TYPE_GPSK,
2028                              EAP_GPSK_OPCODE_GPSK_3)
2029            msg += req[14:46]
2030            msg += struct.pack(">8L", 1, 1, 1, 1, 1, 1, 1, 1)
2031            return msg
2032
2033        idx += 1
2034        if ctx['num'] == idx:
2035            logger.info("Test: GPSK-1 Supported CSuite")
2036            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2037                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2038                               EAP_TYPE_GPSK,
2039                               EAP_GPSK_OPCODE_GPSK_1, 0,
2040                               0, 0, 0, 0, 0, 0, 0, 0,
2041                               6, 0, 1)
2042        idx += 1
2043        if ctx['num'] == idx:
2044            logger.info("Test: GPSK-3 Missing ID_Server")
2045            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2046                              4 + 1 + 1 + 32 + 32,
2047                              EAP_TYPE_GPSK,
2048                              EAP_GPSK_OPCODE_GPSK_3)
2049            msg += req[14:46]
2050            msg += struct.pack(">8L", 0, 0, 0, 0, 0, 0, 0, 0)
2051            return msg
2052
2053        idx += 1
2054        if ctx['num'] == idx:
2055            logger.info("Test: GPSK-1 Supported CSuite")
2056            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2057                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2058                               EAP_TYPE_GPSK,
2059                               EAP_GPSK_OPCODE_GPSK_1, 0,
2060                               0, 0, 0, 0, 0, 0, 0, 0,
2061                               6, 0, 1)
2062        idx += 1
2063        if ctx['num'] == idx:
2064            logger.info("Test: GPSK-3 Truncated ID_Server")
2065            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2066                              4 + 1 + 1 + 32 + 32 + 2,
2067                              EAP_TYPE_GPSK,
2068                              EAP_GPSK_OPCODE_GPSK_3)
2069            msg += req[14:46]
2070            msg += struct.pack(">8LH", 0, 0, 0, 0, 0, 0, 0, 0, 1)
2071            return msg
2072
2073        idx += 1
2074        if ctx['num'] == idx:
2075            logger.info("Test: GPSK-1 Supported CSuite")
2076            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2077                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2078                               EAP_TYPE_GPSK,
2079                               EAP_GPSK_OPCODE_GPSK_1, 0,
2080                               0, 0, 0, 0, 0, 0, 0, 0,
2081                               6, 0, 1)
2082        idx += 1
2083        if ctx['num'] == idx:
2084            logger.info("Test: GPSK-3 Mismatch in ID_Server")
2085            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2086                              4 + 1 + 1 + 32 + 32 + 3,
2087                              EAP_TYPE_GPSK,
2088                              EAP_GPSK_OPCODE_GPSK_3)
2089            msg += req[14:46]
2090            msg += struct.pack(">8LHB", 0, 0, 0, 0, 0, 0, 0, 0, 1, ord('B'))
2091            return msg
2092
2093        idx += 1
2094        if ctx['num'] == idx:
2095            logger.info("Test: GPSK-1 Supported CSuite")
2096            return struct.pack(">BBHBBHB8LHLH", EAP_CODE_REQUEST, ctx['id'],
2097                               4 + 1 + 1 + 3 + 32 + 2 + 6,
2098                               EAP_TYPE_GPSK,
2099                               EAP_GPSK_OPCODE_GPSK_1, 1, ord('A'),
2100                               0, 0, 0, 0, 0, 0, 0, 0,
2101                               6, 0, 1)
2102        idx += 1
2103        if ctx['num'] == idx:
2104            logger.info("Test: GPSK-3 Mismatch in ID_Server (same length)")
2105            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2106                              4 + 1 + 1 + 32 + 32 + 3,
2107                              EAP_TYPE_GPSK,
2108                              EAP_GPSK_OPCODE_GPSK_3)
2109            msg += req[15:47]
2110            msg += struct.pack(">8LHB", 0, 0, 0, 0, 0, 0, 0, 0, 1, ord('B'))
2111            return msg
2112
2113        idx += 1
2114        if ctx['num'] == idx:
2115            logger.info("Test: GPSK-1 Supported CSuite")
2116            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2117                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2118                               EAP_TYPE_GPSK,
2119                               EAP_GPSK_OPCODE_GPSK_1, 0,
2120                               0, 0, 0, 0, 0, 0, 0, 0,
2121                               6, 0, 1)
2122        idx += 1
2123        if ctx['num'] == idx:
2124            logger.info("Test: GPSK-3 Missing CSuite_Sel")
2125            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2126                              4 + 1 + 1 + 32 + 32 + 2,
2127                              EAP_TYPE_GPSK,
2128                              EAP_GPSK_OPCODE_GPSK_3)
2129            msg += req[14:46]
2130            msg += struct.pack(">8LH", 0, 0, 0, 0, 0, 0, 0, 0, 0)
2131            return msg
2132
2133        idx += 1
2134        if ctx['num'] == idx:
2135            logger.info("Test: GPSK-1 Supported CSuite")
2136            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2137                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2138                               EAP_TYPE_GPSK,
2139                               EAP_GPSK_OPCODE_GPSK_1, 0,
2140                               0, 0, 0, 0, 0, 0, 0, 0,
2141                               6, 0, 1)
2142        idx += 1
2143        if ctx['num'] == idx:
2144            logger.info("Test: GPSK-3 Mismatch in CSuite_Sel")
2145            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2146                              4 + 1 + 1 + 32 + 32 + 2 + 6,
2147                              EAP_TYPE_GPSK,
2148                              EAP_GPSK_OPCODE_GPSK_3)
2149            msg += req[14:46]
2150            msg += struct.pack(">8LHLH", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2)
2151            return msg
2152
2153        idx += 1
2154        if ctx['num'] == idx:
2155            logger.info("Test: GPSK-1 Supported CSuite")
2156            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2157                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2158                               EAP_TYPE_GPSK,
2159                               EAP_GPSK_OPCODE_GPSK_1, 0,
2160                               0, 0, 0, 0, 0, 0, 0, 0,
2161                               6, 0, 1)
2162        idx += 1
2163        if ctx['num'] == idx:
2164            logger.info("Test: GPSK-3 Missing len(PD_Payload_Block)")
2165            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2166                              4 + 1 + 1 + 32 + 32 + 2 + 6,
2167                              EAP_TYPE_GPSK,
2168                              EAP_GPSK_OPCODE_GPSK_3)
2169            msg += req[14:46]
2170            msg += struct.pack(">8LHLH", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)
2171            return msg
2172
2173        idx += 1
2174        if ctx['num'] == idx:
2175            logger.info("Test: GPSK-1 Supported CSuite")
2176            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2177                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2178                               EAP_TYPE_GPSK,
2179                               EAP_GPSK_OPCODE_GPSK_1, 0,
2180                               0, 0, 0, 0, 0, 0, 0, 0,
2181                               6, 0, 1)
2182        idx += 1
2183        if ctx['num'] == idx:
2184            logger.info("Test: GPSK-3 Truncated PD_Payload_Block")
2185            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2186                              4 + 1 + 1 + 32 + 32 + 2 + 6 + 2,
2187                              EAP_TYPE_GPSK,
2188                              EAP_GPSK_OPCODE_GPSK_3)
2189            msg += req[14:46]
2190            msg += struct.pack(">8LHLHH", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1)
2191            return msg
2192
2193        idx += 1
2194        if ctx['num'] == idx:
2195            logger.info("Test: GPSK-1 Supported CSuite")
2196            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2197                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2198                               EAP_TYPE_GPSK,
2199                               EAP_GPSK_OPCODE_GPSK_1, 0,
2200                               0, 0, 0, 0, 0, 0, 0, 0,
2201                               6, 0, 1)
2202        idx += 1
2203        if ctx['num'] == idx:
2204            logger.info("Test: GPSK-3 Missing MAC")
2205            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2206                              4 + 1 + 1 + 32 + 32 + 2 + 6 + 3,
2207                              EAP_TYPE_GPSK,
2208                              EAP_GPSK_OPCODE_GPSK_3)
2209            msg += req[14:46]
2210            msg += struct.pack(">8LHLHHB",
2211                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 123)
2212            return msg
2213
2214        idx += 1
2215        if ctx['num'] == idx:
2216            logger.info("Test: GPSK-1 Supported CSuite")
2217            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2218                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2219                               EAP_TYPE_GPSK,
2220                               EAP_GPSK_OPCODE_GPSK_1, 0,
2221                               0, 0, 0, 0, 0, 0, 0, 0,
2222                               6, 0, 1)
2223        idx += 1
2224        if ctx['num'] == idx:
2225            logger.info("Test: GPSK-3 Incorrect MAC")
2226            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2227                              4 + 1 + 1 + 32 + 32 + 2 + 6 + 3 + 16,
2228                              EAP_TYPE_GPSK,
2229                              EAP_GPSK_OPCODE_GPSK_3)
2230            msg += req[14:46]
2231            msg += struct.pack(">8LHLHHB4L",
2232                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 123,
2233                               0, 0, 0, 0)
2234            return msg
2235
2236        return None
2237
2238    srv = start_radius_server(gpsk_handler)
2239
2240    try:
2241        hapd = start_ap(apdev[0])
2242        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
2243
2244        for i in range(0, 27):
2245            if i == 12:
2246                pw = "short"
2247            else:
2248                pw = "abcdefghijklmnop0123456789abcdef"
2249            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
2250                           eap="GPSK", identity="user", password=pw,
2251                           wait_connect=False)
2252            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
2253                                   timeout=15)
2254            if ev is None:
2255                raise Exception("Timeout on EAP start")
2256            time.sleep(0.05)
2257            dev[0].request("REMOVE_NETWORK all")
2258    finally:
2259        stop_radius_server(srv)
2260
2261def run_eap_gpsk_connect(dev):
2262    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
2263                eap="GPSK", identity="gpsk user",
2264                password="abcdefghijklmnop0123456789abcdef",
2265                wait_connect=False)
2266    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
2267                         "CTRL-EVENT-DISCONNECTED"],
2268                        timeout=1)
2269    dev.request("REMOVE_NETWORK all")
2270    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
2271        dev.wait_disconnected()
2272    dev.dump_monitor()
2273
2274def test_eap_proto_gpsk_errors_server(dev, apdev):
2275    """EAP-GPSK local error cases on server"""
2276    check_eap_capa(dev[0], "GPSK")
2277    params = int_eap_server_params()
2278    params['erp_domain'] = 'example.com'
2279    params['eap_server_erp'] = '1'
2280    hapd = hostapd.add_ap(apdev[0], params)
2281    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
2282
2283    tests = [(1, "eap_gpsk_init"),
2284             (1, "eap_msg_alloc;eap_gpsk_build_gpsk_1"),
2285             (1, "eap_msg_alloc;eap_gpsk_build_gpsk_3"),
2286             (1, "eap_gpsk_process_gpsk_2"),
2287             (1, "eap_gpsk_derive_keys;eap_gpsk_process_gpsk_2"),
2288             (1, "eap_gpsk_derive_session_id;eap_gpsk_process_gpsk_2"),
2289             (1, "eap_gpsk_getKey"),
2290             (1, "eap_gpsk_get_emsk"),
2291             (1, "eap_gpsk_get_session_id")]
2292    for count, func in tests:
2293        with alloc_fail(hapd, count, func):
2294            run_eap_gpsk_connect(dev[0])
2295
2296    tests = [(1, "os_get_random;eap_gpsk_build_gpsk_1"),
2297             (1, "eap_gpsk_compute_mic;eap_gpsk_build_gpsk_3"),
2298             (1, "eap_gpsk_derive_keys;eap_gpsk_process_gpsk_2"),
2299             (1, "eap_gpsk_derive_session_id;eap_gpsk_process_gpsk_2"),
2300             (1, "eap_gpsk_compute_mic;eap_gpsk_process_gpsk_2"),
2301             (1, "eap_gpsk_compute_mic;eap_gpsk_process_gpsk_4")]
2302    for count, func in tests:
2303        with fail_test(hapd, count, func):
2304            run_eap_gpsk_connect(dev[0])
2305
2306def start_gpsk_assoc(dev, hapd):
2307    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
2308                eap="GPSK", identity="gpsk user",
2309                password="abcdefghijklmnop0123456789abcdef",
2310                wait_connect=False)
2311    proxy_msg(hapd, dev) # EAP-Identity/Request
2312    proxy_msg(dev, hapd) # EAP-Identity/Response
2313    proxy_msg(hapd, dev) # GPSK-1
2314
2315def stop_gpsk_assoc(dev, hapd):
2316    dev.request("REMOVE_NETWORK all")
2317    dev.wait_disconnected()
2318    dev.dump_monitor()
2319    hapd.dump_monitor()
2320
2321def test_eap_proto_gpsk_server(dev, apdev):
2322    """EAP-GPSK protocol testing for the server"""
2323    check_eap_capa(dev[0], "GPSK")
2324    params = int_eap_server_params()
2325    params['erp_domain'] = 'example.com'
2326    params['eap_server_erp'] = '1'
2327    hapd = hostapd.add_ap(apdev[0], params)
2328    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
2329    hapd.request("SET ext_eapol_frame_io 1")
2330    dev[0].request("SET ext_eapol_frame_io 1")
2331
2332    # Successful exchange to verify proxying mechanism
2333    start_gpsk_assoc(dev[0], hapd)
2334    proxy_msg(dev[0], hapd) # GPSK-2
2335    proxy_msg(hapd, dev[0]) # GPSK-3
2336    proxy_msg(dev[0], hapd) # GPSK-4
2337    proxy_msg(hapd, dev[0]) # EAP-Success
2338    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 1/4
2339    proxy_msg(dev[0], hapd) # EAPOL-Key msg 2/4
2340    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 3/4
2341    proxy_msg(dev[0], hapd) # EAPOL-Key msg 4/4
2342    dev[0].wait_connected()
2343    stop_gpsk_assoc(dev[0], hapd)
2344
2345    start_gpsk_assoc(dev[0], hapd)
2346    resp = rx_msg(dev[0])
2347    # Too short EAP-GPSK header (no OP-Code)
2348    # --> EAP-GPSK: Invalid frame
2349    msg = resp[0:4] + "0005" + resp[8:12] + "0005" + "33"
2350    tx_msg(dev[0], hapd, msg)
2351    # Unknown OP-Code
2352    # --> EAP-GPSK: Unexpected opcode=7 in state=0
2353    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "3307"
2354    tx_msg(dev[0], hapd, msg)
2355    # Too short GPSK-2
2356    # --> EAP-GPSK: Too short message for ID_Peer length
2357    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "3302"
2358    tx_msg(dev[0], hapd, msg)
2359    rx_msg(hapd)
2360    stop_gpsk_assoc(dev[0], hapd)
2361
2362    start_gpsk_assoc(dev[0], hapd)
2363    resp = rx_msg(dev[0])
2364    # Too short GPSK-2
2365    # --> EAP-GPSK: Too short message for ID_Peer
2366    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "33020001"
2367    tx_msg(dev[0], hapd, msg)
2368    rx_msg(hapd)
2369    stop_gpsk_assoc(dev[0], hapd)
2370
2371    start_gpsk_assoc(dev[0], hapd)
2372    resp = rx_msg(dev[0])
2373    # Too short GPSK-2
2374    # --> EAP-GPSK: Too short message for ID_Server length
2375    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "33020000"
2376    tx_msg(dev[0], hapd, msg)
2377    rx_msg(hapd)
2378    stop_gpsk_assoc(dev[0], hapd)
2379
2380    start_gpsk_assoc(dev[0], hapd)
2381    resp = rx_msg(dev[0])
2382    # Too short GPSK-2
2383    # --> EAP-GPSK: Too short message for ID_Server
2384    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "330200000001"
2385    tx_msg(dev[0], hapd, msg)
2386    rx_msg(hapd)
2387    stop_gpsk_assoc(dev[0], hapd)
2388
2389    start_gpsk_assoc(dev[0], hapd)
2390    resp = rx_msg(dev[0])
2391    # ID_Server mismatch
2392    # --> EAP-GPSK: ID_Server in GPSK-1 and GPSK-2 did not match
2393    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "330200000000"
2394    tx_msg(dev[0], hapd, msg)
2395    rx_msg(hapd)
2396    stop_gpsk_assoc(dev[0], hapd)
2397
2398    start_gpsk_assoc(dev[0], hapd)
2399    resp = rx_msg(dev[0])
2400    # Too short GPSK-2
2401    # --> EAP-GPSK: Too short message for RAND_Peer
2402    msg = resp[0:4] + "0011" + resp[8:12] + "0011" + "330200000007" + binascii.hexlify(b"hostapd").decode()
2403    tx_msg(dev[0], hapd, msg)
2404    rx_msg(hapd)
2405    stop_gpsk_assoc(dev[0], hapd)
2406
2407    start_gpsk_assoc(dev[0], hapd)
2408    resp = rx_msg(dev[0])
2409    # Too short GPSK-2
2410    # --> EAP-GPSK: Too short message for RAND_Server
2411    msg = resp[0:4] + "0031" + resp[8:12] + "0031" + "330200000007" + binascii.hexlify(b"hostapd").decode() + 32*"00"
2412    tx_msg(dev[0], hapd, msg)
2413    rx_msg(hapd)
2414    stop_gpsk_assoc(dev[0], hapd)
2415
2416    start_gpsk_assoc(dev[0], hapd)
2417    resp = rx_msg(dev[0])
2418    # RAND_Server mismatch
2419    # --> EAP-GPSK: RAND_Server in GPSK-1 and GPSK-2 did not match
2420    msg = resp[0:4] + "0051" + resp[8:12] + "0051" + "330200000007" + binascii.hexlify(b"hostapd").decode() + 32*"00" + 32*"00"
2421    tx_msg(dev[0], hapd, msg)
2422    rx_msg(hapd)
2423    stop_gpsk_assoc(dev[0], hapd)
2424
2425    start_gpsk_assoc(dev[0], hapd)
2426    resp = rx_msg(dev[0])
2427    # Too short GPSK-2
2428    # --> EAP-GPSK: Too short message for CSuite_List length
2429    msg = resp[0:4] + "005a" + resp[8:12] + "005a" + resp[16:188]
2430    tx_msg(dev[0], hapd, msg)
2431    rx_msg(hapd)
2432    stop_gpsk_assoc(dev[0], hapd)
2433
2434    start_gpsk_assoc(dev[0], hapd)
2435    resp = rx_msg(dev[0])
2436    # Too short GPSK-2
2437    # --> EAP-GPSK: Too short message for CSuite_List
2438    msg = resp[0:4] + "005c" + resp[8:12] + "005c" + resp[16:192]
2439    tx_msg(dev[0], hapd, msg)
2440    rx_msg(hapd)
2441    stop_gpsk_assoc(dev[0], hapd)
2442
2443    start_gpsk_assoc(dev[0], hapd)
2444    resp = rx_msg(dev[0])
2445    # Too short GPSK-2
2446    # --> EAP-GPSK: CSuite_List in GPSK-1 and GPSK-2 did not match
2447    msg = resp[0:4] + "005c" + resp[8:12] + "005c" + resp[16:188] + "0000"
2448    tx_msg(dev[0], hapd, msg)
2449    rx_msg(hapd)
2450    stop_gpsk_assoc(dev[0], hapd)
2451
2452    start_gpsk_assoc(dev[0], hapd)
2453    resp = rx_msg(dev[0])
2454    # Too short GPSK-2
2455    # --> EAP-GPSK: Too short message for CSuite_Sel
2456    msg = resp[0:4] + "0068" + resp[8:12] + "0068" + resp[16:216]
2457    tx_msg(dev[0], hapd, msg)
2458    rx_msg(hapd)
2459    stop_gpsk_assoc(dev[0], hapd)
2460
2461    start_gpsk_assoc(dev[0], hapd)
2462    resp = rx_msg(dev[0])
2463    # Unsupported CSuite_Sel
2464    # --> EAP-GPSK: Peer selected unsupported ciphersuite 0:255
2465    msg = resp[0:4] + "006e" + resp[8:12] + "006e" + resp[16:226] + "ff"
2466    tx_msg(dev[0], hapd, msg)
2467    rx_msg(hapd)
2468    stop_gpsk_assoc(dev[0], hapd)
2469
2470    start_gpsk_assoc(dev[0], hapd)
2471    resp = rx_msg(dev[0])
2472    # Too short GPSK-2
2473    # --> EAP-GPSK: Too short message for PD_Payload_1 length
2474    msg = resp[0:4] + "006e" + resp[8:12] + "006e" + resp[16:228]
2475    tx_msg(dev[0], hapd, msg)
2476    rx_msg(hapd)
2477    stop_gpsk_assoc(dev[0], hapd)
2478
2479    start_gpsk_assoc(dev[0], hapd)
2480    resp = rx_msg(dev[0])
2481    # Too short GPSK-2
2482    # --> EAP-GPSK: Too short message for PD_Payload_1
2483    msg = resp[0:4] + "0070" + resp[8:12] + "0070" + resp[16:230] + "ff"
2484    tx_msg(dev[0], hapd, msg)
2485    rx_msg(hapd)
2486    stop_gpsk_assoc(dev[0], hapd)
2487
2488    start_gpsk_assoc(dev[0], hapd)
2489    resp = rx_msg(dev[0])
2490    # Too short GPSK-2
2491    # --> EAP-GPSK: Message too short for MIC (left=0 miclen=16)
2492    msg = resp[0:4] + "0070" + resp[8:12] + "0070" + resp[16:232]
2493    tx_msg(dev[0], hapd, msg)
2494    rx_msg(hapd)
2495    stop_gpsk_assoc(dev[0], hapd)
2496
2497    start_gpsk_assoc(dev[0], hapd)
2498    resp = rx_msg(dev[0])
2499    # Extra data in the end of GPSK-2
2500    # --> EAP-GPSK: Ignored 1 bytes of extra data in the end of GPSK-2
2501    msg = resp[0:4] + "0081" + resp[8:12] + "0081" + resp[16:264] + "00"
2502    tx_msg(dev[0], hapd, msg)
2503    proxy_msg(hapd, dev[0]) # GPSK-3
2504    resp = rx_msg(dev[0])
2505    # Too short GPSK-4
2506    # --> EAP-GPSK: Too short message for PD_Payload_1 length
2507    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "3304"
2508    tx_msg(dev[0], hapd, msg)
2509    rx_msg(hapd) # EAP-Failure
2510    stop_gpsk_assoc(dev[0], hapd)
2511
2512    start_gpsk_assoc(dev[0], hapd)
2513    proxy_msg(dev[0], hapd) # GPSK-2
2514    proxy_msg(hapd, dev[0]) # GPSK-3
2515    resp = rx_msg(dev[0])
2516    # Too short GPSK-4
2517    # --> EAP-GPSK: Too short message for PD_Payload_1
2518    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "33040001"
2519    tx_msg(dev[0], hapd, msg)
2520    rx_msg(hapd) # EAP-Failure
2521    stop_gpsk_assoc(dev[0], hapd)
2522
2523    start_gpsk_assoc(dev[0], hapd)
2524    proxy_msg(dev[0], hapd) # GPSK-2
2525    proxy_msg(hapd, dev[0]) # GPSK-3
2526    resp = rx_msg(dev[0])
2527    # Too short GPSK-4
2528    # --> EAP-GPSK: Message too short for MIC (left=0 miclen=16)
2529    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "33040000"
2530    tx_msg(dev[0], hapd, msg)
2531    rx_msg(hapd) # EAP-Failure
2532    stop_gpsk_assoc(dev[0], hapd)
2533
2534    start_gpsk_assoc(dev[0], hapd)
2535    proxy_msg(dev[0], hapd) # GPSK-2
2536    proxy_msg(hapd, dev[0]) # GPSK-3
2537    resp = rx_msg(dev[0])
2538    # Incorrect MIC in GPSK-4
2539    # --> EAP-GPSK: Incorrect MIC in GPSK-4
2540    msg = resp[0:4] + "0018" + resp[8:12] + "0018" + "33040000" + 16*"00"
2541    tx_msg(dev[0], hapd, msg)
2542    rx_msg(hapd) # EAP-Failure
2543    stop_gpsk_assoc(dev[0], hapd)
2544
2545    start_gpsk_assoc(dev[0], hapd)
2546    proxy_msg(dev[0], hapd) # GPSK-2
2547    proxy_msg(hapd, dev[0]) # GPSK-3
2548    resp = rx_msg(dev[0])
2549    # Incorrect MIC in GPSK-4
2550    # --> EAP-GPSK: Ignored 1 bytes of extra data in the end of GPSK-4
2551    msg = resp[0:4] + "0019" + resp[8:12] + "0019" + resp[16:] + "00"
2552    tx_msg(dev[0], hapd, msg)
2553    rx_msg(hapd) # EAP-Success
2554    stop_gpsk_assoc(dev[0], hapd)
2555
2556EAP_EKE_ID = 1
2557EAP_EKE_COMMIT = 2
2558EAP_EKE_CONFIRM = 3
2559EAP_EKE_FAILURE = 4
2560
2561def test_eap_proto_eke(dev, apdev):
2562    """EAP-EKE protocol tests"""
2563    def eke_handler(ctx, req):
2564        logger.info("eke_handler - RX " + binascii.hexlify(req).decode())
2565        if 'num' not in ctx:
2566            ctx['num'] = 0
2567        ctx['num'] = ctx['num'] + 1
2568        if 'id' not in ctx:
2569            ctx['id'] = 1
2570        ctx['id'] = (ctx['id'] + 1) % 256
2571
2572        idx = 0
2573
2574        idx += 1
2575        if ctx['num'] == idx:
2576            logger.info("Test: Missing payload")
2577            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
2578                               4 + 1,
2579                               EAP_TYPE_EKE)
2580
2581        idx += 1
2582        if ctx['num'] == idx:
2583            logger.info("Test: Unknown exchange")
2584            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2585                               4 + 1 + 1,
2586                               EAP_TYPE_EKE,
2587                               255)
2588
2589        idx += 1
2590        if ctx['num'] == idx:
2591            logger.info("Test: No NumProposals in EAP-EKE-ID/Request")
2592            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2593                               4 + 1 + 1,
2594                               EAP_TYPE_EKE,
2595                               EAP_EKE_ID)
2596        idx += 1
2597        if ctx['num'] == idx:
2598            logger.info("Test: EAP-Failure")
2599            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2600
2601        idx += 1
2602        if ctx['num'] == idx:
2603            logger.info("Test: NumProposals=0 in EAP-EKE-ID/Request")
2604            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
2605                               4 + 1 + 1 + 1,
2606                               EAP_TYPE_EKE,
2607                               EAP_EKE_ID,
2608                               0)
2609        idx += 1
2610        if ctx['num'] == idx:
2611            logger.info("Test: EAP-Failure")
2612            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2613
2614        idx += 1
2615        if ctx['num'] == idx:
2616            logger.info("Test: Truncated Proposals list in EAP-EKE-ID/Request")
2617            return struct.pack(">BBHBBBB4B", EAP_CODE_REQUEST, ctx['id'],
2618                               4 + 1 + 1 + 2 + 4,
2619                               EAP_TYPE_EKE,
2620                               EAP_EKE_ID,
2621                               2, 0, 0, 0, 0, 0)
2622        idx += 1
2623        if ctx['num'] == idx:
2624            logger.info("Test: EAP-Failure")
2625            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2626
2627        idx += 1
2628        if ctx['num'] == idx:
2629            logger.info("Test: Unsupported proposals in EAP-EKE-ID/Request")
2630            return struct.pack(">BBHBBBB4B4B4B4B", EAP_CODE_REQUEST, ctx['id'],
2631                               4 + 1 + 1 + 2 + 4 * 4,
2632                               EAP_TYPE_EKE,
2633                               EAP_EKE_ID,
2634                               4, 0,
2635                               0, 0, 0, 0,
2636                               3, 0, 0, 0,
2637                               3, 1, 0, 0,
2638                               3, 1, 1, 0)
2639        idx += 1
2640        if ctx['num'] == idx:
2641            logger.info("Test: EAP-Failure")
2642            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2643
2644        idx += 1
2645        if ctx['num'] == idx:
2646            logger.info("Test: Missing IDType/Identity in EAP-EKE-ID/Request")
2647            return struct.pack(">BBHBBBB4B4B4B4B4B",
2648                               EAP_CODE_REQUEST, ctx['id'],
2649                               4 + 1 + 1 + 2 + 5 * 4,
2650                               EAP_TYPE_EKE,
2651                               EAP_EKE_ID,
2652                               5, 0,
2653                               0, 0, 0, 0,
2654                               3, 0, 0, 0,
2655                               3, 1, 0, 0,
2656                               3, 1, 1, 0,
2657                               3, 1, 1, 1)
2658        idx += 1
2659        if ctx['num'] == idx:
2660            logger.info("Test: EAP-Failure")
2661            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2662
2663        idx += 1
2664        if ctx['num'] == idx:
2665            logger.info("Test: Valid EAP-EKE-ID/Request")
2666            return struct.pack(">BBHBBBB4BB",
2667                               EAP_CODE_REQUEST, ctx['id'],
2668                               4 + 1 + 1 + 2 + 4 + 1,
2669                               EAP_TYPE_EKE,
2670                               EAP_EKE_ID,
2671                               1, 0,
2672                               3, 1, 1, 1,
2673                               255)
2674        idx += 1
2675        if ctx['num'] == idx:
2676            logger.info("Test: Unexpected EAP-EKE-ID/Request")
2677            return struct.pack(">BBHBBBB4BB",
2678                               EAP_CODE_REQUEST, ctx['id'],
2679                               4 + 1 + 1 + 2 + 4 + 1,
2680                               EAP_TYPE_EKE,
2681                               EAP_EKE_ID,
2682                               1, 0,
2683                               3, 1, 1, 1,
2684                               255)
2685        idx += 1
2686        if ctx['num'] == idx:
2687            logger.info("Test: EAP-Failure")
2688            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2689
2690        idx += 1
2691        if ctx['num'] == idx:
2692            logger.info("Test: Valid EAP-EKE-ID/Request")
2693            return struct.pack(">BBHBBBB4BB",
2694                               EAP_CODE_REQUEST, ctx['id'],
2695                               4 + 1 + 1 + 2 + 4 + 1,
2696                               EAP_TYPE_EKE,
2697                               EAP_EKE_ID,
2698                               1, 0,
2699                               3, 1, 1, 1,
2700                               255)
2701        idx += 1
2702        if ctx['num'] == idx:
2703            logger.info("Test: Unexpected EAP-EKE-Confirm/Request")
2704            return struct.pack(">BBHBB",
2705                               EAP_CODE_REQUEST, ctx['id'],
2706                               4 + 1 + 1,
2707                               EAP_TYPE_EKE,
2708                               EAP_EKE_CONFIRM)
2709        idx += 1
2710        if ctx['num'] == idx:
2711            logger.info("Test: EAP-Failure")
2712            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2713
2714        idx += 1
2715        if ctx['num'] == idx:
2716            logger.info("Test: Too short EAP-EKE-Failure/Request")
2717            return struct.pack(">BBHBB",
2718                               EAP_CODE_REQUEST, ctx['id'],
2719                               4 + 1 + 1,
2720                               EAP_TYPE_EKE,
2721                               EAP_EKE_FAILURE)
2722        idx += 1
2723        if ctx['num'] == idx:
2724            logger.info("Test: EAP-Failure")
2725            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2726
2727        idx += 1
2728        if ctx['num'] == idx:
2729            logger.info("Test: Unexpected EAP-EKE-Commit/Request")
2730            return struct.pack(">BBHBB",
2731                               EAP_CODE_REQUEST, ctx['id'],
2732                               4 + 1 + 1,
2733                               EAP_TYPE_EKE,
2734                               EAP_EKE_COMMIT)
2735        idx += 1
2736        if ctx['num'] == idx:
2737            logger.info("Test: EAP-Failure")
2738            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2739
2740        idx += 1
2741        if ctx['num'] == idx:
2742            logger.info("Test: Valid EAP-EKE-ID/Request")
2743            return struct.pack(">BBHBBBB4BB",
2744                               EAP_CODE_REQUEST, ctx['id'],
2745                               4 + 1 + 1 + 2 + 4 + 1,
2746                               EAP_TYPE_EKE,
2747                               EAP_EKE_ID,
2748                               1, 0,
2749                               3, 1, 1, 1,
2750                               255)
2751        idx += 1
2752        if ctx['num'] == idx:
2753            logger.info("Test: Too short EAP-EKE-Commit/Request")
2754            return struct.pack(">BBHBB",
2755                               EAP_CODE_REQUEST, ctx['id'],
2756                               4 + 1 + 1,
2757                               EAP_TYPE_EKE,
2758                               EAP_EKE_COMMIT)
2759        idx += 1
2760        if ctx['num'] == idx:
2761            logger.info("Test: EAP-Failure")
2762            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2763
2764        idx += 1
2765        if ctx['num'] == idx:
2766            logger.info("Test: Valid EAP-EKE-ID/Request")
2767            return struct.pack(">BBHBBBB4BB",
2768                               EAP_CODE_REQUEST, ctx['id'],
2769                               4 + 1 + 1 + 2 + 4 + 1,
2770                               EAP_TYPE_EKE,
2771                               EAP_EKE_ID,
2772                               1, 0,
2773                               1, 1, 1, 1,
2774                               255)
2775        idx += 1
2776        if ctx['num'] == idx:
2777            logger.info("Test: All zeroes DHComponent_S and empty CBvalue in EAP-EKE-Commit/Request")
2778            return struct.pack(">BBHBB4L32L",
2779                               EAP_CODE_REQUEST, ctx['id'],
2780                               4 + 1 + 1 + 16 + 128,
2781                               EAP_TYPE_EKE,
2782                               EAP_EKE_COMMIT,
2783                               0, 0, 0, 0,
2784                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2785                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
2786        idx += 1
2787        if ctx['num'] == idx:
2788            logger.info("Test: Too short EAP-EKE-Confirm/Request")
2789            return struct.pack(">BBHBB",
2790                               EAP_CODE_REQUEST, ctx['id'],
2791                               4 + 1 + 1,
2792                               EAP_TYPE_EKE,
2793                               EAP_EKE_CONFIRM)
2794        idx += 1
2795        if ctx['num'] == idx:
2796            logger.info("Test: EAP-Failure")
2797            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2798
2799        idx += 1
2800        if ctx['num'] == idx:
2801            logger.info("Test: Valid EAP-EKE-ID/Request")
2802            return struct.pack(">BBHBBBB4BB",
2803                               EAP_CODE_REQUEST, ctx['id'],
2804                               4 + 1 + 1 + 2 + 4 + 1,
2805                               EAP_TYPE_EKE,
2806                               EAP_EKE_ID,
2807                               1, 0,
2808                               1, 1, 1, 1,
2809                               255)
2810        idx += 1
2811        if ctx['num'] == idx:
2812            logger.info("Test: All zeroes DHComponent_S and empty CBvalue in EAP-EKE-Commit/Request")
2813            return struct.pack(">BBHBB4L32L",
2814                               EAP_CODE_REQUEST, ctx['id'],
2815                               4 + 1 + 1 + 16 + 128,
2816                               EAP_TYPE_EKE,
2817                               EAP_EKE_COMMIT,
2818                               0, 0, 0, 0,
2819                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2820                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
2821        idx += 1
2822        if ctx['num'] == idx:
2823            logger.info("Test: Invalid PNonce_PS and Auth_S values in EAP-EKE-Confirm/Request")
2824            return struct.pack(">BBHBB4L8L5L5L",
2825                               EAP_CODE_REQUEST, ctx['id'],
2826                               4 + 1 + 1 + 16 + 2 * 16 + 20 + 20,
2827                               EAP_TYPE_EKE,
2828                               EAP_EKE_CONFIRM,
2829                               0, 0, 0, 0,
2830                               0, 0, 0, 0, 0, 0, 0, 0,
2831                               0, 0, 0, 0, 0,
2832                               0, 0, 0, 0, 0)
2833        idx += 1
2834        if ctx['num'] == idx:
2835            logger.info("Test: EAP-Failure")
2836            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2837
2838        return None
2839
2840    srv = start_radius_server(eke_handler)
2841
2842    try:
2843        hapd = start_ap(apdev[0])
2844        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
2845
2846        for i in range(0, 14):
2847            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
2848                           eap="EKE", identity="user", password="password",
2849                           wait_connect=False)
2850            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
2851                                   timeout=15)
2852            if ev is None:
2853                raise Exception("Timeout on EAP start")
2854            if i in [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]:
2855                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
2856                                       timeout=10)
2857                if ev is None:
2858                    raise Exception("Timeout on EAP failure")
2859            else:
2860                time.sleep(0.05)
2861            dev[0].request("REMOVE_NETWORK all")
2862            dev[0].dump_monitor()
2863    finally:
2864        stop_radius_server(srv)
2865
2866def eap_eke_test_fail(dev, phase1=None, success=False):
2867    dev.connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
2868                eap="EKE", identity="eke user@domain", password="hello",
2869                phase1=phase1, erp="1", wait_connect=False)
2870    ev = dev.wait_event(["CTRL-EVENT-EAP-FAILURE",
2871                         "CTRL-EVENT-EAP-SUCCESS"], timeout=5)
2872    if ev is None:
2873        raise Exception("Timeout on EAP failure")
2874    if not success and "CTRL-EVENT-EAP-FAILURE" not in ev:
2875        raise Exception("EAP did not fail during failure test")
2876    dev.request("REMOVE_NETWORK all")
2877    dev.wait_disconnected()
2878
2879def test_eap_proto_eke_errors(dev, apdev):
2880    """EAP-EKE local error cases"""
2881    check_eap_capa(dev[0], "EKE")
2882    params = hostapd.wpa2_eap_params(ssid="eap-test")
2883    hapd = hostapd.add_ap(apdev[0], params)
2884    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
2885
2886    for i in range(1, 3):
2887        with alloc_fail(dev[0], i, "eap_eke_init"):
2888            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
2889                           eap="EKE", identity="eke user", password="hello",
2890                           wait_connect=False)
2891            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
2892                                   timeout=15)
2893            if ev is None:
2894                raise Exception("Timeout on EAP start")
2895            dev[0].request("REMOVE_NETWORK all")
2896            dev[0].wait_disconnected()
2897
2898    tests = [(1, "eap_eke_dh_init", None),
2899             (1, "eap_eke_prf_hmac_sha1", "dhgroup=3 encr=1 prf=1 mac=1"),
2900             (1, "eap_eke_prf_hmac_sha256", "dhgroup=5 encr=1 prf=2 mac=2"),
2901             (1, "eap_eke_prf_*", None),
2902             (1, "os_get_random;eap_eke_dhcomp", None),
2903             (1, "aes_128_cbc_encrypt;eap_eke_dhcomp", None),
2904             (1, "aes_128_cbc_decrypt;eap_eke_shared_secret", None),
2905             (1, "hmac_sha256_vector;eap_eke_shared_secret", None),
2906             (1, "eap_eke_prf_hmac_sha256;eap_eke_derive_ke_ki", None),
2907             (1, "eap_eke_prf_hmac_sha256;eap_eke_derive_ka", None),
2908             (1, "eap_eke_prf_hmac_sha256;eap_eke_derive_msk", None),
2909             (1, "os_get_random;eap_eke_prot", None),
2910             (1, "aes_128_cbc_decrypt;eap_eke_decrypt_prot", None),
2911             (1, "eap_eke_derive_key;eap_eke_process_commit", None),
2912             (1, "eap_eke_dh_init;eap_eke_process_commit", None),
2913             (1, "eap_eke_shared_secret;eap_eke_process_commit", None),
2914             (1, "eap_eke_derive_ke_ki;eap_eke_process_commit", None),
2915             (1, "eap_eke_dhcomp;eap_eke_process_commit", None),
2916             (1, "os_get_random;eap_eke_process_commit", None),
2917             (1, "os_get_random;=eap_eke_process_commit", None),
2918             (1, "eap_eke_prot;eap_eke_process_commit", None),
2919             (1, "eap_eke_decrypt_prot;eap_eke_process_confirm", None),
2920             (1, "eap_eke_derive_ka;eap_eke_process_confirm", None),
2921             (1, "eap_eke_auth;eap_eke_process_confirm", None),
2922             (2, "eap_eke_auth;eap_eke_process_confirm", None),
2923             (1, "eap_eke_prot;eap_eke_process_confirm", None),
2924             (1, "aes_128_cbc_encrypt;eap_eke_prot;eap_eke_process_confirm", None),
2925             (1, "hmac_sha256;eap_eke_prot;eap_eke_process_confirm", None),
2926             (1, "eap_eke_derive_msk;eap_eke_process_confirm", None)]
2927    for count, func, phase1 in tests:
2928        with fail_test(dev[0], count, func):
2929            eap_eke_test_fail(dev[0], phase1)
2930
2931    tests = [(1, "=eap_eke_derive_ke_ki", None),
2932             (1, "=eap_eke_derive_ka", None),
2933             (1, "=eap_eke_derive_msk", None),
2934             (1, "eap_eke_build_msg;eap_eke_process_id", None),
2935             (1, "wpabuf_alloc;eap_eke_process_id", None),
2936             (1, "=eap_eke_process_id", None),
2937             (1, "wpabuf_alloc;=eap_eke_process_id", None),
2938             (1, "wpabuf_alloc;eap_eke_process_id", None),
2939             (1, "eap_eke_build_msg;eap_eke_process_commit", None),
2940             (1, "wpabuf_resize;eap_eke_process_commit", None),
2941             (1, "eap_eke_build_msg;eap_eke_process_confirm", None)]
2942    for count, func, phase1 in tests:
2943        with alloc_fail(dev[0], count, func):
2944            eap_eke_test_fail(dev[0], phase1)
2945
2946    tests = [(1, "eap_eke_getKey", None),
2947             (1, "eap_eke_get_emsk", None),
2948             (1, "eap_eke_get_session_id", None)]
2949    for count, func, phase1 in tests:
2950        with alloc_fail(dev[0], count, func):
2951            eap_eke_test_fail(dev[0], phase1, success=True)
2952
2953EAP_PAX_OP_STD_1 = 0x01
2954EAP_PAX_OP_STD_2 = 0x02
2955EAP_PAX_OP_STD_3 = 0x03
2956EAP_PAX_OP_SEC_1 = 0x11
2957EAP_PAX_OP_SEC_2 = 0x12
2958EAP_PAX_OP_SEC_3 = 0x13
2959EAP_PAX_OP_SEC_4 = 0x14
2960EAP_PAX_OP_SEC_5 = 0x15
2961EAP_PAX_OP_ACK = 0x21
2962
2963EAP_PAX_FLAGS_MF = 0x01
2964EAP_PAX_FLAGS_CE = 0x02
2965EAP_PAX_FLAGS_AI = 0x04
2966
2967EAP_PAX_MAC_HMAC_SHA1_128 = 0x01
2968EAP_PAX_HMAC_SHA256_128 = 0x02
2969
2970EAP_PAX_DH_GROUP_NONE = 0x00
2971EAP_PAX_DH_GROUP_2048_MODP = 0x01
2972EAP_PAX_DH_GROUP_3072_MODP = 0x02
2973EAP_PAX_DH_GROUP_NIST_ECC_P_256 = 0x03
2974
2975EAP_PAX_PUBLIC_KEY_NONE = 0x00
2976EAP_PAX_PUBLIC_KEY_RSAES_OAEP = 0x01
2977EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5 = 0x02
2978EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC = 0x03
2979
2980EAP_PAX_ADE_VENDOR_SPECIFIC = 0x01
2981EAP_PAX_ADE_CLIENT_CHANNEL_BINDING = 0x02
2982EAP_PAX_ADE_SERVER_CHANNEL_BINDING = 0x03
2983
2984def test_eap_proto_pax(dev, apdev):
2985    """EAP-PAX protocol tests"""
2986    def pax_std_1(ctx):
2987            logger.info("Test: STD-1")
2988            ctx['id'] = 10
2989            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
2990                               4 + 1 + 5 + 2 + 32 + 16,
2991                               EAP_TYPE_PAX,
2992                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
2993                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
2994                               32, 0, 0, 0, 0, 0, 0, 0, 0,
2995                               0x16, 0xc9, 0x08, 0x9d, 0x98, 0xa5, 0x6e, 0x1f,
2996                               0xf0, 0xac, 0xcf, 0xc4, 0x66, 0xcd, 0x2d, 0xbf)
2997
2998    def pax_handler(ctx, req):
2999        logger.info("pax_handler - RX " + binascii.hexlify(req).decode())
3000        if 'num' not in ctx:
3001            ctx['num'] = 0
3002        ctx['num'] = ctx['num'] + 1
3003        if 'id' not in ctx:
3004            ctx['id'] = 1
3005        ctx['id'] = (ctx['id'] + 1) % 256
3006
3007        idx = 0
3008
3009        idx += 1
3010        if ctx['num'] == idx:
3011            logger.info("Test: Missing payload")
3012            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
3013                               4 + 1,
3014                               EAP_TYPE_PAX)
3015
3016        idx += 1
3017        if ctx['num'] == idx:
3018            logger.info("Test: Minimum length payload")
3019            return struct.pack(">BBHB4L", EAP_CODE_REQUEST, ctx['id'],
3020                               4 + 1 + 16,
3021                               EAP_TYPE_PAX,
3022                               0, 0, 0, 0)
3023
3024        idx += 1
3025        if ctx['num'] == idx:
3026            logger.info("Test: Unsupported MAC ID")
3027            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
3028                               4 + 1 + 5 + 16,
3029                               EAP_TYPE_PAX,
3030                               EAP_PAX_OP_STD_1, 0, 255, EAP_PAX_DH_GROUP_NONE,
3031                               EAP_PAX_PUBLIC_KEY_NONE,
3032                               0, 0, 0, 0)
3033
3034        idx += 1
3035        if ctx['num'] == idx:
3036            logger.info("Test: Unsupported DH Group ID")
3037            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
3038                               4 + 1 + 5 + 16,
3039                               EAP_TYPE_PAX,
3040                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3041                               255, EAP_PAX_PUBLIC_KEY_NONE,
3042                               0, 0, 0, 0)
3043
3044        idx += 1
3045        if ctx['num'] == idx:
3046            logger.info("Test: Unsupported Public Key ID")
3047            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
3048                               4 + 1 + 5 + 16,
3049                               EAP_TYPE_PAX,
3050                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3051                               EAP_PAX_DH_GROUP_NONE, 255,
3052                               0, 0, 0, 0)
3053
3054        idx += 1
3055        if ctx['num'] == idx:
3056            logger.info("Test: More fragments")
3057            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
3058                               4 + 1 + 5 + 16,
3059                               EAP_TYPE_PAX,
3060                               EAP_PAX_OP_STD_1, EAP_PAX_FLAGS_MF,
3061                               EAP_PAX_MAC_HMAC_SHA1_128,
3062                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3063                               0, 0, 0, 0)
3064
3065        idx += 1
3066        if ctx['num'] == idx:
3067            logger.info("Test: Invalid ICV")
3068            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
3069                               4 + 1 + 5 + 16,
3070                               EAP_TYPE_PAX,
3071                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3072                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3073                               0, 0, 0, 0)
3074
3075        idx += 1
3076        if ctx['num'] == idx:
3077            logger.info("Test: Invalid ICV in short frame")
3078            return struct.pack(">BBHBBBBBB3L", EAP_CODE_REQUEST, ctx['id'],
3079                               4 + 1 + 5 + 12,
3080                               EAP_TYPE_PAX,
3081                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3082                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3083                               0, 0, 0)
3084
3085        idx += 1
3086        if ctx['num'] == idx:
3087            logger.info("Test: Correct ICV - unsupported op_code")
3088            ctx['id'] = 10
3089            return struct.pack(">BBHBBBBBB16B", EAP_CODE_REQUEST, ctx['id'],
3090                               4 + 1 + 5 + 16,
3091                               EAP_TYPE_PAX,
3092                               255, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3093                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3094                               0x90, 0x78, 0x97, 0x38, 0x29, 0x94, 0x32, 0xd4,
3095                               0x81, 0x27, 0xe0, 0xf6, 0x3b, 0x0d, 0xb2, 0xb2)
3096
3097        idx += 1
3098        if ctx['num'] == idx:
3099            logger.info("Test: Correct ICV - CE flag in STD-1")
3100            ctx['id'] = 10
3101            return struct.pack(">BBHBBBBBB16B", EAP_CODE_REQUEST, ctx['id'],
3102                               4 + 1 + 5 + 16,
3103                               EAP_TYPE_PAX,
3104                               EAP_PAX_OP_STD_1, EAP_PAX_FLAGS_CE,
3105                               EAP_PAX_MAC_HMAC_SHA1_128,
3106                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3107                               0x9c, 0x98, 0xb4, 0x0b, 0x94, 0x90, 0xde, 0x88,
3108                               0xb7, 0x72, 0x63, 0x44, 0x1d, 0xe3, 0x7c, 0x5c)
3109
3110        idx += 1
3111        if ctx['num'] == idx:
3112            logger.info("Test: Correct ICV - too short STD-1 payload")
3113            ctx['id'] = 10
3114            return struct.pack(">BBHBBBBBB16B", EAP_CODE_REQUEST, ctx['id'],
3115                               4 + 1 + 5 + 16,
3116                               EAP_TYPE_PAX,
3117                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3118                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3119                               0xda, 0xab, 0x2c, 0xe7, 0x84, 0x41, 0xb5, 0x5c,
3120                               0xee, 0xcf, 0x62, 0x03, 0xc5, 0x69, 0xcb, 0xf4)
3121
3122        idx += 1
3123        if ctx['num'] == idx:
3124            logger.info("Test: Correct ICV - incorrect A length in STD-1")
3125            ctx['id'] = 10
3126            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3127                               4 + 1 + 5 + 2 + 32 + 16,
3128                               EAP_TYPE_PAX,
3129                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3130                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3131                               0, 0, 0, 0, 0, 0, 0, 0, 0,
3132                               0xc4, 0xb0, 0x81, 0xe4, 0x6c, 0x8c, 0x20, 0x23,
3133                               0x60, 0x46, 0x89, 0xea, 0x94, 0x60, 0xf3, 0x2a)
3134
3135        idx += 1
3136        if ctx['num'] == idx:
3137            logger.info("Test: Correct ICV - extra data in STD-1")
3138            ctx['id'] = 10
3139            return struct.pack(">BBHBBBBBBH8LB16B", EAP_CODE_REQUEST, ctx['id'],
3140                               4 + 1 + 5 + 2 + 32 + 1 + 16,
3141                               EAP_TYPE_PAX,
3142                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3143                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3144                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3145                               1,
3146                               0x61, 0x49, 0x65, 0x37, 0x21, 0xe8, 0xd8, 0xbf,
3147                               0xf3, 0x02, 0x01, 0xe5, 0x42, 0x51, 0xd3, 0x34)
3148        idx += 1
3149        if ctx['num'] == idx:
3150            logger.info("Test: Unexpected STD-1")
3151            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3152                               4 + 1 + 5 + 2 + 32 + 16,
3153                               EAP_TYPE_PAX,
3154                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3155                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3156                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3157                               0xe5, 0x1d, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
3158                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
3159
3160        idx += 1
3161        if ctx['num'] == idx:
3162            return pax_std_1(ctx)
3163        idx += 1
3164        if ctx['num'] == idx:
3165            logger.info("Test: MAC ID changed during session")
3166            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3167                               4 + 1 + 5 + 2 + 32 + 16,
3168                               EAP_TYPE_PAX,
3169                               EAP_PAX_OP_STD_1, 0, EAP_PAX_HMAC_SHA256_128,
3170                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3171                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3172                               0xee, 0x00, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
3173                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
3174
3175        idx += 1
3176        if ctx['num'] == idx:
3177            return pax_std_1(ctx)
3178        idx += 1
3179        if ctx['num'] == idx:
3180            logger.info("Test: DH Group ID changed during session")
3181            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3182                               4 + 1 + 5 + 2 + 32 + 16,
3183                               EAP_TYPE_PAX,
3184                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3185                               EAP_PAX_DH_GROUP_2048_MODP,
3186                               EAP_PAX_PUBLIC_KEY_NONE,
3187                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3188                               0xee, 0x01, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
3189                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
3190
3191        idx += 1
3192        if ctx['num'] == idx:
3193            return pax_std_1(ctx)
3194        idx += 1
3195        if ctx['num'] == idx:
3196            logger.info("Test: Public Key ID changed during session")
3197            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3198                               4 + 1 + 5 + 2 + 32 + 16,
3199                               EAP_TYPE_PAX,
3200                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3201                               EAP_PAX_DH_GROUP_NONE,
3202                               EAP_PAX_PUBLIC_KEY_RSAES_OAEP,
3203                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3204                               0xee, 0x02, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
3205                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
3206
3207        idx += 1
3208        if ctx['num'] == idx:
3209            logger.info("Test: Unexpected STD-3")
3210            ctx['id'] = 10
3211            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3212                               4 + 1 + 5 + 2 + 32 + 16,
3213                               EAP_TYPE_PAX,
3214                               EAP_PAX_OP_STD_3, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3215                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3216                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3217                               0x47, 0xbb, 0xc0, 0xf9, 0xb9, 0x69, 0xf5, 0xcb,
3218                               0x3a, 0xe8, 0xe7, 0xd6, 0x80, 0x28, 0xf2, 0x59)
3219
3220        idx += 1
3221        if ctx['num'] == idx:
3222            return pax_std_1(ctx)
3223        idx += 1
3224        if ctx['num'] == idx:
3225            # TODO: MAC calculation; for now, this gets dropped due to incorrect
3226            # ICV
3227            logger.info("Test: STD-3 with CE flag")
3228            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3229                               4 + 1 + 5 + 2 + 32 + 16,
3230                               EAP_TYPE_PAX,
3231                               EAP_PAX_OP_STD_3, EAP_PAX_FLAGS_CE,
3232                               EAP_PAX_MAC_HMAC_SHA1_128,
3233                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3234                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3235                               0x8a, 0xc2, 0xf9, 0xf4, 0x8b, 0x75, 0x72, 0xa2,
3236                               0x4d, 0xd3, 0x1e, 0x54, 0x77, 0x04, 0x05, 0xe2)
3237
3238        idx += 1
3239        if ctx['num'] & 0x1 == idx & 0x1:
3240            logger.info("Test: Default request")
3241            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
3242                               4 + 1,
3243                               EAP_TYPE_PAX)
3244        else:
3245            logger.info("Test: Default EAP-Failure")
3246            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
3247
3248    srv = start_radius_server(pax_handler)
3249
3250    try:
3251        hapd = start_ap(apdev[0])
3252        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3253
3254        for i in range(0, 18):
3255            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3256                           eap="PAX", identity="user",
3257                           password_hex="0123456789abcdef0123456789abcdef",
3258                           wait_connect=False)
3259            logger.info("Waiting for EAP method to start")
3260            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
3261                                   timeout=15)
3262            if ev is None:
3263                raise Exception("Timeout on EAP start")
3264            time.sleep(0.05)
3265            dev[0].request("REMOVE_NETWORK all")
3266            dev[0].dump_monitor()
3267
3268        logger.info("Too short password")
3269        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3270                       eap="PAX", identity="user",
3271                       password_hex="0123456789abcdef0123456789abcd",
3272                       wait_connect=False)
3273        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
3274        if ev is None:
3275            raise Exception("Timeout on EAP start")
3276        time.sleep(0.1)
3277        dev[0].request("REMOVE_NETWORK all")
3278        dev[0].dump_monitor()
3279
3280        logger.info("No password")
3281        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3282                       eap="PAX", identity="user",
3283                       wait_connect=False)
3284        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
3285        if ev is None:
3286            raise Exception("Timeout on EAP start")
3287        time.sleep(0.1)
3288        dev[0].request("REMOVE_NETWORK all")
3289        dev[0].dump_monitor()
3290    finally:
3291        stop_radius_server(srv)
3292
3293def test_eap_proto_pax_errors(dev, apdev):
3294    """EAP-PAX local error cases"""
3295    check_eap_capa(dev[0], "PAX")
3296    params = hostapd.wpa2_eap_params(ssid="eap-test")
3297    hapd = hostapd.add_ap(apdev[0], params)
3298    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3299
3300    for i in range(1, 3):
3301        with alloc_fail(dev[0], i, "eap_pax_init"):
3302            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3303                           eap="PAX", identity="pax.user@example.com",
3304                           password_hex="0123456789abcdef0123456789abcdef",
3305                           wait_connect=False)
3306            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
3307                                   timeout=15)
3308            if ev is None:
3309                raise Exception("Timeout on EAP start")
3310            dev[0].request("REMOVE_NETWORK all")
3311            dev[0].wait_disconnected()
3312
3313    tests = ["eap_msg_alloc;eap_pax_alloc_resp;eap_pax_process_std_1",
3314             "eap_msg_alloc;eap_pax_alloc_resp;eap_pax_process_std_3",
3315             "eap_pax_getKey",
3316             "eap_pax_get_emsk",
3317             "eap_pax_get_session_id"]
3318    for func in tests:
3319        with alloc_fail(dev[0], 1, func):
3320            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3321                           eap="PAX", identity="pax.user@example.com",
3322                           password_hex="0123456789abcdef0123456789abcdef",
3323                           erp="1", wait_connect=False)
3324            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
3325            dev[0].request("REMOVE_NETWORK all")
3326            dev[0].wait_disconnected()
3327
3328    tests = [(1, "os_get_random;eap_pax_process_std_1"),
3329             (1, "eap_pax_initial_key_derivation"),
3330             (1, "eap_pax_mac;eap_pax_process_std_3"),
3331             (2, "eap_pax_mac;eap_pax_process_std_3"),
3332             (1, "eap_pax_kdf;eap_pax_getKey"),
3333             (1, "eap_pax_kdf;eap_pax_get_emsk")]
3334    for count, func in tests:
3335        with fail_test(dev[0], count, func):
3336            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3337                           eap="PAX", identity="pax.user@example.com",
3338                           password_hex="0123456789abcdef0123456789abcdef",
3339                           erp="1", wait_connect=False)
3340            wait_fail_trigger(dev[0], "GET_FAIL")
3341            dev[0].request("REMOVE_NETWORK all")
3342            dev[0].wait_disconnected()
3343
3344def run_eap_pax_connect(dev):
3345    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
3346                eap="PAX", identity="pax.user@example.com",
3347                password_hex="0123456789abcdef0123456789abcdef",
3348                wait_connect=False)
3349    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
3350                         "CTRL-EVENT-DISCONNECTED"],
3351                        timeout=1)
3352    dev.request("REMOVE_NETWORK all")
3353    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
3354        dev.wait_disconnected()
3355    dev.dump_monitor()
3356
3357def test_eap_proto_pax_errors_server(dev, apdev):
3358    """EAP-PAX local error cases on server"""
3359    check_eap_capa(dev[0], "PAX")
3360    params = int_eap_server_params()
3361    params['erp_domain'] = 'example.com'
3362    params['eap_server_erp'] = '1'
3363    hapd = hostapd.add_ap(apdev[0], params)
3364    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3365
3366    tests = [(1, "eap_pax_init"),
3367             (1, "eap_msg_alloc;eap_pax_build_std_1"),
3368             (1, "eap_msg_alloc;eap_pax_build_std_3"),
3369             (1, "=eap_pax_process_std_2"),
3370             (1, "eap_pax_getKey"),
3371             (1, "eap_pax_get_emsk"),
3372             (1, "eap_pax_get_session_id")]
3373    for count, func in tests:
3374        with alloc_fail(hapd, count, func):
3375            run_eap_pax_connect(dev[0])
3376
3377    tests = [(1, "os_get_random;eap_pax_build_std_1"),
3378             (1, "eap_pax_mac;eap_pax_build_std_1"),
3379             (1, "eap_pax_mac;eap_pax_build_std_3"),
3380             (2, "eap_pax_mac;=eap_pax_build_std_3"),
3381             (1, "eap_pax_initial_key_derivation;eap_pax_process_std_2"),
3382             (1, "eap_pax_mac;eap_pax_process_std_2"),
3383             (2, "eap_pax_mac;=eap_pax_process_std_2"),
3384             (1, "eap_pax_mac;eap_pax_check")]
3385    for count, func in tests:
3386        with fail_test(hapd, count, func):
3387            run_eap_pax_connect(dev[0])
3388
3389def start_pax_assoc(dev, hapd):
3390    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
3391                eap="PAX", identity="pax.user@example.com",
3392                password_hex="0123456789abcdef0123456789abcdef",
3393                wait_connect=False)
3394    proxy_msg(hapd, dev) # EAP-Identity/Request
3395    proxy_msg(dev, hapd) # EAP-Identity/Response
3396    proxy_msg(hapd, dev) # PAX_STD-1
3397
3398def stop_pax_assoc(dev, hapd):
3399    dev.request("REMOVE_NETWORK all")
3400    dev.wait_disconnected()
3401    dev.dump_monitor()
3402    hapd.dump_monitor()
3403
3404def test_eap_proto_pax_server(dev, apdev):
3405    """EAP-PAX protocol testing for the server"""
3406    check_eap_capa(dev[0], "PAX")
3407    params = int_eap_server_params()
3408    params['erp_domain'] = 'example.com'
3409    params['eap_server_erp'] = '1'
3410    hapd = hostapd.add_ap(apdev[0], params)
3411    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3412    hapd.request("SET ext_eapol_frame_io 1")
3413    dev[0].request("SET ext_eapol_frame_io 1")
3414
3415    # Successful exchange to verify proxying mechanism
3416    start_pax_assoc(dev[0], hapd)
3417    proxy_msg(dev[0], hapd) # PAX_STD-2
3418    proxy_msg(hapd, dev[0]) # PAX_STD-3
3419    proxy_msg(dev[0], hapd) # PAX-ACK
3420    proxy_msg(hapd, dev[0]) # EAP-Success
3421    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 1/4
3422    proxy_msg(dev[0], hapd) # EAPOL-Key msg 2/4
3423    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 3/4
3424    proxy_msg(dev[0], hapd) # EAPOL-Key msg 4/4
3425    dev[0].wait_connected()
3426    stop_pax_assoc(dev[0], hapd)
3427
3428    start_pax_assoc(dev[0], hapd)
3429    resp = rx_msg(dev[0])
3430    # Too short EAP-PAX header (no OP-Code)
3431    hapd.note("EAP-PAX: Invalid frame")
3432    msg = resp[0:4] + "0005" + resp[8:12] + "0005" + "2e"
3433    tx_msg(dev[0], hapd, msg)
3434    # Too short EAP-PAX message (no payload)
3435    hapd.note("EAP-PAX: Invalid frame")
3436    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "2e1100000000"
3437    tx_msg(dev[0], hapd, msg)
3438    # Unexpected PAX_SEC-2
3439    hapd.note("EAP-PAX: Expected PAX_STD-2 - ignore op 17")
3440    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e1100000000" + 16*"00"
3441    tx_msg(dev[0], hapd, msg)
3442    # Unexpected MAC ID
3443    hapd.note("EAP-PAX: Expected MAC ID 0x1, received 0xff")
3444    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e0200ff0000" + 16*"00"
3445    tx_msg(dev[0], hapd, msg)
3446    # Unexpected DH Group ID
3447    hapd.note("EAP-PAX: Expected DH Group ID 0x0, received 0xff")
3448    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e020001ff00" + 16*"00"
3449    tx_msg(dev[0], hapd, msg)
3450    # Unexpected Public Key ID
3451    hapd.note("EAP-PAX: Expected Public Key ID 0x0, received 0xff")
3452    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e02000100ff" + 16*"00"
3453    tx_msg(dev[0], hapd, msg)
3454    # Unsupported Flags - MF
3455    hapd.note("EAP-PAX: fragmentation not supported")
3456    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e0201010000" + 16*"00"
3457    tx_msg(dev[0], hapd, msg)
3458    # Unsupported Flags - CE
3459    hapd.note("EAP-PAX: Unexpected CE flag")
3460    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e0202010000" + 16*"00"
3461    tx_msg(dev[0], hapd, msg)
3462    # Too short Payload in PAX_STD-2
3463    hapd.note("EAP-PAX: Too short PAX_STD-2 (B)")
3464    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e0200010000" + 16*"00"
3465    tx_msg(dev[0], hapd, msg)
3466    rx_msg(hapd)
3467    stop_pax_assoc(dev[0], hapd)
3468
3469    start_pax_assoc(dev[0], hapd)
3470    resp = rx_msg(dev[0])
3471    # Too short Payload in PAX_STD-2
3472    hapd.note("EAP-PAX: Too short PAX_STD-2 (CID)")
3473    msg = resp[0:4] + "002c" + resp[8:12] + "002c" + "2e0200010000" + "0020" + 32*"00"
3474    tx_msg(dev[0], hapd, msg)
3475    rx_msg(hapd)
3476    stop_pax_assoc(dev[0], hapd)
3477
3478    start_pax_assoc(dev[0], hapd)
3479    resp = rx_msg(dev[0])
3480    # Too short Payload in PAX_STD-2
3481    hapd.note("EAP-PAX: Too short PAX_STD-2 (CID)")
3482    msg = resp[0:4] + "002e" + resp[8:12] + "002e" + "2e0200010000" + "0020" + 32*"00" + "ffff"
3483    tx_msg(dev[0], hapd, msg)
3484    rx_msg(hapd)
3485    stop_pax_assoc(dev[0], hapd)
3486
3487    start_pax_assoc(dev[0], hapd)
3488    resp = rx_msg(dev[0])
3489    # Too long CID in PAX_STD-2
3490    hapd.note("EAP-PAX: Too long CID")
3491    msg = resp[0:4] + "062e" + resp[8:12] + "062e" + "2e0200010000" + "0020" + 32*"00" + "0600" + 1536*"00"
3492    tx_msg(dev[0], hapd, msg)
3493    rx_msg(hapd)
3494    stop_pax_assoc(dev[0], hapd)
3495
3496    start_pax_assoc(dev[0], hapd)
3497    resp = rx_msg(dev[0])
3498    # Too short Payload in PAX_STD-2
3499    hapd.note("EAP-PAX: Too short PAX_STD-2 (MAC_CK)")
3500    msg = resp[0:4] + "003c" + resp[8:12] + "003c" + "2e0200010000" + "0020" + 32*"00" + 16*"00"
3501    tx_msg(dev[0], hapd, msg)
3502    rx_msg(hapd)
3503    stop_pax_assoc(dev[0], hapd)
3504
3505    start_pax_assoc(dev[0], hapd)
3506    resp = rx_msg(dev[0])
3507    # Unknown CID for PAX
3508    hapd.note("EAP-PAX: EAP-PAX not enabled for CID")
3509    msg = resp[0:4] + "0041" + resp[8:12] + "0041" + "2e0200010000" + "0020" + 32*"00" + "0001" + "00" + "0010" + 16*"00"
3510    tx_msg(dev[0], hapd, msg)
3511    rx_msg(hapd)
3512    stop_pax_assoc(dev[0], hapd)
3513
3514    start_pax_assoc(dev[0], hapd)
3515    resp = rx_msg(dev[0])
3516    # Too short ICV
3517    hapd.note("EAP-PAX: Too short ICV (15) in PAX_STD-2")
3518    msg = resp[0:4] + "0063" + resp[8:12] + "0063" + resp[16:206]
3519    tx_msg(dev[0], hapd, msg)
3520    rx_msg(hapd)
3521    stop_pax_assoc(dev[0], hapd)
3522
3523    start_pax_assoc(dev[0], hapd)
3524    proxy_msg(dev[0], hapd) # PAX_STD-2
3525    proxy_msg(hapd, dev[0]) # PAX_STD-3
3526    resp = rx_msg(dev[0])
3527    # Unexpected PAX_STD-2
3528    hapd.note("EAP-PAX: Expected PAX-ACK - ignore op 1")
3529    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e0100000000" + 16*"00"
3530    tx_msg(dev[0], hapd, msg)
3531    stop_pax_assoc(dev[0], hapd)
3532
3533def test_eap_proto_psk(dev, apdev):
3534    """EAP-PSK protocol tests"""
3535    def psk_handler(ctx, req):
3536        logger.info("psk_handler - RX " + binascii.hexlify(req).decode())
3537        if 'num' not in ctx:
3538            ctx['num'] = 0
3539        ctx['num'] = ctx['num'] + 1
3540        if 'id' not in ctx:
3541            ctx['id'] = 1
3542        ctx['id'] = (ctx['id'] + 1) % 256
3543
3544        idx = 0
3545
3546        idx += 1
3547        if ctx['num'] == idx:
3548            logger.info("Test: Missing payload")
3549            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
3550                               4 + 1,
3551                               EAP_TYPE_PSK)
3552
3553        idx += 1
3554        if ctx['num'] == idx:
3555            logger.info("Test: Non-zero T in first message")
3556            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
3557                               4 + 1 + 1 + 16,
3558                               EAP_TYPE_PSK, 0xc0, 0, 0, 0, 0)
3559
3560        idx += 1
3561        if ctx['num'] == idx:
3562            logger.info("Test: Valid first message")
3563            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
3564                               4 + 1 + 1 + 16,
3565                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
3566        idx += 1
3567        if ctx['num'] == idx:
3568            logger.info("Test: Too short third message")
3569            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
3570                               4 + 1,
3571                               EAP_TYPE_PSK)
3572
3573        idx += 1
3574        if ctx['num'] == idx:
3575            logger.info("Test: Valid first message")
3576            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
3577                               4 + 1 + 1 + 16,
3578                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
3579        idx += 1
3580        if ctx['num'] == idx:
3581            logger.info("Test: Incorrect T in third message")
3582            return struct.pack(">BBHBB4L4L", EAP_CODE_REQUEST, ctx['id'],
3583                               4 + 1 + 1 + 16 + 16,
3584                               EAP_TYPE_PSK, 0, 0, 0, 0, 0, 0, 0, 0, 0)
3585
3586        idx += 1
3587        if ctx['num'] == idx:
3588            logger.info("Test: Valid first message")
3589            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
3590                               4 + 1 + 1 + 16,
3591                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
3592        idx += 1
3593        if ctx['num'] == idx:
3594            logger.info("Test: Missing PCHANNEL in third message")
3595            return struct.pack(">BBHBB4L4L", EAP_CODE_REQUEST, ctx['id'],
3596                               4 + 1 + 1 + 16 + 16,
3597                               EAP_TYPE_PSK, 0x80, 0, 0, 0, 0, 0, 0, 0, 0)
3598
3599        idx += 1
3600        if ctx['num'] == idx:
3601            logger.info("Test: Valid first message")
3602            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
3603                               4 + 1 + 1 + 16,
3604                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
3605        idx += 1
3606        if ctx['num'] == idx:
3607            logger.info("Test: Invalic MAC_S in third message")
3608            return struct.pack(">BBHBB4L4L5LB", EAP_CODE_REQUEST, ctx['id'],
3609                               4 + 1 + 1 + 16 + 16 + 21,
3610                               EAP_TYPE_PSK, 0x80, 0, 0, 0, 0, 0, 0, 0, 0,
3611                               0, 0, 0, 0, 0, 0)
3612
3613        idx += 1
3614        if ctx['num'] == idx:
3615            logger.info("Test: Valid first message")
3616            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
3617                               4 + 1 + 1 + 16,
3618                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
3619        idx += 1
3620        if ctx['num'] == idx:
3621            logger.info("Test: EAP-Failure")
3622            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
3623
3624        return None
3625
3626    srv = start_radius_server(psk_handler)
3627
3628    try:
3629        hapd = start_ap(apdev[0])
3630        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3631
3632        for i in range(0, 6):
3633            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3634                           eap="PSK", identity="user",
3635                           password_hex="0123456789abcdef0123456789abcdef",
3636                           wait_connect=False)
3637            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
3638                                   timeout=15)
3639            if ev is None:
3640                raise Exception("Timeout on EAP start")
3641            time.sleep(0.1)
3642            dev[0].request("REMOVE_NETWORK all")
3643
3644        logger.info("Test: Invalid PSK length")
3645        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3646                       eap="PSK", identity="user",
3647                       password_hex="0123456789abcdef0123456789abcd",
3648                       wait_connect=False)
3649        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
3650                               timeout=15)
3651        if ev is None:
3652            raise Exception("Timeout on EAP start")
3653        time.sleep(0.1)
3654        dev[0].request("REMOVE_NETWORK all")
3655    finally:
3656        stop_radius_server(srv)
3657
3658def test_eap_proto_psk_errors(dev, apdev):
3659    """EAP-PSK local error cases"""
3660    check_eap_capa(dev[0], "PSK")
3661    params = hostapd.wpa2_eap_params(ssid="eap-test")
3662    hapd = hostapd.add_ap(apdev[0], params)
3663    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3664
3665    for i in range(1, 3):
3666        with alloc_fail(dev[0], i, "eap_psk_init"):
3667            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3668                           eap="PSK", identity="psk.user@example.com",
3669                           password_hex="0123456789abcdef0123456789abcdef",
3670                           wait_connect=False)
3671            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
3672                                   timeout=15)
3673            if ev is None:
3674                raise Exception("Timeout on EAP start")
3675            dev[0].request("REMOVE_NETWORK all")
3676            dev[0].wait_disconnected()
3677
3678    for i in range(1, 4):
3679        with fail_test(dev[0], i, "eap_psk_key_setup;eap_psk_init"):
3680            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3681                           eap="PSK", identity="psk.user@example.com",
3682                           password_hex="0123456789abcdef0123456789abcdef",
3683                           wait_connect=False)
3684            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
3685                                   timeout=15)
3686            if ev is None:
3687                raise Exception("Timeout on EAP start")
3688            dev[0].request("REMOVE_NETWORK all")
3689            dev[0].wait_disconnected()
3690
3691    tests = [(1, "=eap_psk_process_1"),
3692             (2, "=eap_psk_process_1"),
3693             (1, "eap_msg_alloc;eap_psk_process_1"),
3694             (1, "=eap_psk_process_3"),
3695             (2, "=eap_psk_process_3"),
3696             (1, "eap_msg_alloc;eap_psk_process_3"),
3697             (1, "eap_psk_getKey"),
3698             (1, "eap_psk_get_session_id"),
3699             (1, "eap_psk_get_emsk")]
3700    for count, func in tests:
3701        with alloc_fail(dev[0], count, func):
3702            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3703                           eap="PSK", identity="psk.user@example.com",
3704                           password_hex="0123456789abcdef0123456789abcdef",
3705                           erp="1", wait_connect=False)
3706            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
3707                                   timeout=15)
3708            if ev is None:
3709                raise Exception("Timeout on EAP start")
3710            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL",
3711                              note="No allocation failure seen for %d:%s" % (count, func))
3712            dev[0].request("REMOVE_NETWORK all")
3713            dev[0].wait_disconnected()
3714
3715    tests = [(1, "os_get_random;eap_psk_process_1"),
3716             (1, "omac1_aes_128;eap_psk_process_3"),
3717             (1, "=omac1_aes_vector;omac1_aes_128;aes_128_eax_encrypt"),
3718             (2, "=omac1_aes_vector;omac1_aes_128;aes_128_eax_encrypt"),
3719             (3, "=omac1_aes_vector;omac1_aes_128;aes_128_eax_encrypt"),
3720             (1, "=omac1_aes_vector;omac1_aes_128;aes_128_eax_decrypt"),
3721             (2, "=omac1_aes_vector;omac1_aes_128;aes_128_eax_decrypt"),
3722             (3, "=omac1_aes_vector;omac1_aes_128;aes_128_eax_decrypt"),
3723             (1, "aes_128_eax_decrypt;eap_psk_process_3"),
3724             (2, "aes_128_eax_decrypt;eap_psk_process_3"),
3725             (3, "aes_128_eax_decrypt;eap_psk_process_3"),
3726             (1, "aes_128_eax_encrypt;eap_psk_process_3"),
3727             (2, "aes_128_eax_encrypt;eap_psk_process_3"),
3728             (3, "aes_128_eax_encrypt;eap_psk_process_3"),
3729             (1, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3730             (2, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3731             (3, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3732             (4, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3733             (5, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3734             (6, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3735             (7, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3736             (8, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3737             (9, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3738             (10, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3739             (1, "aes_ctr_encrypt;aes_128_eax_decrypt;eap_psk_process_3"),
3740             (1, "aes_ctr_encrypt;aes_128_eax_encrypt;eap_psk_process_3")]
3741    for count, func in tests:
3742        with fail_test(dev[0], count, func):
3743            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3744                           eap="PSK", identity="psk.user@example.com",
3745                           password_hex="0123456789abcdef0123456789abcdef",
3746                           wait_connect=False)
3747            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
3748                                   timeout=15)
3749            if ev is None:
3750                raise Exception("Timeout on EAP start")
3751            wait_fail_trigger(dev[0], "GET_FAIL",
3752                              note="No failure seen for %d:%s" % (count, func))
3753            dev[0].request("REMOVE_NETWORK all")
3754            dev[0].wait_disconnected()
3755            dev[0].dump_monitor()
3756
3757def run_eap_psk_connect(dev):
3758    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
3759                eap="PSK", identity="psk.user@example.com",
3760                password_hex="0123456789abcdef0123456789abcdef",
3761                wait_connect=False)
3762    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
3763                         "CTRL-EVENT-DISCONNECTED"],
3764                        timeout=1)
3765    dev.request("REMOVE_NETWORK all")
3766    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
3767        dev.wait_disconnected()
3768    dev.dump_monitor()
3769
3770def test_eap_proto_psk_errors_server(dev, apdev):
3771    """EAP-PSK local error cases on server"""
3772    check_eap_capa(dev[0], "PSK")
3773    params = int_eap_server_params()
3774    params['erp_domain'] = 'example.com'
3775    params['eap_server_erp'] = '1'
3776    hapd = hostapd.add_ap(apdev[0], params)
3777    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3778
3779    tests = [(1, "eap_psk_init"),
3780             (1, "eap_msg_alloc;eap_psk_build_1"),
3781             (1, "eap_msg_alloc;eap_psk_build_3"),
3782             (1, "=eap_psk_build_3"),
3783             (1, "=eap_psk_process_2"),
3784             (2, "=eap_psk_process_2"),
3785             (1, "=eap_psk_process_4"),
3786             (1, "aes_128_eax_decrypt;eap_psk_process_4"),
3787             (1, "eap_psk_getKey"),
3788             (1, "eap_psk_get_emsk"),
3789             (1, "eap_psk_get_session_id")]
3790    for count, func in tests:
3791        with alloc_fail(hapd, count, func):
3792            run_eap_psk_connect(dev[0])
3793
3794    tests = [(1, "os_get_random;eap_psk_build_1"),
3795             (1, "omac1_aes_128;eap_psk_build_3"),
3796             (1, "eap_psk_derive_keys;eap_psk_build_3"),
3797             (1, "aes_128_eax_encrypt;eap_psk_build_3"),
3798             (1, "eap_psk_key_setup;eap_psk_process_2"),
3799             (1, "omac1_aes_128;eap_psk_process_2"),
3800             (1, "aes_128_eax_decrypt;eap_psk_process_4")]
3801    for count, func in tests:
3802        with fail_test(hapd, count, func):
3803            run_eap_psk_connect(dev[0])
3804
3805def start_psk_assoc(dev, hapd):
3806    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
3807                eap="PSK", identity="psk.user@example.com",
3808                password_hex="0123456789abcdef0123456789abcdef",
3809                wait_connect=False)
3810    proxy_msg(hapd, dev) # EAP-Identity/Request
3811    proxy_msg(dev, hapd) # EAP-Identity/Response
3812    proxy_msg(hapd, dev) # PSK-1
3813
3814def stop_psk_assoc(dev, hapd):
3815    dev.request("REMOVE_NETWORK all")
3816    dev.wait_disconnected()
3817    dev.dump_monitor()
3818    hapd.dump_monitor()
3819
3820def test_eap_proto_psk_server(dev, apdev):
3821    """EAP-PSK protocol testing for the server"""
3822    check_eap_capa(dev[0], "PSK")
3823    params = int_eap_server_params()
3824    params['erp_domain'] = 'example.com'
3825    params['eap_server_erp'] = '1'
3826    hapd = hostapd.add_ap(apdev[0], params)
3827    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3828    hapd.request("SET ext_eapol_frame_io 1")
3829    dev[0].request("SET ext_eapol_frame_io 1")
3830
3831    # Successful exchange to verify proxying mechanism
3832    start_psk_assoc(dev[0], hapd)
3833    proxy_msg(dev[0], hapd) # PSK-2
3834    proxy_msg(hapd, dev[0]) # PSK-3
3835    proxy_msg(dev[0], hapd) # PSK-4
3836    proxy_msg(hapd, dev[0]) # EAP-Success
3837    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 1/4
3838    proxy_msg(dev[0], hapd) # EAPOL-Key msg 2/4
3839    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 3/4
3840    proxy_msg(dev[0], hapd) # EAPOL-Key msg 4/4
3841    dev[0].wait_connected()
3842    stop_psk_assoc(dev[0], hapd)
3843
3844    start_psk_assoc(dev[0], hapd)
3845    resp = rx_msg(dev[0])
3846    # Too short EAP-PSK header (no Flags)
3847    hapd.note("EAP-PSK: Invalid frame")
3848    msg = resp[0:4] + "0005" + resp[8:12] + "0005" + "2f"
3849    tx_msg(dev[0], hapd, msg)
3850    # Unexpected PSK-1
3851    hapd.note("EAP-PSK: Expected PSK-2 - ignore T=0")
3852    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "2f00"
3853    tx_msg(dev[0], hapd, msg)
3854    # Too short PSK-2
3855    hapd.note("EAP-PSK: Too short frame")
3856    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "2f40"
3857    tx_msg(dev[0], hapd, msg)
3858    # PSK-2 with unknown ID_P
3859    hapd.note("EAP-PSK: EAP-PSK not enabled for ID_P")
3860    msg = resp[0:4] + "004a" + resp[8:12] + "004a" + "2f40" + 3*16*"00" + 20*"00"
3861    tx_msg(dev[0], hapd, msg)
3862    rx_msg(hapd) # EAP-Failure
3863    stop_psk_assoc(dev[0], hapd)
3864
3865    start_psk_assoc(dev[0], hapd)
3866    proxy_msg(dev[0], hapd) # PSK-2
3867    proxy_msg(hapd, dev[0]) # PSK-3
3868    resp = rx_msg(dev[0])
3869    # Unexpected PSK-2
3870    hapd.note("EAP-PSK: Expected PSK-4 - ignore T=1")
3871    msg = resp[0:4] + "0016" + resp[8:12] + "0016" + "2f40" + 16*"00"
3872    tx_msg(dev[0], hapd, msg)
3873    # Too short PSK-4 (no PCHANNEL)
3874    hapd.note("EAP-PSK: Too short PCHANNEL data in PSK-4 (len=0, expected 21)")
3875    msg = resp[0:4] + "0016" + resp[8:12] + "0016" + "2fc0" + 16*"00"
3876    tx_msg(dev[0], hapd, msg)
3877    rx_msg(hapd) # PSK-3 retry
3878    stop_psk_assoc(dev[0], hapd)
3879
3880    start_psk_assoc(dev[0], hapd)
3881    proxy_msg(dev[0], hapd) # PSK-2
3882    proxy_msg(hapd, dev[0]) # PSK-3
3883    resp = rx_msg(dev[0])
3884    # PCHANNEL Nonce did not increase
3885    hapd.note("EAP-PSK: Nonce did not increase")
3886    msg = resp[0:4] + "002b" + resp[8:12] + "002b" + "2fc0" + 16*"00" + 21*"00"
3887    tx_msg(dev[0], hapd, msg)
3888    rx_msg(hapd) # PSK-3 retry
3889    stop_psk_assoc(dev[0], hapd)
3890
3891    start_psk_assoc(dev[0], hapd)
3892    proxy_msg(dev[0], hapd) # PSK-2
3893    proxy_msg(hapd, dev[0]) # PSK-3
3894    resp = rx_msg(dev[0])
3895    # Invalid PCHANNEL encryption
3896    hapd.note("EAP-PSK: PCHANNEL decryption failed")
3897    msg = resp[0:4] + "002b" + resp[8:12] + "002b" + "2fc0" + 16*"00" + 21*"11"
3898    tx_msg(dev[0], hapd, msg)
3899    rx_msg(hapd) # PSK-3 retry
3900    stop_psk_assoc(dev[0], hapd)
3901
3902EAP_SIM_SUBTYPE_START = 10
3903EAP_SIM_SUBTYPE_CHALLENGE = 11
3904EAP_SIM_SUBTYPE_NOTIFICATION = 12
3905EAP_SIM_SUBTYPE_REAUTHENTICATION = 13
3906EAP_SIM_SUBTYPE_CLIENT_ERROR = 14
3907
3908EAP_AKA_SUBTYPE_CHALLENGE = 1
3909EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT = 2
3910EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE = 4
3911EAP_AKA_SUBTYPE_IDENTITY = 5
3912EAP_AKA_SUBTYPE_NOTIFICATION = 12
3913EAP_AKA_SUBTYPE_REAUTHENTICATION = 13
3914EAP_AKA_SUBTYPE_CLIENT_ERROR = 14
3915
3916EAP_SIM_AT_RAND = 1
3917EAP_SIM_AT_AUTN = 2
3918EAP_SIM_AT_RES = 3
3919EAP_SIM_AT_AUTS = 4
3920EAP_SIM_AT_PADDING = 6
3921EAP_SIM_AT_NONCE_MT = 7
3922EAP_SIM_AT_PERMANENT_ID_REQ = 10
3923EAP_SIM_AT_MAC = 11
3924EAP_SIM_AT_NOTIFICATION = 12
3925EAP_SIM_AT_ANY_ID_REQ = 13
3926EAP_SIM_AT_IDENTITY = 14
3927EAP_SIM_AT_VERSION_LIST = 15
3928EAP_SIM_AT_SELECTED_VERSION = 16
3929EAP_SIM_AT_FULLAUTH_ID_REQ = 17
3930EAP_SIM_AT_COUNTER = 19
3931EAP_SIM_AT_COUNTER_TOO_SMALL = 20
3932EAP_SIM_AT_NONCE_S = 21
3933EAP_SIM_AT_CLIENT_ERROR_CODE = 22
3934EAP_SIM_AT_KDF_INPUT = 23
3935EAP_SIM_AT_KDF = 24
3936EAP_SIM_AT_IV = 129
3937EAP_SIM_AT_ENCR_DATA = 130
3938EAP_SIM_AT_NEXT_PSEUDONYM = 132
3939EAP_SIM_AT_NEXT_REAUTH_ID = 133
3940EAP_SIM_AT_CHECKCODE = 134
3941EAP_SIM_AT_RESULT_IND = 135
3942EAP_SIM_AT_BIDDING = 136
3943
3944def test_eap_proto_aka(dev, apdev):
3945    """EAP-AKA protocol tests"""
3946    def aka_handler(ctx, req):
3947        logger.info("aka_handler - RX " + binascii.hexlify(req).decode())
3948        if 'num' not in ctx:
3949            ctx['num'] = 0
3950        ctx['num'] = ctx['num'] + 1
3951        if 'id' not in ctx:
3952            ctx['id'] = 1
3953        ctx['id'] = (ctx['id'] + 1) % 256
3954
3955        idx = 0
3956
3957        idx += 1
3958        if ctx['num'] == idx:
3959            logger.info("Test: Missing payload")
3960            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
3961                               4 + 1,
3962                               EAP_TYPE_AKA)
3963
3964        idx += 1
3965        if ctx['num'] == idx:
3966            logger.info("Test: Unknown subtype")
3967            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
3968                               4 + 1 + 3,
3969                               EAP_TYPE_AKA, 255, 0)
3970        idx += 1
3971        if ctx['num'] == idx:
3972            logger.info("Test: EAP-Failure")
3973            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
3974
3975        idx += 1
3976        if ctx['num'] == idx:
3977            logger.info("Test: Client Error")
3978            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
3979                               4 + 1 + 3,
3980                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CLIENT_ERROR, 0)
3981        idx += 1
3982        if ctx['num'] == idx:
3983            logger.info("Test: EAP-Failure")
3984            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
3985
3986        idx += 1
3987        if ctx['num'] == idx:
3988            logger.info("Test: Too short attribute header")
3989            return struct.pack(">BBHBBHB", EAP_CODE_REQUEST, ctx['id'],
3990                               4 + 1 + 1 + 3,
3991                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0, 255)
3992        idx += 1
3993        if ctx['num'] == idx:
3994            logger.info("Test: EAP-Failure")
3995            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
3996
3997        idx += 1
3998        if ctx['num'] == idx:
3999            logger.info("Test: Truncated attribute")
4000            return struct.pack(">BBHBBHBB", EAP_CODE_REQUEST, ctx['id'],
4001                               4 + 1 + 1 + 4,
4002                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0, 255,
4003                               255)
4004        idx += 1
4005        if ctx['num'] == idx:
4006            logger.info("Test: EAP-Failure")
4007            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4008
4009        idx += 1
4010        if ctx['num'] == idx:
4011            logger.info("Test: Too short attribute data")
4012            return struct.pack(">BBHBBHBB", EAP_CODE_REQUEST, ctx['id'],
4013                               4 + 1 + 1 + 4,
4014                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0, 255,
4015                               0)
4016        idx += 1
4017        if ctx['num'] == idx:
4018            logger.info("Test: EAP-Failure")
4019            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4020
4021        idx += 1
4022        if ctx['num'] == idx:
4023            logger.info("Test: Skippable/non-skippable unrecognzized attribute")
4024            return struct.pack(">BBHBBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4025                               4 + 1 + 1 + 10,
4026                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4027                               255, 1, 0, 127, 1, 0)
4028        idx += 1
4029        if ctx['num'] == idx:
4030            logger.info("Test: EAP-Failure")
4031            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4032
4033        idx += 1
4034        if ctx['num'] == idx:
4035            logger.info("Test: Identity request without ID type")
4036            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
4037                               4 + 1 + 3,
4038                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0)
4039        idx += 1
4040        if ctx['num'] == idx:
4041            logger.info("Test: Identity request ANY_ID")
4042            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4043                               4 + 1 + 3 + 4,
4044                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4045                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
4046        idx += 1
4047        if ctx['num'] == idx:
4048            logger.info("Test: Identity request ANY_ID (duplicate)")
4049            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4050                               4 + 1 + 3 + 4,
4051                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4052                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
4053        idx += 1
4054        if ctx['num'] == idx:
4055            logger.info("Test: EAP-Failure")
4056            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4057
4058        idx += 1
4059        if ctx['num'] == idx:
4060            logger.info("Test: Identity request ANY_ID")
4061            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4062                               4 + 1 + 3 + 4,
4063                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4064                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
4065        idx += 1
4066        if ctx['num'] == idx:
4067            logger.info("Test: Identity request FULLAUTH_ID")
4068            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4069                               4 + 1 + 3 + 4,
4070                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4071                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
4072        idx += 1
4073        if ctx['num'] == idx:
4074            logger.info("Test: Identity request FULLAUTH_ID (duplicate)")
4075            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4076                               4 + 1 + 3 + 4,
4077                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4078                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
4079        idx += 1
4080        if ctx['num'] == idx:
4081            logger.info("Test: EAP-Failure")
4082            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4083
4084        idx += 1
4085        if ctx['num'] == idx:
4086            logger.info("Test: Identity request ANY_ID")
4087            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4088                               4 + 1 + 3 + 4,
4089                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4090                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
4091        idx += 1
4092        if ctx['num'] == idx:
4093            logger.info("Test: Identity request FULLAUTH_ID")
4094            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4095                               4 + 1 + 3 + 4,
4096                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4097                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
4098        idx += 1
4099        if ctx['num'] == idx:
4100            logger.info("Test: Identity request PERMANENT_ID")
4101            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4102                               4 + 1 + 3 + 4,
4103                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4104                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
4105        idx += 1
4106        if ctx['num'] == idx:
4107            logger.info("Test: Identity request PERMANENT_ID (duplicate)")
4108            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4109                               4 + 1 + 3 + 4,
4110                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4111                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
4112        idx += 1
4113        if ctx['num'] == idx:
4114            logger.info("Test: EAP-Failure")
4115            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4116
4117        idx += 1
4118        if ctx['num'] == idx:
4119            logger.info("Test: Challenge with no attributes")
4120            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
4121                               4 + 1 + 3,
4122                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0)
4123        idx += 1
4124        if ctx['num'] == idx:
4125            logger.info("Test: EAP-Failure")
4126            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4127
4128        idx += 1
4129        if ctx['num'] == idx:
4130            logger.info("Test: AKA Challenge with BIDDING")
4131            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4132                               4 + 1 + 3 + 4,
4133                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4134                               EAP_SIM_AT_BIDDING, 1, 0x8000)
4135        idx += 1
4136        if ctx['num'] == idx:
4137            logger.info("Test: EAP-Failure")
4138            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4139
4140        idx += 1
4141        if ctx['num'] == idx:
4142            logger.info("Test: Notification with no attributes")
4143            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
4144                               4 + 1 + 3,
4145                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0)
4146        idx += 1
4147        if ctx['num'] == idx:
4148            logger.info("Test: EAP-Failure")
4149            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4150
4151        idx += 1
4152        if ctx['num'] == idx:
4153            logger.info("Test: Notification indicating success, but no MAC")
4154            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4155                               4 + 1 + 3 + 4,
4156                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4157                               EAP_SIM_AT_NOTIFICATION, 1, 32768)
4158        idx += 1
4159        if ctx['num'] == idx:
4160            logger.info("Test: EAP-Failure")
4161            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4162
4163        idx += 1
4164        if ctx['num'] == idx:
4165            logger.info("Test: Notification indicating success, but invalid MAC value")
4166            return struct.pack(">BBHBBHBBHBBH4L", EAP_CODE_REQUEST, ctx['id'],
4167                               4 + 1 + 3 + 4 + 20,
4168                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4169                               EAP_SIM_AT_NOTIFICATION, 1, 32768,
4170                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
4171        idx += 1
4172        if ctx['num'] == idx:
4173            logger.info("Test: EAP-Failure")
4174            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4175
4176        idx += 1
4177        if ctx['num'] == idx:
4178            logger.info("Test: Notification indicating success with zero-key MAC")
4179            return struct.pack(">BBHBBHBBHBBH16B", EAP_CODE_REQUEST,
4180                               ctx['id'] - 2,
4181                               4 + 1 + 3 + 4 + 20,
4182                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4183                               EAP_SIM_AT_NOTIFICATION, 1, 32768,
4184                               EAP_SIM_AT_MAC, 5, 0,
4185                               0xbe, 0x2e, 0xbb, 0xa9, 0xfa, 0x2e, 0x82, 0x36,
4186                               0x37, 0x8c, 0x32, 0x41, 0xb7, 0xc7, 0x58, 0xa3)
4187        idx += 1
4188        if ctx['num'] == idx:
4189            logger.info("Test: EAP-Success")
4190            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
4191
4192        idx += 1
4193        if ctx['num'] == idx:
4194            logger.info("Test: Notification before auth")
4195            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4196                               4 + 1 + 3 + 4,
4197                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4198                               EAP_SIM_AT_NOTIFICATION, 1, 16384)
4199        idx += 1
4200        if ctx['num'] == idx:
4201            logger.info("Test: EAP-Failure")
4202            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4203
4204        idx += 1
4205        if ctx['num'] == idx:
4206            logger.info("Test: Notification before auth")
4207            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4208                               4 + 1 + 3 + 4,
4209                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4210                               EAP_SIM_AT_NOTIFICATION, 1, 16385)
4211        idx += 1
4212        if ctx['num'] == idx:
4213            logger.info("Test: EAP-Failure")
4214            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4215
4216        idx += 1
4217        if ctx['num'] == idx:
4218            logger.info("Test: Notification with unrecognized non-failure")
4219            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4220                               4 + 1 + 3 + 4,
4221                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4222                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
4223        idx += 1
4224        if ctx['num'] == idx:
4225            logger.info("Test: Notification before auth (duplicate)")
4226            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4227                               4 + 1 + 3 + 4,
4228                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4229                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
4230        idx += 1
4231        if ctx['num'] == idx:
4232            logger.info("Test: EAP-Failure")
4233            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4234
4235        idx += 1
4236        if ctx['num'] == idx:
4237            logger.info("Test: Re-authentication (unexpected) with no attributes")
4238            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
4239                               4 + 1 + 3,
4240                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_REAUTHENTICATION,
4241                               0)
4242        idx += 1
4243        if ctx['num'] == idx:
4244            logger.info("Test: EAP-Failure")
4245            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4246
4247        idx += 1
4248        if ctx['num'] == idx:
4249            logger.info("Test: AKA Challenge with Checkcode claiming identity round was used")
4250            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
4251                               4 + 1 + 3 + 24,
4252                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4253                               EAP_SIM_AT_CHECKCODE, 6, 0, 0, 0, 0, 0, 0)
4254        idx += 1
4255        if ctx['num'] == idx:
4256            logger.info("Test: EAP-Failure")
4257            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4258
4259        idx += 1
4260        if ctx['num'] == idx:
4261            logger.info("Test: Identity request ANY_ID")
4262            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4263                               4 + 1 + 3 + 4,
4264                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4265                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
4266        idx += 1
4267        if ctx['num'] == idx:
4268            logger.info("Test: AKA Challenge with Checkcode claiming no identity round was used")
4269            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4270                               4 + 1 + 3 + 4,
4271                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4272                               EAP_SIM_AT_CHECKCODE, 1, 0)
4273        idx += 1
4274        if ctx['num'] == idx:
4275            logger.info("Test: EAP-Failure")
4276            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4277
4278        idx += 1
4279        if ctx['num'] == idx:
4280            logger.info("Test: Identity request ANY_ID")
4281            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4282                               4 + 1 + 3 + 4,
4283                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4284                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
4285        idx += 1
4286        if ctx['num'] == idx:
4287            logger.info("Test: AKA Challenge with mismatching Checkcode value")
4288            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
4289                               4 + 1 + 3 + 24,
4290                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4291                               EAP_SIM_AT_CHECKCODE, 6, 0, 0, 0, 0, 0, 0)
4292        idx += 1
4293        if ctx['num'] == idx:
4294            logger.info("Test: EAP-Failure")
4295            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4296
4297        idx += 1
4298        if ctx['num'] == idx:
4299            logger.info("Test: Re-authentication (unexpected) with Checkcode claimin identity round was used")
4300            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
4301                               4 + 1 + 3 + 24,
4302                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_REAUTHENTICATION,
4303                               0,
4304                               EAP_SIM_AT_CHECKCODE, 6, 0, 0, 0, 0, 0, 0)
4305        idx += 1
4306        if ctx['num'] == idx:
4307            logger.info("Test: EAP-Failure")
4308            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4309
4310        idx += 1
4311        if ctx['num'] == idx:
4312            logger.info("Test: Invalid AT_RAND length")
4313            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4314                               4 + 1 + 3 + 4,
4315                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4316                               EAP_SIM_AT_RAND, 1, 0)
4317        idx += 1
4318        if ctx['num'] == idx:
4319            logger.info("Test: EAP-Failure")
4320            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4321
4322        idx += 1
4323        if ctx['num'] == idx:
4324            logger.info("Test: Invalid AT_AUTN length")
4325            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4326                               4 + 1 + 3 + 4,
4327                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4328                               EAP_SIM_AT_AUTN, 1, 0)
4329        idx += 1
4330        if ctx['num'] == idx:
4331            logger.info("Test: EAP-Failure")
4332            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4333
4334        idx += 1
4335        if ctx['num'] == idx:
4336            logger.info("Test: Unencrypted AT_PADDING")
4337            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4338                               4 + 1 + 3 + 4,
4339                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4340                               EAP_SIM_AT_PADDING, 1, 0)
4341        idx += 1
4342        if ctx['num'] == idx:
4343            logger.info("Test: EAP-Failure")
4344            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4345
4346        idx += 1
4347        if ctx['num'] == idx:
4348            logger.info("Test: Invalid AT_NONCE_MT length")
4349            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4350                               4 + 1 + 3 + 4,
4351                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4352                               EAP_SIM_AT_NONCE_MT, 1, 0)
4353        idx += 1
4354        if ctx['num'] == idx:
4355            logger.info("Test: EAP-Failure")
4356            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4357
4358        idx += 1
4359        if ctx['num'] == idx:
4360            logger.info("Test: Invalid AT_MAC length")
4361            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4362                               4 + 1 + 3 + 4,
4363                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4364                               EAP_SIM_AT_MAC, 1, 0)
4365        idx += 1
4366        if ctx['num'] == idx:
4367            logger.info("Test: EAP-Failure")
4368            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4369
4370        idx += 1
4371        if ctx['num'] == idx:
4372            logger.info("Test: Invalid AT_NOTIFICATION length")
4373            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4374                               4 + 1 + 3 + 8,
4375                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4376                               EAP_SIM_AT_NOTIFICATION, 2, 0, 0)
4377        idx += 1
4378        if ctx['num'] == idx:
4379            logger.info("Test: EAP-Failure")
4380            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4381
4382        idx += 1
4383        if ctx['num'] == idx:
4384            logger.info("Test: AT_IDENTITY overflow")
4385            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4386                               4 + 1 + 3 + 4,
4387                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4388                               EAP_SIM_AT_IDENTITY, 1, 0xffff)
4389        idx += 1
4390        if ctx['num'] == idx:
4391            logger.info("Test: EAP-Failure")
4392            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4393
4394        idx += 1
4395        if ctx['num'] == idx:
4396            logger.info("Test: Unexpected AT_VERSION_LIST")
4397            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4398                               4 + 1 + 3 + 4,
4399                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4400                               EAP_SIM_AT_VERSION_LIST, 1, 0)
4401        idx += 1
4402        if ctx['num'] == idx:
4403            logger.info("Test: EAP-Failure")
4404            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4405
4406        idx += 1
4407        if ctx['num'] == idx:
4408            logger.info("Test: Invalid AT_SELECTED_VERSION length")
4409            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4410                               4 + 1 + 3 + 8,
4411                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4412                               EAP_SIM_AT_SELECTED_VERSION, 2, 0, 0)
4413        idx += 1
4414        if ctx['num'] == idx:
4415            logger.info("Test: EAP-Failure")
4416            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4417
4418        idx += 1
4419        if ctx['num'] == idx:
4420            logger.info("Test: Unencrypted AT_COUNTER")
4421            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4422                               4 + 1 + 3 + 4,
4423                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4424                               EAP_SIM_AT_COUNTER, 1, 0)
4425        idx += 1
4426        if ctx['num'] == idx:
4427            logger.info("Test: EAP-Failure")
4428            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4429
4430        idx += 1
4431        if ctx['num'] == idx:
4432            logger.info("Test: Unencrypted AT_COUNTER_TOO_SMALL")
4433            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4434                               4 + 1 + 3 + 4,
4435                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4436                               EAP_SIM_AT_COUNTER_TOO_SMALL, 1, 0)
4437        idx += 1
4438        if ctx['num'] == idx:
4439            logger.info("Test: EAP-Failure")
4440            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4441
4442        idx += 1
4443        if ctx['num'] == idx:
4444            logger.info("Test: Unencrypted AT_NONCE_S")
4445            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4446                               4 + 1 + 3 + 4,
4447                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4448                               EAP_SIM_AT_NONCE_S, 1, 0)
4449        idx += 1
4450        if ctx['num'] == idx:
4451            logger.info("Test: EAP-Failure")
4452            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4453
4454        idx += 1
4455        if ctx['num'] == idx:
4456            logger.info("Test: Invalid AT_CLIENT_ERROR_CODE length")
4457            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4458                               4 + 1 + 3 + 8,
4459                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4460                               EAP_SIM_AT_CLIENT_ERROR_CODE, 2, 0, 0)
4461        idx += 1
4462        if ctx['num'] == idx:
4463            logger.info("Test: EAP-Failure")
4464            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4465
4466        idx += 1
4467        if ctx['num'] == idx:
4468            logger.info("Test: Invalid AT_IV length")
4469            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4470                               4 + 1 + 3 + 4,
4471                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4472                               EAP_SIM_AT_IV, 1, 0)
4473        idx += 1
4474        if ctx['num'] == idx:
4475            logger.info("Test: EAP-Failure")
4476            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4477
4478        idx += 1
4479        if ctx['num'] == idx:
4480            logger.info("Test: Invalid AT_ENCR_DATA length")
4481            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4482                               4 + 1 + 3 + 8,
4483                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4484                               EAP_SIM_AT_ENCR_DATA, 2, 0, 0)
4485        idx += 1
4486        if ctx['num'] == idx:
4487            logger.info("Test: EAP-Failure")
4488            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4489
4490        idx += 1
4491        if ctx['num'] == idx:
4492            logger.info("Test: Unencrypted AT_NEXT_PSEUDONYM")
4493            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4494                               4 + 1 + 3 + 4,
4495                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4496                               EAP_SIM_AT_NEXT_PSEUDONYM, 1, 0)
4497        idx += 1
4498        if ctx['num'] == idx:
4499            logger.info("Test: EAP-Failure")
4500            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4501
4502        idx += 1
4503        if ctx['num'] == idx:
4504            logger.info("Test: Unencrypted AT_NEXT_REAUTH_ID")
4505            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4506                               4 + 1 + 3 + 4,
4507                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4508                               EAP_SIM_AT_NEXT_REAUTH_ID, 1, 0)
4509        idx += 1
4510        if ctx['num'] == idx:
4511            logger.info("Test: EAP-Failure")
4512            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4513
4514        idx += 1
4515        if ctx['num'] == idx:
4516            logger.info("Test: Invalid AT_RES length")
4517            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4518                               4 + 1 + 3 + 4,
4519                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4520                               EAP_SIM_AT_RES, 1, 0)
4521        idx += 1
4522        if ctx['num'] == idx:
4523            logger.info("Test: EAP-Failure")
4524            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4525
4526        idx += 1
4527        if ctx['num'] == idx:
4528            logger.info("Test: Invalid AT_RES length")
4529            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
4530                               4 + 1 + 3 + 24,
4531                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4532                               EAP_SIM_AT_RES, 6, 0xffff, 0, 0, 0, 0, 0)
4533        idx += 1
4534        if ctx['num'] == idx:
4535            logger.info("Test: EAP-Failure")
4536            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4537
4538        idx += 1
4539        if ctx['num'] == idx:
4540            logger.info("Test: Invalid AT_AUTS length")
4541            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4542                               4 + 1 + 3 + 8,
4543                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4544                               EAP_SIM_AT_AUTS, 2, 0, 0)
4545        idx += 1
4546        if ctx['num'] == idx:
4547            logger.info("Test: EAP-Failure")
4548            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4549
4550        idx += 1
4551        if ctx['num'] == idx:
4552            logger.info("Test: Invalid AT_CHECKCODE length")
4553            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4554                               4 + 1 + 3 + 8,
4555                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4556                               EAP_SIM_AT_CHECKCODE, 2, 0, 0)
4557        idx += 1
4558        if ctx['num'] == idx:
4559            logger.info("Test: EAP-Failure")
4560            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4561
4562        idx += 1
4563        if ctx['num'] == idx:
4564            logger.info("Test: Invalid AT_RESULT_IND length")
4565            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4566                               4 + 1 + 3 + 8,
4567                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4568                               EAP_SIM_AT_RESULT_IND, 2, 0, 0)
4569        idx += 1
4570        if ctx['num'] == idx:
4571            logger.info("Test: EAP-Failure")
4572            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4573
4574        idx += 1
4575        if ctx['num'] == idx:
4576            logger.info("Test: Unexpected AT_KDF_INPUT")
4577            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4578                               4 + 1 + 3 + 8,
4579                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4580                               EAP_SIM_AT_KDF_INPUT, 2, 0, 0)
4581        idx += 1
4582        if ctx['num'] == idx:
4583            logger.info("Test: EAP-Failure")
4584            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4585
4586        idx += 1
4587        if ctx['num'] == idx:
4588            logger.info("Test: Unexpected AT_KDF")
4589            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4590                               4 + 1 + 3 + 8,
4591                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4592                               EAP_SIM_AT_KDF, 2, 0, 0)
4593        idx += 1
4594        if ctx['num'] == idx:
4595            logger.info("Test: EAP-Failure")
4596            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4597
4598        idx += 1
4599        if ctx['num'] == idx:
4600            logger.info("Test: Invalid AT_BIDDING length")
4601            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4602                               4 + 1 + 3 + 8,
4603                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4604                               EAP_SIM_AT_BIDDING, 2, 0, 0)
4605        idx += 1
4606        if ctx['num'] == idx:
4607            logger.info("Test: EAP-Failure")
4608            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4609
4610        return None
4611
4612    srv = start_radius_server(aka_handler)
4613
4614    try:
4615        hapd = start_ap(apdev[0])
4616        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
4617
4618        for i in range(0, 49):
4619            eap = "AKA AKA'" if i == 11 else "AKA"
4620            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
4621                           eap=eap, identity="0232010000000000",
4622                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
4623                           wait_connect=False)
4624            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
4625                                   timeout=15)
4626            if ev is None:
4627                raise Exception("Timeout on EAP start")
4628            if i in [0, 15]:
4629                time.sleep(0.1)
4630            else:
4631                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
4632                                       timeout=10)
4633                if ev is None:
4634                    raise Exception("Timeout on EAP failure")
4635            dev[0].request("REMOVE_NETWORK all")
4636            dev[0].dump_monitor()
4637    finally:
4638        stop_radius_server(srv)
4639
4640def test_eap_proto_aka_prime(dev, apdev):
4641    """EAP-AKA' protocol tests"""
4642    def aka_prime_handler(ctx, req):
4643        logger.info("aka_prime_handler - RX " + binascii.hexlify(req).decode())
4644        if 'num' not in ctx:
4645            ctx['num'] = 0
4646        ctx['num'] = ctx['num'] + 1
4647        if 'id' not in ctx:
4648            ctx['id'] = 1
4649        ctx['id'] = (ctx['id'] + 1) % 256
4650
4651        idx = 0
4652
4653        idx += 1
4654        if ctx['num'] == idx:
4655            logger.info("Test: Missing payload")
4656            dev[0].note("Missing payload")
4657            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
4658                               4 + 1,
4659                               EAP_TYPE_AKA_PRIME)
4660
4661        idx += 1
4662        if ctx['num'] == idx:
4663            logger.info("Test: Challenge with no attributes")
4664            dev[0].note("Challenge with no attributes")
4665            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
4666                               4 + 1 + 3,
4667                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0)
4668        idx += 1
4669        if ctx['num'] == idx:
4670            logger.info("Test: EAP-Failure")
4671            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4672
4673        idx += 1
4674        if ctx['num'] == idx:
4675            logger.info("Test: Challenge with empty AT_KDF_INPUT")
4676            dev[0].note("Challenge with empty AT_KDF_INPUT")
4677            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4678                               4 + 1 + 3 + 4,
4679                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4680                               EAP_SIM_AT_KDF_INPUT, 1, 0)
4681        idx += 1
4682        if ctx['num'] == idx:
4683            logger.info("Test: EAP-Failure")
4684            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4685
4686        idx += 1
4687        if ctx['num'] == idx:
4688            logger.info("Test: Challenge with AT_KDF_INPUT")
4689            dev[0].note("Test: Challenge with AT_KDF_INPUT")
4690            return struct.pack(">BBHBBHBBHBBBB", EAP_CODE_REQUEST, ctx['id'],
4691                               4 + 1 + 3 + 8,
4692                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4693                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4694                               ord('c'), ord('d'))
4695        idx += 1
4696        if ctx['num'] == idx:
4697            logger.info("Test: EAP-Failure")
4698            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4699
4700        idx += 1
4701        if ctx['num'] == idx:
4702            logger.info("Test: Challenge with duplicated KDF")
4703            dev[0].note("Challenge with duplicated KDF")
4704            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
4705                               EAP_CODE_REQUEST, ctx['id'],
4706                               4 + 1 + 3 + 8 + 3 * 4,
4707                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4708                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4709                               ord('c'), ord('d'),
4710                               EAP_SIM_AT_KDF, 1, 1,
4711                               EAP_SIM_AT_KDF, 1, 2,
4712                               EAP_SIM_AT_KDF, 1, 1)
4713        idx += 1
4714        if ctx['num'] == idx:
4715            logger.info("Test: EAP-Failure")
4716            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4717
4718        idx += 1
4719        if ctx['num'] == idx:
4720            logger.info("Test: Challenge with multiple KDF proposals")
4721            dev[0].note("Challenge with multiple KDF proposals (preparation)")
4722            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
4723                               EAP_CODE_REQUEST, ctx['id'],
4724                               4 + 1 + 3 + 8 + 3 * 4,
4725                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4726                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4727                               ord('c'), ord('d'),
4728                               EAP_SIM_AT_KDF, 1, 255,
4729                               EAP_SIM_AT_KDF, 1, 254,
4730                               EAP_SIM_AT_KDF, 1, 1)
4731        idx += 1
4732        if ctx['num'] == idx:
4733            logger.info("Test: Challenge with incorrect KDF selected")
4734            dev[0].note("Challenge with incorrect KDF selected")
4735            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBH",
4736                               EAP_CODE_REQUEST, ctx['id'],
4737                               4 + 1 + 3 + 8 + 4 * 4,
4738                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4739                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4740                               ord('c'), ord('d'),
4741                               EAP_SIM_AT_KDF, 1, 255,
4742                               EAP_SIM_AT_KDF, 1, 255,
4743                               EAP_SIM_AT_KDF, 1, 254,
4744                               EAP_SIM_AT_KDF, 1, 1)
4745        idx += 1
4746        if ctx['num'] == idx:
4747            logger.info("Test: EAP-Failure")
4748            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4749
4750        idx += 1
4751        if ctx['num'] == idx:
4752            logger.info("Test: Challenge with multiple KDF proposals")
4753            dev[0].note("Challenge with multiple KDF proposals (preparation)")
4754            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
4755                               EAP_CODE_REQUEST, ctx['id'],
4756                               4 + 1 + 3 + 8 + 3 * 4,
4757                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4758                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4759                               ord('c'), ord('d'),
4760                               EAP_SIM_AT_KDF, 1, 255,
4761                               EAP_SIM_AT_KDF, 1, 254,
4762                               EAP_SIM_AT_KDF, 1, 1)
4763        idx += 1
4764        if ctx['num'] == idx:
4765            logger.info("Test: Challenge with selected KDF not duplicated")
4766            dev[0].note("Challenge with selected KDF not duplicated")
4767            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
4768                               EAP_CODE_REQUEST, ctx['id'],
4769                               4 + 1 + 3 + 8 + 3 * 4,
4770                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4771                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4772                               ord('c'), ord('d'),
4773                               EAP_SIM_AT_KDF, 1, 1,
4774                               EAP_SIM_AT_KDF, 1, 255,
4775                               EAP_SIM_AT_KDF, 1, 254)
4776        idx += 1
4777        if ctx['num'] == idx:
4778            logger.info("Test: EAP-Failure")
4779            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4780
4781        idx += 1
4782        if ctx['num'] == idx:
4783            logger.info("Test: Challenge with multiple KDF proposals")
4784            dev[0].note("Challenge with multiple KDF proposals (preparation)")
4785            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
4786                               EAP_CODE_REQUEST, ctx['id'],
4787                               4 + 1 + 3 + 8 + 3 * 4,
4788                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4789                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4790                               ord('c'), ord('d'),
4791                               EAP_SIM_AT_KDF, 1, 255,
4792                               EAP_SIM_AT_KDF, 1, 254,
4793                               EAP_SIM_AT_KDF, 1, 1)
4794        idx += 1
4795        if ctx['num'] == idx:
4796            logger.info("Test: Challenge with selected KDF duplicated (missing MAC, RAND, AUTN)")
4797            dev[0].note("Challenge with selected KDF duplicated (missing MAC, RAND, AUTN)")
4798            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBH",
4799                               EAP_CODE_REQUEST, ctx['id'],
4800                               4 + 1 + 3 + 8 + 4 * 4,
4801                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4802                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4803                               ord('c'), ord('d'),
4804                               EAP_SIM_AT_KDF, 1, 1,
4805                               EAP_SIM_AT_KDF, 1, 255,
4806                               EAP_SIM_AT_KDF, 1, 254,
4807                               EAP_SIM_AT_KDF, 1, 1)
4808        idx += 1
4809        if ctx['num'] == idx:
4810            logger.info("Test: EAP-Failure")
4811            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4812
4813        idx += 1
4814        if ctx['num'] == idx:
4815            logger.info("Test: Challenge with multiple unsupported KDF proposals")
4816            dev[0].note("Challenge with multiple unsupported KDF proposals")
4817            return struct.pack(">BBHBBHBBHBBBBBBHBBH",
4818                               EAP_CODE_REQUEST, ctx['id'],
4819                               4 + 1 + 3 + 8 + 2 * 4,
4820                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4821                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4822                               ord('c'), ord('d'),
4823                               EAP_SIM_AT_KDF, 1, 255,
4824                               EAP_SIM_AT_KDF, 1, 254)
4825        idx += 1
4826        if ctx['num'] == idx:
4827            logger.info("Test: EAP-Failure")
4828            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4829
4830        idx += 1
4831        if ctx['num'] == idx:
4832            logger.info("Test: Challenge with multiple KDF proposals")
4833            dev[0].note("Challenge with multiple KDF proposals (preparation)")
4834            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
4835                               EAP_CODE_REQUEST, ctx['id'],
4836                               4 + 1 + 3 + 8 + 3 * 4,
4837                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4838                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4839                               ord('c'), ord('d'),
4840                               EAP_SIM_AT_KDF, 1, 255,
4841                               EAP_SIM_AT_KDF, 1, 254,
4842                               EAP_SIM_AT_KDF, 1, 1)
4843        idx += 1
4844        if ctx['num'] == idx:
4845            logger.info("Test: Challenge with invalid MAC, RAND, AUTN values)")
4846            dev[0].note("Challenge with invalid MAC, RAND, AUTN values)")
4847            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBHBBH4LBBH4LBBH4L",
4848                               EAP_CODE_REQUEST, ctx['id'],
4849                               4 + 1 + 3 + 8 + 4 * 4 + 20 + 20 + 20,
4850                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4851                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4852                               ord('c'), ord('d'),
4853                               EAP_SIM_AT_KDF, 1, 1,
4854                               EAP_SIM_AT_KDF, 1, 255,
4855                               EAP_SIM_AT_KDF, 1, 254,
4856                               EAP_SIM_AT_KDF, 1, 1,
4857                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0,
4858                               EAP_SIM_AT_RAND, 5, 0, 0, 0, 0, 0,
4859                               EAP_SIM_AT_AUTN, 5, 0, 0, 0, 0, 0)
4860        idx += 1
4861        if ctx['num'] == idx:
4862            logger.info("Test: EAP-Failure")
4863            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4864
4865        idx += 1
4866        if ctx['num'] == idx:
4867            logger.info("Test: Challenge - AMF separation bit not set)")
4868            dev[0].note("Challenge - AMF separation bit not set)")
4869            return struct.pack(">BBHBBHBBHBBBBBBHBBH4LBBH4LBBH4L",
4870                               EAP_CODE_REQUEST, ctx['id'],
4871                               4 + 1 + 3 + 8 + 4 + 20 + 20 + 20,
4872                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4873                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4874                               ord('c'), ord('d'),
4875                               EAP_SIM_AT_KDF, 1, 1,
4876                               EAP_SIM_AT_MAC, 5, 0, 1, 2, 3, 4,
4877                               EAP_SIM_AT_RAND, 5, 0, 5, 6, 7, 8,
4878                               EAP_SIM_AT_AUTN, 5, 0, 9, 10,
4879                               0x2fda8ef7, 0xbba518cc)
4880        idx += 1
4881        if ctx['num'] == idx:
4882            logger.info("Test: EAP-Failure")
4883            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4884
4885        idx += 1
4886        if ctx['num'] == idx:
4887            logger.info("Test: Challenge - Invalid MAC")
4888            dev[0].note("Challenge - Invalid MAC")
4889            return struct.pack(">BBHBBHBBHBBBBBBHBBH4LBBH4LBBH4L",
4890                               EAP_CODE_REQUEST, ctx['id'],
4891                               4 + 1 + 3 + 8 + 4 + 20 + 20 + 20,
4892                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4893                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4894                               ord('c'), ord('d'),
4895                               EAP_SIM_AT_KDF, 1, 1,
4896                               EAP_SIM_AT_MAC, 5, 0, 1, 2, 3, 4,
4897                               EAP_SIM_AT_RAND, 5, 0, 5, 6, 7, 8,
4898                               EAP_SIM_AT_AUTN, 5, 0, 0xffffffff, 0xffffffff,
4899                               0xd1f90322, 0x40514cb4)
4900        idx += 1
4901        if ctx['num'] == idx:
4902            logger.info("Test: EAP-Failure")
4903            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4904
4905        idx += 1
4906        if ctx['num'] == idx:
4907            logger.info("Test: Challenge - Valid MAC")
4908            dev[0].note("Challenge - Valid MAC")
4909            return struct.pack(">BBHBBHBBHBBBBBBHBBH4LBBH4LBBH4L",
4910                               EAP_CODE_REQUEST, ctx['id'],
4911                               4 + 1 + 3 + 8 + 4 + 20 + 20 + 20,
4912                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4913                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4914                               ord('c'), ord('d'),
4915                               EAP_SIM_AT_KDF, 1, 1,
4916                               EAP_SIM_AT_MAC, 5, 0,
4917                               0xf4a3c1d3, 0x7c901401, 0x34bd8b01, 0x6f7fa32f,
4918                               EAP_SIM_AT_RAND, 5, 0, 5, 6, 7, 8,
4919                               EAP_SIM_AT_AUTN, 5, 0, 0xffffffff, 0xffffffff,
4920                               0xd1f90322, 0x40514cb4)
4921        idx += 1
4922        if ctx['num'] == idx:
4923            logger.info("Test: EAP-Failure")
4924            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4925
4926        idx += 1
4927        if ctx['num'] == idx:
4928            logger.info("Test: Invalid AT_KDF_INPUT length")
4929            dev[0].note("Invalid AT_KDF_INPUT length")
4930            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4931                               4 + 1 + 3 + 8,
4932                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_IDENTITY, 0,
4933                               EAP_SIM_AT_KDF_INPUT, 2, 0xffff, 0)
4934        idx += 1
4935        if ctx['num'] == idx:
4936            logger.info("Test: EAP-Failure")
4937            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4938
4939        idx += 1
4940        if ctx['num'] == idx:
4941            logger.info("Test: Invalid AT_KDF length")
4942            dev[0].note("Invalid AT_KDF length")
4943            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4944                               4 + 1 + 3 + 8,
4945                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_IDENTITY, 0,
4946                               EAP_SIM_AT_KDF, 2, 0, 0)
4947        idx += 1
4948        if ctx['num'] == idx:
4949            logger.info("Test: EAP-Failure")
4950            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4951
4952        idx += 1
4953        if ctx['num'] == idx:
4954            logger.info("Test: Challenge with large number of KDF proposals")
4955            dev[0].note("Challenge with large number of KDF proposals")
4956            return struct.pack(">BBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBH",
4957                               EAP_CODE_REQUEST, ctx['id'],
4958                               4 + 1 + 3 + 12 * 4,
4959                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4960                               EAP_SIM_AT_KDF, 1, 255,
4961                               EAP_SIM_AT_KDF, 1, 254,
4962                               EAP_SIM_AT_KDF, 1, 253,
4963                               EAP_SIM_AT_KDF, 1, 252,
4964                               EAP_SIM_AT_KDF, 1, 251,
4965                               EAP_SIM_AT_KDF, 1, 250,
4966                               EAP_SIM_AT_KDF, 1, 249,
4967                               EAP_SIM_AT_KDF, 1, 248,
4968                               EAP_SIM_AT_KDF, 1, 247,
4969                               EAP_SIM_AT_KDF, 1, 246,
4970                               EAP_SIM_AT_KDF, 1, 245,
4971                               EAP_SIM_AT_KDF, 1, 244)
4972        idx += 1
4973        if ctx['num'] == idx:
4974            logger.info("Test: EAP-Failure")
4975            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4976
4977        idx += 1
4978        if ctx['num'] == idx:
4979            logger.info("Test: Challenge with multiple KDF proposals")
4980            dev[0].note("Challenge with multiple KDF proposals (preparation)")
4981            return struct.pack(">BBHBBHBBHBBBBBBHBBH",
4982                               EAP_CODE_REQUEST, ctx['id'],
4983                               4 + 1 + 3 + 8 + 2 * 4,
4984                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4985                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4986                               ord('c'), ord('d'),
4987                               EAP_SIM_AT_KDF, 1, 2,
4988                               EAP_SIM_AT_KDF, 1, 1)
4989        idx += 1
4990        if ctx['num'] == idx:
4991            logger.info("Test: Challenge with an extra KDF appended")
4992            dev[0].note("Challenge with an extra KDF appended")
4993            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBH",
4994                               EAP_CODE_REQUEST, ctx['id'],
4995                               4 + 1 + 3 + 8 + 4 * 4,
4996                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4997                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4998                               ord('c'), ord('d'),
4999                               EAP_SIM_AT_KDF, 1, 1,
5000                               EAP_SIM_AT_KDF, 1, 2,
5001                               EAP_SIM_AT_KDF, 1, 1,
5002                               EAP_SIM_AT_KDF, 1, 0)
5003        idx += 1
5004        if ctx['num'] == idx:
5005            logger.info("Test: EAP-Failure")
5006            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5007
5008        idx += 1
5009        if ctx['num'] == idx:
5010            logger.info("Test: Challenge with multiple KDF proposals")
5011            dev[0].note("Challenge with multiple KDF proposals (preparation)")
5012            return struct.pack(">BBHBBHBBHBBBBBBHBBH",
5013                               EAP_CODE_REQUEST, ctx['id'],
5014                               4 + 1 + 3 + 8 + 2 * 4,
5015                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
5016                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
5017                               ord('c'), ord('d'),
5018                               EAP_SIM_AT_KDF, 1, 2,
5019                               EAP_SIM_AT_KDF, 1, 1)
5020        idx += 1
5021        if ctx['num'] == idx:
5022            logger.info("Test: Challenge with a modified KDF")
5023            dev[0].note("Challenge with a modified KDF")
5024            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
5025                               EAP_CODE_REQUEST, ctx['id'],
5026                               4 + 1 + 3 + 8 + 3 * 4,
5027                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
5028                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
5029                               ord('c'), ord('d'),
5030                               EAP_SIM_AT_KDF, 1, 1,
5031                               EAP_SIM_AT_KDF, 1, 0,
5032                               EAP_SIM_AT_KDF, 1, 1)
5033        idx += 1
5034        if ctx['num'] == idx:
5035            logger.info("Test: EAP-Failure")
5036            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5037
5038        return None
5039
5040    srv = start_radius_server(aka_prime_handler)
5041
5042    try:
5043        hapd = start_ap(apdev[0])
5044        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
5045
5046        for i in range(0, 18):
5047            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5048                           eap="AKA'", identity="6555444333222111",
5049                           password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
5050                           wait_connect=False)
5051            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
5052                                   timeout=15)
5053            if ev is None:
5054                raise Exception("Timeout on EAP start")
5055            if i in [0]:
5056                time.sleep(0.1)
5057            else:
5058                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
5059                                       timeout=10)
5060                if ev is None:
5061                    raise Exception("Timeout on EAP failure")
5062            dev[0].request("REMOVE_NETWORK all")
5063            dev[0].dump_monitor()
5064    finally:
5065        stop_radius_server(srv)
5066
5067def test_eap_proto_sim(dev, apdev):
5068    """EAP-SIM protocol tests"""
5069    def sim_handler(ctx, req):
5070        logger.info("sim_handler - RX " + binascii.hexlify(req).decode())
5071        if 'num' not in ctx:
5072            ctx['num'] = 0
5073        ctx['num'] = ctx['num'] + 1
5074        if 'id' not in ctx:
5075            ctx['id'] = 1
5076        ctx['id'] = (ctx['id'] + 1) % 256
5077
5078        idx = 0
5079
5080        idx += 1
5081        if ctx['num'] == idx:
5082            logger.info("Test: Missing payload")
5083            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
5084                               4 + 1,
5085                               EAP_TYPE_SIM)
5086
5087        idx += 1
5088        if ctx['num'] == idx:
5089            logger.info("Test: Unexpected AT_AUTN")
5090            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
5091                               4 + 1 + 3 + 8,
5092                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5093                               EAP_SIM_AT_AUTN, 2, 0, 0)
5094        idx += 1
5095        if ctx['num'] == idx:
5096            logger.info("Test: EAP-Failure")
5097            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5098
5099        idx += 1
5100        if ctx['num'] == idx:
5101            logger.info("Test: Too short AT_VERSION_LIST")
5102            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5103                               4 + 1 + 3 + 4,
5104                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5105                               EAP_SIM_AT_VERSION_LIST, 1, 0)
5106        idx += 1
5107        if ctx['num'] == idx:
5108            logger.info("Test: EAP-Failure")
5109            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5110
5111        idx += 1
5112        if ctx['num'] == idx:
5113            logger.info("Test: AT_VERSION_LIST overflow")
5114            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5115                               4 + 1 + 3 + 4,
5116                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5117                               EAP_SIM_AT_VERSION_LIST, 1, 0xffff)
5118        idx += 1
5119        if ctx['num'] == idx:
5120            logger.info("Test: EAP-Failure")
5121            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5122
5123        idx += 1
5124        if ctx['num'] == idx:
5125            logger.info("Test: Unexpected AT_AUTS")
5126            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
5127                               4 + 1 + 3 + 8,
5128                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5129                               EAP_SIM_AT_AUTS, 2, 0, 0)
5130        idx += 1
5131        if ctx['num'] == idx:
5132            logger.info("Test: EAP-Failure")
5133            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5134
5135        idx += 1
5136        if ctx['num'] == idx:
5137            logger.info("Test: Unexpected AT_CHECKCODE")
5138            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
5139                               4 + 1 + 3 + 8,
5140                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5141                               EAP_SIM_AT_CHECKCODE, 2, 0, 0)
5142        idx += 1
5143        if ctx['num'] == idx:
5144            logger.info("Test: EAP-Failure")
5145            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5146
5147        idx += 1
5148        if ctx['num'] == idx:
5149            logger.info("Test: No AT_VERSION_LIST in Start")
5150            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
5151                               4 + 1 + 3,
5152                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0)
5153        idx += 1
5154        if ctx['num'] == idx:
5155            logger.info("Test: EAP-Failure")
5156            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5157
5158        idx += 1
5159        if ctx['num'] == idx:
5160            logger.info("Test: No support version in AT_VERSION_LIST")
5161            return struct.pack(">BBHBBHBBH4B", EAP_CODE_REQUEST, ctx['id'],
5162                               4 + 1 + 3 + 8,
5163                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5164                               EAP_SIM_AT_VERSION_LIST, 2, 3, 2, 3, 4, 5)
5165        idx += 1
5166        if ctx['num'] == idx:
5167            logger.info("Test: EAP-Failure")
5168            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5169
5170
5171        idx += 1
5172        if ctx['num'] == idx:
5173            logger.info("Test: Identity request without ID type")
5174            return struct.pack(">BBHBBHBBH2H", EAP_CODE_REQUEST, ctx['id'],
5175                               4 + 1 + 3 + 8,
5176                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5177                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0)
5178        idx += 1
5179        if ctx['num'] == idx:
5180            logger.info("Test: Identity request ANY_ID")
5181            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5182                               4 + 1 + 3 + 8 + 4,
5183                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5184                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5185                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
5186        idx += 1
5187        if ctx['num'] == idx:
5188            logger.info("Test: Identity request ANY_ID (duplicate)")
5189            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5190                               4 + 1 + 3 + 8 + 4,
5191                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5192                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5193                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
5194        idx += 1
5195        if ctx['num'] == idx:
5196            logger.info("Test: EAP-Failure")
5197            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5198
5199        idx += 1
5200        if ctx['num'] == idx:
5201            logger.info("Test: Identity request ANY_ID")
5202            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5203                               4 + 1 + 3 + 8 + 4,
5204                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5205                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5206                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
5207        idx += 1
5208        if ctx['num'] == idx:
5209            logger.info("Test: Identity request FULLAUTH_ID")
5210            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5211                               4 + 1 + 3 + 8 + 4,
5212                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5213                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5214                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
5215        idx += 1
5216        if ctx['num'] == idx:
5217            logger.info("Test: Identity request FULLAUTH_ID (duplicate)")
5218            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5219                               4 + 1 + 3 + 8 + 4,
5220                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5221                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5222                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
5223        idx += 1
5224        if ctx['num'] == idx:
5225            logger.info("Test: EAP-Failure")
5226            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5227
5228        idx += 1
5229        if ctx['num'] == idx:
5230            logger.info("Test: Identity request ANY_ID")
5231            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5232                               4 + 1 + 3 + 8 + 4,
5233                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5234                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5235                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
5236        idx += 1
5237        if ctx['num'] == idx:
5238            logger.info("Test: Identity request FULLAUTH_ID")
5239            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5240                               4 + 1 + 3 + 8 + 4,
5241                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5242                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5243                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
5244        idx += 1
5245        if ctx['num'] == idx:
5246            logger.info("Test: Identity request PERMANENT_ID")
5247            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5248                               4 + 1 + 3 + 8 + 4,
5249                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5250                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5251                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
5252        idx += 1
5253        if ctx['num'] == idx:
5254            logger.info("Test: Identity request PERMANENT_ID (duplicate)")
5255            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5256                               4 + 1 + 3 + 8 + 4,
5257                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5258                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5259                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
5260        idx += 1
5261        if ctx['num'] == idx:
5262            logger.info("Test: EAP-Failure")
5263            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5264
5265        idx += 1
5266        if ctx['num'] == idx:
5267            logger.info("Test: No AT_MAC and AT_RAND in Challenge")
5268            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
5269                               4 + 1 + 3,
5270                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0)
5271        idx += 1
5272        if ctx['num'] == idx:
5273            logger.info("Test: EAP-Failure")
5274            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5275
5276        idx += 1
5277        if ctx['num'] == idx:
5278            logger.info("Test: No AT_RAND in Challenge")
5279            return struct.pack(">BBHBBHBBH4L", EAP_CODE_REQUEST, ctx['id'],
5280                               4 + 1 + 3 + 20,
5281                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
5282                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
5283        idx += 1
5284        if ctx['num'] == idx:
5285            logger.info("Test: EAP-Failure")
5286            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5287
5288        idx += 1
5289        if ctx['num'] == idx:
5290            logger.info("Test: Insufficient number of challenges in Challenge")
5291            return struct.pack(">BBHBBHBBH4LBBH4L", EAP_CODE_REQUEST, ctx['id'],
5292                               4 + 1 + 3 + 20 + 20,
5293                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
5294                               EAP_SIM_AT_RAND, 5, 0, 0, 0, 0, 0,
5295                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
5296        idx += 1
5297        if ctx['num'] == idx:
5298            logger.info("Test: EAP-Failure")
5299            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5300
5301        idx += 1
5302        if ctx['num'] == idx:
5303            logger.info("Test: Too many challenges in Challenge")
5304            return struct.pack(">BBHBBHBBH4L4L4L4LBBH4L", EAP_CODE_REQUEST,
5305                               ctx['id'],
5306                               4 + 1 + 3 + 4 + 4 * 16 + 20,
5307                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
5308                               EAP_SIM_AT_RAND, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5309                               0, 0, 0, 0, 0, 0, 0, 0,
5310                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
5311        idx += 1
5312        if ctx['num'] == idx:
5313            logger.info("Test: EAP-Failure")
5314            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5315
5316        idx += 1
5317        if ctx['num'] == idx:
5318            logger.info("Test: Same RAND multiple times in Challenge")
5319            return struct.pack(">BBHBBHBBH4L4L4LBBH4L", EAP_CODE_REQUEST,
5320                               ctx['id'],
5321                               4 + 1 + 3 + 4 + 3 * 16 + 20,
5322                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
5323                               EAP_SIM_AT_RAND, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1,
5324                               0, 0, 0, 0,
5325                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
5326        idx += 1
5327        if ctx['num'] == idx:
5328            logger.info("Test: EAP-Failure")
5329            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5330
5331        idx += 1
5332        if ctx['num'] == idx:
5333            logger.info("Test: Notification with no attributes")
5334            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
5335                               4 + 1 + 3,
5336                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0)
5337        idx += 1
5338        if ctx['num'] == idx:
5339            logger.info("Test: EAP-Failure")
5340            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5341
5342        idx += 1
5343        if ctx['num'] == idx:
5344            logger.info("Test: Notification indicating success, but no MAC")
5345            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5346                               4 + 1 + 3 + 4,
5347                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
5348                               EAP_SIM_AT_NOTIFICATION, 1, 32768)
5349        idx += 1
5350        if ctx['num'] == idx:
5351            logger.info("Test: EAP-Failure")
5352            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5353
5354        idx += 1
5355        if ctx['num'] == idx:
5356            logger.info("Test: Notification indicating success, but invalid MAC value")
5357            return struct.pack(">BBHBBHBBHBBH4L", EAP_CODE_REQUEST, ctx['id'],
5358                               4 + 1 + 3 + 4 + 20,
5359                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
5360                               EAP_SIM_AT_NOTIFICATION, 1, 32768,
5361                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
5362        idx += 1
5363        if ctx['num'] == idx:
5364            logger.info("Test: EAP-Failure")
5365            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5366
5367        idx += 1
5368        if ctx['num'] == idx:
5369            logger.info("Test: Notification before auth")
5370            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5371                               4 + 1 + 3 + 4,
5372                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
5373                               EAP_SIM_AT_NOTIFICATION, 1, 16384)
5374        idx += 1
5375        if ctx['num'] == idx:
5376            logger.info("Test: EAP-Failure")
5377            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5378
5379        idx += 1
5380        if ctx['num'] == idx:
5381            logger.info("Test: Notification before auth")
5382            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5383                               4 + 1 + 3 + 4,
5384                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
5385                               EAP_SIM_AT_NOTIFICATION, 1, 16385)
5386        idx += 1
5387        if ctx['num'] == idx:
5388            logger.info("Test: EAP-Failure")
5389            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5390
5391        idx += 1
5392        if ctx['num'] == idx:
5393            logger.info("Test: Notification with unrecognized non-failure")
5394            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5395                               4 + 1 + 3 + 4,
5396                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
5397                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
5398        idx += 1
5399        if ctx['num'] == idx:
5400            logger.info("Test: Notification before auth (duplicate)")
5401            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5402                               4 + 1 + 3 + 4,
5403                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
5404                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
5405        idx += 1
5406        if ctx['num'] == idx:
5407            logger.info("Test: EAP-Failure")
5408            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5409
5410        idx += 1
5411        if ctx['num'] == idx:
5412            logger.info("Test: Re-authentication (unexpected) with no attributes")
5413            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
5414                               4 + 1 + 3,
5415                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_REAUTHENTICATION,
5416                               0)
5417        idx += 1
5418        if ctx['num'] == idx:
5419            logger.info("Test: EAP-Failure")
5420            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5421
5422        idx += 1
5423        if ctx['num'] == idx:
5424            logger.info("Test: Client Error")
5425            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
5426                               4 + 1 + 3,
5427                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CLIENT_ERROR, 0)
5428        idx += 1
5429        if ctx['num'] == idx:
5430            logger.info("Test: EAP-Failure")
5431            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5432
5433        idx += 1
5434        if ctx['num'] == idx:
5435            logger.info("Test: Unknown subtype")
5436            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
5437                               4 + 1 + 3,
5438                               EAP_TYPE_SIM, 255, 0)
5439        idx += 1
5440        if ctx['num'] == idx:
5441            logger.info("Test: EAP-Failure")
5442            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5443
5444        return None
5445
5446    srv = start_radius_server(sim_handler)
5447
5448    try:
5449        hapd = start_ap(apdev[0])
5450        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
5451
5452        for i in range(0, 25):
5453            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5454                           eap="SIM", identity="1232010000000000",
5455                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
5456                           wait_connect=False)
5457            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
5458                                   timeout=15)
5459            if ev is None:
5460                raise Exception("Timeout on EAP start")
5461            if i in [0]:
5462                time.sleep(0.1)
5463            else:
5464                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
5465                                       timeout=10)
5466                if ev is None:
5467                    raise Exception("Timeout on EAP failure")
5468            dev[0].request("REMOVE_NETWORK all")
5469            dev[0].dump_monitor()
5470    finally:
5471        stop_radius_server(srv)
5472
5473def test_eap_proto_sim_errors(dev, apdev):
5474    """EAP-SIM protocol tests (error paths)"""
5475    check_hlr_auc_gw_support()
5476    params = hostapd.wpa2_eap_params(ssid="eap-test")
5477    hapd = hostapd.add_ap(apdev[0], params)
5478    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
5479
5480    with alloc_fail(dev[0], 1, "eap_sim_init"):
5481        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5482                       eap="SIM", identity="1232010000000000",
5483                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
5484                       wait_connect=False)
5485        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
5486                               timeout=15)
5487        if ev is None:
5488            raise Exception("Timeout on EAP start")
5489        dev[0].request("REMOVE_NETWORK all")
5490        dev[0].wait_disconnected()
5491
5492    with fail_test(dev[0], 1, "os_get_random;eap_sim_init"):
5493        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5494                       eap="SIM", identity="1232010000000000",
5495                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
5496                       wait_connect=False)
5497        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
5498                               timeout=15)
5499        if ev is None:
5500            raise Exception("Timeout on EAP start")
5501        dev[0].request("REMOVE_NETWORK all")
5502        dev[0].wait_disconnected()
5503
5504    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5505                   eap="SIM", identity="1232010000000000",
5506                   password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
5507
5508    with fail_test(dev[0], 1, "aes_128_cbc_encrypt;eap_sim_response_reauth"):
5509        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
5510        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
5511        if ev is None:
5512            raise Exception("EAP re-authentication did not start")
5513        wait_fail_trigger(dev[0], "GET_FAIL")
5514        dev[0].request("REMOVE_NETWORK all")
5515        dev[0].dump_monitor()
5516
5517    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5518                   eap="SIM", identity="1232010000000000",
5519                   password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
5520
5521    with fail_test(dev[0], 1, "os_get_random;eap_sim_msg_add_encr_start"):
5522        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
5523        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
5524        if ev is None:
5525            raise Exception("EAP re-authentication did not start")
5526        wait_fail_trigger(dev[0], "GET_FAIL")
5527        dev[0].request("REMOVE_NETWORK all")
5528        dev[0].dump_monitor()
5529
5530    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5531                   eap="SIM", identity="1232010000000000",
5532                   password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
5533
5534    with fail_test(dev[0], 1, "os_get_random;eap_sim_init_for_reauth"):
5535        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
5536        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
5537        if ev is None:
5538            raise Exception("EAP re-authentication did not start")
5539        wait_fail_trigger(dev[0], "GET_FAIL")
5540        dev[0].request("REMOVE_NETWORK all")
5541        dev[0].dump_monitor()
5542
5543    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5544                   eap="SIM", identity="1232010000000000",
5545                   password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
5546
5547    with alloc_fail(dev[0], 1, "eap_sim_parse_encr;eap_sim_process_reauthentication"):
5548        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
5549        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
5550        if ev is None:
5551            raise Exception("EAP re-authentication did not start")
5552        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5553        dev[0].request("REMOVE_NETWORK all")
5554        dev[0].dump_monitor()
5555
5556    tests = [(1, "eap_sim_verify_mac"),
5557             (1, "eap_sim_parse_encr;eap_sim_process_challenge"),
5558             (1, "eap_sim_msg_init;eap_sim_response_start"),
5559             (1, "wpabuf_alloc;eap_sim_msg_init;eap_sim_response_start"),
5560             (1, "=eap_sim_learn_ids"),
5561             (2, "=eap_sim_learn_ids"),
5562             (2, "eap_sim_learn_ids"),
5563             (3, "eap_sim_learn_ids"),
5564             (1, "eap_sim_process_start"),
5565             (1, "eap_sim_getKey"),
5566             (1, "eap_sim_get_emsk"),
5567             (1, "eap_sim_get_session_id")]
5568    for count, func in tests:
5569        with alloc_fail(dev[0], count, func):
5570            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5571                           eap="SIM", identity="1232010000000000@domain",
5572                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
5573                           erp="1", wait_connect=False)
5574            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5575            dev[0].request("REMOVE_NETWORK all")
5576            dev[0].dump_monitor()
5577
5578    tests = [(1, "aes_128_cbc_decrypt;eap_sim_parse_encr")]
5579    for count, func in tests:
5580        with fail_test(dev[0], count, func):
5581            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5582                           eap="SIM", identity="1232010000000000",
5583                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
5584                           wait_connect=False)
5585            wait_fail_trigger(dev[0], "GET_FAIL")
5586            dev[0].request("REMOVE_NETWORK all")
5587            dev[0].dump_monitor()
5588
5589    params = int_eap_server_params()
5590    params['eap_sim_db'] = "unix:/tmp/hlr_auc_gw.sock"
5591    params['eap_sim_aka_result_ind'] = "1"
5592    hapd2 = hostapd.add_ap(apdev[1], params)
5593    dev[0].scan_for_bss(hapd2.own_addr(), freq=2412)
5594
5595    with alloc_fail(dev[0], 1,
5596                    "eap_sim_msg_init;eap_sim_response_notification"):
5597        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
5598                       scan_freq="2412",
5599                       eap="SIM", identity="1232010000000000",
5600                       phase1="result_ind=1",
5601                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
5602                       wait_connect=False)
5603        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5604        dev[0].request("REMOVE_NETWORK all")
5605        dev[0].dump_monitor()
5606
5607    hapd2.dump_monitor()
5608    tests = ["eap_sim_msg_add_encr_start;eap_sim_response_notification",
5609             "aes_128_cbc_encrypt;eap_sim_response_notification"]
5610    for func in tests:
5611        with fail_test(dev[0], 1, func):
5612            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
5613                           scan_freq="2412",
5614                           eap="SIM", identity="1232010000000000",
5615                           phase1="result_ind=1",
5616                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
5617            hapd2.wait_sta()
5618            dev[0].request("REAUTHENTICATE")
5619            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
5620            if ev is None:
5621                raise Exception("EAP method not started on reauthentication")
5622            time.sleep(0.1)
5623            wait_fail_trigger(dev[0], "GET_FAIL")
5624            dev[0].request("REMOVE_NETWORK all")
5625            dev[0].dump_monitor()
5626            hapd2.wait_sta_disconnect()
5627
5628    hapd2.dump_monitor()
5629    tests = ["eap_sim_parse_encr;eap_sim_process_notification_reauth"]
5630    for func in tests:
5631        with alloc_fail(dev[0], 1, func):
5632            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
5633                           scan_freq="2412",
5634                           eap="SIM", identity="1232010000000000",
5635                           phase1="result_ind=1",
5636                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
5637            hapd2.wait_sta()
5638            dev[0].request("REAUTHENTICATE")
5639            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
5640            if ev is None:
5641                raise Exception("EAP method not started on reauthentication")
5642            time.sleep(0.1)
5643            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5644            dev[0].request("REMOVE_NETWORK all")
5645            dev[0].dump_monitor()
5646            hapd2.wait_sta_disconnect()
5647
5648def test_eap_proto_aka_errors(dev, apdev):
5649    """EAP-AKA protocol tests (error paths)"""
5650    check_hlr_auc_gw_support()
5651    params = hostapd.wpa2_eap_params(ssid="eap-test")
5652    hapd = hostapd.add_ap(apdev[0], params)
5653    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
5654
5655    with alloc_fail(dev[0], 1, "eap_aka_init"):
5656        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5657                       eap="AKA", identity="0232010000000000",
5658                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
5659                       wait_connect=False)
5660        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
5661                               timeout=15)
5662        if ev is None:
5663            raise Exception("Timeout on EAP start")
5664        dev[0].request("REMOVE_NETWORK all")
5665        dev[0].wait_disconnected()
5666
5667    tests = [(1, "=eap_aka_learn_ids"),
5668             (2, "=eap_aka_learn_ids"),
5669             (1, "eap_sim_parse_encr;eap_aka_process_challenge"),
5670             (1, "wpabuf_alloc;eap_aka_add_id_msg"),
5671             (1, "eap_aka_getKey"),
5672             (1, "eap_aka_get_emsk"),
5673             (1, "eap_aka_get_session_id")]
5674    for count, func in tests:
5675        with alloc_fail(dev[0], count, func):
5676            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5677                           eap="AKA", identity="0232010000000000@domain",
5678                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
5679                           erp="1", wait_connect=False)
5680            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5681            dev[0].request("REMOVE_NETWORK all")
5682            dev[0].dump_monitor()
5683
5684    params = int_eap_server_params()
5685    params['eap_sim_db'] = "unix:/tmp/hlr_auc_gw.sock"
5686    params['eap_sim_aka_result_ind'] = "1"
5687    hapd2 = hostapd.add_ap(apdev[1], params)
5688    dev[0].scan_for_bss(hapd2.own_addr(), freq=2412)
5689
5690    with alloc_fail(dev[0], 1,
5691                    "eap_sim_msg_init;eap_aka_response_notification"):
5692        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
5693                       eap="AKA", identity="0232010000000000",
5694                       phase1="result_ind=1",
5695                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
5696                       wait_connect=False)
5697        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5698        dev[0].request("REMOVE_NETWORK all")
5699        dev[0].dump_monitor()
5700
5701    tests = [(1, "aes_128_encrypt_block;milenage_f1;milenage_check", None),
5702             (2, "aes_128_encrypt_block;milenage_f1;milenage_check", None),
5703             (1, "milenage_f2345;milenage_check", None),
5704             (7, "aes_128_encrypt_block;milenage_f2345;milenage_check",
5705              "ff0000000123"),
5706             (1, "aes_128_encrypt_block;milenage_f1;milenage_check",
5707              "fff000000123")]
5708    for count, func, seq in tests:
5709        if not seq:
5710            seq = "000000000123"
5711        with fail_test(dev[0], count, func):
5712            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
5713                           scan_freq="2412",
5714                           eap="AKA", identity="0232010000000000",
5715                           phase1="result_ind=1",
5716                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:" + seq,
5717                           wait_connect=False)
5718            wait_fail_trigger(dev[0], "GET_FAIL")
5719            dev[0].request("REMOVE_NETWORK all")
5720            dev[0].wait_disconnected()
5721            dev[0].dump_monitor()
5722
5723    hapd2.dump_monitor()
5724    tests = ["eap_sim_msg_add_encr_start;eap_aka_response_notification",
5725             "aes_128_cbc_encrypt;eap_aka_response_notification"]
5726    for func in tests:
5727        with fail_test(dev[0], 1, func):
5728            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
5729                           scan_freq="2412",
5730                           eap="AKA", identity="0232010000000000",
5731                           phase1="result_ind=1",
5732                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
5733            hapd2.wait_sta()
5734            dev[0].request("REAUTHENTICATE")
5735            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
5736            if ev is None:
5737                raise Exception("EAP method not started on reauthentication")
5738            time.sleep(0.1)
5739            wait_fail_trigger(dev[0], "GET_FAIL")
5740            dev[0].request("REMOVE_NETWORK all")
5741            dev[0].dump_monitor()
5742            hapd2.wait_sta_disconnect()
5743
5744    hapd2.dump_monitor()
5745    tests = ["eap_sim_parse_encr;eap_aka_process_notification_reauth"]
5746    for func in tests:
5747        with alloc_fail(dev[0], 1, func):
5748            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
5749                           scan_freq="2412",
5750                           eap="AKA", identity="0232010000000000",
5751                           phase1="result_ind=1",
5752                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
5753            hapd2.wait_sta()
5754            dev[0].request("REAUTHENTICATE")
5755            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
5756            if ev is None:
5757                raise Exception("EAP method not started on reauthentication")
5758            time.sleep(0.1)
5759            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5760            dev[0].request("REMOVE_NETWORK all")
5761            dev[0].dump_monitor()
5762            hapd2.wait_sta_disconnect()
5763
5764def test_eap_proto_aka_prime_errors(dev, apdev):
5765    """EAP-AKA' protocol tests (error paths)"""
5766    check_hlr_auc_gw_support()
5767    params = hostapd.wpa2_eap_params(ssid="eap-test")
5768    hapd = hostapd.add_ap(apdev[0], params)
5769    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
5770
5771    with alloc_fail(dev[0], 1, "eap_aka_init"):
5772        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5773                       eap="AKA'", identity="6555444333222111",
5774                       password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
5775                       wait_connect=False)
5776        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
5777                               timeout=15)
5778        if ev is None:
5779            raise Exception("Timeout on EAP start")
5780        dev[0].request("REMOVE_NETWORK all")
5781        dev[0].wait_disconnected()
5782
5783    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5784                   eap="AKA'", identity="6555444333222111",
5785                   password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
5786
5787    with fail_test(dev[0], 1, "aes_128_cbc_encrypt;eap_aka_response_reauth"):
5788        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
5789        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
5790        if ev is None:
5791            raise Exception("EAP re-authentication did not start")
5792        wait_fail_trigger(dev[0], "GET_FAIL")
5793        dev[0].request("REMOVE_NETWORK all")
5794        dev[0].dump_monitor()
5795
5796    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5797                   eap="AKA'", identity="6555444333222111",
5798                   password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
5799
5800    with alloc_fail(dev[0], 1, "eap_sim_parse_encr;eap_aka_process_reauthentication"):
5801        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
5802        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
5803        if ev is None:
5804            raise Exception("EAP re-authentication did not start")
5805        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5806        dev[0].request("REMOVE_NETWORK all")
5807        dev[0].dump_monitor()
5808
5809    tests = [(1, "eap_sim_verify_mac_sha256"),
5810             (1, "=eap_aka_process_challenge")]
5811    for count, func in tests:
5812        with alloc_fail(dev[0], count, func):
5813            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5814                           eap="AKA'", identity="6555444333222111",
5815                           password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
5816                           erp="1", wait_connect=False)
5817            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5818            dev[0].request("REMOVE_NETWORK all")
5819            dev[0].dump_monitor()
5820
5821def test_eap_proto_ikev2(dev, apdev):
5822    """EAP-IKEv2 protocol tests"""
5823    check_eap_capa(dev[0], "IKEV2")
5824
5825    global eap_proto_ikev2_test_done
5826    eap_proto_ikev2_test_done = False
5827
5828    def ikev2_handler(ctx, req):
5829        logger.info("ikev2_handler - RX " + binascii.hexlify(req).decode())
5830        if 'num' not in ctx:
5831            ctx['num'] = 0
5832        ctx['num'] = ctx['num'] + 1
5833        if 'id' not in ctx:
5834            ctx['id'] = 1
5835        ctx['id'] = (ctx['id'] + 1) % 256
5836
5837        idx = 0
5838
5839        idx += 1
5840        if ctx['num'] == idx:
5841            logger.info("Test: Missing payload")
5842            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
5843                               4 + 1,
5844                               EAP_TYPE_IKEV2)
5845
5846        idx += 1
5847        if ctx['num'] == idx:
5848            logger.info("Test: Truncated Message Length field")
5849            return struct.pack(">BBHBB3B", EAP_CODE_REQUEST, ctx['id'],
5850                               4 + 1 + 1 + 3,
5851                               EAP_TYPE_IKEV2, 0x80, 0, 0, 0)
5852
5853        idx += 1
5854        if ctx['num'] == idx:
5855            logger.info("Test: Too short Message Length value")
5856            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
5857                               4 + 1 + 1 + 4 + 1,
5858                               EAP_TYPE_IKEV2, 0x80, 0, 1)
5859
5860        idx += 1
5861        if ctx['num'] == idx:
5862            logger.info("Test: Truncated message")
5863            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
5864                               4 + 1 + 1 + 4,
5865                               EAP_TYPE_IKEV2, 0x80, 1)
5866
5867        idx += 1
5868        if ctx['num'] == idx:
5869            logger.info("Test: Truncated message(2)")
5870            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
5871                               4 + 1 + 1 + 4,
5872                               EAP_TYPE_IKEV2, 0x80, 0xffffffff)
5873
5874        idx += 1
5875        if ctx['num'] == idx:
5876            logger.info("Test: Truncated message(3)")
5877            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
5878                               4 + 1 + 1 + 4,
5879                               EAP_TYPE_IKEV2, 0xc0, 0xffffffff)
5880
5881        idx += 1
5882        if ctx['num'] == idx:
5883            logger.info("Test: Truncated message(4)")
5884            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
5885                               4 + 1 + 1 + 4,
5886                               EAP_TYPE_IKEV2, 0xc0, 10000000)
5887
5888        idx += 1
5889        if ctx['num'] == idx:
5890            logger.info("Test: Too long fragments (first fragment)")
5891            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
5892                               4 + 1 + 1 + 4 + 1,
5893                               EAP_TYPE_IKEV2, 0xc0, 2, 1)
5894
5895        idx += 1
5896        if ctx['num'] == idx:
5897            logger.info("Test: Too long fragments (second fragment)")
5898            return struct.pack(">BBHBB2B", EAP_CODE_REQUEST, ctx['id'],
5899                               4 + 1 + 1 + 2,
5900                               EAP_TYPE_IKEV2, 0x00, 2, 3)
5901
5902        idx += 1
5903        if ctx['num'] == idx:
5904            logger.info("Test: No Message Length field in first fragment")
5905            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
5906                               4 + 1 + 1 + 1,
5907                               EAP_TYPE_IKEV2, 0x40, 1)
5908
5909        idx += 1
5910        if ctx['num'] == idx:
5911            logger.info("Test: ICV before keys")
5912            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
5913                               4 + 1 + 1,
5914                               EAP_TYPE_IKEV2, 0x20)
5915
5916        idx += 1
5917        if ctx['num'] == idx:
5918            logger.info("Test: Unsupported IKEv2 header version")
5919            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5920                               4 + 1 + 1 + 28,
5921                               EAP_TYPE_IKEV2, 0x00,
5922                               0, 0, 0, 0,
5923                               0, 0, 0, 0, 0, 0)
5924
5925        idx += 1
5926        if ctx['num'] == idx:
5927            logger.info("Test: Incorrect IKEv2 header Length")
5928            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5929                               4 + 1 + 1 + 28,
5930                               EAP_TYPE_IKEV2, 0x00,
5931                               0, 0, 0, 0,
5932                               0, 0x20, 0, 0, 0, 0)
5933
5934        idx += 1
5935        if ctx['num'] == idx:
5936            logger.info("Test: Unexpected IKEv2 Exchange Type in SA_INIT state")
5937            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5938                               4 + 1 + 1 + 28,
5939                               EAP_TYPE_IKEV2, 0x00,
5940                               0, 0, 0, 0,
5941                               0, 0x20, 0, 0, 0, 28)
5942
5943        idx += 1
5944        if ctx['num'] == idx:
5945            logger.info("Test: Unexpected IKEv2 Message ID in SA_INIT state")
5946            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5947                               4 + 1 + 1 + 28,
5948                               EAP_TYPE_IKEV2, 0x00,
5949                               0, 0, 0, 0,
5950                               0, 0x20, 34, 0, 1, 28)
5951
5952        idx += 1
5953        if ctx['num'] == idx:
5954            logger.info("Test: Unexpected IKEv2 Flags value")
5955            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5956                               4 + 1 + 1 + 28,
5957                               EAP_TYPE_IKEV2, 0x00,
5958                               0, 0, 0, 0,
5959                               0, 0x20, 34, 0, 0, 28)
5960
5961        idx += 1
5962        if ctx['num'] == idx:
5963            logger.info("Test: Unexpected IKEv2 Flags value(2)")
5964            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5965                               4 + 1 + 1 + 28,
5966                               EAP_TYPE_IKEV2, 0x00,
5967                               0, 0, 0, 0,
5968                               0, 0x20, 34, 0x20, 0, 28)
5969
5970        idx += 1
5971        if ctx['num'] == idx:
5972            logger.info("Test: No SAi1 in SA_INIT")
5973            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5974                               4 + 1 + 1 + 28,
5975                               EAP_TYPE_IKEV2, 0x00,
5976                               0, 0, 0, 0,
5977                               0, 0x20, 34, 0x08, 0, 28)
5978
5979        def build_ike(id, next=0, exch_type=34, flags=0x00, ike=b''):
5980            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, id,
5981                               4 + 1 + 1 + 28 + len(ike),
5982                               EAP_TYPE_IKEV2, flags,
5983                               0, 0, 0, 0,
5984                               next, 0x20, exch_type, 0x08, 0,
5985                               28 + len(ike)) + ike
5986
5987        idx += 1
5988        if ctx['num'] == idx:
5989            logger.info("Test: Unexpected extra data after payloads")
5990            return build_ike(ctx['id'], ike=struct.pack(">B", 1))
5991
5992        idx += 1
5993        if ctx['num'] == idx:
5994            logger.info("Test: Truncated payload header")
5995            return build_ike(ctx['id'], next=128, ike=struct.pack(">B", 1))
5996
5997        idx += 1
5998        if ctx['num'] == idx:
5999            logger.info("Test: Too small payload header length")
6000            ike = struct.pack(">BBH", 0, 0, 3)
6001            return build_ike(ctx['id'], next=128, ike=ike)
6002
6003        idx += 1
6004        if ctx['num'] == idx:
6005            logger.info("Test: Too large payload header length")
6006            ike = struct.pack(">BBH", 0, 0, 5)
6007            return build_ike(ctx['id'], next=128, ike=ike)
6008
6009        idx += 1
6010        if ctx['num'] == idx:
6011            logger.info("Test: Unsupported payload (non-critical and critical)")
6012            ike = struct.pack(">BBHBBH", 129, 0, 4, 0, 0x01, 4)
6013            return build_ike(ctx['id'], next=128, ike=ike)
6014
6015        idx += 1
6016        if ctx['num'] == idx:
6017            logger.info("Test: Certificate and empty SAi1")
6018            ike = struct.pack(">BBHBBH", 33, 0, 4, 0, 0, 4)
6019            return build_ike(ctx['id'], next=37, ike=ike)
6020
6021        idx += 1
6022        if ctx['num'] == idx:
6023            logger.info("Test: Too short proposal")
6024            ike = struct.pack(">BBHBBHBBB", 0, 0, 4 + 7,
6025                              0, 0, 7, 0, 0, 0)
6026            return build_ike(ctx['id'], next=33, ike=ike)
6027
6028        idx += 1
6029        if ctx['num'] == idx:
6030            logger.info("Test: Too small proposal length in SAi1")
6031            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6032                              0, 0, 7, 0, 0, 0, 0)
6033            return build_ike(ctx['id'], next=33, ike=ike)
6034
6035        idx += 1
6036        if ctx['num'] == idx:
6037            logger.info("Test: Too large proposal length in SAi1")
6038            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6039                              0, 0, 9, 0, 0, 0, 0)
6040            return build_ike(ctx['id'], next=33, ike=ike)
6041
6042        idx += 1
6043        if ctx['num'] == idx:
6044            logger.info("Test: Unexpected proposal type in SAi1")
6045            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6046                              1, 0, 8, 0, 0, 0, 0)
6047            return build_ike(ctx['id'], next=33, ike=ike)
6048
6049        idx += 1
6050        if ctx['num'] == idx:
6051            logger.info("Test: Unexpected Protocol ID in SAi1")
6052            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6053                              0, 0, 8, 0, 0, 0, 0)
6054            return build_ike(ctx['id'], next=33, ike=ike)
6055
6056        idx += 1
6057        if ctx['num'] == idx:
6058            logger.info("Test: Unexpected proposal number in SAi1")
6059            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6060                              0, 0, 8, 0, 1, 0, 0)
6061            return build_ike(ctx['id'], next=33, ike=ike)
6062
6063        idx += 1
6064        if ctx['num'] == idx:
6065            logger.info("Test: Not enough room for SPI in SAi1")
6066            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6067                              0, 0, 8, 1, 1, 1, 0)
6068            return build_ike(ctx['id'], next=33, ike=ike)
6069
6070        idx += 1
6071        if ctx['num'] == idx:
6072            logger.info("Test: Unexpected SPI in SAi1")
6073            ike = struct.pack(">BBHBBHBBBBB", 0, 0, 4 + 9,
6074                              0, 0, 9, 1, 1, 1, 0, 1)
6075            return build_ike(ctx['id'], next=33, ike=ike)
6076
6077        idx += 1
6078        if ctx['num'] == idx:
6079            logger.info("Test: No transforms in SAi1")
6080            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6081                              0, 0, 8, 1, 1, 0, 0)
6082            return build_ike(ctx['id'], next=33, ike=ike)
6083
6084        idx += 1
6085        if ctx['num'] == idx:
6086            logger.info("Test: Too short transform in SAi1")
6087            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6088                              0, 0, 8, 1, 1, 0, 1)
6089            return build_ike(ctx['id'], next=33, ike=ike)
6090
6091        idx += 1
6092        if ctx['num'] == idx:
6093            logger.info("Test: Too small transform length in SAi1")
6094            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
6095                              0, 0, 8 + 8, 1, 1, 0, 1,
6096                              0, 0, 7, 0, 0, 0)
6097            return build_ike(ctx['id'], next=33, ike=ike)
6098
6099        idx += 1
6100        if ctx['num'] == idx:
6101            logger.info("Test: Too large transform length in SAi1")
6102            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
6103                              0, 0, 8 + 8, 1, 1, 0, 1,
6104                              0, 0, 9, 0, 0, 0)
6105            return build_ike(ctx['id'], next=33, ike=ike)
6106
6107        idx += 1
6108        if ctx['num'] == idx:
6109            logger.info("Test: Unexpected Transform type in SAi1")
6110            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
6111                              0, 0, 8 + 8, 1, 1, 0, 1,
6112                              1, 0, 8, 0, 0, 0)
6113            return build_ike(ctx['id'], next=33, ike=ike)
6114
6115        idx += 1
6116        if ctx['num'] == idx:
6117            logger.info("Test: No transform attributes in SAi1")
6118            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
6119                              0, 0, 8 + 8, 1, 1, 0, 1,
6120                              0, 0, 8, 0, 0, 0)
6121            return build_ike(ctx['id'], next=33, ike=ike)
6122
6123        idx += 1
6124        if ctx['num'] == idx:
6125            logger.info("Test: No transform attr for AES and unexpected data after transforms in SAi1")
6126            tlen1 = 8 + 3
6127            tlen2 = 8 + 4
6128            tlen3 = 8 + 4
6129            tlen = tlen1 + tlen2 + tlen3
6130            ike = struct.pack(">BBHBBHBBBBBBHBBH3BBBHBBHHHBBHBBHHHB",
6131                              0, 0, 4 + 8 + tlen + 1,
6132                              0, 0, 8 + tlen + 1, 1, 1, 0, 3,
6133                              3, 0, tlen1, 1, 0, 12, 1, 2, 3,
6134                              3, 0, tlen2, 1, 0, 12, 0, 128,
6135                              0, 0, tlen3, 1, 0, 12, 0x8000 | 14, 127,
6136                              1)
6137            return build_ike(ctx['id'], next=33, ike=ike)
6138
6139        def build_sa(next=0):
6140            tlen = 5 * 8
6141            return struct.pack(">BBHBBHBBBBBBHBBHBBHBBHBBHBBHBBHBBHBBHBBH",
6142                               next, 0, 4 + 8 + tlen,
6143                               0, 0, 8 + tlen, 1, 1, 0, 5,
6144                               3, 0, 8, 1, 0, 3,
6145                               3, 0, 8, 2, 0, 1,
6146                               3, 0, 8, 3, 0, 1,
6147                               3, 0, 8, 4, 0, 5,
6148                               0, 0, 8, 241, 0, 0)
6149
6150        idx += 1
6151        if ctx['num'] == idx:
6152            logger.info("Test: Valid proposal, but no KEi in SAi1")
6153            ike = build_sa()
6154            return build_ike(ctx['id'], next=33, ike=ike)
6155
6156        idx += 1
6157        if ctx['num'] == idx:
6158            logger.info("Test: Empty KEi in SAi1")
6159            ike = build_sa(next=34) + struct.pack(">BBH", 0, 0, 4)
6160            return build_ike(ctx['id'], next=33, ike=ike)
6161
6162        idx += 1
6163        if ctx['num'] == idx:
6164            logger.info("Test: Mismatch in DH Group in SAi1")
6165            ike = build_sa(next=34)
6166            ike += struct.pack(">BBHHH", 0, 0, 4 + 4 + 96, 12345, 0)
6167            ike += 96*b'\x00'
6168            return build_ike(ctx['id'], next=33, ike=ike)
6169        idx += 1
6170        if ctx['num'] == idx:
6171            logger.info("Test: EAP-Failure")
6172            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6173
6174        idx += 1
6175        if ctx['num'] == idx:
6176            logger.info("Test: Invalid DH public value length in SAi1")
6177            ike = build_sa(next=34)
6178            ike += struct.pack(">BBHHH", 0, 0, 4 + 4 + 96, 5, 0)
6179            ike += 96*b'\x00'
6180            return build_ike(ctx['id'], next=33, ike=ike)
6181
6182        def build_ke(next=0):
6183            ke = struct.pack(">BBHHH", next, 0, 4 + 4 + 192, 5, 0)
6184            ke += 191*b'\x00'+b'\x02'
6185            return ke
6186
6187        idx += 1
6188        if ctx['num'] == idx:
6189            logger.info("Test: Valid proposal and KEi, but no Ni in SAi1")
6190            ike = build_sa(next=34)
6191            ike += build_ke()
6192            return build_ike(ctx['id'], next=33, ike=ike)
6193
6194        idx += 1
6195        if ctx['num'] == idx:
6196            logger.info("Test: Too short Ni in SAi1")
6197            ike = build_sa(next=34)
6198            ike += build_ke(next=40)
6199            ike += struct.pack(">BBH", 0, 0, 4)
6200            return build_ike(ctx['id'], next=33, ike=ike)
6201
6202        idx += 1
6203        if ctx['num'] == idx:
6204            logger.info("Test: Too long Ni in SAi1")
6205            ike = build_sa(next=34)
6206            ike += build_ke(next=40)
6207            ike += struct.pack(">BBH", 0, 0, 4 + 257) + 257*b'\x00'
6208            return build_ike(ctx['id'], next=33, ike=ike)
6209
6210        def build_ni(next=0):
6211            return struct.pack(">BBH", next, 0, 4 + 256) + 256*b'\x00'
6212
6213        def build_sai1(id):
6214            ike = build_sa(next=34)
6215            ike += build_ke(next=40)
6216            ike += build_ni()
6217            return build_ike(ctx['id'], next=33, ike=ike)
6218
6219        idx += 1
6220        if ctx['num'] == idx:
6221            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
6222            return build_sai1(ctx['id'])
6223        idx += 1
6224        if ctx['num'] == idx:
6225            logger.info("Test: EAP-Failure")
6226            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6227
6228        idx += 1
6229        if ctx['num'] == idx:
6230            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
6231            return build_sai1(ctx['id'])
6232        idx += 1
6233        if ctx['num'] == idx:
6234            logger.info("Test: No integrity checksum")
6235            ike = b''
6236            return build_ike(ctx['id'], next=37, ike=ike)
6237
6238        idx += 1
6239        if ctx['num'] == idx:
6240            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
6241            return build_sai1(ctx['id'])
6242        idx += 1
6243        if ctx['num'] == idx:
6244            logger.info("Test: Truncated integrity checksum")
6245            return struct.pack(">BBHBB",
6246                               EAP_CODE_REQUEST, ctx['id'],
6247                               4 + 1 + 1,
6248                               EAP_TYPE_IKEV2, 0x20)
6249
6250        idx += 1
6251        if ctx['num'] == idx:
6252            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
6253            return build_sai1(ctx['id'])
6254        idx += 1
6255        if ctx['num'] == idx:
6256            logger.info("Test: Invalid integrity checksum")
6257            ike = b''
6258            return build_ike(ctx['id'], next=37, flags=0x20, ike=ike)
6259
6260        idx += 1
6261        if ctx['num'] == idx:
6262            logger.info("No more test responses available - test case completed")
6263            global eap_proto_ikev2_test_done
6264            eap_proto_ikev2_test_done = True
6265            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
6266                               4 + 1,
6267                               EAP_TYPE_IKEV2)
6268        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6269
6270    srv = start_radius_server(ikev2_handler)
6271
6272    try:
6273        hapd = start_ap(apdev[0])
6274        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
6275
6276        i = 0
6277        while not eap_proto_ikev2_test_done:
6278            i += 1
6279            logger.info("Running connection iteration %d" % i)
6280            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
6281                           eap="IKEV2", identity="user",
6282                           password="password",
6283                           wait_connect=False)
6284            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15)
6285            if ev is None:
6286                raise Exception("Timeout on EAP start")
6287            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
6288                                   timeout=15)
6289            if ev is None:
6290                raise Exception("Timeout on EAP method start")
6291            if i in [41, 46]:
6292                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
6293                                       timeout=10)
6294                if ev is None:
6295                    raise Exception("Timeout on EAP failure")
6296            else:
6297                time.sleep(0.05)
6298            dev[0].request("REMOVE_NETWORK all")
6299            dev[0].wait_disconnected()
6300            dev[0].dump_monitor()
6301            dev[1].dump_monitor()
6302            dev[2].dump_monitor()
6303    finally:
6304        stop_radius_server(srv)
6305
6306def NtPasswordHash(password):
6307    pw = password.encode('utf_16_le')
6308    return hashlib.new('md4', pw).digest()
6309
6310def HashNtPasswordHash(password_hash):
6311    return hashlib.new('md4', password_hash).digest()
6312
6313def ChallengeHash(peer_challenge, auth_challenge, username):
6314    data = peer_challenge + auth_challenge + username
6315    return hashlib.sha1(data).digest()[0:8]
6316
6317def GenerateAuthenticatorResponse(password, nt_response, peer_challenge,
6318                                  auth_challenge, username):
6319    magic1 = binascii.unhexlify("4D616769632073657276657220746F20636C69656E74207369676E696E6720636F6E7374616E74")
6320    magic2 = binascii.unhexlify("50616420746F206D616B6520697420646F206D6F7265207468616E206F6E6520697465726174696F6E")
6321
6322    password_hash = NtPasswordHash(password)
6323    password_hash_hash = HashNtPasswordHash(password_hash)
6324    data = password_hash_hash + nt_response + magic1
6325    digest = hashlib.sha1(data).digest()
6326
6327    challenge = ChallengeHash(peer_challenge, auth_challenge, username.encode())
6328
6329    data = digest + challenge + magic2
6330    resp = hashlib.sha1(data).digest()
6331    return resp
6332
6333def test_eap_proto_ikev2_errors(dev, apdev):
6334    """EAP-IKEv2 local error cases"""
6335    check_eap_capa(dev[0], "IKEV2")
6336    params = hostapd.wpa2_eap_params(ssid="eap-test")
6337    hapd = hostapd.add_ap(apdev[0], params)
6338    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
6339
6340    for i in range(1, 5):
6341        with alloc_fail(dev[0], i, "eap_ikev2_init"):
6342            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
6343                           eap="IKEV2", identity="ikev2 user",
6344                           password="ike password",
6345                           wait_connect=False)
6346            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
6347                                   timeout=15)
6348            if ev is None:
6349                raise Exception("Timeout on EAP start")
6350            dev[0].request("REMOVE_NETWORK all")
6351            dev[0].wait_disconnected()
6352
6353    tests = [(1, "ikev2_encr_encrypt"),
6354             (1, "ikev2_encr_decrypt"),
6355             (1, "ikev2_derive_auth_data"),
6356             (2, "ikev2_derive_auth_data"),
6357             (1, "=ikev2_decrypt_payload"),
6358             (1, "ikev2_encr_decrypt;ikev2_decrypt_payload"),
6359             (1, "ikev2_encr_encrypt;ikev2_build_encrypted"),
6360             (1, "ikev2_derive_sk_keys"),
6361             (2, "ikev2_derive_sk_keys"),
6362             (3, "ikev2_derive_sk_keys"),
6363             (4, "ikev2_derive_sk_keys"),
6364             (5, "ikev2_derive_sk_keys"),
6365             (6, "ikev2_derive_sk_keys"),
6366             (7, "ikev2_derive_sk_keys"),
6367             (8, "ikev2_derive_sk_keys"),
6368             (1, "eap_ikev2_derive_keymat;eap_ikev2_peer_keymat"),
6369             (1, "eap_msg_alloc;eap_ikev2_build_msg"),
6370             (1, "eap_ikev2_getKey"),
6371             (1, "eap_ikev2_get_emsk"),
6372             (1, "eap_ikev2_get_session_id"),
6373             (1, "=ikev2_derive_keys"),
6374             (2, "=ikev2_derive_keys"),
6375             (1, "wpabuf_alloc;ikev2_process_kei"),
6376             (1, "=ikev2_process_idi"),
6377             (1, "ikev2_derive_auth_data;ikev2_build_auth"),
6378             (1, "wpabuf_alloc;ikev2_build_sa_init"),
6379             (2, "wpabuf_alloc;ikev2_build_sa_init"),
6380             (3, "wpabuf_alloc;ikev2_build_sa_init"),
6381             (4, "wpabuf_alloc;ikev2_build_sa_init"),
6382             (5, "wpabuf_alloc;ikev2_build_sa_init"),
6383             (6, "wpabuf_alloc;ikev2_build_sa_init"),
6384             (1, "wpabuf_alloc;ikev2_build_sa_auth"),
6385             (2, "wpabuf_alloc;ikev2_build_sa_auth"),
6386             (1, "ikev2_build_auth;ikev2_build_sa_auth")]
6387    for count, func in tests:
6388        with alloc_fail(dev[0], count, func):
6389            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
6390                           eap="IKEV2", identity="ikev2 user@domain",
6391                           password="ike password", erp="1", wait_connect=False)
6392            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
6393                                   timeout=15)
6394            if ev is None:
6395                raise Exception("Timeout on EAP start")
6396            ok = False
6397            for j in range(10):
6398                state = dev[0].request('GET_ALLOC_FAIL')
6399                if state.startswith('0:'):
6400                    ok = True
6401                    break
6402                time.sleep(0.1)
6403            if not ok:
6404                raise Exception("No allocation failure seen for %d:%s" % (count, func))
6405            dev[0].request("REMOVE_NETWORK all")
6406            dev[0].wait_disconnected()
6407
6408    tests = [(1, "wpabuf_alloc;ikev2_build_notify"),
6409             (2, "wpabuf_alloc;ikev2_build_notify"),
6410             (1, "ikev2_build_encrypted;ikev2_build_notify")]
6411    for count, func in tests:
6412        with alloc_fail(dev[0], count, func):
6413            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
6414                           eap="IKEV2", identity="ikev2 user",
6415                           password="wrong password", erp="1",
6416                           wait_connect=False)
6417            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
6418                                   timeout=15)
6419            if ev is None:
6420                raise Exception("Timeout on EAP start")
6421            ok = False
6422            for j in range(10):
6423                state = dev[0].request('GET_ALLOC_FAIL')
6424                if state.startswith('0:'):
6425                    ok = True
6426                    break
6427                time.sleep(0.1)
6428            if not ok:
6429                raise Exception("No allocation failure seen for %d:%s" % (count, func))
6430            dev[0].request("REMOVE_NETWORK all")
6431            dev[0].wait_disconnected()
6432
6433    tests = [(1, "ikev2_integ_hash"),
6434             (1, "ikev2_integ_hash;ikev2_decrypt_payload"),
6435             (1, "os_get_random;ikev2_build_encrypted"),
6436             (1, "ikev2_prf_plus;ikev2_derive_sk_keys"),
6437             (1, "eap_ikev2_derive_keymat;eap_ikev2_peer_keymat"),
6438             (1, "os_get_random;ikev2_build_sa_init"),
6439             (2, "os_get_random;ikev2_build_sa_init"),
6440             (1, "ikev2_integ_hash;eap_ikev2_validate_icv"),
6441             (1, "hmac_sha1_vector;?ikev2_prf_hash;ikev2_derive_keys"),
6442             (1, "hmac_sha1_vector;?ikev2_prf_hash;ikev2_derive_auth_data"),
6443             (2, "hmac_sha1_vector;?ikev2_prf_hash;ikev2_derive_auth_data"),
6444             (3, "hmac_sha1_vector;?ikev2_prf_hash;ikev2_derive_auth_data")]
6445    for count, func in tests:
6446        with fail_test(dev[0], count, func):
6447            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
6448                           eap="IKEV2", identity="ikev2 user",
6449                           password="ike password", wait_connect=False)
6450            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
6451                                   timeout=15)
6452            if ev is None:
6453                raise Exception("Timeout on EAP start")
6454            ok = False
6455            for j in range(10):
6456                state = dev[0].request('GET_FAIL')
6457                if state.startswith('0:'):
6458                    ok = True
6459                    break
6460                time.sleep(0.1)
6461            if not ok:
6462                raise Exception("No failure seen for %d:%s" % (count, func))
6463            dev[0].request("REMOVE_NETWORK all")
6464            dev[0].wait_disconnected()
6465
6466    params = {"ssid": "eap-test2", "wpa": "2", "wpa_key_mgmt": "WPA-EAP",
6467              "rsn_pairwise": "CCMP", "ieee8021x": "1",
6468              "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf",
6469              "fragment_size": "50"}
6470    hapd2 = hostapd.add_ap(apdev[1], params)
6471    dev[0].scan_for_bss(hapd2.own_addr(), freq=2412)
6472
6473    tests = [(1, "eap_ikev2_build_frag_ack"),
6474             (1, "wpabuf_alloc;eap_ikev2_process_fragment")]
6475    for count, func in tests:
6476        with alloc_fail(dev[0], count, func):
6477            dev[0].connect("eap-test2", key_mgmt="WPA-EAP", scan_freq="2412",
6478                           eap="IKEV2", identity="ikev2 user",
6479                           password="ike password", erp="1", wait_connect=False)
6480            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
6481                                   timeout=15)
6482            if ev is None:
6483                raise Exception("Timeout on EAP start")
6484            ok = False
6485            for j in range(10):
6486                state = dev[0].request('GET_ALLOC_FAIL')
6487                if state.startswith('0:'):
6488                    ok = True
6489                    break
6490                time.sleep(0.1)
6491            if not ok:
6492                raise Exception("No allocation failure seen for %d:%s" % (count, func))
6493            dev[0].request("REMOVE_NETWORK all")
6494            dev[0].wait_disconnected()
6495
6496def run_eap_ikev2_connect(dev):
6497    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
6498                eap="IKEV2", identity="ikev2 user",
6499                password="ike password",
6500                fragment_size="30", wait_connect=False)
6501    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
6502                         "CTRL-EVENT-DISCONNECTED"],
6503                        timeout=1)
6504    dev.request("REMOVE_NETWORK all")
6505    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
6506        dev.wait_disconnected()
6507    ev = dev.wait_event(["CTRL-EVENT-NETWORK-REMOVED"], timeout=1)
6508    if ev is None:
6509        raise Exception("Network removal not reported")
6510    time.sleep(0.01)
6511    dev.dump_monitor()
6512
6513def test_eap_proto_ikev2_errors_server(dev, apdev):
6514    """EAP-IKEV2 local error cases on server"""
6515    check_eap_capa(dev[0], "IKEV2")
6516    params = int_eap_server_params()
6517    params['erp_domain'] = 'example.com'
6518    params['eap_server_erp'] = '1'
6519    hapd = hostapd.add_ap(apdev[0], params)
6520    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
6521
6522    tests = [(1, "eap_ikev2_init"),
6523             (2, "=eap_ikev2_init"),
6524             (3, "=eap_ikev2_init"),
6525             (1, "eap_msg_alloc;eap_ikev2_build_msg"),
6526             (1, "ikev2_initiator_build;eap_ikev2_buildReq"),
6527             (1, "eap_ikev2_process_fragment"),
6528             (1, "wpabuf_alloc_copy;ikev2_process_ker"),
6529             (1, "ikev2_process_idr"),
6530             (1, "ikev2_derive_auth_data;ikev2_process_auth_secret"),
6531             (1, "ikev2_decrypt_payload;ikev2_process_sa_auth"),
6532             (1, "ikev2_process_sa_auth_decrypted;ikev2_process_sa_auth"),
6533             (1, "dh_init;ikev2_build_kei"),
6534             (1, "ikev2_build_auth"),
6535             (1, "wpabuf_alloc;ikev2_build_sa_init"),
6536             (1, "ikev2_build_sa_auth"),
6537             (1, "=ikev2_build_sa_auth"),
6538             (2, "=ikev2_derive_auth_data"),
6539             (1, "wpabuf_alloc;ikev2_build_sa_auth"),
6540             (2, "wpabuf_alloc;=ikev2_build_sa_auth"),
6541             (1, "ikev2_decrypt_payload;ikev2_process_sa_init_encr"),
6542             (1, "dh_derive_shared;ikev2_derive_keys"),
6543             (1, "=ikev2_derive_keys"),
6544             (2, "=ikev2_derive_keys"),
6545             (1, "eap_ikev2_getKey"),
6546             (1, "eap_ikev2_get_emsk"),
6547             (1, "eap_ikev2_get_session_id")]
6548    for count, func in tests:
6549        with alloc_fail(hapd, count, func):
6550            run_eap_ikev2_connect(dev[0])
6551
6552    tests = [(1, "eap_ikev2_validate_icv;eap_ikev2_process_icv"),
6553             (1, "eap_ikev2_server_keymat"),
6554             (1, "ikev2_build_auth"),
6555             (1, "os_get_random;ikev2_build_sa_init"),
6556             (2, "os_get_random;ikev2_build_sa_init"),
6557             (1, "ikev2_derive_keys"),
6558             (2, "ikev2_derive_keys"),
6559             (3, "ikev2_derive_keys"),
6560             (4, "ikev2_derive_keys"),
6561             (5, "ikev2_derive_keys"),
6562             (6, "ikev2_derive_keys"),
6563             (7, "ikev2_derive_keys"),
6564             (8, "ikev2_derive_keys"),
6565             (1, "ikev2_decrypt_payload;ikev2_process_sa_auth"),
6566             (1, "eap_ikev2_process_icv;eap_ikev2_process")]
6567    for count, func in tests:
6568        with fail_test(hapd, count, func):
6569            run_eap_ikev2_connect(dev[0])
6570
6571def start_ikev2_assoc(dev, hapd):
6572    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
6573                eap="IKEV2", identity="ikev2 user",
6574                password="ike password", wait_connect=False)
6575    proxy_msg(hapd, dev) # EAP-Identity/Request
6576    proxy_msg(dev, hapd) # EAP-Identity/Response
6577    proxy_msg(hapd, dev) # IKEV2 1
6578
6579def stop_ikev2_assoc(dev, hapd):
6580    dev.request("REMOVE_NETWORK all")
6581    dev.wait_disconnected()
6582    dev.dump_monitor()
6583    hapd.dump_monitor()
6584
6585def test_eap_proto_ikev2_server(dev, apdev):
6586    """EAP-IKEV2 protocol testing for the server"""
6587    check_eap_capa(dev[0], "IKEV2")
6588    params = int_eap_server_params()
6589    params['erp_domain'] = 'example.com'
6590    params['eap_server_erp'] = '1'
6591    hapd = hostapd.add_ap(apdev[0], params)
6592    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
6593    hapd.request("SET ext_eapol_frame_io 1")
6594    dev[0].request("SET ext_eapol_frame_io 1")
6595
6596    # Successful exchange to verify proxying mechanism
6597    start_ikev2_assoc(dev[0], hapd)
6598    proxy_msg(dev[0], hapd) # IKEV2 2
6599    proxy_msg(hapd, dev[0]) # IKEV2 3
6600    proxy_msg(dev[0], hapd) # IKEV2 4
6601    proxy_msg(hapd, dev[0]) # EAP-Success
6602    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 1/4
6603    proxy_msg(dev[0], hapd) # EAPOL-Key msg 2/4
6604    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 3/4
6605    proxy_msg(dev[0], hapd) # EAPOL-Key msg 4/4
6606    dev[0].wait_connected()
6607    stop_ikev2_assoc(dev[0], hapd)
6608
6609    start_ikev2_assoc(dev[0], hapd)
6610    resp = rx_msg(dev[0])
6611    # Too short EAP-IKEV2 header
6612    hapd.note("IKEV2: Too short frame to include HDR")
6613    msg = resp[0:4] + "0005" + resp[8:12] + "0005" + "31"
6614    tx_msg(dev[0], hapd, msg)
6615    rx_msg(hapd)
6616    stop_ikev2_assoc(dev[0], hapd)
6617
6618    start_ikev2_assoc(dev[0], hapd)
6619    resp = rx_msg(dev[0])
6620    # Too short EAP-IKEV2 header - missing Message Length field
6621    hapd.note("EAP-IKEV2: Message underflow")
6622    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "3180"
6623    tx_msg(dev[0], hapd, msg)
6624    rx_msg(hapd)
6625    stop_ikev2_assoc(dev[0], hapd)
6626
6627    start_ikev2_assoc(dev[0], hapd)
6628    resp = rx_msg(dev[0])
6629    # Too short EAP-IKEV2 header - too small Message Length
6630    hapd.note("EAP-IKEV2: Invalid Message Length (0; 1 remaining in this msg)")
6631    msg = resp[0:4] + "000b" + resp[8:12] + "000b" + "318000000000ff"
6632    tx_msg(dev[0], hapd, msg)
6633    rx_msg(hapd)
6634    stop_ikev2_assoc(dev[0], hapd)
6635
6636    start_ikev2_assoc(dev[0], hapd)
6637    resp = rx_msg(dev[0])
6638    # Too short EAP-IKEV2 header - too large Message Length
6639    hapd.note("EAP-IKEV2: Ignore too long message")
6640    msg = resp[0:4] + "000b" + resp[8:12] + "000b" + "31c0bbccddeeff"
6641    tx_msg(dev[0], hapd, msg)
6642    rx_msg(hapd)
6643    stop_ikev2_assoc(dev[0], hapd)
6644
6645    start_ikev2_assoc(dev[0], hapd)
6646    resp = rx_msg(dev[0])
6647    # No Message Length in first fragment
6648    hapd.note("EAP-IKEV2: No Message Length field in a fragmented packet")
6649    msg = resp[0:4] + "0007" + resp[8:12] + "0007" + "3140ff"
6650    tx_msg(dev[0], hapd, msg)
6651    rx_msg(hapd)
6652    stop_ikev2_assoc(dev[0], hapd)
6653
6654    start_ikev2_assoc(dev[0], hapd)
6655    resp = rx_msg(dev[0])
6656    # First fragment (valid)
6657    hapd.note("EAP-IKEV2: Received 1 bytes in first fragment, waiting for 255 bytes more")
6658    msg = resp[0:4] + "000b" + resp[8:12] + "000b" + "31c000000100ff"
6659    tx_msg(dev[0], hapd, msg)
6660    req = rx_msg(hapd)
6661    id, = struct.unpack('B', binascii.unhexlify(req)[5:6])
6662    hapd.note("EAP-IKEV2: Received 1 bytes in first fragment, waiting for 254 bytes more")
6663    payload = struct.pack('BBB', 49, 0x40, 0)
6664    msg = struct.pack('>BBHBBH', 1, 0, 4 + len(payload), 2, id, 4 + len(payload)) + payload
6665    tx_msg(dev[0], hapd, binascii.hexlify(msg).decode())
6666    req = rx_msg(hapd)
6667    id, = struct.unpack('B', binascii.unhexlify(req)[5:6])
6668    hapd.note("EAP-IKEV2: Fragment overflow")
6669    payload = struct.pack('BB', 49, 0x40) + 255*b'\x00'
6670    msg = struct.pack('>BBHBBH', 1, 0, 4 + len(payload), 2, id, 4 + len(payload)) + payload
6671    tx_msg(dev[0], hapd, binascii.hexlify(msg).decode())
6672    rx_msg(hapd)
6673    stop_ikev2_assoc(dev[0], hapd)
6674
6675    start_ikev2_assoc(dev[0], hapd)
6676    proxy_msg(dev[0], hapd) # IKEV2 2
6677    req = proxy_msg(hapd, dev[0]) # IKEV2 3
6678    id, = struct.unpack('B', binascii.unhexlify(req)[5:6])
6679    # Missing ICV
6680    hapd.note("EAP-IKEV2: The message should have included integrity checksum")
6681    payload = struct.pack('BB', 49, 0) + b'\x00'
6682    msg = struct.pack('>BBHBBH', 1, 0, 4 + len(payload), 2, id, 4 + len(payload)) + payload
6683    tx_msg(dev[0], hapd, binascii.hexlify(msg).decode())
6684    rx_msg(hapd)
6685    stop_ikev2_assoc(dev[0], hapd)
6686
6687    tests = [("Unsupported HDR version 0x0 (expected 0x20)",
6688              struct.pack('BB', 49, 0) + 16*b'\x00' +
6689              struct.pack('>BBBBLL', 0, 0, 0, 0, 0, 0)),
6690             ("IKEV2: Invalid length (HDR: 0 != RX: 28)",
6691              struct.pack('BB', 49, 0) + 16*b'\x00' +
6692              struct.pack('>BBBBLL', 0, 0x20, 0, 0, 0, 0)),
6693             ("IKEV2: Unexpected Exchange Type 0 in SA_INIT state",
6694              struct.pack('BB', 49, 0) + 16*b'\x00' +
6695              struct.pack('>BBBBLL', 0, 0x20, 0, 0, 0, 28)),
6696             ("IKEV2: Unexpected Flags value 0x0",
6697              struct.pack('BB', 49, 0) + 16*b'\x00' +
6698              struct.pack('>BBBBLL', 0, 0x20, 34, 0, 0, 28)),
6699             ("IKEV2: SAr1 not received",
6700              struct.pack('BB', 49, 0) + 16*b'\x00' +
6701              struct.pack('>BBBBLL', 0, 0x20, 34, 0x20, 0, 28))]
6702    for txt, payload in tests:
6703        start_ikev2_assoc(dev[0], hapd)
6704        resp = rx_msg(dev[0])
6705        id, = struct.unpack('B', binascii.unhexlify(resp)[5:6])
6706        hapd.note(txt)
6707        msg = struct.pack('>BBHBBH', 1, 0, 4 + len(payload), 2, id, 4 + len(payload)) + payload
6708        tx_msg(dev[0], hapd, binascii.hexlify(msg).decode())
6709        rx_msg(hapd)
6710        stop_ikev2_assoc(dev[0], hapd)
6711
6712def test_eap_proto_mschapv2(dev, apdev):
6713    """EAP-MSCHAPv2 protocol tests"""
6714    check_eap_capa(dev[0], "MSCHAPV2")
6715
6716    def mschapv2_handler(ctx, req):
6717        logger.info("mschapv2_handler - RX " + binascii.hexlify(req).decode())
6718        if 'num' not in ctx:
6719            ctx['num'] = 0
6720        ctx['num'] = ctx['num'] + 1
6721        if 'id' not in ctx:
6722            ctx['id'] = 1
6723        ctx['id'] = (ctx['id'] + 1) % 256
6724        idx = 0
6725
6726        idx += 1
6727        if ctx['num'] == idx:
6728            logger.info("Test: Missing payload")
6729            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
6730                               4 + 1,
6731                               EAP_TYPE_MSCHAPV2)
6732
6733        idx += 1
6734        if ctx['num'] == idx:
6735            logger.info("Test: Unknown MSCHAPv2 op_code")
6736            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6737                               4 + 1 + 4 + 1,
6738                               EAP_TYPE_MSCHAPV2,
6739                               0, 0, 5, 0)
6740
6741        idx += 1
6742        if ctx['num'] == idx:
6743            logger.info("Test: Invalid ms_len and unknown MSCHAPv2 op_code")
6744            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6745                               4 + 1 + 4 + 1,
6746                               EAP_TYPE_MSCHAPV2,
6747                               255, 0, 0, 0)
6748
6749        idx += 1
6750        if ctx['num'] == idx:
6751            logger.info("Test: Success before challenge")
6752            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6753                               4 + 1 + 4 + 1,
6754                               EAP_TYPE_MSCHAPV2,
6755                               3, 0, 5, 0)
6756
6757        idx += 1
6758        if ctx['num'] == idx:
6759            logger.info("Test: Failure before challenge - required challenge field not present")
6760            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6761                               4 + 1 + 4 + 1,
6762                               EAP_TYPE_MSCHAPV2,
6763                               4, 0, 5, 0)
6764        idx += 1
6765        if ctx['num'] == idx:
6766            logger.info("Test: Failure")
6767            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6768
6769        idx += 1
6770        if ctx['num'] == idx:
6771            logger.info("Test: Failure before challenge - invalid failure challenge len")
6772            payload = b'C=12'
6773            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6774                               4 + 1 + 4 + len(payload),
6775                               EAP_TYPE_MSCHAPV2,
6776                               4, 0, 4 + len(payload)) + payload
6777        idx += 1
6778        if ctx['num'] == idx:
6779            logger.info("Test: Failure")
6780            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6781
6782        idx += 1
6783        if ctx['num'] == idx:
6784            logger.info("Test: Failure before challenge - invalid failure challenge len")
6785            payload = b'C=12 V=3'
6786            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6787                               4 + 1 + 4 + len(payload),
6788                               EAP_TYPE_MSCHAPV2,
6789                               4, 0, 4 + len(payload)) + payload
6790        idx += 1
6791        if ctx['num'] == idx:
6792            logger.info("Test: Failure")
6793            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6794
6795        idx += 1
6796        if ctx['num'] == idx:
6797            logger.info("Test: Failure before challenge - invalid failure challenge")
6798            payload = b'C=00112233445566778899aabbccddeefQ '
6799            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6800                               4 + 1 + 4 + len(payload),
6801                               EAP_TYPE_MSCHAPV2,
6802                               4, 0, 4 + len(payload)) + payload
6803        idx += 1
6804        if ctx['num'] == idx:
6805            logger.info("Test: Failure")
6806            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6807
6808        idx += 1
6809        if ctx['num'] == idx:
6810            logger.info("Test: Failure before challenge - password expired")
6811            payload = b'E=648 R=1 C=00112233445566778899aabbccddeeff V=3 M=Password expired'
6812            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6813                               4 + 1 + 4 + len(payload),
6814                               EAP_TYPE_MSCHAPV2,
6815                               4, 0, 4 + len(payload)) + payload
6816        idx += 1
6817        if ctx['num'] == idx:
6818            logger.info("Test: Success after password change")
6819            payload = b"S=1122334455667788990011223344556677889900"
6820            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6821                               4 + 1 + 4 + len(payload),
6822                               EAP_TYPE_MSCHAPV2,
6823                               3, 0, 4 + len(payload)) + payload
6824
6825        idx += 1
6826        if ctx['num'] == idx:
6827            logger.info("Test: Invalid challenge length")
6828            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6829                               4 + 1 + 4 + 1,
6830                               EAP_TYPE_MSCHAPV2,
6831                               1, 0, 4 + 1, 0)
6832
6833        idx += 1
6834        if ctx['num'] == idx:
6835            logger.info("Test: Too short challenge packet")
6836            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6837                               4 + 1 + 4 + 1,
6838                               EAP_TYPE_MSCHAPV2,
6839                               1, 0, 4 + 1, 16)
6840
6841        idx += 1
6842        if ctx['num'] == idx:
6843            logger.info("Test: Challenge")
6844            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6845                               4 + 1 + 4 + 1 + 16 + 6,
6846                               EAP_TYPE_MSCHAPV2,
6847                               1, 0, 4 + 1 + 16 + 6, 16) + 16*b'A' + b'foobar'
6848        idx += 1
6849        if ctx['num'] == idx:
6850            logger.info("Test: Failure - password expired")
6851            payload = b'E=648 R=1 C=00112233445566778899aabbccddeeff V=3 M=Password expired'
6852            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6853                               4 + 1 + 4 + len(payload),
6854                               EAP_TYPE_MSCHAPV2,
6855                               4, 0, 4 + len(payload)) + payload
6856        idx += 1
6857        if ctx['num'] == idx:
6858            logger.info("Test: Success after password change")
6859            if len(req) != 591:
6860                logger.info("Unexpected Change-Password packet length: %s" % len(req))
6861                return None
6862            data = req[9:]
6863            enc_pw = data[0:516]
6864            data = data[516:]
6865            enc_hash = data[0:16]
6866            data = data[16:]
6867            peer_challenge = data[0:16]
6868            data = data[16:]
6869            # Reserved
6870            data = data[8:]
6871            nt_response = data[0:24]
6872            data = data[24:]
6873            flags = data
6874            logger.info("enc_hash: " + binascii.hexlify(enc_hash).decode())
6875            logger.info("peer_challenge: " + binascii.hexlify(peer_challenge).decode())
6876            logger.info("nt_response: " + binascii.hexlify(nt_response).decode())
6877            logger.info("flags: " + binascii.hexlify(flags).decode())
6878
6879            auth_challenge = binascii.unhexlify("00112233445566778899aabbccddeeff")
6880            logger.info("auth_challenge: " + binascii.hexlify(auth_challenge).decode())
6881
6882            auth_resp = GenerateAuthenticatorResponse("new-pw", nt_response,
6883                                                      peer_challenge,
6884                                                      auth_challenge, "user")
6885            payload = b"S=" + binascii.hexlify(auth_resp).decode().upper().encode()
6886            logger.info("Success message payload: " + payload.decode())
6887            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6888                               4 + 1 + 4 + len(payload),
6889                               EAP_TYPE_MSCHAPV2,
6890                               3, 0, 4 + len(payload)) + payload
6891        idx += 1
6892        if ctx['num'] == idx:
6893            logger.info("Test: EAP-Success")
6894            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
6895
6896        idx += 1
6897        if ctx['num'] == idx:
6898            logger.info("Test: Failure - password expired")
6899            payload = b'E=648 R=1 C=00112233445566778899aabbccddeeff V=3 M=Password expired'
6900            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6901                               4 + 1 + 4 + len(payload),
6902                               EAP_TYPE_MSCHAPV2,
6903                               4, 0, 4 + len(payload)) + payload
6904        idx += 1
6905        if ctx['num'] == idx:
6906            logger.info("Test: Success after password change")
6907            if len(req) != 591:
6908                logger.info("Unexpected Change-Password packet length: %s" % len(req))
6909                return None
6910            data = req[9:]
6911            enc_pw = data[0:516]
6912            data = data[516:]
6913            enc_hash = data[0:16]
6914            data = data[16:]
6915            peer_challenge = data[0:16]
6916            data = data[16:]
6917            # Reserved
6918            data = data[8:]
6919            nt_response = data[0:24]
6920            data = data[24:]
6921            flags = data
6922            logger.info("enc_hash: " + binascii.hexlify(enc_hash).decode())
6923            logger.info("peer_challenge: " + binascii.hexlify(peer_challenge).decode())
6924            logger.info("nt_response: " + binascii.hexlify(nt_response).decode())
6925            logger.info("flags: " + binascii.hexlify(flags).decode())
6926
6927            auth_challenge = binascii.unhexlify("00112233445566778899aabbccddeeff")
6928            logger.info("auth_challenge: " + binascii.hexlify(auth_challenge).decode())
6929
6930            auth_resp = GenerateAuthenticatorResponse("new-pw", nt_response,
6931                                                      peer_challenge,
6932                                                      auth_challenge, "user")
6933            payload = b"S=" + binascii.hexlify(auth_resp).decode().upper().encode()
6934            logger.info("Success message payload: " + payload.decode())
6935            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6936                               4 + 1 + 4 + len(payload),
6937                               EAP_TYPE_MSCHAPV2,
6938                               3, 0, 4 + len(payload)) + payload
6939        idx += 1
6940        if ctx['num'] == idx:
6941            logger.info("Test: EAP-Success")
6942            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
6943
6944        idx += 1
6945        if ctx['num'] == idx:
6946            logger.info("Test: Challenge")
6947            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6948                               4 + 1 + 4 + 1 + 16 + 6,
6949                               EAP_TYPE_MSCHAPV2,
6950                               1, 0, 4 + 1 + 16 + 6, 16) + 16*b'A' + b'foobar'
6951        idx += 1
6952        if ctx['num'] == idx:
6953            logger.info("Test: Failure - authentication failure")
6954            payload = b'E=691 R=1 C=00112233445566778899aabbccddeeff V=3 M=Authentication failed'
6955            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6956                               4 + 1 + 4 + len(payload),
6957                               EAP_TYPE_MSCHAPV2,
6958                               4, 0, 4 + len(payload)) + payload
6959
6960        idx += 1
6961        if ctx['num'] == idx:
6962            logger.info("Test: Challenge")
6963            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6964                               4 + 1 + 4 + 1 + 16 + 6,
6965                               EAP_TYPE_MSCHAPV2,
6966                               1, 0, 4 + 1 + 16 + 6, 16) + 16*b'A' + b'foobar'
6967        idx += 1
6968        if ctx['num'] == idx:
6969            logger.info("Test: Failure - authentication failure")
6970            payload = b'E=691 R=1 C=00112233445566778899aabbccddeeff V=3 M=Authentication failed (2)'
6971            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6972                               4 + 1 + 4 + len(payload),
6973                               EAP_TYPE_MSCHAPV2,
6974                               4, 0, 4 + len(payload)) + payload
6975        idx += 1
6976        if ctx['num'] == idx:
6977            logger.info("Test: Failure")
6978            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6979
6980        idx += 1
6981        if ctx['num'] == idx:
6982            logger.info("Test: Challenge - invalid ms_len and workaround disabled")
6983            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6984                               4 + 1 + 4 + 1 + 16 + 6,
6985                               EAP_TYPE_MSCHAPV2,
6986                               1, 0, 4 + 1 + 16 + 6 + 1, 16) + 16*b'A' + b'foobar'
6987
6988        return None
6989
6990    srv = start_radius_server(mschapv2_handler)
6991
6992    try:
6993        hapd = start_ap(apdev[0])
6994        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
6995
6996        for i in range(0, 16):
6997            logger.info("RUN: %d" % i)
6998            if i == 12:
6999                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7000                               eap="MSCHAPV2", identity="user",
7001                               password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
7002                               wait_connect=False)
7003            elif i == 14:
7004                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7005                               eap="MSCHAPV2", identity="user",
7006                               phase2="mschapv2_retry=0",
7007                               password="password", wait_connect=False)
7008            elif i == 15:
7009                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7010                               eap="MSCHAPV2", identity="user",
7011                               eap_workaround="0",
7012                               password="password", wait_connect=False)
7013            else:
7014                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7015                               eap="MSCHAPV2", identity="user",
7016                               password="password", wait_connect=False)
7017            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
7018            if ev is None:
7019                raise Exception("Timeout on EAP start")
7020
7021            if i in [8, 11, 12]:
7022                ev = dev[0].wait_event(["CTRL-REQ-NEW_PASSWORD"],
7023                                       timeout=10)
7024                if ev is None:
7025                    raise Exception("Timeout on new password request")
7026                id = ev.split(':')[0].split('-')[-1]
7027                dev[0].request("CTRL-RSP-NEW_PASSWORD-" + id + ":new-pw")
7028                if i in [11, 12]:
7029                    ev = dev[0].wait_event(["CTRL-EVENT-PASSWORD-CHANGED"],
7030                                       timeout=10)
7031                    if ev is None:
7032                        raise Exception("Timeout on password change")
7033                    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"],
7034                                       timeout=10)
7035                    if ev is None:
7036                        raise Exception("Timeout on EAP success")
7037                else:
7038                    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
7039                                           timeout=10)
7040                    if ev is None:
7041                        raise Exception("Timeout on EAP failure")
7042
7043            if i in [13]:
7044                ev = dev[0].wait_event(["CTRL-REQ-IDENTITY"],
7045                                       timeout=10)
7046                if ev is None:
7047                    raise Exception("Timeout on identity request")
7048                id = ev.split(':')[0].split('-')[-1]
7049                dev[0].request("CTRL-RSP-IDENTITY-" + id + ":user")
7050
7051                ev = dev[0].wait_event(["CTRL-REQ-PASSWORD"],
7052                                       timeout=10)
7053                if ev is None:
7054                    raise Exception("Timeout on password request")
7055                id = ev.split(':')[0].split('-')[-1]
7056                dev[0].request("CTRL-RSP-PASSWORD-" + id + ":password")
7057
7058                # TODO: Does this work correctly?
7059
7060                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
7061                                       timeout=10)
7062                if ev is None:
7063                    raise Exception("Timeout on EAP failure")
7064
7065            if i in [4, 5, 6, 7, 14]:
7066                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
7067                                       timeout=10)
7068                if ev is None:
7069                    raise Exception("Timeout on EAP failure")
7070            else:
7071                time.sleep(0.05)
7072            dev[0].request("REMOVE_NETWORK all")
7073            dev[0].wait_disconnected(timeout=1)
7074    finally:
7075        stop_radius_server(srv)
7076
7077def test_eap_proto_mschapv2_errors(dev, apdev):
7078    """EAP-MSCHAPv2 protocol tests (error paths)"""
7079    check_eap_capa(dev[0], "MSCHAPV2")
7080
7081    def mschapv2_fail_password_expired(ctx):
7082        logger.info("Test: Failure before challenge - password expired")
7083        payload = b'E=648 R=1 C=00112233445566778899aabbccddeeff V=3 M=Password expired'
7084        return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
7085                           4 + 1 + 4 + len(payload),
7086                           EAP_TYPE_MSCHAPV2,
7087                           4, 0, 4 + len(payload)) + payload
7088
7089    def mschapv2_success_after_password_change(ctx, req=None):
7090        logger.info("Test: Success after password change")
7091        if req is None or len(req) != 591:
7092            payload = b"S=1122334455667788990011223344556677889900"
7093        else:
7094            data = req[9:]
7095            enc_pw = data[0:516]
7096            data = data[516:]
7097            enc_hash = data[0:16]
7098            data = data[16:]
7099            peer_challenge = data[0:16]
7100            data = data[16:]
7101            # Reserved
7102            data = data[8:]
7103            nt_response = data[0:24]
7104            data = data[24:]
7105            flags = data
7106            logger.info("enc_hash: " + binascii.hexlify(enc_hash).decode())
7107            logger.info("peer_challenge: " + binascii.hexlify(peer_challenge).decode())
7108            logger.info("nt_response: " + binascii.hexlify(nt_response).decode())
7109            logger.info("flags: " + binascii.hexlify(flags).decode())
7110
7111            auth_challenge = binascii.unhexlify("00112233445566778899aabbccddeeff")
7112            logger.info("auth_challenge: " + binascii.hexlify(auth_challenge).decode())
7113
7114            auth_resp = GenerateAuthenticatorResponse("new-pw", nt_response,
7115                                                      peer_challenge,
7116                                                      auth_challenge, "user")
7117            payload = b"S=" + binascii.hexlify(auth_resp).decode().upper().encode()
7118        return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
7119                           4 + 1 + 4 + len(payload),
7120                           EAP_TYPE_MSCHAPV2,
7121                           3, 0, 4 + len(payload)) + payload
7122
7123    def mschapv2_handler(ctx, req):
7124        logger.info("mschapv2_handler - RX " + binascii.hexlify(req).decode())
7125        if 'num' not in ctx:
7126            ctx['num'] = 0
7127        ctx['num'] = ctx['num'] + 1
7128        if 'id' not in ctx:
7129            ctx['id'] = 1
7130        ctx['id'] = (ctx['id'] + 1) % 256
7131        idx = 0
7132
7133        idx += 1
7134        if ctx['num'] == idx:
7135            return mschapv2_fail_password_expired(ctx)
7136        idx += 1
7137        if ctx['num'] == idx:
7138            return mschapv2_success_after_password_change(ctx, req)
7139        idx += 1
7140        if ctx['num'] == idx:
7141            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7142
7143        idx += 1
7144        if ctx['num'] == idx:
7145            return mschapv2_fail_password_expired(ctx)
7146        idx += 1
7147        if ctx['num'] == idx:
7148            return mschapv2_success_after_password_change(ctx, req)
7149        idx += 1
7150        if ctx['num'] == idx:
7151            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7152
7153        idx += 1
7154        if ctx['num'] == idx:
7155            return mschapv2_fail_password_expired(ctx)
7156        idx += 1
7157        if ctx['num'] == idx:
7158            return mschapv2_success_after_password_change(ctx, req)
7159        idx += 1
7160        if ctx['num'] == idx:
7161            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7162
7163        idx += 1
7164        if ctx['num'] == idx:
7165            return mschapv2_fail_password_expired(ctx)
7166        idx += 1
7167        if ctx['num'] == idx:
7168            return mschapv2_success_after_password_change(ctx, req)
7169        idx += 1
7170        if ctx['num'] == idx:
7171            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7172
7173        idx += 1
7174        if ctx['num'] == idx:
7175            return mschapv2_fail_password_expired(ctx)
7176        idx += 1
7177        if ctx['num'] == idx:
7178            return mschapv2_success_after_password_change(ctx, req)
7179        idx += 1
7180        if ctx['num'] == idx:
7181            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7182
7183        idx += 1
7184        if ctx['num'] == idx:
7185            return mschapv2_fail_password_expired(ctx)
7186        idx += 1
7187        if ctx['num'] == idx:
7188            return mschapv2_success_after_password_change(ctx, req)
7189        idx += 1
7190        if ctx['num'] == idx:
7191            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7192
7193        idx += 1
7194        if ctx['num'] == idx:
7195            return mschapv2_fail_password_expired(ctx)
7196        idx += 1
7197        if ctx['num'] == idx:
7198            return mschapv2_success_after_password_change(ctx, req)
7199        idx += 1
7200        if ctx['num'] == idx:
7201            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7202
7203        idx += 1
7204        if ctx['num'] == idx:
7205            return mschapv2_fail_password_expired(ctx)
7206        idx += 1
7207        if ctx['num'] == idx:
7208            return mschapv2_success_after_password_change(ctx, req)
7209        idx += 1
7210        if ctx['num'] == idx:
7211            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7212
7213        idx += 1
7214        if ctx['num'] == idx:
7215            return mschapv2_fail_password_expired(ctx)
7216        idx += 1
7217        if ctx['num'] == idx:
7218            return mschapv2_success_after_password_change(ctx, req)
7219        idx += 1
7220        if ctx['num'] == idx:
7221            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7222
7223        return None
7224
7225    srv = start_radius_server(mschapv2_handler)
7226
7227    try:
7228        hapd = start_ap(apdev[0])
7229        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
7230
7231        tests = ["os_get_random;eap_mschapv2_change_password",
7232                 "generate_nt_response;eap_mschapv2_change_password",
7233                 "get_master_key;eap_mschapv2_change_password",
7234                 "nt_password_hash;eap_mschapv2_change_password",
7235                 "old_nt_password_hash_encrypted_with_new_nt_password_hash"]
7236        for func in tests:
7237            with fail_test(dev[0], 1, func):
7238                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7239                               eap="MSCHAPV2", identity="user",
7240                               password="password", wait_connect=False)
7241                ev = dev[0].wait_event(["CTRL-REQ-NEW_PASSWORD"], timeout=10)
7242                if ev is None:
7243                    raise Exception("Timeout on new password request")
7244                id = ev.split(':')[0].split('-')[-1]
7245                dev[0].request("CTRL-RSP-NEW_PASSWORD-" + id + ":new-pw")
7246                time.sleep(0.1)
7247                wait_fail_trigger(dev[0], "GET_FAIL")
7248                dev[0].request("REMOVE_NETWORK all")
7249                dev[0].wait_disconnected(timeout=1)
7250
7251        tests = ["encrypt_pw_block_with_password_hash;eap_mschapv2_change_password",
7252                 "nt_password_hash;eap_mschapv2_change_password",
7253                 "nt_password_hash;eap_mschapv2_success"]
7254        for func in tests:
7255            with fail_test(dev[0], 1, func):
7256                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7257                               eap="MSCHAPV2", identity="user",
7258                               password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
7259                               wait_connect=False)
7260                ev = dev[0].wait_event(["CTRL-REQ-NEW_PASSWORD"], timeout=10)
7261                if ev is None:
7262                    raise Exception("Timeout on new password request")
7263                id = ev.split(':')[0].split('-')[-1]
7264                dev[0].request("CTRL-RSP-NEW_PASSWORD-" + id + ":new-pw")
7265                time.sleep(0.1)
7266                wait_fail_trigger(dev[0], "GET_FAIL")
7267                dev[0].request("REMOVE_NETWORK all")
7268                dev[0].wait_disconnected(timeout=1)
7269
7270        tests = ["eap_msg_alloc;eap_mschapv2_change_password"]
7271        for func in tests:
7272            with alloc_fail(dev[0], 1, func):
7273                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7274                               eap="MSCHAPV2", identity="user",
7275                               password="password", wait_connect=False)
7276                ev = dev[0].wait_event(["CTRL-REQ-NEW_PASSWORD"], timeout=10)
7277                if ev is None:
7278                    raise Exception("Timeout on new password request")
7279                id = ev.split(':')[0].split('-')[-1]
7280                dev[0].request("CTRL-RSP-NEW_PASSWORD-" + id + ":new-pw")
7281                time.sleep(0.1)
7282                wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
7283                dev[0].request("REMOVE_NETWORK all")
7284                dev[0].wait_disconnected(timeout=1)
7285    finally:
7286        stop_radius_server(srv)
7287
7288def test_eap_proto_pwd(dev, apdev):
7289    """EAP-pwd protocol tests"""
7290    check_eap_capa(dev[0], "PWD")
7291
7292    global eap_proto_pwd_test_done, eap_proto_pwd_test_wait
7293    eap_proto_pwd_test_done = False
7294    eap_proto_pwd_test_wait = False
7295
7296    def pwd_handler(ctx, req):
7297        logger.info("pwd_handler - RX " + binascii.hexlify(req).decode())
7298        if 'num' not in ctx:
7299            ctx['num'] = 0
7300        ctx['num'] = ctx['num'] + 1
7301        if 'id' not in ctx:
7302            ctx['id'] = 1
7303        ctx['id'] = (ctx['id'] + 1) % 256
7304        idx = 0
7305
7306        global eap_proto_pwd_test_wait
7307        eap_proto_pwd_test_wait = False
7308
7309        idx += 1
7310        if ctx['num'] == idx:
7311            logger.info("Test: Missing payload")
7312            # EAP-pwd: Got a frame but pos is not NULL and len is 0
7313            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'], 4 + 1,
7314                               EAP_TYPE_PWD)
7315
7316        idx += 1
7317        if ctx['num'] == idx:
7318            logger.info("Test: Missing Total-Length field")
7319            # EAP-pwd: Frame too short to contain Total-Length field
7320            payload = struct.pack("B", 0x80)
7321            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7322                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7323
7324        idx += 1
7325        if ctx['num'] == idx:
7326            logger.info("Test: Too large Total-Length")
7327            # EAP-pwd: Incoming fragments whose total length = 65535
7328            payload = struct.pack(">BH", 0x80, 65535)
7329            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7330                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7331
7332        idx += 1
7333        if ctx['num'] == idx:
7334            eap_proto_pwd_test_wait = True
7335            logger.info("Test: First fragment")
7336            # EAP-pwd: Incoming fragments whose total length = 10
7337            # EAP-pwd: ACKing a 0 byte fragment
7338            payload = struct.pack(">BH", 0xc0, 10)
7339            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7340                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7341        idx += 1
7342        if ctx['num'] == idx:
7343            logger.info("Test: Unexpected Total-Length value in the second fragment")
7344            # EAP-pwd: Incoming fragments whose total length = 0
7345            # EAP-pwd: Unexpected new fragment start when previous fragment is still in use
7346            payload = struct.pack(">BH", 0x80, 0)
7347            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7348                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7349
7350        idx += 1
7351        if ctx['num'] == idx:
7352            logger.info("Test: First and only fragment")
7353            # EAP-pwd: Incoming fragments whose total length = 0
7354            # EAP-pwd: processing frame: exch 0, len 0
7355            # EAP-pwd: Ignoring message with unknown opcode 128
7356            payload = struct.pack(">BH", 0x80, 0)
7357            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7358                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7359
7360        idx += 1
7361        if ctx['num'] == idx:
7362            logger.info("Test: First and only fragment with extra data")
7363            # EAP-pwd: Incoming fragments whose total length = 0
7364            # EAP-pwd: processing frame: exch 0, len 1
7365            # EAP-pwd: Ignoring message with unknown opcode 128
7366            payload = struct.pack(">BHB", 0x80, 0, 0)
7367            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7368                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7369
7370        idx += 1
7371        if ctx['num'] == idx:
7372            eap_proto_pwd_test_wait = True
7373            logger.info("Test: First fragment")
7374            # EAP-pwd: Incoming fragments whose total length = 2
7375            # EAP-pwd: ACKing a 1 byte fragment
7376            payload = struct.pack(">BHB", 0xc0, 2, 1)
7377            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7378                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7379        idx += 1
7380        if ctx['num'] == idx:
7381            logger.info("Test: Extra data in the second fragment")
7382            # EAP-pwd: Buffer overflow attack detected (3 vs. 1)!
7383            payload = struct.pack(">BBB", 0x0, 2, 3)
7384            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7385                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7386
7387        idx += 1
7388        if ctx['num'] == idx:
7389            logger.info("Test: Too short id exchange")
7390            # EAP-pwd: processing frame: exch 1, len 0
7391            # EAP-PWD: PWD-ID-Req -> FAILURE
7392            payload = struct.pack(">B", 0x01)
7393            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7394                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7395
7396        idx += 1
7397        if ctx['num'] == idx:
7398            logger.info("Test: Unsupported rand func in id exchange")
7399            # EAP-PWD: Server EAP-pwd-ID proposal: group=0 random=0 prf=0 prep=0
7400            # EAP-PWD: PWD-ID-Req -> FAILURE
7401            payload = struct.pack(">BHBBLB", 0x01, 0, 0, 0, 0, 0)
7402            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7403                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7404
7405        idx += 1
7406        if ctx['num'] == idx:
7407            logger.info("Test: Unsupported prf in id exchange")
7408            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=0 prep=0
7409            # EAP-PWD: PWD-ID-Req -> FAILURE
7410            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 0, 0, 0)
7411            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7412                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7413
7414        idx += 1
7415        if ctx['num'] == idx:
7416            logger.info("Test: Unsupported password pre-processing technique in id exchange")
7417            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=255
7418            # EAP-PWD: Unsupported password pre-processing technique (Prep=255)
7419            # EAP-PWD: PWD-ID-Req -> FAILURE
7420            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 255)
7421            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7422                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7423
7424        idx += 1
7425        if ctx['num'] == idx:
7426            eap_proto_pwd_test_wait = True
7427            logger.info("Test: Valid id exchange")
7428            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=0
7429            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7430            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7431                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7432        idx += 1
7433        if ctx['num'] == idx:
7434            logger.info("Test: Unexpected id exchange")
7435            # EAP-pwd: processing frame: exch 1, len 9
7436            # EAP-PWD: PWD-Commit-Req -> FAILURE
7437            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7438            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7439                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7440
7441        idx += 1
7442        if ctx['num'] == idx:
7443            logger.info("Test: Unexpected commit exchange")
7444            # EAP-pwd: processing frame: exch 2, len 0
7445            # EAP-PWD: PWD-ID-Req -> FAILURE
7446            payload = struct.pack(">B", 0x02)
7447            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7448                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7449
7450        idx += 1
7451        if ctx['num'] == idx:
7452            eap_proto_pwd_test_wait = True
7453            logger.info("Test: Valid id exchange")
7454            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=0
7455            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7456            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7457                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7458        idx += 1
7459        if ctx['num'] == idx:
7460            logger.info("Test: Unexpected Commit payload length (prep=None)")
7461            # EAP-pwd commit request, password prep is NONE
7462            # EAP-pwd: Unexpected Commit payload length 0 (expected 96)
7463            payload = struct.pack(">B", 0x02)
7464            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7465                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7466
7467        idx += 1
7468        if ctx['num'] == idx:
7469            eap_proto_pwd_test_wait = True
7470            logger.info("Test: Valid id exchange")
7471            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=0
7472            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7473            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7474                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7475        idx += 1
7476        if ctx['num'] == idx:
7477            logger.info("Test: Commit payload with all zeros values --> Shared key at infinity")
7478            # EAP-pwd: Invalid coordinate in element
7479            payload = struct.pack(">B", 0x02) + 96*b'\0'
7480            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7481                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7482
7483        idx += 1
7484        if ctx['num'] == idx:
7485            eap_proto_pwd_test_wait = True
7486            logger.info("Test: Valid id exchange")
7487            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=0
7488            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7489            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7490                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7491        idx += 1
7492        if ctx['num'] == idx:
7493            eap_proto_pwd_test_wait = True
7494            logger.info("Test: Commit payload with valid values")
7495            # EAP-pwd commit request, password prep is NONE
7496            element = binascii.unhexlify("8dcab2862c5396839a6bac0c689ff03d962863108e7c275bbf1d6eedf634ee832a214db99f0d0a1a6317733eecdd97f0fc4cda19f57e1bb9bb9c8dcf8c60ba6f")
7497            scalar = binascii.unhexlify("450f31e058cf2ac2636a5d6e2b3c70b1fcc301957f0716e77f13aa69f9a2e5bd")
7498            payload = struct.pack(">B", 0x02) + element + scalar
7499            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7500                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7501        idx += 1
7502        if ctx['num'] == idx:
7503            logger.info("Test: Unexpected Confirm payload length 0")
7504            # EAP-pwd: Unexpected Confirm payload length 0 (expected 32)
7505            payload = struct.pack(">B", 0x03)
7506            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7507                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7508
7509        idx += 1
7510        if ctx['num'] == idx:
7511            eap_proto_pwd_test_wait = True
7512            logger.info("Test: Valid id exchange")
7513            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=0
7514            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7515            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7516                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7517        idx += 1
7518        if ctx['num'] == idx:
7519            eap_proto_pwd_test_wait = True
7520            logger.info("Test: Commit payload with valid values")
7521            # EAP-pwd commit request, password prep is NONE
7522            element = binascii.unhexlify("8dcab2862c5396839a6bac0c689ff03d962863108e7c275bbf1d6eedf634ee832a214db99f0d0a1a6317733eecdd97f0fc4cda19f57e1bb9bb9c8dcf8c60ba6f")
7523            scalar = binascii.unhexlify("450f31e058cf2ac2636a5d6e2b3c70b1fcc301957f0716e77f13aa69f9a2e5bd")
7524            payload = struct.pack(">B", 0x02) + element + scalar
7525            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7526                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7527        idx += 1
7528        if ctx['num'] == idx:
7529            logger.info("Test: Confirm payload with incorrect value")
7530            # EAP-PWD (peer): confirm did not verify
7531            payload = struct.pack(">B", 0x03) + 32*b'\0'
7532            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7533                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7534
7535        idx += 1
7536        if ctx['num'] == idx:
7537            logger.info("Test: Unexpected confirm exchange")
7538            # EAP-pwd: processing frame: exch 3, len 0
7539            # EAP-PWD: PWD-ID-Req -> FAILURE
7540            payload = struct.pack(">B", 0x03)
7541            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7542                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7543
7544        idx += 1
7545        if ctx['num'] == idx:
7546            logger.info("Test: Unsupported password pre-processing technique SASLprep in id exchange")
7547            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=2
7548            # EAP-PWD: Unsupported password pre-processing technique (Prep=2)
7549            # EAP-PWD: PWD-ID-Req -> FAILURE
7550            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 2)
7551            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7552                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7553
7554        idx += 1
7555        if ctx['num'] == idx:
7556            eap_proto_pwd_test_wait = True
7557            logger.info("Test: Valid id exchange")
7558            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=1
7559            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 1)
7560            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7561                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7562        idx += 1
7563        if ctx['num'] == idx:
7564            logger.info("Test: Unexpected Commit payload length (prep=MS)")
7565            # EAP-pwd commit request, password prep is MS
7566            # EAP-pwd: Unexpected Commit payload length 0 (expected 96)
7567            payload = struct.pack(">B", 0x02)
7568            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7569                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7570
7571        idx += 1
7572        if ctx['num'] == idx:
7573            eap_proto_pwd_test_wait = True
7574            logger.info("Test: Valid id exchange")
7575            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=3
7576            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 3)
7577            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7578                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7579        idx += 1
7580        if ctx['num'] == idx:
7581            logger.info("Test: Unexpected Commit payload length (prep=ssha1)")
7582            # EAP-pwd commit request, password prep is salted sha1
7583            # EAP-pwd: Invalid Salt-len
7584            payload = struct.pack(">B", 0x02)
7585            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7586                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7587
7588        idx += 1
7589        if ctx['num'] == idx:
7590            eap_proto_pwd_test_wait = True
7591            logger.info("Test: Valid id exchange")
7592            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=3
7593            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 3)
7594            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7595                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7596        idx += 1
7597        if ctx['num'] == idx:
7598            logger.info("Test: Unexpected Commit payload length (prep=ssha1)")
7599            # EAP-pwd commit request, password prep is salted sha1
7600            # EAP-pwd: Invalid Salt-len
7601            payload = struct.pack(">BB", 0x02, 0)
7602            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7603                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7604
7605        idx += 1
7606        if ctx['num'] == idx:
7607            eap_proto_pwd_test_wait = True
7608            logger.info("Test: Valid id exchange")
7609            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=3
7610            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 3)
7611            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7612                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7613        idx += 1
7614        if ctx['num'] == idx:
7615            logger.info("Test: Unexpected Commit payload length (prep=ssha1)")
7616            # EAP-pwd commit request, password prep is salted sha1
7617            # EAP-pwd: Unexpected Commit payload length 1 (expected 98)
7618            payload = struct.pack(">BB", 0x02, 1)
7619            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7620                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7621
7622        idx += 1
7623        if ctx['num'] == idx:
7624            eap_proto_pwd_test_wait = True
7625            logger.info("Test: Valid id exchange")
7626            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=4
7627            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 4)
7628            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7629                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7630        idx += 1
7631        if ctx['num'] == idx:
7632            logger.info("Test: Unexpected Commit payload length (prep=ssha256)")
7633            # EAP-pwd commit request, password prep is salted sha256
7634            # EAP-pwd: Invalid Salt-len
7635            payload = struct.pack(">B", 0x02)
7636            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7637                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7638
7639        idx += 1
7640        if ctx['num'] == idx:
7641            eap_proto_pwd_test_wait = True
7642            logger.info("Test: Valid id exchange")
7643            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=4
7644            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 4)
7645            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7646                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7647        idx += 1
7648        if ctx['num'] == idx:
7649            logger.info("Test: Unexpected Commit payload length (prep=ssha256)")
7650            # EAP-pwd commit request, password prep is salted sha256
7651            # EAP-pwd: Invalid Salt-len
7652            payload = struct.pack(">BB", 0x02, 0)
7653            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7654                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7655
7656        idx += 1
7657        if ctx['num'] == idx:
7658            eap_proto_pwd_test_wait = True
7659            logger.info("Test: Valid id exchange")
7660            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=4
7661            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 4)
7662            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7663                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7664        idx += 1
7665        if ctx['num'] == idx:
7666            logger.info("Test: Unexpected Commit payload length (prep=ssha256)")
7667            # EAP-pwd commit request, password prep is salted sha256
7668            # EAP-pwd: Unexpected Commit payload length 1 (expected 98)
7669            payload = struct.pack(">BB", 0x02, 1)
7670            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7671                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7672
7673        idx += 1
7674        if ctx['num'] == idx:
7675            eap_proto_pwd_test_wait = True
7676            logger.info("Test: Valid id exchange")
7677            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=5
7678            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 5)
7679            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7680                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7681        idx += 1
7682        if ctx['num'] == idx:
7683            logger.info("Test: Unexpected Commit payload length (prep=ssha512)")
7684            # EAP-pwd commit request, password prep is salted sha512
7685            # EAP-pwd: Invalid Salt-len
7686            payload = struct.pack(">B", 0x02)
7687            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7688                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7689
7690        idx += 1
7691        if ctx['num'] == idx:
7692            eap_proto_pwd_test_wait = True
7693            logger.info("Test: Valid id exchange")
7694            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=5
7695            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 5)
7696            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7697                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7698        idx += 1
7699        if ctx['num'] == idx:
7700            logger.info("Test: Unexpected Commit payload length (prep=ssha512)")
7701            # EAP-pwd commit request, password prep is salted sha512
7702            # EAP-pwd: Invalid Salt-len
7703            payload = struct.pack(">BB", 0x02, 0)
7704            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7705                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7706
7707        idx += 1
7708        if ctx['num'] == idx:
7709            eap_proto_pwd_test_wait = True
7710            logger.info("Test: Valid id exchange")
7711            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=5
7712            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 5)
7713            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7714                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7715        idx += 1
7716        if ctx['num'] == idx:
7717            logger.info("Test: Unexpected Commit payload length (prep=ssha512)")
7718            # EAP-pwd commit request, password prep is salted sha512
7719            # EAP-pwd: Unexpected Commit payload length 1 (expected 98)
7720            payload = struct.pack(">BB", 0x02, 1)
7721            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7722                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7723
7724        logger.info("No more test responses available - test case completed")
7725        global eap_proto_pwd_test_done
7726        eap_proto_pwd_test_done = True
7727        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7728
7729    srv = start_radius_server(pwd_handler)
7730
7731    try:
7732        hapd = start_ap(apdev[0])
7733        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
7734
7735        i = 0
7736        while not eap_proto_pwd_test_done:
7737            i += 1
7738            logger.info("Running connection iteration %d" % i)
7739            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7740                           eap="PWD", identity="pwd user",
7741                           password="secret password",
7742                           wait_connect=False)
7743            ok = False
7744            for j in range(5):
7745                ev = dev[0].wait_event(["CTRL-EVENT-EAP-STATUS",
7746                                        "CTRL-EVENT-EAP-PROPOSED-METHOD"],
7747                                       timeout=5)
7748                if ev is None:
7749                    raise Exception("Timeout on EAP start")
7750                if "CTRL-EVENT-EAP-PROPOSED-METHOD" in ev:
7751                    ok = True
7752                    break
7753                if "CTRL-EVENT-EAP-STATUS" in ev and "status='completion' parameter='failure'" in ev:
7754                    ok = True
7755                    break
7756            if not ok:
7757                raise Exception("Expected EAP event not seen")
7758            if eap_proto_pwd_test_wait:
7759                for k in range(20):
7760                    time.sleep(0.1)
7761                    if not eap_proto_pwd_test_wait:
7762                        break
7763                if eap_proto_pwd_test_wait:
7764                    raise Exception("eap_proto_pwd_test_wait not cleared")
7765            dev[0].request("REMOVE_NETWORK all")
7766            dev[0].wait_disconnected(timeout=1)
7767            dev[0].dump_monitor()
7768    finally:
7769        stop_radius_server(srv)
7770
7771def test_eap_proto_pwd_invalid_scalar(dev, apdev):
7772    """EAP-pwd protocol tests - invalid server scalar"""
7773    check_eap_capa(dev[0], "PWD")
7774    run_eap_proto_pwd_invalid_scalar(dev, apdev, 32*b'\0')
7775    run_eap_proto_pwd_invalid_scalar(dev, apdev, 31*b'\0' + b'\x01')
7776    # Group Order
7777    val = binascii.unhexlify("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")
7778    run_eap_proto_pwd_invalid_scalar(dev, apdev, val)
7779    # Group Order - 1
7780    val = binascii.unhexlify("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632550")
7781    run_eap_proto_pwd_invalid_scalar(dev, apdev, val, valid_scalar=True)
7782
7783def run_eap_proto_pwd_invalid_scalar(dev, apdev, scalar, valid_scalar=False):
7784    global eap_proto_pwd_invalid_scalar_fail
7785    eap_proto_pwd_invalid_scalar_fail = False
7786
7787    def pwd_handler(ctx, req):
7788        logger.info("pwd_handler - RX " + binascii.hexlify(req).decode())
7789        if 'num' not in ctx:
7790            ctx['num'] = 0
7791        ctx['num'] = ctx['num'] + 1
7792        if 'id' not in ctx:
7793            ctx['id'] = 1
7794        ctx['id'] = (ctx['id'] + 1) % 256
7795        idx = 0
7796
7797        idx += 1
7798        if ctx['num'] == idx:
7799            logger.info("Test: Valid id exchange")
7800            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7801            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7802                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7803        idx += 1
7804        if ctx['num'] == idx:
7805            logger.info("Test: Commit payload with invalid scalar")
7806            payload = struct.pack(">B", 0x02) + binascii.unhexlify("67feb2b46d59e6dd3af3a429ec9c04a949337564615d3a2c19bdf6826eb6f5efa303aed86af3a072ed819d518d620adb2659f0e84c4f8b739629db8c93088cfc") + scalar
7807            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7808                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7809        idx += 1
7810        if ctx['num'] == idx:
7811            logger.info("Confirm message next - should not get here")
7812            global eap_proto_pwd_invalid_scalar_fail
7813            eap_proto_pwd_invalid_scalar_fail = True
7814            payload = struct.pack(">B", 0x03) + 32*b'\0'
7815            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7816                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7817
7818        logger.info("No more test responses available - test case completed")
7819        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7820
7821    srv = start_radius_server(pwd_handler)
7822
7823    try:
7824        hapd = start_ap(apdev[0])
7825        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
7826
7827        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7828                       eap="PWD", identity="pwd user",
7829                       password="secret password",
7830                       wait_connect=False)
7831        ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
7832        if ev is None:
7833            raise Exception("EAP failure not reported")
7834        dev[0].request("REMOVE_NETWORK all")
7835        dev[0].wait_disconnected(timeout=1)
7836        dev[0].dump_monitor()
7837    finally:
7838        stop_radius_server(srv)
7839
7840    if valid_scalar and not eap_proto_pwd_invalid_scalar_fail:
7841        raise Exception("Peer did not accept valid EAP-pwd-Commit scalar")
7842    if not valid_scalar and eap_proto_pwd_invalid_scalar_fail:
7843        raise Exception("Peer did not stop after invalid EAP-pwd-Commit scalar")
7844
7845def test_eap_proto_pwd_invalid_element(dev, apdev):
7846    """EAP-pwd protocol tests - invalid server element"""
7847    check_eap_capa(dev[0], "PWD")
7848    # Invalid x,y coordinates
7849    run_eap_proto_pwd_invalid_element(dev, apdev, 64*b'\x00')
7850    run_eap_proto_pwd_invalid_element(dev, apdev, 32*b'\x00' + 32*b'\x01')
7851    run_eap_proto_pwd_invalid_element(dev, apdev, 32*b'\x01' + 32*b'\x00')
7852    run_eap_proto_pwd_invalid_element(dev, apdev, 32*b'\xff' + 32*b'\x01')
7853    run_eap_proto_pwd_invalid_element(dev, apdev, 32*b'\x01' + 32*b'\xff')
7854    run_eap_proto_pwd_invalid_element(dev, apdev, 64*b'\xff')
7855    # Not on curve
7856    run_eap_proto_pwd_invalid_element(dev, apdev, 64*b'\x01')
7857
7858def run_eap_proto_pwd_invalid_element(dev, apdev, element):
7859    global eap_proto_pwd_invalid_element_fail
7860    eap_proto_pwd_invalid_element_fail = False
7861
7862    def pwd_handler(ctx, req):
7863        logger.info("pwd_handler - RX " + binascii.hexlify(req).decode())
7864        if 'num' not in ctx:
7865            ctx['num'] = 0
7866        ctx['num'] = ctx['num'] + 1
7867        if 'id' not in ctx:
7868            ctx['id'] = 1
7869        ctx['id'] = (ctx['id'] + 1) % 256
7870        idx = 0
7871
7872        idx += 1
7873        if ctx['num'] == idx:
7874            logger.info("Test: Valid id exchange")
7875            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7876            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7877                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7878        idx += 1
7879        if ctx['num'] == idx:
7880            logger.info("Test: Commit payload with invalid element")
7881            payload = struct.pack(">B", 0x02) + element + 31*b'\0' + b'\x02'
7882            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7883                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7884        idx += 1
7885        if ctx['num'] == idx:
7886            logger.info("Confirm message next - should not get here")
7887            global eap_proto_pwd_invalid_element_fail
7888            eap_proto_pwd_invalid_element_fail = True
7889            payload = struct.pack(">B", 0x03) + 32*b'\0'
7890            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7891                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7892
7893        logger.info("No more test responses available - test case completed")
7894        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7895
7896    srv = start_radius_server(pwd_handler)
7897
7898    try:
7899        hapd = start_ap(apdev[0])
7900        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
7901
7902        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7903                       eap="PWD", identity="pwd user",
7904                       password="secret password",
7905                       wait_connect=False)
7906        ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
7907        if ev is None:
7908            raise Exception("EAP failure not reported")
7909        dev[0].request("REMOVE_NETWORK all")
7910        dev[0].wait_disconnected(timeout=1)
7911        dev[0].dump_monitor()
7912    finally:
7913        stop_radius_server(srv)
7914
7915    if eap_proto_pwd_invalid_element_fail:
7916        raise Exception("Peer did not stop after invalid EAP-pwd-Commit element")
7917
7918def rx_msg(src):
7919    ev = src.wait_event(["EAPOL-TX"], timeout=5)
7920    if ev is None:
7921        raise Exception("No EAPOL-TX")
7922    return ev.split(' ')[2]
7923
7924def tx_msg(src, dst, msg):
7925    dst.request("EAPOL_RX " + src.own_addr() + " " + msg)
7926
7927def proxy_msg(src, dst):
7928    msg = rx_msg(src)
7929    tx_msg(src, dst, msg)
7930    return msg
7931
7932def start_pwd_exchange(dev, ap):
7933    check_eap_capa(dev, "PWD")
7934    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
7935    hapd = hostapd.add_ap(ap, params)
7936    hapd.request("SET ext_eapol_frame_io 1")
7937    dev.request("SET ext_eapol_frame_io 1")
7938    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP",
7939                   eap="PWD", identity="pwd user", password="secret password",
7940                   wait_connect=False, scan_freq="2412")
7941    proxy_msg(hapd, dev) # EAP-Identity/Request
7942    proxy_msg(dev, hapd) # EAP-Identity/Response
7943    proxy_msg(hapd, dev) # EAP-pwd-ID/Request
7944    proxy_msg(dev, hapd) # EAP-pwd-ID/Response
7945    return hapd
7946
7947def test_eap_proto_pwd_unexpected_fragment(dev, apdev):
7948    """EAP-pwd protocol tests - unexpected more-fragment frame"""
7949    hapd = start_pwd_exchange(dev[0], apdev[0])
7950
7951    # EAP-pwd-Commit/Request
7952    req = rx_msg(hapd)
7953    if req[18:20] != "02":
7954        raise Exception("Unexpected EAP-pwd-Commit/Request flag")
7955    msg = req[0:18] + "42" + req[20:]
7956    tx_msg(hapd, dev[0], msg)
7957
7958def test_eap_proto_pwd_reflection_attack(dev, apdev):
7959    """EAP-pwd protocol tests - reflection attack on the server"""
7960    hapd = start_pwd_exchange(dev[0], apdev[0])
7961
7962    # EAP-pwd-Commit/Request
7963    req = proxy_msg(hapd, dev[0])
7964    if len(req) != 212:
7965        raise Exception("Unexpected EAP-pwd-Commit/Response length")
7966
7967    # EAP-pwd-Commit/Response
7968    resp = rx_msg(dev[0])
7969    # Reflect same Element/Scalar back to the server
7970    msg = resp[0:20] + req[20:]
7971    tx_msg(dev[0], hapd, msg)
7972
7973    # EAP-pwd-Commit/Response or EAP-Failure
7974    req = rx_msg(hapd)
7975    if req[8:10] != "04":
7976        # reflect EAP-pwd-Confirm/Request
7977        msg = req[0:8] + "02" + req[10:]
7978        tx_msg(dev[0], hapd, msg)
7979        req = rx_msg(hapd)
7980        if req[8:10] == "03":
7981            raise Exception("EAP-Success after reflected Element/Scalar")
7982        raise Exception("No EAP-Failure to reject invalid EAP-pwd-Commit/Response")
7983
7984def test_eap_proto_pwd_invalid_scalar_peer(dev, apdev):
7985    """EAP-pwd protocol tests - invalid peer scalar"""
7986    run_eap_proto_pwd_invalid_scalar_peer(dev, apdev, 32*"00")
7987    run_eap_proto_pwd_invalid_scalar_peer(dev, apdev, 31*"00" + "01")
7988    # Group Order
7989    run_eap_proto_pwd_invalid_scalar_peer(dev, apdev,
7990                                          "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")
7991    # Group Order - 1
7992    run_eap_proto_pwd_invalid_scalar_peer(dev, apdev,
7993                                          "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632550",
7994                                          valid_scalar=True)
7995
7996def run_eap_proto_pwd_invalid_scalar_peer(dev, apdev, scalar,
7997                                          valid_scalar=False):
7998    hapd = start_pwd_exchange(dev[0], apdev[0])
7999    proxy_msg(hapd, dev[0]) # EAP-pwd-Commit/Request
8000
8001    # EAP-pwd-Commit/Response
8002    resp = rx_msg(dev[0])
8003    # Replace scalar with an invalid value
8004    msg = resp[0:20] + resp[20:148] + scalar
8005    tx_msg(dev[0], hapd, msg)
8006
8007    # EAP-pwd-Commit/Response or EAP-Failure
8008    req = rx_msg(hapd)
8009    if valid_scalar and req[8:10] == "04":
8010        raise Exception("Unexpected EAP-Failure with valid scalar")
8011    if not valid_scalar and req[8:10] != "04":
8012        raise Exception("No EAP-Failure to reject invalid scalar")
8013    dev[0].request("REMOVE_NETWORK all")
8014    dev[0].wait_disconnected(timeout=1)
8015    hapd.disable()
8016
8017def test_eap_proto_pwd_invalid_element_peer(dev, apdev):
8018    """EAP-pwd protocol tests - invalid peer element"""
8019    # Invalid x,y coordinates
8020    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 64*'00')
8021    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 32*'00' + 32*'01')
8022    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 32*'01' + 32*'00')
8023    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 32*'ff' + 32*'01')
8024    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 32*'01' + 32*'ff')
8025    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 64*'ff')
8026    # Not on curve
8027    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 64*'01')
8028
8029def run_eap_proto_pwd_invalid_element_peer(dev, apdev, element):
8030    hapd = start_pwd_exchange(dev[0], apdev[0])
8031    proxy_msg(hapd, dev[0]) # EAP-pwd-Commit/Request
8032
8033    # EAP-pwd-Commit/Response
8034    resp = rx_msg(dev[0])
8035    # Replace element with an invalid value
8036    msg = resp[0:20] + element + resp[148:]
8037    tx_msg(dev[0], hapd, msg)
8038
8039    # EAP-pwd-Commit/Response or EAP-Failure
8040    req = rx_msg(hapd)
8041    if req[8:10] != "04":
8042        raise Exception("No EAP-Failure to reject invalid element")
8043    dev[0].request("REMOVE_NETWORK all")
8044    dev[0].wait_disconnected(timeout=1)
8045    hapd.disable()
8046
8047def test_eap_proto_pwd_errors(dev, apdev):
8048    """EAP-pwd local error cases"""
8049    check_eap_capa(dev[0], "PWD")
8050    params = hostapd.wpa2_eap_params(ssid="eap-test")
8051    hapd = hostapd.add_ap(apdev[0], params)
8052    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8053
8054    for i in range(1, 4):
8055        with alloc_fail(dev[0], i, "eap_pwd_init"):
8056            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8057                           eap="PWD", identity="pwd user",
8058                           password="secret password",
8059                           wait_connect=False)
8060            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
8061                                   timeout=15)
8062            if ev is None:
8063                raise Exception("Timeout on EAP start")
8064            dev[0].request("REMOVE_NETWORK all")
8065            dev[0].wait_disconnected()
8066
8067    with alloc_fail(dev[0], 1, "eap_pwd_get_session_id"):
8068        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8069                       eap="PWD", identity="pwd user",
8070                       fragment_size="0",
8071                       password="secret password")
8072        dev[0].request("REMOVE_NETWORK all")
8073        dev[0].wait_disconnected()
8074
8075    funcs = ["eap_pwd_getkey", "eap_pwd_get_emsk",
8076             "=wpabuf_alloc;eap_pwd_perform_commit_exchange",
8077             "=wpabuf_alloc;eap_pwd_perform_confirm_exchange"]
8078    for func in funcs:
8079        with alloc_fail(dev[0], 1, func):
8080            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8081                           eap="PWD", identity="pwd user@domain",
8082                           password="secret password", erp="1",
8083                           wait_connect=False)
8084            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8085            dev[0].request("REMOVE_NETWORK all")
8086            dev[0].wait_disconnected()
8087
8088    for i in range(1, 5):
8089        with alloc_fail(dev[0], i, "eap_pwd_perform_id_exchange"):
8090            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8091                           eap="PWD", identity="pwd user",
8092                           password="secret password",
8093                           wait_connect=False)
8094            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8095                                   timeout=15)
8096            if ev is None:
8097                raise Exception("Timeout on EAP start")
8098            ok = False
8099            for j in range(10):
8100                state = dev[0].request('GET_ALLOC_FAIL')
8101                if state.startswith('0:'):
8102                    ok = True
8103                    break
8104                time.sleep(0.1)
8105            if not ok:
8106                raise Exception("No allocation failure seen")
8107            dev[0].request("REMOVE_NETWORK all")
8108            dev[0].wait_disconnected()
8109
8110    with alloc_fail(dev[0], 1, "wpabuf_alloc;eap_pwd_perform_id_exchange"):
8111        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8112                       eap="PWD", identity="pwd user",
8113                       password="secret password",
8114                       wait_connect=False)
8115        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8116                               timeout=15)
8117        if ev is None:
8118            raise Exception("Timeout on EAP start")
8119        dev[0].request("REMOVE_NETWORK all")
8120        dev[0].wait_disconnected()
8121
8122    for i in range(1, 9):
8123        with alloc_fail(dev[0], i, "eap_pwd_perform_commit_exchange"):
8124            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8125                           eap="PWD", identity="pwd user",
8126                           password="secret password",
8127                           wait_connect=False)
8128            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8129                                   timeout=15)
8130            if ev is None:
8131                raise Exception("Timeout on EAP start")
8132            ok = False
8133            for j in range(10):
8134                state = dev[0].request('GET_ALLOC_FAIL')
8135                if state.startswith('0:'):
8136                    ok = True
8137                    break
8138                time.sleep(0.1)
8139            if not ok:
8140                raise Exception("No allocation failure seen")
8141            dev[0].request("REMOVE_NETWORK all")
8142            dev[0].wait_disconnected()
8143
8144    for i in range(1, 12):
8145        with alloc_fail(dev[0], i, "eap_pwd_perform_confirm_exchange"):
8146            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8147                           eap="PWD", identity="pwd user",
8148                           password="secret password",
8149                           wait_connect=False)
8150            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8151                                   timeout=15)
8152            if ev is None:
8153                raise Exception("Timeout on EAP start")
8154            ok = False
8155            for j in range(10):
8156                state = dev[0].request('GET_ALLOC_FAIL')
8157                if state.startswith('0:'):
8158                    ok = True
8159                    break
8160                time.sleep(0.1)
8161            if not ok:
8162                raise Exception("No allocation failure seen")
8163            dev[0].request("REMOVE_NETWORK all")
8164            dev[0].wait_disconnected()
8165
8166    for i in range(1, 5):
8167        with alloc_fail(dev[0], i, "eap_msg_alloc;=eap_pwd_process"):
8168            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8169                           eap="PWD", identity="pwd user",
8170                           password="secret password", fragment_size="50",
8171                           wait_connect=False)
8172            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8173                                   timeout=15)
8174            if ev is None:
8175                raise Exception("Timeout on EAP start")
8176            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8177            dev[0].request("REMOVE_NETWORK all")
8178            dev[0].wait_disconnected()
8179
8180    # No password configured
8181    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8182                   eap="PWD", identity="pwd user",
8183                   wait_connect=False)
8184    ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=52"],
8185                           timeout=15)
8186    if ev is None:
8187        raise Exception("EAP-pwd not started")
8188    dev[0].request("REMOVE_NETWORK all")
8189    dev[0].wait_disconnected()
8190
8191    funcs = [(1, "hash_nt_password_hash;eap_pwd_perform_commit_exchange"),
8192             (1, "=crypto_bignum_init;eap_pwd_perform_commit_exchange"),
8193             (1, "=crypto_ec_point_init;eap_pwd_perform_commit_exchange"),
8194             (2, "=crypto_ec_point_init;eap_pwd_perform_commit_exchange"),
8195             (1, "=crypto_ec_point_mul;eap_pwd_perform_commit_exchange"),
8196             (2, "=crypto_ec_point_mul;eap_pwd_perform_commit_exchange"),
8197             (3, "=crypto_ec_point_mul;eap_pwd_perform_commit_exchange"),
8198             (1, "=crypto_ec_point_add;eap_pwd_perform_commit_exchange"),
8199             (1, "=crypto_ec_point_invert;eap_pwd_perform_commit_exchange"),
8200             (1, "=crypto_ec_point_to_bin;eap_pwd_perform_commit_exchange"),
8201             (1, "crypto_hash_finish;eap_pwd_kdf"),
8202             (1, "crypto_ec_point_from_bin;eap_pwd_get_element"),
8203             (3, "crypto_bignum_init;compute_password_element"),
8204             (4, "crypto_bignum_init;compute_password_element"),
8205             (1, "crypto_bignum_init_set;compute_password_element"),
8206             (2, "crypto_bignum_init_set;compute_password_element"),
8207             (3, "crypto_bignum_init_set;compute_password_element"),
8208             (1, "crypto_bignum_to_bin;compute_password_element"),
8209             (1, "crypto_ec_point_compute_y_sqr;compute_password_element"),
8210             (1, "crypto_bignum_rand;compute_password_element"),
8211             (1, "crypto_bignum_sub;compute_password_element")]
8212    for count, func in funcs:
8213        with fail_test(dev[0], count, func):
8214            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8215                           eap="PWD", identity="pwd-hash",
8216                           password_hex="hash:e3718ece8ab74792cbbfffd316d2d19a",
8217                           wait_connect=False)
8218            ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
8219            if ev is None:
8220                raise Exception("No EAP-Failure reported")
8221            dev[0].request("REMOVE_NETWORK all")
8222            dev[0].wait_disconnected()
8223
8224    params = {"ssid": "eap-test2", "wpa": "2", "wpa_key_mgmt": "WPA-EAP",
8225              "rsn_pairwise": "CCMP", "ieee8021x": "1",
8226              "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf",
8227              "pwd_group": "19", "fragment_size": "40"}
8228    hapd2 = hostapd.add_ap(apdev[1], params)
8229    dev[0].scan_for_bss(hapd2.own_addr(), freq=2412)
8230
8231    with alloc_fail(dev[0], 1, "wpabuf_alloc;=eap_pwd_process"):
8232        dev[0].connect("eap-test2", key_mgmt="WPA-EAP", scan_freq="2412",
8233                       eap="PWD", identity="pwd user",
8234                       password="secret password",
8235                       wait_connect=False)
8236        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8237        dev[0].request("REMOVE_NETWORK all")
8238        dev[0].wait_disconnected()
8239
8240    for i in range(1, 5):
8241        with fail_test(dev[0], i,
8242                       "=crypto_ec_point_to_bin;eap_pwd_perform_confirm_exchange"):
8243            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8244                           eap="PWD", identity="pwd-hash",
8245                           password_hex="hash:e3718ece8ab74792cbbfffd316d2d19a",
8246                           wait_connect=False)
8247            ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
8248            if ev is None:
8249                raise Exception("No EAP-Failure reported")
8250            dev[0].request("REMOVE_NETWORK all")
8251            dev[0].wait_disconnected()
8252            dev[0].dump_monitor()
8253
8254def run_eap_pwd_connect(dev, hash=True, fragment=2000):
8255    if hash:
8256        dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP",
8257                    fragment_size=str(fragment),
8258                    eap="PWD", identity="pwd-hash",
8259                    password_hex="hash:e3718ece8ab74792cbbfffd316d2d19a",
8260                    scan_freq="2412", wait_connect=False)
8261    else:
8262        dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP",
8263                    fragment_size=str(fragment),
8264                    eap="PWD", identity="pwd-hash-sha1",
8265                    password="secret password",
8266                    scan_freq="2412", wait_connect=False)
8267    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
8268                         "CTRL-EVENT-DISCONNECTED"],
8269                        timeout=1)
8270    dev.request("REMOVE_NETWORK all")
8271    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
8272        dev.wait_disconnected()
8273    dev.dump_monitor()
8274
8275def test_eap_proto_pwd_errors_server(dev, apdev):
8276    """EAP-pwd local error cases on server"""
8277    check_eap_capa(dev[0], "PWD")
8278    params = int_eap_server_params()
8279    params['erp_domain'] = 'example.com'
8280    params['eap_server_erp'] = '1'
8281    hapd = hostapd.add_ap(apdev[0], params)
8282    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8283
8284    tests = [(1, "eap_pwd_init"),
8285             (2, "eap_pwd_init"),
8286             (3, "eap_pwd_init"),
8287             (1, "eap_pwd_build_id_req"),
8288             (1, "eap_pwd_build_commit_req"),
8289             (1, "eap_pwd_build_confirm_req"),
8290             (1, "eap_pwd_h_init;eap_pwd_build_confirm_req"),
8291             (1, "wpabuf_alloc;eap_pwd_build_confirm_req"),
8292             (1, "eap_msg_alloc;eap_pwd_build_req"),
8293             (1, "eap_pwd_process_id_resp"),
8294             (1, "get_eap_pwd_group;eap_pwd_process_id_resp"),
8295             (1, "eap_pwd_process_confirm_resp"),
8296             (1, "eap_pwd_h_init;eap_pwd_process_confirm_resp"),
8297             (1, "compute_keys;eap_pwd_process_confirm_resp"),
8298             (1, "eap_pwd_getkey"),
8299             (1, "eap_pwd_get_emsk"),
8300             (1, "eap_pwd_get_session_id")]
8301    for count, func in tests:
8302        with alloc_fail(hapd, count, func):
8303            run_eap_pwd_connect(dev[0], hash=True)
8304
8305    tests = [(1, "eap_msg_alloc;eap_pwd_build_req"),
8306             (2, "eap_msg_alloc;eap_pwd_build_req"),
8307             (1, "wpabuf_alloc;eap_pwd_process")]
8308    for count, func in tests:
8309        with alloc_fail(hapd, count, func):
8310            run_eap_pwd_connect(dev[0], hash=True, fragment=13)
8311
8312    tests = [(4, "eap_pwd_init")]
8313    for count, func in tests:
8314        with alloc_fail(hapd, count, func):
8315            run_eap_pwd_connect(dev[0], hash=False)
8316
8317    tests = [(1, "eap_pwd_build_id_req"),
8318             (1, "eap_pwd_build_commit_req"),
8319             (1, "crypto_ec_point_mul;eap_pwd_build_commit_req"),
8320             (1, "crypto_ec_point_invert;eap_pwd_build_commit_req"),
8321             (1, "crypto_ec_point_to_bin;eap_pwd_build_commit_req"),
8322             (1, "crypto_ec_point_to_bin;eap_pwd_build_confirm_req"),
8323             (2, "=crypto_ec_point_to_bin;eap_pwd_build_confirm_req"),
8324             (1, "hash_nt_password_hash;eap_pwd_process_id_resp"),
8325             (1, "compute_password_element;eap_pwd_process_id_resp"),
8326             (1, "crypto_bignum_init;eap_pwd_process_commit_resp"),
8327             (1, "crypto_ec_point_mul;eap_pwd_process_commit_resp"),
8328             (2, "crypto_ec_point_mul;eap_pwd_process_commit_resp"),
8329             (1, "crypto_ec_point_add;eap_pwd_process_commit_resp"),
8330             (1, "crypto_ec_point_to_bin;eap_pwd_process_confirm_resp"),
8331             (2, "=crypto_ec_point_to_bin;eap_pwd_process_confirm_resp")]
8332    for count, func in tests:
8333        with fail_test(hapd, count, func):
8334            run_eap_pwd_connect(dev[0], hash=True)
8335
8336def start_pwd_assoc(dev, hapd):
8337    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP",
8338                eap="PWD", identity="pwd user", password="secret password",
8339                wait_connect=False, scan_freq="2412")
8340    proxy_msg(hapd, dev) # EAP-Identity/Request
8341    proxy_msg(dev, hapd) # EAP-Identity/Response
8342    proxy_msg(hapd, dev) # EAP-pwd-Identity/Request
8343
8344def stop_pwd_assoc(dev, hapd):
8345    dev.request("REMOVE_NETWORK all")
8346    dev.wait_disconnected()
8347    dev.dump_monitor()
8348    hapd.dump_monitor()
8349
8350def test_eap_proto_pwd_server(dev, apdev):
8351    """EAP-pwd protocol testing for the server"""
8352    check_eap_capa(dev[0], "PWD")
8353    params = int_eap_server_params()
8354    hapd = hostapd.add_ap(apdev[0], params)
8355    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8356    hapd.request("SET ext_eapol_frame_io 1")
8357    dev[0].request("SET ext_eapol_frame_io 1")
8358
8359    start_pwd_assoc(dev[0], hapd)
8360    resp = rx_msg(dev[0])
8361    # Replace exch field with unexpected value
8362    # --> EAP-pwd: Unexpected opcode=4 in state=0
8363    msg = resp[0:18] + "04" + resp[20:]
8364    tx_msg(dev[0], hapd, msg)
8365
8366    # Too short EAP-pwd header (no flags/exch field)
8367    # --> EAP-pwd: Invalid frame
8368    msg = resp[0:4] + "0005" + resp[8:12] + "0005" + "34"
8369    tx_msg(dev[0], hapd, msg)
8370
8371    # Too short EAP-pwd header (L=1 but only one octet of total length field)
8372    # --> EAP-pwd: Frame too short to contain Total-Length field
8373    msg = resp[0:4] + "0007" + resp[8:12] + "0007" + "34" + "81ff"
8374    tx_msg(dev[0], hapd, msg)
8375    # server continues exchange, so start from scratch for the next step
8376    rx_msg(hapd)
8377    stop_pwd_assoc(dev[0], hapd)
8378
8379    start_pwd_assoc(dev[0], hapd)
8380    resp = rx_msg(dev[0])
8381    # Too large total length
8382    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "34" + "c1ffff"
8383    tx_msg(dev[0], hapd, msg)
8384    # server continues exchange, so start from scratch for the next step
8385    rx_msg(hapd)
8386    stop_pwd_assoc(dev[0], hapd)
8387
8388    start_pwd_assoc(dev[0], hapd)
8389    resp = rx_msg(dev[0])
8390    # First fragment
8391    msg = resp[0:4] + "0009" + resp[8:12] + "0009" + "34" + "c100ff" + "aa"
8392    tx_msg(dev[0], hapd, msg)
8393    # Ack
8394    req = rx_msg(hapd)
8395    # Unexpected first fragment
8396    # --> EAP-pwd: Unexpected new fragment start when previous fragment is still in use
8397    msg = resp[0:4] + "0009" + resp[8:10] + req[10:12] + "0009" + "34" + "c100ee" + "bb"
8398    tx_msg(dev[0], hapd, msg)
8399    # server continues exchange, so start from scratch for the next step
8400    rx_msg(hapd)
8401    stop_pwd_assoc(dev[0], hapd)
8402
8403    start_pwd_assoc(dev[0], hapd)
8404    resp = rx_msg(dev[0])
8405    # Too much data in first fragment
8406    # --> EAP-pwd: Buffer overflow attack detected! (0+2 > 1)
8407    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "34" + "c10001" + "aabb"
8408    tx_msg(dev[0], hapd, msg)
8409    # EAP-Failure
8410    rx_msg(hapd)
8411    stop_pwd_assoc(dev[0], hapd)
8412
8413    start_pwd_assoc(dev[0], hapd)
8414    resp = rx_msg(dev[0])
8415    # Change parameters
8416    # --> EAP-pwd: peer changed parameters
8417    msg = resp[0:20] + "ff" + resp[22:]
8418    tx_msg(dev[0], hapd, msg)
8419    # EAP-Failure
8420    rx_msg(hapd)
8421    stop_pwd_assoc(dev[0], hapd)
8422
8423    start_pwd_assoc(dev[0], hapd)
8424    resp = rx_msg(dev[0])
8425    # Too short ID response
8426    # --> EAP-pwd: Invalid ID response
8427    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "34" + "01ffeeddcc"
8428    tx_msg(dev[0], hapd, msg)
8429    # server continues exchange, so start from scratch for the next step
8430    rx_msg(hapd)
8431    stop_pwd_assoc(dev[0], hapd)
8432
8433    start_pwd_assoc(dev[0], hapd)
8434    # EAP-pwd-Identity/Response
8435    resp = rx_msg(dev[0])
8436    tx_msg(dev[0], hapd, resp)
8437    # EAP-pwd-Commit/Request
8438    req = rx_msg(hapd)
8439    # Unexpected EAP-pwd-Identity/Response
8440    # --> EAP-pwd: Unexpected opcode=1 in state=1
8441    msg = resp[0:10] + req[10:12] + resp[12:]
8442    tx_msg(dev[0], hapd, msg)
8443    # server continues exchange, so start from scratch for the next step
8444    rx_msg(hapd)
8445    stop_pwd_assoc(dev[0], hapd)
8446
8447    start_pwd_assoc(dev[0], hapd)
8448    proxy_msg(dev[0], hapd) # EAP-pwd-Identity/Response
8449    proxy_msg(hapd, dev[0]) # EAP-pwd-Commit/Request
8450    # EAP-pwd-Commit/Response
8451    resp = rx_msg(dev[0])
8452    # Too short Commit response
8453    # --> EAP-pwd: Unexpected Commit payload length 4 (expected 96)
8454    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "34" + "02ffeeddcc"
8455    tx_msg(dev[0], hapd, msg)
8456    # EAP-Failure
8457    rx_msg(hapd)
8458    stop_pwd_assoc(dev[0], hapd)
8459
8460    start_pwd_assoc(dev[0], hapd)
8461    proxy_msg(dev[0], hapd) # EAP-pwd-Identity/Response
8462    proxy_msg(hapd, dev[0]) # EAP-pwd-Commit/Request
8463    proxy_msg(dev[0], hapd) # EAP-pwd-Commit/Response
8464    proxy_msg(hapd, dev[0]) # EAP-pwd-Confirm/Request
8465    # EAP-pwd-Confirm/Response
8466    resp = rx_msg(dev[0])
8467    # Too short Confirm response
8468    # --> EAP-pwd: Unexpected Confirm payload length 4 (expected 32)
8469    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "34" + "03ffeeddcc"
8470    tx_msg(dev[0], hapd, msg)
8471    # EAP-Failure
8472    rx_msg(hapd)
8473    stop_pwd_assoc(dev[0], hapd)
8474
8475    start_pwd_assoc(dev[0], hapd)
8476    resp = rx_msg(dev[0])
8477    # Set M=1
8478    # --> EAP-pwd: No buffer for reassembly
8479    msg = resp[0:18] + "41" + resp[20:]
8480    tx_msg(dev[0], hapd, msg)
8481    # EAP-Failure
8482    rx_msg(hapd)
8483    stop_pwd_assoc(dev[0], hapd)
8484
8485def test_eap_proto_erp(dev, apdev):
8486    """ERP protocol tests"""
8487    check_erp_capa(dev[0])
8488
8489    global eap_proto_erp_test_done
8490    eap_proto_erp_test_done = False
8491
8492    def erp_handler(ctx, req):
8493        logger.info("erp_handler - RX " + binascii.hexlify(req).decode())
8494        if 'num' not in ctx:
8495            ctx['num'] = 0
8496        ctx['num'] += 1
8497        if 'id' not in ctx:
8498            ctx['id'] = 1
8499        ctx['id'] = (ctx['id'] + 1) % 256
8500        idx = 0
8501
8502        idx += 1
8503        if ctx['num'] == idx:
8504            logger.info("Test: Missing type")
8505            return struct.pack(">BBH", EAP_CODE_INITIATE, ctx['id'], 4)
8506
8507        idx += 1
8508        if ctx['num'] == idx:
8509            logger.info("Test: Unexpected type")
8510            return struct.pack(">BBHB", EAP_CODE_INITIATE, ctx['id'], 4 + 1,
8511                               255)
8512
8513        idx += 1
8514        if ctx['num'] == idx:
8515            logger.info("Test: Missing Reserved field")
8516            return struct.pack(">BBHB", EAP_CODE_INITIATE, ctx['id'], 4 + 1,
8517                               EAP_ERP_TYPE_REAUTH_START)
8518
8519        idx += 1
8520        if ctx['num'] == idx:
8521            logger.info("Test: Zero-length TVs/TLVs")
8522            payload = b""
8523            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8524                               4 + 1 + 1 + len(payload),
8525                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8526
8527        idx += 1
8528        if ctx['num'] == idx:
8529            logger.info("Test: Too short TLV")
8530            payload = struct.pack("B", 191)
8531            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8532                               4 + 1 + 1 + len(payload),
8533                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8534
8535        idx += 1
8536        if ctx['num'] == idx:
8537            logger.info("Test: Truncated TLV")
8538            payload = struct.pack("BB", 191, 1)
8539            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8540                               4 + 1 + 1 + len(payload),
8541                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8542
8543        idx += 1
8544        if ctx['num'] == idx:
8545            logger.info("Test: Ignored unknown TLV and unknown TV/TLV terminating parsing")
8546            payload = struct.pack("BBB", 191, 0, 192)
8547            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8548                               4 + 1 + 1 + len(payload),
8549                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8550
8551        idx += 1
8552        if ctx['num'] == idx:
8553            logger.info("Test: More than one keyName-NAI")
8554            payload = struct.pack("BBBB", EAP_ERP_TLV_KEYNAME_NAI, 0,
8555                                  EAP_ERP_TLV_KEYNAME_NAI, 0)
8556            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8557                               4 + 1 + 1 + len(payload),
8558                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8559
8560        idx += 1
8561        if ctx['num'] == idx:
8562            logger.info("Test: Too short TLV keyName-NAI")
8563            payload = struct.pack("B", EAP_ERP_TLV_KEYNAME_NAI)
8564            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8565                               4 + 1 + 1 + len(payload),
8566                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8567
8568        idx += 1
8569        if ctx['num'] == idx:
8570            logger.info("Test: Truncated TLV keyName-NAI")
8571            payload = struct.pack("BB", EAP_ERP_TLV_KEYNAME_NAI, 1)
8572            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8573                               4 + 1 + 1 + len(payload),
8574                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8575
8576        idx += 1
8577        if ctx['num'] == idx:
8578            logger.info("Test: Valid rRK lifetime TV followed by too short rMSK lifetime TV")
8579            payload = struct.pack(">BLBH", EAP_ERP_TV_RRK_LIFETIME, 0,
8580                                  EAP_ERP_TV_RMSK_LIFETIME, 0)
8581            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8582                               4 + 1 + 1 + len(payload),
8583                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8584
8585        idx += 1
8586        if ctx['num'] == idx:
8587            logger.info("Test: Missing type (Finish)")
8588            return struct.pack(">BBH", EAP_CODE_FINISH, ctx['id'], 4)
8589
8590        idx += 1
8591        if ctx['num'] == idx:
8592            logger.info("Test: Unexpected type (Finish)")
8593            return struct.pack(">BBHB", EAP_CODE_FINISH, ctx['id'], 4 + 1,
8594                               255)
8595
8596        idx += 1
8597        if ctx['num'] == idx:
8598            logger.info("Test: Missing fields (Finish)")
8599            return struct.pack(">BBHB", EAP_CODE_FINISH, ctx['id'], 4 + 1,
8600                               EAP_ERP_TYPE_REAUTH)
8601
8602        idx += 1
8603        if ctx['num'] == idx:
8604            logger.info("Test: Unexpected SEQ (Finish)")
8605            return struct.pack(">BBHBBHB", EAP_CODE_FINISH, ctx['id'],
8606                               4 + 1 + 4,
8607                               EAP_ERP_TYPE_REAUTH, 0, 0xffff, 0)
8608
8609        logger.info("No more test responses available - test case completed")
8610        global eap_proto_erp_test_done
8611        eap_proto_erp_test_done = True
8612        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
8613
8614    srv = start_radius_server(erp_handler)
8615
8616    try:
8617        hapd = start_ap(apdev[0])
8618        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8619
8620        i = 0
8621        while not eap_proto_erp_test_done:
8622            i += 1
8623            logger.info("Running connection iteration %d" % i)
8624            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8625                           eap="PAX", identity="pax.user@example.com",
8626                           password_hex="0123456789abcdef0123456789abcdef",
8627                           wait_connect=False)
8628            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
8629            if ev is None:
8630                raise Exception("Timeout on EAP start")
8631            time.sleep(0.1)
8632            dev[0].request("REMOVE_NETWORK all")
8633            dev[0].wait_disconnected(timeout=1)
8634            dev[0].dump_monitor()
8635    finally:
8636        stop_radius_server(srv)
8637
8638def test_eap_proto_fast_errors(dev, apdev):
8639    """EAP-FAST local error cases"""
8640    check_eap_capa(dev[0], "FAST")
8641    params = hostapd.wpa2_eap_params(ssid="eap-test")
8642    hapd = hostapd.add_ap(apdev[0], params)
8643    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8644
8645    for i in range(1, 5):
8646        with alloc_fail(dev[0], i, "eap_fast_init"):
8647            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8648                           eap="FAST", anonymous_identity="FAST",
8649                           identity="user", password="password",
8650                           ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
8651                           phase1="fast_provisioning=2",
8652                           pac_file="blob://fast_pac_auth",
8653                           wait_connect=False)
8654            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
8655                                   timeout=5)
8656            if ev is None:
8657                raise Exception("Timeout on EAP start")
8658            dev[0].request("REMOVE_NETWORK all")
8659            dev[0].wait_disconnected()
8660
8661    tests = [(1, "wpabuf_alloc;eap_fast_tlv_eap_payload"),
8662             (1, "eap_fast_derive_key;eap_fast_derive_key_auth"),
8663             (1, "eap_msg_alloc;eap_peer_tls_phase2_nak"),
8664             (1, "wpabuf_alloc;eap_fast_tlv_result"),
8665             (1, "wpabuf_alloc;eap_fast_tlv_pac_ack"),
8666             (1, "=eap_peer_tls_derive_session_id;eap_fast_process_crypto_binding"),
8667             (1, "eap_peer_tls_decrypt;eap_fast_decrypt"),
8668             (1, "eap_fast_getKey"),
8669             (1, "eap_fast_get_session_id"),
8670             (1, "eap_fast_get_emsk")]
8671    for count, func in tests:
8672        dev[0].request("SET blob fast_pac_auth_errors ")
8673        with alloc_fail(dev[0], count, func):
8674            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8675                           eap="FAST", anonymous_identity="FAST",
8676                           identity="user@example.com", password="password",
8677                           ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
8678                           phase1="fast_provisioning=2",
8679                           pac_file="blob://fast_pac_auth_errors",
8680                           erp="1",
8681                           wait_connect=False)
8682            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8683                                   timeout=15)
8684            if ev is None:
8685                raise Exception("Timeout on EAP start")
8686            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8687            dev[0].request("REMOVE_NETWORK all")
8688            dev[0].wait_disconnected()
8689
8690    tests = [(1, "eap_fast_derive_key;eap_fast_derive_key_provisioning"),
8691             (1, "eap_mschapv2_getKey;eap_fast_get_phase2_key"),
8692             (1, "=eap_fast_use_pac_opaque"),
8693             (1, "eap_fast_copy_buf"),
8694             (1, "=eap_fast_add_pac"),
8695             (1, "=eap_fast_init_pac_data"),
8696             (1, "=eap_fast_write_pac"),
8697             (2, "=eap_fast_write_pac")]
8698    for count, func in tests:
8699        dev[0].request("SET blob fast_pac_errors ")
8700        with alloc_fail(dev[0], count, func):
8701            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8702                           eap="FAST", anonymous_identity="FAST",
8703                           identity="user", password="password",
8704                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8705                           phase1="fast_provisioning=1",
8706                           pac_file="blob://fast_pac_errors",
8707                           erp="1",
8708                           wait_connect=False)
8709            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8710                                   timeout=15)
8711            if ev is None:
8712                raise Exception("Timeout on EAP start")
8713            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8714            dev[0].request("REMOVE_NETWORK all")
8715            dev[0].wait_disconnected()
8716
8717    tests = [(1, "eap_fast_get_cmk;eap_fast_process_crypto_binding"),
8718             (1, "eap_fast_derive_eap_msk;eap_fast_process_crypto_binding"),
8719             (1, "eap_fast_derive_eap_emsk;eap_fast_process_crypto_binding")]
8720    for count, func in tests:
8721        dev[0].request("SET blob fast_pac_auth_errors ")
8722        with fail_test(dev[0], count, func):
8723            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8724                           eap="FAST", anonymous_identity="FAST",
8725                           identity="user", password="password",
8726                           ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
8727                           phase1="fast_provisioning=2",
8728                           pac_file="blob://fast_pac_auth_errors",
8729                           erp="1",
8730                           wait_connect=False)
8731            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8732                                   timeout=15)
8733            if ev is None:
8734                raise Exception("Timeout on EAP start")
8735            wait_fail_trigger(dev[0], "GET_FAIL")
8736            dev[0].request("REMOVE_NETWORK all")
8737            dev[0].wait_disconnected()
8738
8739    dev[0].request("SET blob fast_pac_errors ")
8740    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8741                   eap="FAST", anonymous_identity="FAST",
8742                   identity="user", password="password",
8743                   ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
8744                   phase1="fast_provisioning=1",
8745                   pac_file="blob://fast_pac_errors",
8746                   wait_connect=False)
8747    ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
8748    if ev is None:
8749        raise Exception("Timeout on EAP start")
8750    # EAP-FAST: Only EAP-MSCHAPv2 is allowed during unauthenticated
8751    # provisioning; reject phase2 type 6
8752    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
8753    if ev is None:
8754        raise Exception("Timeout on EAP failure")
8755    dev[0].request("REMOVE_NETWORK all")
8756    dev[0].wait_disconnected()
8757
8758    logger.info("Wrong password in Phase 2")
8759    dev[0].request("SET blob fast_pac_errors ")
8760    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8761                   eap="FAST", anonymous_identity="FAST",
8762                   identity="user", password="wrong password",
8763                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8764                   phase1="fast_provisioning=1",
8765                   pac_file="blob://fast_pac_errors",
8766                   wait_connect=False)
8767    ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
8768    if ev is None:
8769        raise Exception("Timeout on EAP start")
8770    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
8771    if ev is None:
8772        raise Exception("Timeout on EAP failure")
8773    dev[0].request("REMOVE_NETWORK all")
8774    dev[0].wait_disconnected()
8775
8776    tests = ["FOOBAR\n",
8777             "wpa_supplicant EAP-FAST PAC file - version 1\nFOOBAR\n",
8778             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\n",
8779             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nSTART\n",
8780             "wpa_supplicant EAP-FAST PAC file - version 1\nEND\n",
8781             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Type=12345\nEND\n"
8782             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Key=12\nEND\n",
8783             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Key=1\nEND\n",
8784             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Key=1q\nEND\n",
8785             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Opaque=1\nEND\n",
8786             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nA-ID=1\nEND\n",
8787             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nI-ID=1\nEND\n",
8788             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nA-ID-Info=1\nEND\n"]
8789    for pac in tests:
8790        blob = binascii.hexlify(pac.encode()).decode()
8791        dev[0].request("SET blob fast_pac_errors " + blob)
8792        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8793                       eap="FAST", anonymous_identity="FAST",
8794                       identity="user", password="password",
8795                       ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
8796                       phase1="fast_provisioning=2",
8797                       pac_file="blob://fast_pac_errors",
8798                       wait_connect=False)
8799        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
8800                               timeout=5)
8801        if ev is None:
8802            raise Exception("Timeout on EAP start")
8803        dev[0].request("REMOVE_NETWORK all")
8804        dev[0].wait_disconnected()
8805
8806    tests = ["wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nEND\n",
8807             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nEND\nSTART\nEND\nSTART\nEND\n"]
8808    for pac in tests:
8809        blob = binascii.hexlify(pac.encode()).decode()
8810        dev[0].request("SET blob fast_pac_errors " + blob)
8811        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8812                       eap="FAST", anonymous_identity="FAST",
8813                       identity="user", password="password",
8814                       ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
8815                       phase1="fast_provisioning=2",
8816                       pac_file="blob://fast_pac_errors")
8817        dev[0].request("REMOVE_NETWORK all")
8818        dev[0].wait_disconnected()
8819
8820    dev[0].request("SET blob fast_pac_errors ")
8821
8822def test_eap_proto_peap_errors_server(dev, apdev):
8823    """EAP-PEAP local error cases on server"""
8824    params = int_eap_server_params()
8825    hapd = hostapd.add_ap(apdev[0], params)
8826    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8827
8828    tests = [(1, "get_asymetric_start_key;eap_mschapv2_getKey"),
8829             (1, "generate_authenticator_response_pwhash;eap_mschapv2_process_response"),
8830             (1, "hash_nt_password_hash;eap_mschapv2_process_response"),
8831             (1, "get_master_key;eap_mschapv2_process_response")]
8832    for count, func in tests:
8833        with fail_test(hapd, count, func):
8834            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
8835                           scan_freq="2412",
8836                           eap="PEAP", anonymous_identity="peap",
8837                           identity="user", password="password",
8838                           phase1="peapver=0 crypto_binding=2",
8839                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8840                           erp="1", wait_connect=False)
8841            ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
8842            if ev is None:
8843                raise Exception("EAP-Failure not reported")
8844            dev[0].request("REMOVE_NETWORK all")
8845            dev[0].wait_disconnected()
8846
8847def test_eap_proto_peap_errors(dev, apdev):
8848    """EAP-PEAP local error cases"""
8849    check_eap_capa(dev[0], "PEAP")
8850    check_eap_capa(dev[0], "MSCHAPV2")
8851    params = hostapd.wpa2_eap_params(ssid="eap-test")
8852    hapd = hostapd.add_ap(apdev[0], params)
8853    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8854
8855    for i in range(1, 5):
8856        with alloc_fail(dev[0], i, "eap_peap_init"):
8857            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8858                           eap="PEAP", anonymous_identity="peap",
8859                           identity="user", password="password",
8860                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8861                           wait_connect=False)
8862            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
8863                                   timeout=5)
8864            if ev is None:
8865                raise Exception("Timeout on EAP start")
8866            dev[0].request("REMOVE_NETWORK all")
8867            dev[0].wait_disconnected()
8868
8869    tests = [(1, "eap_mschapv2_getKey;eap_peap_get_isk;eap_peap_derive_cmk"),
8870             (1, "eap_msg_alloc;eap_tlv_build_result"),
8871             (1, "eap_mschapv2_init;eap_peap_phase2_request"),
8872             (1, "eap_peer_tls_decrypt;eap_peap_decrypt"),
8873             (1, "wpabuf_alloc;=eap_peap_decrypt"),
8874             (1, "eap_peer_tls_encrypt;eap_peap_decrypt"),
8875             (1, "eap_peer_tls_process_helper;eap_peap_process"),
8876             (1, "eap_peer_tls_derive_key;eap_peap_process"),
8877             (1, "eap_peer_tls_derive_session_id;eap_peap_process"),
8878             (1, "eap_peap_getKey"),
8879             (1, "eap_peap_get_session_id")]
8880    for count, func in tests:
8881        with alloc_fail(dev[0], count, func):
8882            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8883                           eap="PEAP", anonymous_identity="peap",
8884                           identity="user", password="password",
8885                           phase1="peapver=0 crypto_binding=2",
8886                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8887                           erp="1", wait_connect=False)
8888            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8889                                   timeout=15)
8890            if ev is None:
8891                raise Exception("Timeout on EAP start")
8892            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8893            dev[0].request("REMOVE_NETWORK all")
8894            dev[0].wait_disconnected()
8895
8896    tests = [(1, "peap_prfplus;eap_peap_derive_cmk"),
8897             (1, "eap_tlv_add_cryptobinding;eap_tlv_build_result"),
8898             (1, "peap_prfplus;eap_peap_getKey"),
8899             (1, "get_asymetric_start_key;eap_mschapv2_getKey")]
8900    for count, func in tests:
8901        with fail_test(dev[0], count, func):
8902            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8903                           eap="PEAP", anonymous_identity="peap",
8904                           identity="user", password="password",
8905                           phase1="peapver=0 crypto_binding=2",
8906                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8907                           erp="1", wait_connect=False)
8908            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8909                                   timeout=15)
8910            if ev is None:
8911                raise Exception("Timeout on EAP start")
8912            wait_fail_trigger(dev[0], "GET_FAIL")
8913            dev[0].request("REMOVE_NETWORK all")
8914            dev[0].wait_disconnected()
8915
8916    with alloc_fail(dev[0], 1,
8917                    "eap_peer_tls_phase2_nak;eap_peap_phase2_request"):
8918        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8919                       eap="PEAP", anonymous_identity="peap",
8920                       identity="cert user", password="password",
8921                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8922                       wait_connect=False)
8923        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8924        dev[0].request("REMOVE_NETWORK all")
8925        dev[0].wait_disconnected()
8926
8927def test_eap_proto_ttls_errors(dev, apdev):
8928    """EAP-TTLS local error cases"""
8929    check_eap_capa(dev[0], "TTLS")
8930    check_eap_capa(dev[0], "MSCHAPV2")
8931    params = hostapd.wpa2_eap_params(ssid="eap-test")
8932    hapd = hostapd.add_ap(apdev[0], params)
8933    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8934
8935    for i in range(1, 5):
8936        with alloc_fail(dev[0], i, "eap_ttls_init"):
8937            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8938                           eap="TTLS", anonymous_identity="ttls",
8939                           identity="user", password="password",
8940                           ca_cert="auth_serv/ca.pem",
8941                           phase2="autheap=MSCHAPV2",
8942                           wait_connect=False)
8943            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
8944                                   timeout=5)
8945            if ev is None:
8946                raise Exception("Timeout on EAP start")
8947            dev[0].request("REMOVE_NETWORK all")
8948            dev[0].wait_disconnected()
8949
8950    tests = [(1, "eap_peer_tls_derive_key;eap_ttls_v0_derive_key",
8951              "DOMAIN\\mschapv2 user", "auth=MSCHAPV2"),
8952             (1, "eap_peer_tls_derive_session_id;eap_ttls_v0_derive_key",
8953              "DOMAIN\\mschapv2 user", "auth=MSCHAPV2"),
8954             (1, "wpabuf_alloc;eap_ttls_phase2_request_mschapv2",
8955              "DOMAIN\\mschapv2 user", "auth=MSCHAPV2"),
8956             (1, "eap_peer_tls_derive_key;eap_ttls_phase2_request_mschapv2",
8957              "DOMAIN\\mschapv2 user", "auth=MSCHAPV2"),
8958             (1, "eap_peer_tls_encrypt;eap_ttls_encrypt_response;eap_ttls_implicit_identity_request",
8959              "DOMAIN\\mschapv2 user", "auth=MSCHAPV2"),
8960             (1, "eap_peer_tls_decrypt;eap_ttls_decrypt",
8961              "DOMAIN\\mschapv2 user", "auth=MSCHAPV2"),
8962             (1, "eap_ttls_getKey",
8963              "DOMAIN\\mschapv2 user", "auth=MSCHAPV2"),
8964             (1, "eap_ttls_get_session_id",
8965              "DOMAIN\\mschapv2 user", "auth=MSCHAPV2"),
8966             (1, "eap_ttls_get_emsk",
8967              "mschapv2 user@domain", "auth=MSCHAPV2"),
8968             (1, "wpabuf_alloc;eap_ttls_phase2_request_mschap",
8969              "mschap user", "auth=MSCHAP"),
8970             (1, "eap_peer_tls_derive_key;eap_ttls_phase2_request_mschap",
8971              "mschap user", "auth=MSCHAP"),
8972             (1, "wpabuf_alloc;eap_ttls_phase2_request_chap",
8973              "chap user", "auth=CHAP"),
8974             (1, "eap_peer_tls_derive_key;eap_ttls_phase2_request_chap",
8975              "chap user", "auth=CHAP"),
8976             (1, "wpabuf_alloc;eap_ttls_phase2_request_pap",
8977              "pap user", "auth=PAP"),
8978             (1, "wpabuf_alloc;eap_ttls_avp_encapsulate",
8979              "user", "autheap=MSCHAPV2"),
8980             (1, "eap_mschapv2_init;eap_ttls_phase2_request_eap_method",
8981              "user", "autheap=MSCHAPV2"),
8982             (1, "eap_sm_buildIdentity;eap_ttls_phase2_request_eap",
8983              "user", "autheap=MSCHAPV2"),
8984             (1, "eap_ttls_avp_encapsulate;eap_ttls_phase2_request_eap",
8985              "user", "autheap=MSCHAPV2"),
8986             (1, "eap_ttls_parse_attr_eap",
8987              "user", "autheap=MSCHAPV2"),
8988             (1, "eap_peer_tls_encrypt;eap_ttls_encrypt_response;eap_ttls_process_decrypted",
8989              "user", "autheap=MSCHAPV2"),
8990             (1, "eap_ttls_fake_identity_request",
8991              "user", "autheap=MSCHAPV2"),
8992             (1, "eap_msg_alloc;eap_tls_process_output",
8993              "user", "autheap=MSCHAPV2"),
8994             (1, "eap_msg_alloc;eap_peer_tls_build_ack",
8995              "user", "autheap=MSCHAPV2"),
8996             (1, "eap_peer_tls_phase2_nak;eap_ttls_phase2_request_eap_method",
8997              "cert user", "autheap=MSCHAPV2")]
8998    tls = dev[0].request("GET tls_library")
8999    if tls.startswith("internal"):
9000        tests += [(1, "tlsv1_client_decrypt;eap_peer_tls_decrypt",
9001                   "user", "autheap=MSCHAPV2")]
9002    else:
9003        tests += [(1, "tls_connection_decrypt;eap_peer_tls_decrypt",
9004                   "user", "autheap=MSCHAPV2")]
9005    for count, func, identity, phase2 in tests:
9006        with alloc_fail(dev[0], count, func):
9007            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9008                           eap="TTLS", anonymous_identity="ttls",
9009                           identity=identity, password="password",
9010                           ca_cert="auth_serv/ca.pem", phase2=phase2,
9011                           erp="1", wait_connect=False)
9012            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
9013                                   timeout=15)
9014            if ev is None:
9015                raise Exception("Timeout on EAP start")
9016            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL",
9017                              note="Allocation failure not triggered for: %d:%s" % (count, func))
9018            dev[0].request("REMOVE_NETWORK all")
9019            dev[0].wait_disconnected()
9020
9021    tests = [(1, "os_get_random;eap_ttls_phase2_request_mschapv2"),
9022             (1, "mschapv2_derive_response;eap_ttls_phase2_request_mschapv2")]
9023    for count, func in tests:
9024        with fail_test(dev[0], count, func):
9025            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9026                           eap="TTLS", anonymous_identity="ttls",
9027                           identity="DOMAIN\\mschapv2 user",
9028                           password="password",
9029                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
9030                           erp="1", wait_connect=False)
9031            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
9032                                   timeout=15)
9033            if ev is None:
9034                raise Exception("Timeout on EAP start")
9035            wait_fail_trigger(dev[0], "GET_FAIL",
9036                              note="Test failure not triggered for: %d:%s" % (count, func))
9037            dev[0].request("REMOVE_NETWORK all")
9038            dev[0].wait_disconnected()
9039
9040    tests = [(1, "nt_challenge_response;eap_ttls_phase2_request_mschap")]
9041    for count, func in tests:
9042        with fail_test(dev[0], count, func):
9043            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9044                           eap="TTLS", anonymous_identity="ttls",
9045                           identity="mschap user", password="password",
9046                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
9047                           erp="1", wait_connect=False)
9048            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
9049                                   timeout=15)
9050            if ev is None:
9051                raise Exception("Timeout on EAP start")
9052            wait_fail_trigger(dev[0], "GET_FAIL",
9053                              note="Test failure not triggered for: %d:%s" % (count, func))
9054            dev[0].request("REMOVE_NETWORK all")
9055            dev[0].wait_disconnected()
9056
9057def test_eap_proto_expanded(dev, apdev):
9058    """EAP protocol tests with expanded header"""
9059    global eap_proto_expanded_test_done
9060    eap_proto_expanded_test_done = False
9061
9062    def expanded_handler(ctx, req):
9063        logger.info("expanded_handler - RX " + binascii.hexlify(req).decode())
9064        if 'num' not in ctx:
9065            ctx['num'] = 0
9066        ctx['num'] += 1
9067        if 'id' not in ctx:
9068            ctx['id'] = 1
9069        ctx['id'] = (ctx['id'] + 1) % 256
9070        idx = 0
9071
9072        idx += 1
9073        if ctx['num'] == idx:
9074            logger.info("Test: MD5 challenge in expanded header")
9075            return struct.pack(">BBHB3BLBBB", EAP_CODE_REQUEST, ctx['id'],
9076                               4 + 1 + 3 + 4 + 3,
9077                               EAP_TYPE_EXPANDED, 0, 0, 0, EAP_TYPE_MD5,
9078                               1, 0xaa, ord('n'))
9079        idx += 1
9080        if ctx['num'] == idx:
9081            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9082
9083        idx += 1
9084        if ctx['num'] == idx:
9085            logger.info("Test: Invalid expanded EAP length")
9086            return struct.pack(">BBHB3BH", EAP_CODE_REQUEST, ctx['id'],
9087                               4 + 1 + 3 + 2,
9088                               EAP_TYPE_EXPANDED, 0, 0, 0, EAP_TYPE_MD5)
9089        idx += 1
9090        if ctx['num'] == idx:
9091            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9092
9093        idx += 1
9094        if ctx['num'] == idx:
9095            logger.info("Test: Invalid expanded frame type")
9096            return struct.pack(">BBHB3BL", EAP_CODE_REQUEST, ctx['id'],
9097                               4 + 1 + 3 + 4,
9098                               EAP_TYPE_EXPANDED, 0, 0, 1, EAP_TYPE_MD5)
9099        idx += 1
9100        if ctx['num'] == idx:
9101            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9102
9103        idx += 1
9104        if ctx['num'] == idx:
9105            logger.info("Test: MSCHAPv2 Challenge")
9106            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
9107                               4 + 1 + 4 + 1 + 16 + 6,
9108                               EAP_TYPE_MSCHAPV2,
9109                               1, 0, 4 + 1 + 16 + 6, 16) + 16*b'A' + b'foobar'
9110        idx += 1
9111        if ctx['num'] == idx:
9112            logger.info("Test: Invalid expanded frame type")
9113            return struct.pack(">BBHB3BL", EAP_CODE_REQUEST, ctx['id'],
9114                               4 + 1 + 3 + 4,
9115                               EAP_TYPE_EXPANDED, 0, 0, 1, EAP_TYPE_MSCHAPV2)
9116
9117        logger.info("No more test responses available - test case completed")
9118        global eap_proto_expanded_test_done
9119        eap_proto_expanded_test_done = True
9120        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9121
9122    srv = start_radius_server(expanded_handler)
9123
9124    try:
9125        hapd = start_ap(apdev[0])
9126        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9127
9128        i = 0
9129        while not eap_proto_expanded_test_done:
9130            i += 1
9131            logger.info("Running connection iteration %d" % i)
9132            if i == 4:
9133                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9134                               eap="MSCHAPV2", identity="user",
9135                               password="password",
9136                               wait_connect=False)
9137            else:
9138                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9139                               eap="MD5", identity="user", password="password",
9140                               wait_connect=False)
9141            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
9142            if ev is None:
9143                raise Exception("Timeout on EAP start")
9144            if i in [1]:
9145                ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
9146                if ev is None:
9147                    raise Exception("Timeout on EAP method start")
9148                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
9149                if ev is None:
9150                    raise Exception("Timeout on EAP failure")
9151            elif i in [2, 3]:
9152                ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
9153                                       timeout=5)
9154                if ev is None:
9155                    raise Exception("Timeout on EAP proposed method")
9156                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
9157                if ev is None:
9158                    raise Exception("Timeout on EAP failure")
9159            else:
9160                time.sleep(0.1)
9161            dev[0].request("REMOVE_NETWORK all")
9162            dev[0].wait_disconnected(timeout=1)
9163            dev[0].dump_monitor()
9164    finally:
9165        stop_radius_server(srv)
9166
9167def test_eap_proto_tls(dev, apdev):
9168    """EAP-TLS protocol tests"""
9169    check_eap_capa(dev[0], "TLS")
9170    global eap_proto_tls_test_done, eap_proto_tls_test_wait
9171    eap_proto_tls_test_done = False
9172    eap_proto_tls_test_wait = False
9173
9174    def tls_handler(ctx, req):
9175        logger.info("tls_handler - RX " + binascii.hexlify(req).decode())
9176        if 'num' not in ctx:
9177            ctx['num'] = 0
9178        ctx['num'] += 1
9179        if 'id' not in ctx:
9180            ctx['id'] = 1
9181        ctx['id'] = (ctx['id'] + 1) % 256
9182        idx = 0
9183
9184        global eap_proto_tls_test_wait
9185
9186        idx += 1
9187        if ctx['num'] == idx:
9188            logger.info("Test: Too much payload in TLS/Start: TLS Message Length (0 bytes) smaller than this fragment (1 bytes)")
9189            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
9190                               4 + 1 + 1 + 4 + 1,
9191                               EAP_TYPE_TLS, 0xa0, 0, 1)
9192
9193        idx += 1
9194        if ctx['num'] == idx:
9195            logger.info("Test: Fragmented TLS/Start")
9196            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
9197                               4 + 1 + 1 + 4 + 1,
9198                               EAP_TYPE_TLS, 0xe0, 2, 1)
9199        idx += 1
9200        if ctx['num'] == idx:
9201            logger.info("Test: Too long fragment of TLS/Start: Invalid reassembly state: tls_in_left=2 tls_in_len=0 in_len=0")
9202            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
9203                               4 + 1 + 1 + 2,
9204                               EAP_TYPE_TLS, 0x00, 2, 3)
9205        idx += 1
9206        if ctx['num'] == idx:
9207            logger.info("Test: EAP-Failure")
9208            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9209
9210        idx += 1
9211        if ctx['num'] == idx:
9212            logger.info("Test: TLS/Start")
9213            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9214                               4 + 1 + 1,
9215                               EAP_TYPE_TLS, 0x20)
9216        idx += 1
9217        if ctx['num'] == idx:
9218            logger.info("Test: Fragmented TLS message")
9219            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
9220                               4 + 1 + 1 + 4 + 1,
9221                               EAP_TYPE_TLS, 0xc0, 2, 1)
9222        idx += 1
9223        if ctx['num'] == idx:
9224            logger.info("Test: Invalid TLS message: no Flags octet included + workaround")
9225            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
9226                               4 + 1,
9227                               EAP_TYPE_TLS)
9228        idx += 1
9229        if ctx['num'] == idx:
9230            logger.info("Test: Too long fragment of TLS message: more data than TLS message length indicated")
9231            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
9232                               4 + 1 + 1 + 2,
9233                               EAP_TYPE_TLS, 0x00, 2, 3)
9234        idx += 1
9235        if ctx['num'] == idx:
9236            logger.info("Test: EAP-Failure")
9237            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9238
9239        idx += 1
9240        if ctx['num'] == idx:
9241            logger.info("Test: Fragmented TLS/Start and truncated Message Length field")
9242            return struct.pack(">BBHBB3B", EAP_CODE_REQUEST, ctx['id'],
9243                               4 + 1 + 1 + 3,
9244                               EAP_TYPE_TLS, 0xe0, 1, 2, 3)
9245
9246        idx += 1
9247        if ctx['num'] == idx:
9248            logger.info("Test: TLS/Start")
9249            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9250                               4 + 1 + 1,
9251                               EAP_TYPE_TLS, 0x20)
9252        idx += 1
9253        if ctx['num'] == idx:
9254            logger.info("Test: Fragmented TLS message")
9255            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
9256                               4 + 1 + 1 + 4 + 1,
9257                               EAP_TYPE_TLS, 0xc0, 2, 1)
9258        idx += 1
9259        if ctx['num'] == idx:
9260            logger.info("Test: Invalid TLS message: no Flags octet included + workaround disabled")
9261            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
9262                               4 + 1,
9263                               EAP_TYPE_TLS)
9264
9265        idx += 1
9266        if ctx['num'] == idx:
9267            logger.info("Test: TLS/Start")
9268            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9269                               4 + 1 + 1,
9270                               EAP_TYPE_TLS, 0x20)
9271        idx += 1
9272        if ctx['num'] == idx:
9273            logger.info("Test: Fragmented TLS message (long; first)")
9274            payload = 1450*b'A'
9275            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
9276                               4 + 1 + 1 + 4 + len(payload),
9277                               EAP_TYPE_TLS, 0xc0, 65536) + payload
9278        # "Too long TLS fragment (size over 64 kB)" on the last one
9279        for i in range(44):
9280            idx += 1
9281            if ctx['num'] == idx:
9282                logger.info("Test: Fragmented TLS message (long; cont %d)" % i)
9283                eap_proto_tls_test_wait = True
9284                payload = 1470*b'A'
9285                return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9286                                   4 + 1 + 1 + len(payload),
9287                                   EAP_TYPE_TLS, 0x40) + payload
9288        eap_proto_tls_test_wait = False
9289        idx += 1
9290        if ctx['num'] == idx:
9291            logger.info("Test: EAP-Failure")
9292            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9293
9294        idx += 1
9295        if ctx['num'] == idx:
9296            logger.info("Test: TLS/Start")
9297            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9298                               4 + 1 + 1,
9299                               EAP_TYPE_TLS, 0x20)
9300        idx += 1
9301        if ctx['num'] == idx:
9302            logger.info("Test: Non-ACK to more-fragment message")
9303            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
9304                               4 + 1 + 1 + 1,
9305                               EAP_TYPE_TLS, 0x00, 255)
9306        idx += 1
9307        if ctx['num'] == idx:
9308            logger.info("Test: EAP-Failure")
9309            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9310
9311        logger.info("No more test responses available - test case completed")
9312        global eap_proto_tls_test_done
9313        eap_proto_tls_test_done = True
9314        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9315
9316    srv = start_radius_server(tls_handler)
9317
9318    try:
9319        hapd = start_ap(apdev[0])
9320        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9321
9322        i = 0
9323        while not eap_proto_tls_test_done:
9324            i += 1
9325            logger.info("Running connection iteration %d" % i)
9326            workaround = "0" if i == 6 else "1"
9327            fragment_size = "100" if i == 8 else "1400"
9328            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9329                           eap="TLS", identity="tls user",
9330                           ca_cert="auth_serv/ca.pem",
9331                           client_cert="auth_serv/user.pem",
9332                           private_key="auth_serv/user.key",
9333                           eap_workaround=workaround,
9334                           fragment_size=fragment_size,
9335                           wait_connect=False)
9336            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
9337            if ev is None:
9338                raise Exception("Timeout on EAP start")
9339            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD",
9340                                    "CTRL-EVENT-EAP-STATUS"], timeout=5)
9341            if ev is None:
9342                raise Exception("Timeout on EAP method start")
9343            time.sleep(0.1)
9344            start = os.times()[4]
9345            while eap_proto_tls_test_wait:
9346                now = os.times()[4]
9347                if now - start > 10:
9348                    break
9349                time.sleep(0.1)
9350            dev[0].request("REMOVE_NETWORK all")
9351            dev[0].wait_disconnected(timeout=1)
9352            dev[0].dump_monitor()
9353    finally:
9354        stop_radius_server(srv)
9355
9356def test_eap_proto_tnc(dev, apdev):
9357    """EAP-TNC protocol tests"""
9358    check_eap_capa(dev[0], "TNC")
9359    global eap_proto_tnc_test_done
9360    eap_proto_tnc_test_done = False
9361
9362    def tnc_handler(ctx, req):
9363        logger.info("tnc_handler - RX " + binascii.hexlify(req).decode())
9364        if 'num' not in ctx:
9365            ctx['num'] = 0
9366        ctx['num'] += 1
9367        if 'id' not in ctx:
9368            ctx['id'] = 1
9369        ctx['id'] = (ctx['id'] + 1) % 256
9370        idx = 0
9371
9372        idx += 1
9373        if ctx['num'] == idx:
9374            logger.info("Test: TNC start with unsupported version")
9375            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9376                               4 + 1 + 1,
9377                               EAP_TYPE_TNC, 0x20)
9378
9379        idx += 1
9380        if ctx['num'] == idx:
9381            logger.info("Test: TNC without Flags field")
9382            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
9383                               4 + 1,
9384                               EAP_TYPE_TNC)
9385
9386        idx += 1
9387        if ctx['num'] == idx:
9388            logger.info("Test: Message underflow due to missing Message Length")
9389            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9390                               4 + 1 + 1,
9391                               EAP_TYPE_TNC, 0xa1)
9392
9393        idx += 1
9394        if ctx['num'] == idx:
9395            logger.info("Test: Invalid Message Length")
9396            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
9397                               4 + 1 + 1 + 4 + 1,
9398                               EAP_TYPE_TNC, 0xa1, 0, 0)
9399
9400        idx += 1
9401        if ctx['num'] == idx:
9402            logger.info("Test: Invalid Message Length")
9403            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
9404                               4 + 1 + 1 + 4,
9405                               EAP_TYPE_TNC, 0xe1, 75001)
9406
9407        idx += 1
9408        if ctx['num'] == idx:
9409            logger.info("Test: Start with Message Length")
9410            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
9411                               4 + 1 + 1 + 4,
9412                               EAP_TYPE_TNC, 0xa1, 1)
9413        idx += 1
9414        if ctx['num'] == idx:
9415            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9416
9417        idx += 1
9418        if ctx['num'] == idx:
9419            logger.info("Test: Server used start flag again")
9420            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9421                               4 + 1 + 1,
9422                               EAP_TYPE_TNC, 0x21)
9423        idx += 1
9424        if ctx['num'] == idx:
9425            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9426                               4 + 1 + 1,
9427                               EAP_TYPE_TNC, 0x21)
9428
9429        idx += 1
9430        if ctx['num'] == idx:
9431            logger.info("Test: Fragmentation and unexpected payload in ack")
9432            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9433                               4 + 1 + 1,
9434                               EAP_TYPE_TNC, 0x21)
9435        idx += 1
9436        if ctx['num'] == idx:
9437            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9438                               4 + 1 + 1,
9439                               EAP_TYPE_TNC, 0x01)
9440        idx += 1
9441        if ctx['num'] == idx:
9442            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
9443                               4 + 1 + 1 + 1,
9444                               EAP_TYPE_TNC, 0x01, 0)
9445
9446        idx += 1
9447        if ctx['num'] == idx:
9448            logger.info("Test: Server fragmenting and fragment overflow")
9449            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
9450                               4 + 1 + 1 + 4 + 1,
9451                               EAP_TYPE_TNC, 0xe1, 2, 1)
9452        idx += 1
9453        if ctx['num'] == idx:
9454            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
9455                               4 + 1 + 1 + 2,
9456                               EAP_TYPE_TNC, 0x01, 2, 3)
9457
9458        idx += 1
9459        if ctx['num'] == idx:
9460            logger.info("Test: Server fragmenting and no message length in a fragment")
9461            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
9462                               4 + 1 + 1 + 1,
9463                               EAP_TYPE_TNC, 0x61, 2)
9464
9465        idx += 1
9466        if ctx['num'] == idx:
9467            logger.info("Test: TNC start followed by invalid TNCCS-Batch")
9468            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9469                               4 + 1 + 1,
9470                               EAP_TYPE_TNC, 0x21)
9471        idx += 1
9472        if ctx['num'] == idx:
9473            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9474            resp = b"FOO"
9475            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9476                               4 + 1 + 1 + len(resp),
9477                               EAP_TYPE_TNC, 0x01) + resp
9478
9479        idx += 1
9480        if ctx['num'] == idx:
9481            logger.info("Test: TNC start followed by invalid TNCCS-Batch (2)")
9482            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9483                               4 + 1 + 1,
9484                               EAP_TYPE_TNC, 0x21)
9485        idx += 1
9486        if ctx['num'] == idx:
9487            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9488            resp = b"</TNCCS-Batch><TNCCS-Batch>"
9489            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9490                               4 + 1 + 1 + len(resp),
9491                               EAP_TYPE_TNC, 0x01) + resp
9492
9493        idx += 1
9494        if ctx['num'] == idx:
9495            logger.info("Test: TNCCS-Batch missing BatchId attribute")
9496            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9497                               4 + 1 + 1,
9498                               EAP_TYPE_TNC, 0x21)
9499        idx += 1
9500        if ctx['num'] == idx:
9501            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9502            resp = b"<TNCCS-Batch    foo=3></TNCCS-Batch>"
9503            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9504                               4 + 1 + 1 + len(resp),
9505                               EAP_TYPE_TNC, 0x01) + resp
9506
9507        idx += 1
9508        if ctx['num'] == idx:
9509            logger.info("Test: Unexpected IF-TNCCS BatchId")
9510            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9511                               4 + 1 + 1,
9512                               EAP_TYPE_TNC, 0x21)
9513        idx += 1
9514        if ctx['num'] == idx:
9515            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9516            resp = b"<TNCCS-Batch    BatchId=123456789></TNCCS-Batch>"
9517            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9518                               4 + 1 + 1 + len(resp),
9519                               EAP_TYPE_TNC, 0x01) + resp
9520
9521        idx += 1
9522        if ctx['num'] == idx:
9523            logger.info("Test: Missing IMC-IMV-Message and TNCC-TNCS-Message end tags")
9524            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9525                               4 + 1 + 1,
9526                               EAP_TYPE_TNC, 0x21)
9527        idx += 1
9528        if ctx['num'] == idx:
9529            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9530            resp = b"<TNCCS-Batch BatchId=2><IMC-IMV-Message><TNCC-TNCS-Message></TNCCS-Batch>"
9531            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9532                               4 + 1 + 1 + len(resp),
9533                               EAP_TYPE_TNC, 0x01) + resp
9534        idx += 1
9535        if ctx['num'] == idx:
9536            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9537
9538        idx += 1
9539        if ctx['num'] == idx:
9540            logger.info("Test: Missing IMC-IMV-Message and TNCC-TNCS-Message Type")
9541            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9542                               4 + 1 + 1,
9543                               EAP_TYPE_TNC, 0x21)
9544        idx += 1
9545        if ctx['num'] == idx:
9546            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9547            resp = b"<TNCCS-Batch BatchId=2><IMC-IMV-Message></IMC-IMV-Message><TNCC-TNCS-Message></TNCC-TNCS-Message></TNCCS-Batch>"
9548            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9549                               4 + 1 + 1 + len(resp),
9550                               EAP_TYPE_TNC, 0x01) + resp
9551        idx += 1
9552        if ctx['num'] == idx:
9553            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9554
9555        idx += 1
9556        if ctx['num'] == idx:
9557            logger.info("Test: Missing TNCC-TNCS-Message XML end tag")
9558            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9559                               4 + 1 + 1,
9560                               EAP_TYPE_TNC, 0x21)
9561        idx += 1
9562        if ctx['num'] == idx:
9563            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9564            resp = b"<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><XML></TNCC-TNCS-Message></TNCCS-Batch>"
9565            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9566                               4 + 1 + 1 + len(resp),
9567                               EAP_TYPE_TNC, 0x01) + resp
9568        idx += 1
9569        if ctx['num'] == idx:
9570            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9571
9572        idx += 1
9573        if ctx['num'] == idx:
9574            logger.info("Test: Missing TNCC-TNCS-Message Base64 start tag")
9575            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9576                               4 + 1 + 1,
9577                               EAP_TYPE_TNC, 0x21)
9578        idx += 1
9579        if ctx['num'] == idx:
9580            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9581            resp = b"<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type></TNCC-TNCS-Message></TNCCS-Batch>"
9582            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9583                               4 + 1 + 1 + len(resp),
9584                               EAP_TYPE_TNC, 0x01) + resp
9585        idx += 1
9586        if ctx['num'] == idx:
9587            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9588
9589        idx += 1
9590        if ctx['num'] == idx:
9591            logger.info("Test: Missing TNCC-TNCS-Message Base64 end tag")
9592            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9593                               4 + 1 + 1,
9594                               EAP_TYPE_TNC, 0x21)
9595        idx += 1
9596        if ctx['num'] == idx:
9597            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9598            resp = b"<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><Base64>abc</TNCC-TNCS-Message></TNCCS-Batch>"
9599            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9600                               4 + 1 + 1 + len(resp),
9601                               EAP_TYPE_TNC, 0x01) + resp
9602        idx += 1
9603        if ctx['num'] == idx:
9604            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9605
9606        idx += 1
9607        if ctx['num'] == idx:
9608            logger.info("Test: TNCC-TNCS-Message Base64 message")
9609            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9610                               4 + 1 + 1,
9611                               EAP_TYPE_TNC, 0x21)
9612        idx += 1
9613        if ctx['num'] == idx:
9614            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9615            resp = b"<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><Base64>aGVsbG8=</Base64></TNCC-TNCS-Message></TNCCS-Batch>"
9616            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9617                               4 + 1 + 1 + len(resp),
9618                               EAP_TYPE_TNC, 0x01) + resp
9619        idx += 1
9620        if ctx['num'] == idx:
9621            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9622
9623        idx += 1
9624        if ctx['num'] == idx:
9625            logger.info("Test: Invalid TNCC-TNCS-Message XML message")
9626            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9627                               4 + 1 + 1,
9628                               EAP_TYPE_TNC, 0x21)
9629        idx += 1
9630        if ctx['num'] == idx:
9631            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9632            resp = b"<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><XML>hello</XML></TNCC-TNCS-Message></TNCCS-Batch>"
9633            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9634                               4 + 1 + 1 + len(resp),
9635                               EAP_TYPE_TNC, 0x01) + resp
9636        idx += 1
9637        if ctx['num'] == idx:
9638            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9639
9640        idx += 1
9641        if ctx['num'] == idx:
9642            logger.info("Test: Missing TNCCS-Recommendation type")
9643            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9644                               4 + 1 + 1,
9645                               EAP_TYPE_TNC, 0x21)
9646        idx += 1
9647        if ctx['num'] == idx:
9648            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9649            resp = b'<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><XML><TNCCS-Recommendation foo=1></TNCCS-Recommendation></XML></TNCC-TNCS-Message></TNCCS-Batch>'
9650            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9651                               4 + 1 + 1 + len(resp),
9652                               EAP_TYPE_TNC, 0x01) + resp
9653        idx += 1
9654        if ctx['num'] == idx:
9655            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9656
9657        idx += 1
9658        if ctx['num'] == idx:
9659            logger.info("Test: TNCCS-Recommendation type=none")
9660            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9661                               4 + 1 + 1,
9662                               EAP_TYPE_TNC, 0x21)
9663        idx += 1
9664        if ctx['num'] == idx:
9665            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9666            resp = b'<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><XML><TNCCS-Recommendation type="none"></TNCCS-Recommendation></XML></TNCC-TNCS-Message></TNCCS-Batch>'
9667            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9668                               4 + 1 + 1 + len(resp),
9669                               EAP_TYPE_TNC, 0x01) + resp
9670        idx += 1
9671        if ctx['num'] == idx:
9672            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9673
9674        idx += 1
9675        if ctx['num'] == idx:
9676            logger.info("Test: TNCCS-Recommendation type=isolate")
9677            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9678                               4 + 1 + 1,
9679                               EAP_TYPE_TNC, 0x21)
9680        idx += 1
9681        if ctx['num'] == idx:
9682            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9683            resp = b'<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><XML><TNCCS-Recommendation type="isolate"></TNCCS-Recommendation></XML></TNCC-TNCS-Message></TNCCS-Batch>'
9684            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9685                               4 + 1 + 1 + len(resp),
9686                               EAP_TYPE_TNC, 0x01) + resp
9687        idx += 1
9688        if ctx['num'] == idx:
9689            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9690
9691        logger.info("No more test responses available - test case completed")
9692        global eap_proto_tnc_test_done
9693        eap_proto_tnc_test_done = True
9694        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9695
9696    srv = start_radius_server(tnc_handler)
9697
9698    try:
9699        hapd = start_ap(apdev[0])
9700        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9701
9702        i = 0
9703        while not eap_proto_tnc_test_done:
9704            i += 1
9705            logger.info("Running connection iteration %d" % i)
9706            frag = 1400
9707            if i == 8:
9708                frag = 150
9709            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9710                           eap="TNC", identity="tnc", fragment_size=str(frag),
9711                           wait_connect=False)
9712            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
9713            if ev is None:
9714                raise Exception("Timeout on EAP start")
9715            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD",
9716                                    "CTRL-EVENT-EAP-STATUS"], timeout=5)
9717            if ev is None:
9718                raise Exception("Timeout on EAP method start")
9719            time.sleep(0.1)
9720            dev[0].request("REMOVE_NETWORK all")
9721            dev[0].wait_disconnected(timeout=1)
9722            dev[0].dump_monitor()
9723    finally:
9724        stop_radius_server(srv)
9725
9726def test_eap_canned_success_after_identity(dev, apdev):
9727    """EAP protocol tests for canned EAP-Success after identity"""
9728    check_eap_capa(dev[0], "MD5")
9729    def eap_canned_success_handler(ctx, req):
9730        logger.info("eap_canned_success_handler - RX " + binascii.hexlify(req).decode())
9731        if 'num' not in ctx:
9732            ctx['num'] = 0
9733        ctx['num'] = ctx['num'] + 1
9734        if 'id' not in ctx:
9735            ctx['id'] = 1
9736        ctx['id'] = (ctx['id'] + 1) % 256
9737        idx = 0
9738
9739        idx += 1
9740        if ctx['num'] == idx:
9741            logger.info("Test: EAP-Success")
9742            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
9743
9744        idx += 1
9745        if ctx['num'] == idx:
9746            logger.info("Test: EAP-Success")
9747            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
9748
9749        return None
9750
9751    srv = start_radius_server(eap_canned_success_handler)
9752
9753    try:
9754        hapd = start_ap(apdev[0])
9755        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9756
9757        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9758                       phase1="allow_canned_success=1",
9759                       eap="MD5", identity="user", password="password",
9760                       wait_connect=False)
9761        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
9762        if ev is None:
9763            raise Exception("Timeout on EAP success")
9764        dev[0].request("REMOVE_NETWORK all")
9765        dev[0].wait_disconnected()
9766
9767        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9768                       eap="MD5", identity="user", password="password",
9769                       wait_connect=False)
9770        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
9771        if ev is None:
9772            raise Exception("Timeout on EAP start")
9773        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=0.1)
9774        if ev is not None:
9775            raise Exception("Unexpected EAP success")
9776        dev[0].request("REMOVE_NETWORK all")
9777        dev[0].wait_disconnected()
9778    finally:
9779        stop_radius_server(srv)
9780
9781def test_eap_proto_wsc(dev, apdev):
9782    """EAP-WSC protocol tests"""
9783    global eap_proto_wsc_test_done, eap_proto_wsc_wait_failure
9784    eap_proto_wsc_test_done = False
9785
9786    def wsc_handler(ctx, req):
9787        logger.info("wsc_handler - RX " + binascii.hexlify(req).decode())
9788        if 'num' not in ctx:
9789            ctx['num'] = 0
9790        ctx['num'] += 1
9791        if 'id' not in ctx:
9792            ctx['id'] = 1
9793        ctx['id'] = (ctx['id'] + 1) % 256
9794        idx = 0
9795
9796        global eap_proto_wsc_wait_failure
9797        eap_proto_wsc_wait_failure = False
9798
9799        idx += 1
9800        if ctx['num'] == idx:
9801            logger.info("Test: Missing Flags field")
9802            return struct.pack(">BBHB3BLB", EAP_CODE_REQUEST, ctx['id'],
9803                               4 + 1 + 3 + 4 + 1,
9804                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9805                               1)
9806
9807        idx += 1
9808        if ctx['num'] == idx:
9809            logger.info("Test: Message underflow (missing Message Length field)")
9810            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9811                               4 + 1 + 3 + 4 + 2,
9812                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9813                               1, 0x02)
9814
9815        idx += 1
9816        if ctx['num'] == idx:
9817            logger.info("Test: Invalid Message Length (> 50000)")
9818            return struct.pack(">BBHB3BLBBH", EAP_CODE_REQUEST, ctx['id'],
9819                               4 + 1 + 3 + 4 + 4,
9820                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9821                               1, 0x02, 65535)
9822
9823        idx += 1
9824        if ctx['num'] == idx:
9825            logger.info("Test: Invalid Message Length (< current payload)")
9826            return struct.pack(">BBHB3BLBBHB", EAP_CODE_REQUEST, ctx['id'],
9827                               4 + 1 + 3 + 4 + 5,
9828                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9829                               1, 0x02, 0, 0xff)
9830
9831        idx += 1
9832        if ctx['num'] == idx:
9833            logger.info("Test: Unexpected Op-Code 5 in WAIT_START state")
9834            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9835                               4 + 1 + 3 + 4 + 2,
9836                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9837                               5, 0x00)
9838
9839        idx += 1
9840        if ctx['num'] == idx:
9841            logger.info("Test: Valid WSC Start to start the sequence")
9842            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9843                               4 + 1 + 3 + 4 + 2,
9844                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9845                               1, 0x00)
9846        idx += 1
9847        if ctx['num'] == idx:
9848            logger.info("Test: No Message Length field in a fragmented packet")
9849            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9850                               4 + 1 + 3 + 4 + 2,
9851                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9852                               4, 0x01)
9853
9854        idx += 1
9855        if ctx['num'] == idx:
9856            logger.info("Test: Valid WSC Start to start the sequence")
9857            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9858                               4 + 1 + 3 + 4 + 2,
9859                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9860                               1, 0x00)
9861        idx += 1
9862        if ctx['num'] == idx:
9863            logger.info("Test: Valid first fragmented packet")
9864            return struct.pack(">BBHB3BLBBHB", EAP_CODE_REQUEST, ctx['id'],
9865                               4 + 1 + 3 + 4 + 5,
9866                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9867                               4, 0x03, 10, 1)
9868        idx += 1
9869        if ctx['num'] == idx:
9870            logger.info("Test: Unexpected Op-Code 5 in fragment (expected 4)")
9871            return struct.pack(">BBHB3BLBBB", EAP_CODE_REQUEST, ctx['id'],
9872                               4 + 1 + 3 + 4 + 3,
9873                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9874                               5, 0x01, 2)
9875
9876        idx += 1
9877        if ctx['num'] == idx:
9878            logger.info("Test: Valid WSC Start to start the sequence")
9879            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9880                               4 + 1 + 3 + 4 + 2,
9881                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9882                               1, 0x00)
9883        idx += 1
9884        if ctx['num'] == idx:
9885            logger.info("Test: Valid first fragmented packet")
9886            return struct.pack(">BBHB3BLBBHB", EAP_CODE_REQUEST, ctx['id'],
9887                               4 + 1 + 3 + 4 + 5,
9888                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9889                               4, 0x03, 2, 1)
9890        idx += 1
9891        if ctx['num'] == idx:
9892            logger.info("Test: Fragment overflow")
9893            return struct.pack(">BBHB3BLBBBB", EAP_CODE_REQUEST, ctx['id'],
9894                               4 + 1 + 3 + 4 + 4,
9895                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9896                               4, 0x01, 2, 3)
9897
9898        idx += 1
9899        if ctx['num'] == idx:
9900            logger.info("Test: Valid WSC Start to start the sequence")
9901            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9902                               4 + 1 + 3 + 4 + 2,
9903                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9904                               1, 0x00)
9905        idx += 1
9906        if ctx['num'] == idx:
9907            logger.info("Test: Unexpected Op-Code 5 in WAIT_FRAG_ACK state")
9908            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9909                               4 + 1 + 3 + 4 + 2,
9910                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9911                               5, 0x00)
9912
9913        idx += 1
9914        if ctx['num'] == idx:
9915            logger.info("Test: Valid WSC Start")
9916            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9917                               4 + 1 + 3 + 4 + 2,
9918                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9919                               1, 0x00)
9920        idx += 1
9921        if ctx['num'] == idx:
9922            logger.info("No more test responses available - test case completed")
9923            global eap_proto_wsc_test_done
9924            eap_proto_wsc_test_done = True
9925            eap_proto_wsc_wait_failure = True
9926            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9927
9928        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9929
9930    srv = start_radius_server(wsc_handler)
9931
9932    try:
9933        hapd = start_ap(apdev[0])
9934        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9935
9936        i = 0
9937        while not eap_proto_wsc_test_done:
9938            i += 1
9939            logger.info("Running connection iteration %d" % i)
9940            fragment_size = 1398 if i != 9 else 50
9941            dev[0].connect("eap-test", key_mgmt="WPA-EAP", eap="WSC",
9942                           fragment_size=str(fragment_size),
9943                           identity="WFA-SimpleConfig-Enrollee-1-0",
9944                           phase1="pin=12345670",
9945                           scan_freq="2412", wait_connect=False)
9946            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
9947            if ev is None:
9948                raise Exception("Timeout on EAP method start")
9949            if eap_proto_wsc_wait_failure:
9950                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
9951                if ev is None:
9952                    raise Exception("Timeout on EAP failure")
9953            else:
9954                time.sleep(0.1)
9955            dev[0].request("REMOVE_NETWORK all")
9956            dev[0].wait_disconnected(timeout=1)
9957            dev[0].dump_monitor()
9958    finally:
9959        stop_radius_server(srv)
9960
9961def test_eap_canned_success_before_method(dev, apdev):
9962    """EAP protocol tests for canned EAP-Success before any method"""
9963    params = int_eap_server_params()
9964    hapd = hostapd.add_ap(apdev[0], params)
9965    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9966    bssid = apdev[0]['bssid']
9967    hapd.request("SET ext_eapol_frame_io 1")
9968
9969    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
9970                   phase1="allow_canned_success=1",
9971                   eap="MD5", identity="user", password="password",
9972                   wait_connect=False)
9973
9974    ev = hapd.wait_event(["EAPOL-TX"], timeout=10)
9975    if ev is None:
9976        raise Exception("Timeout on EAPOL-TX from hostapd")
9977
9978    res = dev[0].request("EAPOL_RX " + bssid + " 0200000403020004")
9979    if "OK" not in res:
9980        raise Exception("EAPOL_RX to wpa_supplicant failed")
9981
9982    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=5)
9983    if ev is None:
9984        raise Exception("Timeout on EAP success")
9985    dev[0].request("REMOVE_NETWORK all")
9986    dev[0].wait_disconnected()
9987
9988def test_eap_canned_failure_before_method(dev, apdev):
9989    """EAP protocol tests for canned EAP-Failure before any method"""
9990    params = int_eap_server_params()
9991    hapd = hostapd.add_ap(apdev[0], params)
9992    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9993    bssid = apdev[0]['bssid']
9994    hapd.request("SET ext_eapol_frame_io 1")
9995    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
9996                   phase1="allow_canned_success=1",
9997                   eap="MD5", identity="user", password="password",
9998                   wait_connect=False)
9999
10000    ev = hapd.wait_event(["EAPOL-TX"], timeout=10)
10001    if ev is None:
10002        raise Exception("Timeout on EAPOL-TX from hostapd")
10003
10004    res = dev[0].request("EAPOL_RX " + bssid + " 0200000404020004")
10005    if "OK" not in res:
10006        raise Exception("EAPOL_RX to wpa_supplicant failed")
10007
10008    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
10009    if ev is None:
10010        raise Exception("Timeout on EAP failure")
10011    dev[0].request("REMOVE_NETWORK all")
10012    dev[0].wait_disconnected()
10013
10014def test_eap_nak_oom(dev, apdev):
10015    """EAP-Nak OOM"""
10016    check_eap_capa(dev[0], "MD5")
10017    params = hostapd.wpa2_eap_params(ssid="eap-test")
10018    hapd = hostapd.add_ap(apdev[0], params)
10019    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
10020    with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_sm_buildNak"):
10021        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
10022                       eap="MD5", identity="sake user", password="password",
10023                       wait_connect=False)
10024        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
10025        dev[0].request("REMOVE_NETWORK all")
10026        dev[0].wait_disconnected()
10027
10028def test_eap_nak_expanded(dev, apdev):
10029    """EAP-Nak with expanded method"""
10030    check_eap_capa(dev[0], "MD5")
10031    check_eap_capa(dev[0], "VENDOR-TEST")
10032    params = hostapd.wpa2_eap_params(ssid="eap-test")
10033    hapd = hostapd.add_ap(apdev[0], params)
10034    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
10035    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
10036                   eap="VENDOR-TEST WSC",
10037                   identity="sake user", password="password",
10038                   wait_connect=False)
10039    ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=10)
10040    if ev is None or "NAK" not in ev:
10041        raise Exception("No NAK event seen")
10042
10043    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
10044    if ev is None:
10045        raise Exception("No EAP-Failure seen")
10046
10047    dev[0].request("REMOVE_NETWORK all")
10048    dev[0].wait_disconnected()
10049
10050EAP_TLV_RESULT_TLV = 3
10051EAP_TLV_NAK_TLV = 4
10052EAP_TLV_ERROR_CODE_TLV = 5
10053EAP_TLV_CONNECTION_BINDING_TLV = 6
10054EAP_TLV_VENDOR_SPECIFIC_TLV = 7
10055EAP_TLV_URI_TLV = 8
10056EAP_TLV_EAP_PAYLOAD_TLV = 9
10057EAP_TLV_INTERMEDIATE_RESULT_TLV = 10
10058EAP_TLV_PAC_TLV = 11
10059EAP_TLV_CRYPTO_BINDING_TLV = 12
10060EAP_TLV_CALLING_STATION_ID_TLV = 13
10061EAP_TLV_CALLED_STATION_ID_TLV = 14
10062EAP_TLV_NAS_PORT_TYPE_TLV = 15
10063EAP_TLV_SERVER_IDENTIFIER_TLV = 16
10064EAP_TLV_IDENTITY_TYPE_TLV = 17
10065EAP_TLV_SERVER_TRUSTED_ROOT_TLV = 18
10066EAP_TLV_REQUEST_ACTION_TLV = 19
10067EAP_TLV_PKCS7_TLV = 20
10068
10069EAP_TLV_RESULT_SUCCESS = 1
10070EAP_TLV_RESULT_FAILURE = 2
10071
10072EAP_TLV_TYPE_MANDATORY = 0x8000
10073EAP_TLV_TYPE_MASK = 0x3fff
10074
10075PAC_TYPE_PAC_KEY = 1
10076PAC_TYPE_PAC_OPAQUE = 2
10077PAC_TYPE_CRED_LIFETIME = 3
10078PAC_TYPE_A_ID = 4
10079PAC_TYPE_I_ID = 5
10080PAC_TYPE_A_ID_INFO = 7
10081PAC_TYPE_PAC_ACKNOWLEDGEMENT = 8
10082PAC_TYPE_PAC_INFO = 9
10083PAC_TYPE_PAC_TYPE = 10
10084
10085def eap_fast_start(ctx):
10086    logger.info("Send EAP-FAST/Start")
10087    return struct.pack(">BBHBBHH", EAP_CODE_REQUEST, ctx['id'],
10088                       4 + 1 + 1 + 4 + 16,
10089                       EAP_TYPE_FAST, 0x21, 4, 16) + 16*b'A'
10090
10091def test_eap_fast_proto(dev, apdev):
10092    """EAP-FAST Phase protocol testing"""
10093    check_eap_capa(dev[0], "FAST")
10094    global eap_fast_proto_ctx
10095    eap_fast_proto_ctx = None
10096
10097    def eap_handler(ctx, req):
10098        logger.info("eap_handler - RX " + binascii.hexlify(req).decode())
10099        if 'num' not in ctx:
10100            ctx['num'] = 0
10101        ctx['num'] = ctx['num'] + 1
10102        if 'id' not in ctx:
10103            ctx['id'] = 1
10104        ctx['id'] = (ctx['id'] + 1) % 256
10105        idx = 0
10106
10107        global eap_fast_proto_ctx
10108        eap_fast_proto_ctx = ctx
10109        ctx['test_done'] = False
10110
10111        idx += 1
10112        if ctx['num'] == idx:
10113            return eap_fast_start(ctx)
10114        idx += 1
10115        if ctx['num'] == idx:
10116            logger.info("EAP-FAST: TLS processing failed")
10117            data = b'ABCDEFGHIK'
10118            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
10119                               4 + 1 + 1 + len(data),
10120                               EAP_TYPE_FAST, 0x01) + data
10121        idx += 1
10122        if ctx['num'] == idx:
10123            ctx['test_done'] = True
10124            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
10125
10126        logger.info("Past last test case")
10127        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
10128
10129    srv = start_radius_server(eap_handler)
10130    try:
10131        hapd = start_ap(apdev[0])
10132        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
10133        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
10134                       eap="FAST", anonymous_identity="FAST",
10135                       identity="user", password="password",
10136                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
10137                       phase1="fast_provisioning=1",
10138                       pac_file="blob://fast_pac_proto",
10139                       wait_connect=False)
10140        ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
10141        if ev is None:
10142            raise Exception("Could not start EAP-FAST")
10143        ok = False
10144        for i in range(100):
10145            if eap_fast_proto_ctx:
10146                if eap_fast_proto_ctx['test_done']:
10147                    ok = True
10148                    break
10149            time.sleep(0.05)
10150        dev[0].request("REMOVE_NETWORK all")
10151        dev[0].wait_disconnected()
10152    finally:
10153        stop_radius_server(srv)
10154
10155def run_eap_fast_phase2(dev, test_payload, test_failure=True):
10156    global eap_fast_proto_ctx
10157    eap_fast_proto_ctx = None
10158
10159    def ssl_info_callback(conn, where, ret):
10160        logger.debug("SSL: info where=%d ret=%d" % (where, ret))
10161
10162    def log_conn_state(conn):
10163        try:
10164            state = conn.state_string()
10165        except AttributeError:
10166            state = conn.get_state_string()
10167        if state:
10168            logger.info("State: " + str(state))
10169
10170    def process_clienthello(ctx, payload):
10171        logger.info("Process ClientHello")
10172        ctx['sslctx'] = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
10173        ctx['sslctx'].set_info_callback(ssl_info_callback)
10174        ctx['sslctx'].load_tmp_dh("auth_serv/dh.conf")
10175        if OpenSSL.SSL.OPENSSL_VERSION_NUMBER >= 0x10100000:
10176            ctx['sslctx'].set_cipher_list("ADH-AES128-SHA:@SECLEVEL=0")
10177        else:
10178            ctx['sslctx'].set_cipher_list("ADH-AES128-SHA")
10179        ctx['conn'] = OpenSSL.SSL.Connection(ctx['sslctx'], None)
10180        ctx['conn'].set_accept_state()
10181        log_conn_state(ctx['conn'])
10182        ctx['conn'].bio_write(payload)
10183        try:
10184            ctx['conn'].do_handshake()
10185        except OpenSSL.SSL.WantReadError:
10186            pass
10187        log_conn_state(ctx['conn'])
10188        data = ctx['conn'].bio_read(4096)
10189        log_conn_state(ctx['conn'])
10190        return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
10191                           4 + 1 + 1 + len(data),
10192                           EAP_TYPE_FAST, 0x01) + data
10193
10194    def process_clientkeyexchange(ctx, payload, appl_data):
10195        logger.info("Process ClientKeyExchange")
10196        log_conn_state(ctx['conn'])
10197        ctx['conn'].bio_write(payload)
10198        try:
10199            ctx['conn'].do_handshake()
10200        except OpenSSL.SSL.WantReadError:
10201            pass
10202        ctx['conn'].send(appl_data)
10203        log_conn_state(ctx['conn'])
10204        data = ctx['conn'].bio_read(4096)
10205        log_conn_state(ctx['conn'])
10206        return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
10207                           4 + 1 + 1 + len(data),
10208                           EAP_TYPE_FAST, 0x01) + data
10209
10210    def eap_handler(ctx, req):
10211        logger.info("eap_handler - RX " + binascii.hexlify(req).decode())
10212        if 'num' not in ctx:
10213            ctx['num'] = 0
10214        ctx['num'] = ctx['num'] + 1
10215        if 'id' not in ctx:
10216            ctx['id'] = 1
10217        ctx['id'] = (ctx['id'] + 1) % 256
10218        idx = 0
10219
10220        global eap_fast_proto_ctx
10221        eap_fast_proto_ctx = ctx
10222        ctx['test_done'] = False
10223        logger.debug("ctx['num']=%d" % ctx['num'])
10224
10225        idx += 1
10226        if ctx['num'] == idx:
10227            return eap_fast_start(ctx)
10228        idx += 1
10229        if ctx['num'] == idx:
10230            return process_clienthello(ctx, req[6:])
10231        idx += 1
10232        if ctx['num'] == idx:
10233            if not test_failure:
10234                ctx['test_done'] = True
10235            return process_clientkeyexchange(ctx, req[6:], test_payload)
10236        idx += 1
10237        if ctx['num'] == idx:
10238            ctx['test_done'] = True
10239            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
10240
10241        logger.info("Past last test case")
10242        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
10243
10244    srv = start_radius_server(eap_handler)
10245    try:
10246        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
10247                       eap="FAST", anonymous_identity="FAST",
10248                       identity="user", password="password",
10249                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
10250                       phase1="fast_provisioning=1",
10251                       pac_file="blob://fast_pac_proto",
10252                       wait_connect=False)
10253        ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
10254        if ev is None:
10255            raise Exception("Could not start EAP-FAST")
10256        dev[0].dump_monitor()
10257        ok = False
10258        for i in range(100):
10259            if eap_fast_proto_ctx:
10260                if eap_fast_proto_ctx['test_done']:
10261                    ok = True
10262                    break
10263            time.sleep(0.05)
10264        time.sleep(0.1)
10265        dev[0].request("REMOVE_NETWORK all")
10266        dev[0].wait_disconnected()
10267        if not ok:
10268            raise Exception("EAP-FAST TLS exchange did not complete")
10269        for i in range(3):
10270            dev[i].dump_monitor()
10271    finally:
10272        stop_radius_server(srv)
10273
10274def test_eap_fast_proto_phase2(dev, apdev):
10275    """EAP-FAST Phase 2 protocol testing"""
10276    if not openssl_imported:
10277        raise HwsimSkip("OpenSSL python method not available")
10278    check_eap_capa(dev[0], "FAST")
10279    hapd = start_ap(apdev[0])
10280    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
10281
10282    tests = [("Too short Phase 2 TLV frame (len=3)",
10283              "ABC",
10284              False),
10285             ("EAP-FAST: TLV overflow",
10286              struct.pack(">HHB", 0, 2, 0xff),
10287              False),
10288             ("EAP-FAST: Unknown TLV (optional and mandatory)",
10289              struct.pack(">HHB", 0, 1, 0xff) +
10290              struct.pack(">HHB", EAP_TLV_TYPE_MANDATORY, 1, 0xff),
10291              True),
10292             ("EAP-FAST: More than one EAP-Payload TLV in the message",
10293              struct.pack(">HHBHHB",
10294                          EAP_TLV_EAP_PAYLOAD_TLV, 1, 0xff,
10295                          EAP_TLV_EAP_PAYLOAD_TLV, 1, 0xff),
10296              True),
10297             ("EAP-FAST: Unknown Result 255 and More than one Result TLV in the message",
10298              struct.pack(">HHHHHH",
10299                          EAP_TLV_RESULT_TLV, 2, 0xff,
10300                          EAP_TLV_RESULT_TLV, 2, 0xff),
10301              True),
10302             ("EAP-FAST: Too short Result TLV",
10303              struct.pack(">HHB", EAP_TLV_RESULT_TLV, 1, 0xff),
10304              True),
10305             ("EAP-FAST: Unknown Intermediate Result 255 and More than one Intermediate-Result TLV in the message",
10306              struct.pack(">HHHHHH",
10307                          EAP_TLV_INTERMEDIATE_RESULT_TLV, 2, 0xff,
10308                          EAP_TLV_INTERMEDIATE_RESULT_TLV, 2, 0xff),
10309              True),
10310             ("EAP-FAST: Too short Intermediate-Result TLV",
10311              struct.pack(">HHB", EAP_TLV_INTERMEDIATE_RESULT_TLV, 1, 0xff),
10312              True),
10313             ("EAP-FAST: More than one Crypto-Binding TLV in the message",
10314              struct.pack(">HH", EAP_TLV_CRYPTO_BINDING_TLV, 60) + 60*b'A' +
10315              struct.pack(">HH", EAP_TLV_CRYPTO_BINDING_TLV, 60) + 60*b'A',
10316              True),
10317             ("EAP-FAST: Too short Crypto-Binding TLV",
10318              struct.pack(">HHB", EAP_TLV_CRYPTO_BINDING_TLV, 1, 0xff),
10319              True),
10320             ("EAP-FAST: More than one Request-Action TLV in the message",
10321              struct.pack(">HHBBHHBB",
10322                          EAP_TLV_REQUEST_ACTION_TLV, 2, 0xff, 0xff,
10323                          EAP_TLV_REQUEST_ACTION_TLV, 2, 0xff, 0xff),
10324              True),
10325             ("EAP-FAST: Too short Request-Action TLV",
10326              struct.pack(">HHB", EAP_TLV_REQUEST_ACTION_TLV, 1, 0xff),
10327              True),
10328             ("EAP-FAST: More than one PAC TLV in the message",
10329              struct.pack(">HHBHHB",
10330                          EAP_TLV_PAC_TLV, 1, 0xff,
10331                          EAP_TLV_PAC_TLV, 1, 0xff),
10332              True),
10333             ("EAP-FAST: Too short EAP Payload TLV (Len=3)",
10334              struct.pack(">HH3B",
10335                          EAP_TLV_EAP_PAYLOAD_TLV, 3, 0, 0, 0),
10336              False),
10337             ("EAP-FAST: Too short Phase 2 request (Len=0)",
10338              struct.pack(">HHBBH",
10339                          EAP_TLV_EAP_PAYLOAD_TLV, 4,
10340                          EAP_CODE_REQUEST, 0, 0),
10341              False),
10342             ("EAP-FAST: EAP packet overflow in EAP Payload TLV",
10343              struct.pack(">HHBBH",
10344                          EAP_TLV_EAP_PAYLOAD_TLV, 4,
10345                          EAP_CODE_REQUEST, 0, 4 + 1),
10346              False),
10347             ("EAP-FAST: Unexpected code=0 in Phase 2 EAP header",
10348              struct.pack(">HHBBH",
10349                          EAP_TLV_EAP_PAYLOAD_TLV, 4,
10350                          0, 0, 0),
10351              False),
10352             ("EAP-FAST: PAC TLV without Result TLV acknowledging success",
10353              struct.pack(">HHB", EAP_TLV_PAC_TLV, 1, 0xff),
10354              True),
10355             ("EAP-FAST: PAC TLV does not include all the required fields",
10356              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10357                          EAP_TLV_RESULT_SUCCESS) +
10358              struct.pack(">HHB", EAP_TLV_PAC_TLV, 1, 0xff),
10359              True),
10360             ("EAP-FAST: Invalid PAC-Key length 0, Ignored unknown PAC type 0, and PAC TLV overrun (type=0 len=2 left=1)",
10361              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10362                          EAP_TLV_RESULT_SUCCESS) +
10363              struct.pack(">HHHHHHHHB", EAP_TLV_PAC_TLV, 4 + 4 + 5,
10364                          PAC_TYPE_PAC_KEY, 0, 0, 0, 0, 2, 0),
10365              True),
10366             ("EAP-FAST: PAC-Info does not include all the required fields",
10367              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10368                          EAP_TLV_RESULT_SUCCESS) +
10369              struct.pack(">HHHHHHHH", EAP_TLV_PAC_TLV, 4 + 4 + 4 + 32,
10370                          PAC_TYPE_PAC_OPAQUE, 0,
10371                          PAC_TYPE_PAC_INFO, 0,
10372                          PAC_TYPE_PAC_KEY, 32) + 32*b'A',
10373              True),
10374             ("EAP-FAST: Invalid CRED_LIFETIME length, Ignored unknown PAC-Info type 0, and Invalid PAC-Type length 1",
10375              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10376                          EAP_TLV_RESULT_SUCCESS) +
10377              struct.pack(">HHHHHHHHHHHHBHH", EAP_TLV_PAC_TLV, 4 + 4 + 13 + 4 + 32,
10378                          PAC_TYPE_PAC_OPAQUE, 0,
10379                          PAC_TYPE_PAC_INFO, 13, PAC_TYPE_CRED_LIFETIME, 0,
10380                          0, 0, PAC_TYPE_PAC_TYPE, 1, 0,
10381                          PAC_TYPE_PAC_KEY, 32) + 32*b'A',
10382              True),
10383             ("EAP-FAST: Unsupported PAC-Type 0",
10384              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10385                          EAP_TLV_RESULT_SUCCESS) +
10386              struct.pack(">HHHHHHHHHHH", EAP_TLV_PAC_TLV, 4 + 4 + 6 + 4 + 32,
10387                          PAC_TYPE_PAC_OPAQUE, 0,
10388                          PAC_TYPE_PAC_INFO, 6, PAC_TYPE_PAC_TYPE, 2, 0,
10389                          PAC_TYPE_PAC_KEY, 32) + 32*b'A',
10390              True),
10391             ("EAP-FAST: PAC-Info overrun (type=0 len=2 left=1)",
10392              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10393                          EAP_TLV_RESULT_SUCCESS) +
10394              struct.pack(">HHHHHHHHBHH", EAP_TLV_PAC_TLV, 4 + 4 + 5 + 4 + 32,
10395                          PAC_TYPE_PAC_OPAQUE, 0,
10396                          PAC_TYPE_PAC_INFO, 5, 0, 2, 1,
10397                          PAC_TYPE_PAC_KEY, 32) + 32*b'A',
10398              True),
10399             ("EAP-FAST: Valid PAC",
10400              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10401                          EAP_TLV_RESULT_SUCCESS) +
10402              struct.pack(">HHHHHHHHBHHBHH", EAP_TLV_PAC_TLV,
10403                          4 + 4 + 10 + 4 + 32,
10404                          PAC_TYPE_PAC_OPAQUE, 0,
10405                          PAC_TYPE_PAC_INFO, 10, PAC_TYPE_A_ID, 1, 0x41,
10406                          PAC_TYPE_A_ID_INFO, 1, 0x42,
10407                          PAC_TYPE_PAC_KEY, 32) + 32*b'A',
10408              True),
10409             ("EAP-FAST: Invalid version/subtype in Crypto-Binding TLV",
10410              struct.pack(">HH", EAP_TLV_CRYPTO_BINDING_TLV, 60) + 60*b'A',
10411              True)]
10412    for title, payload, failure in tests:
10413        logger.info("Phase 2 test: " + title)
10414        run_eap_fast_phase2(dev, payload, failure)
10415
10416def test_eap_fast_tlv_nak_oom(dev, apdev):
10417    """EAP-FAST Phase 2 TLV NAK OOM"""
10418    if not openssl_imported:
10419        raise HwsimSkip("OpenSSL python method not available")
10420    check_eap_capa(dev[0], "FAST")
10421    hapd = start_ap(apdev[0])
10422    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
10423
10424    with alloc_fail(dev[0], 1, "eap_fast_tlv_nak"):
10425        run_eap_fast_phase2(dev, struct.pack(">HHB", EAP_TLV_TYPE_MANDATORY,
10426                                             1, 0xff), False)
10427