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):
86    hmac_obj = hmac.new(reply.secret, digestmod=hashlib.md5)
87    hmac_obj.update(struct.pack("B", reply.code))
88    hmac_obj.update(struct.pack("B", reply.id))
89
90    reply.AddAttribute("Message-Authenticator", 16*b'\x00')
91    attrs = reply._PktEncodeAttributes()
92
93    # Length
94    flen = 4 + 16 + len(attrs)
95    hmac_obj.update(struct.pack(">H", flen))
96    hmac_obj.update(pkt.authenticator)
97    hmac_obj.update(attrs)
98    del reply[80]
99    add_message_authenticator_attr(reply, hmac_obj.digest())
100
101def run_pyrad_server(srv, t_stop, eap_handler):
102    srv.RunWithStop(t_stop, eap_handler)
103
104def start_radius_server(eap_handler):
105    try:
106        import pyrad.server
107        import pyrad.packet
108        import pyrad.dictionary
109    except ImportError:
110        raise HwsimSkip("No pyrad modules available")
111
112    class TestServer(pyrad.server.Server):
113        def _HandleAuthPacket(self, pkt):
114            pyrad.server.Server._HandleAuthPacket(self, pkt)
115            eap = b''
116            for p in pkt[79]:
117                eap += p
118            eap_req = self.eap_handler(self.ctx, eap)
119            reply = self.CreateReplyPacket(pkt)
120            if eap_req:
121                while True:
122                    if len(eap_req) > 253:
123                        reply.AddAttribute("EAP-Message", eap_req[0:253])
124                        eap_req = eap_req[253:]
125                    else:
126                        reply.AddAttribute("EAP-Message", eap_req)
127                        break
128            else:
129                logger.info("No EAP request available")
130            reply.code = pyrad.packet.AccessChallenge
131
132            # reply attributes
133            build_message_auth(pkt, reply)
134
135            self.SendReplyPacket(pkt.fd, reply)
136
137        def RunWithStop(self, t_stop, eap_handler):
138            self._poll = select.poll()
139            self._fdmap = {}
140            self._PrepareSockets()
141            self.t_stop = t_stop
142            self.eap_handler = eap_handler
143            self.ctx = {}
144
145            while not t_stop.is_set():
146                for (fd, event) in self._poll.poll(200):
147                    if event == select.POLLIN:
148                        try:
149                            fdo = self._fdmap[fd]
150                            self._ProcessInput(fdo)
151                        except pyrad.server.ServerPacketError as err:
152                            logger.info("pyrad server dropping packet: " + str(err))
153                        except pyrad.packet.PacketError as err:
154                            logger.info("pyrad server received invalid packet: " + str(err))
155                    else:
156                        logger.error("Unexpected event in pyrad server main loop")
157
158            for fd in self.authfds + self.acctfds:
159                fd.close()
160
161    srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"),
162                     authport=18138, acctport=18139)
163    srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1",
164                                                     b"radius",
165                                                     "localhost")
166    srv.BindToAddress("127.0.0.1")
167    t_stop = threading.Event()
168    t = threading.Thread(target=run_pyrad_server, args=(srv, t_stop, eap_handler))
169    t.start()
170
171    return {'srv': srv, 'stop': t_stop, 'thread': t}
172
173def stop_radius_server(srv):
174    srv['stop'].set()
175    srv['thread'].join()
176
177def start_ap(ap):
178    params = hostapd.wpa2_eap_params(ssid="eap-test")
179    params['auth_server_port'] = "18138"
180    hapd = hostapd.add_ap(ap, params)
181    return hapd
182
183def test_eap_proto(dev, apdev):
184    """EAP protocol tests"""
185    check_eap_capa(dev[0], "MD5")
186    def eap_handler(ctx, req):
187        logger.info("eap_handler - RX " + binascii.hexlify(req).decode())
188        if 'num' not in ctx:
189            ctx['num'] = 0
190        ctx['num'] = ctx['num'] + 1
191        if 'id' not in ctx:
192            ctx['id'] = 1
193        ctx['id'] = (ctx['id'] + 1) % 256
194        idx = 0
195
196        idx += 1
197        if ctx['num'] == idx:
198            logger.info("Test: MD5 challenge")
199            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
200                               4 + 1 + 3,
201                               EAP_TYPE_MD5,
202                               1, 0xaa, ord('n'))
203        idx += 1
204        if ctx['num'] == idx:
205            logger.info("Test: EAP-Success - id off by 2")
206            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'] + 1, 4)
207
208        idx += 1
209        if ctx['num'] == idx:
210            logger.info("Test: MD5 challenge")
211            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
212                               4 + 1 + 3,
213                               EAP_TYPE_MD5,
214                               1, 0xaa, ord('n'))
215        idx += 1
216        if ctx['num'] == idx:
217            logger.info("Test: EAP-Success - id off by 3")
218            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'] + 2, 4)
219
220        idx += 1
221        if ctx['num'] == idx:
222            logger.info("Test: MD5 challenge")
223            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
224                               4 + 1 + 3,
225                               EAP_TYPE_MD5,
226                               1, 0xaa, ord('n'))
227        idx += 1
228        if ctx['num'] == idx:
229            logger.info("Test: EAP-Notification/Request")
230            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
231                               4 + 1 + 1,
232                               EAP_TYPE_NOTIFICATION,
233                               ord('A'))
234        idx += 1
235        if ctx['num'] == idx:
236            logger.info("Test: EAP-Success")
237            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'] - 1, 4)
238
239        idx += 1
240        if ctx['num'] == idx:
241            logger.info("Test: EAP-Notification/Request")
242            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
243                               4 + 1 + 1,
244                               EAP_TYPE_NOTIFICATION,
245                               ord('B'))
246        idx += 1
247        if ctx['num'] == idx:
248            logger.info("Test: MD5 challenge")
249            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
250                               4 + 1 + 3,
251                               EAP_TYPE_MD5,
252                               1, 0xaa, ord('n'))
253        idx += 1
254        if ctx['num'] == idx:
255            logger.info("Test: EAP-Success")
256            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'] - 1, 4)
257
258        idx += 1
259        if ctx['num'] == idx:
260            logger.info("Test: EAP-Notification/Request")
261            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
262                               4 + 1 + 1,
263                               EAP_TYPE_NOTIFICATION,
264                               ord('C'))
265        idx += 1
266        if ctx['num'] == idx:
267            logger.info("Test: MD5 challenge")
268            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
269                               4 + 1 + 3,
270                               EAP_TYPE_MD5,
271                               1, 0xaa, ord('n'))
272        idx += 1
273        if ctx['num'] == idx:
274            logger.info("Test: EAP-Notification/Request")
275            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
276                               4 + 1 + 1,
277                               EAP_TYPE_NOTIFICATION,
278                               ord('D'))
279        idx += 1
280        if ctx['num'] == idx:
281            logger.info("Test: EAP-Success")
282            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'] - 1, 4)
283
284        idx += 1
285        if ctx['num'] == idx:
286            logger.info("Test: EAP-Notification/Request")
287            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
288                               4 + 1 + 1,
289                               EAP_TYPE_NOTIFICATION,
290                               ord('E'))
291        idx += 1
292        if ctx['num'] == idx:
293            logger.info("Test: EAP-Notification/Request (same id)")
294            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'] - 1,
295                               4 + 1 + 1,
296                               EAP_TYPE_NOTIFICATION,
297                               ord('F'))
298        idx += 1
299        if ctx['num'] == idx:
300            logger.info("Test: Unexpected EAP-Success")
301            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'] - 2, 4)
302
303        return None
304
305    srv = start_radius_server(eap_handler)
306
307    try:
308        hapd = start_ap(apdev[0])
309        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
310
311        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
312                       eap="MD5", identity="user", password="password",
313                       wait_connect=False)
314        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
315        if ev is None:
316            raise Exception("Timeout on EAP start")
317        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
318        if ev is None:
319            raise Exception("Timeout on EAP success")
320        dev[0].request("REMOVE_NETWORK all")
321
322        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
323                       eap="MD5", identity="user", password="password",
324                       wait_connect=False)
325        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
326        if ev is None:
327            raise Exception("Timeout on EAP start")
328        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=1)
329        if ev is not None:
330            raise Exception("Unexpected EAP success")
331        dev[0].request("REMOVE_NETWORK all")
332
333        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
334                       eap="MD5", identity="user", password="password",
335                       wait_connect=False)
336        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
337        if ev is None:
338            raise Exception("Timeout on EAP start")
339        ev = dev[0].wait_event(["CTRL-EVENT-EAP-NOTIFICATION"], timeout=10)
340        if ev is None:
341            raise Exception("Timeout on EAP notification")
342        if ev != "<3>CTRL-EVENT-EAP-NOTIFICATION A":
343            raise Exception("Unexpected notification contents: " + ev)
344        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
345        if ev is None:
346            raise Exception("Timeout on EAP success")
347        dev[0].request("REMOVE_NETWORK all")
348
349        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
350                       eap="MD5", identity="user", password="password",
351                       wait_connect=False)
352        ev = dev[0].wait_event(["CTRL-EVENT-EAP-NOTIFICATION"], timeout=10)
353        if ev is None:
354            raise Exception("Timeout on EAP notification")
355        if ev != "<3>CTRL-EVENT-EAP-NOTIFICATION B":
356            raise Exception("Unexpected notification contents: " + ev)
357        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
358        if ev is None:
359            raise Exception("Timeout on EAP start")
360        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
361        if ev is None:
362            raise Exception("Timeout on EAP success")
363        dev[0].request("REMOVE_NETWORK all")
364
365        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
366                       eap="MD5", identity="user", password="password",
367                       wait_connect=False)
368        ev = dev[0].wait_event(["CTRL-EVENT-EAP-NOTIFICATION"], timeout=10)
369        if ev is None:
370            raise Exception("Timeout on EAP notification")
371        if ev != "<3>CTRL-EVENT-EAP-NOTIFICATION C":
372            raise Exception("Unexpected notification contents: " + ev)
373        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
374        if ev is None:
375            raise Exception("Timeout on EAP start")
376        ev = dev[0].wait_event(["CTRL-EVENT-EAP-NOTIFICATION"], timeout=10)
377        if ev is None:
378            raise Exception("Timeout on EAP notification")
379        if ev != "<3>CTRL-EVENT-EAP-NOTIFICATION D":
380            raise Exception("Unexpected notification contents: " + ev)
381        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
382        if ev is None:
383            raise Exception("Timeout on EAP success")
384        dev[0].request("REMOVE_NETWORK all")
385
386        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
387                       eap="MD5", identity="user", password="password",
388                       wait_connect=False)
389        ev = dev[0].wait_event(["CTRL-EVENT-EAP-NOTIFICATION"], timeout=10)
390        if ev is None:
391            raise Exception("Timeout on EAP notification")
392        if ev != "<3>CTRL-EVENT-EAP-NOTIFICATION E":
393            raise Exception("Unexpected notification contents: " + ev)
394        ev = dev[0].wait_event(["CTRL-EVENT-EAP-NOTIFICATION"], timeout=10)
395        if ev is None:
396            raise Exception("Timeout on EAP notification")
397        if ev != "<3>CTRL-EVENT-EAP-NOTIFICATION F":
398            raise Exception("Unexpected notification contents: " + ev)
399        ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=15)
400        if ev is None:
401            raise Exception("Timeout on EAP failure")
402        dev[0].request("REMOVE_NETWORK all")
403    finally:
404        stop_radius_server(srv)
405
406def test_eap_proto_notification_errors(dev, apdev):
407    """EAP Notification errors"""
408    def eap_handler(ctx, req):
409        logger.info("eap_handler - RX " + binascii.hexlify(req).decode())
410        if 'num' not in ctx:
411            ctx['num'] = 0
412        ctx['num'] = ctx['num'] + 1
413        if 'id' not in ctx:
414            ctx['id'] = 1
415        ctx['id'] = (ctx['id'] + 1) % 256
416        idx = 0
417
418        idx += 1
419        if ctx['num'] == idx:
420            logger.info("Test: MD5 challenge")
421            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
422                               4 + 1 + 3,
423                               EAP_TYPE_MD5,
424                               1, 0xaa, ord('n'))
425        idx += 1
426        if ctx['num'] == idx:
427            logger.info("Test: EAP-Notification/Request")
428            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
429                               4 + 1 + 1,
430                               EAP_TYPE_NOTIFICATION,
431                               ord('A'))
432
433        idx += 1
434        if ctx['num'] == idx:
435            logger.info("Test: MD5 challenge")
436            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
437                               4 + 1 + 3,
438                               EAP_TYPE_MD5,
439                               1, 0xaa, ord('n'))
440        idx += 1
441        if ctx['num'] == idx:
442            logger.info("Test: EAP-Notification/Request")
443            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
444                               4 + 1 + 1,
445                               EAP_TYPE_NOTIFICATION,
446                               ord('A'))
447
448        return None
449
450    srv = start_radius_server(eap_handler)
451
452    try:
453        hapd = start_ap(apdev[0])
454        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
455
456        with alloc_fail(dev[0], 1, "eap_sm_processNotify"):
457            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
458                           eap="MD5", identity="user", password="password",
459                           wait_connect=False)
460            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
461            dev[0].request("REMOVE_NETWORK all")
462            dev[0].wait_disconnected()
463
464        with alloc_fail(dev[0], 1, "eap_msg_alloc;sm_EAP_NOTIFICATION_Enter"):
465            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
466                           eap="MD5", identity="user", password="password",
467                           wait_connect=False)
468            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
469            dev[0].request("REMOVE_NETWORK all")
470            dev[0].wait_disconnected()
471    finally:
472        stop_radius_server(srv)
473
474EAP_SAKE_VERSION = 2
475
476EAP_SAKE_SUBTYPE_CHALLENGE = 1
477EAP_SAKE_SUBTYPE_CONFIRM = 2
478EAP_SAKE_SUBTYPE_AUTH_REJECT = 3
479EAP_SAKE_SUBTYPE_IDENTITY = 4
480
481EAP_SAKE_AT_RAND_S = 1
482EAP_SAKE_AT_RAND_P = 2
483EAP_SAKE_AT_MIC_S = 3
484EAP_SAKE_AT_MIC_P = 4
485EAP_SAKE_AT_SERVERID = 5
486EAP_SAKE_AT_PEERID = 6
487EAP_SAKE_AT_SPI_S = 7
488EAP_SAKE_AT_SPI_P = 8
489EAP_SAKE_AT_ANY_ID_REQ = 9
490EAP_SAKE_AT_PERM_ID_REQ = 10
491EAP_SAKE_AT_ENCR_DATA = 128
492EAP_SAKE_AT_IV = 129
493EAP_SAKE_AT_PADDING = 130
494EAP_SAKE_AT_NEXT_TMPID = 131
495EAP_SAKE_AT_MSK_LIFE = 132
496
497def test_eap_proto_sake(dev, apdev):
498    """EAP-SAKE protocol tests"""
499    global eap_proto_sake_test_done
500    eap_proto_sake_test_done = False
501
502    def sake_challenge(ctx):
503        logger.info("Test: Challenge subtype")
504        return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
505                           4 + 1 + 3 + 18,
506                           EAP_TYPE_SAKE,
507                           EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE,
508                           EAP_SAKE_AT_RAND_S, 18, 0, 0, 0, 0)
509
510    def sake_handler(ctx, req):
511        logger.info("sake_handler - RX " + binascii.hexlify(req).decode())
512        if 'num' not in ctx:
513            ctx['num'] = 0
514        ctx['num'] += 1
515        if 'id' not in ctx:
516            ctx['id'] = 1
517        ctx['id'] = (ctx['id'] + 1) % 256
518        idx = 0
519
520        idx += 1
521        if ctx['num'] == idx:
522            logger.info("Test: Missing payload")
523            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'], 4 + 1,
524                               EAP_TYPE_SAKE)
525
526        idx += 1
527        if ctx['num'] == idx:
528            logger.info("Test: Identity subtype without any attributes")
529            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
530                               4 + 1 + 3,
531                               EAP_TYPE_SAKE,
532                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY)
533
534        idx += 1
535        if ctx['num'] == idx:
536            logger.info("Test: Identity subtype")
537            return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
538                               4 + 1 + 3 + 4,
539                               EAP_TYPE_SAKE,
540                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
541                               EAP_SAKE_AT_ANY_ID_REQ, 4, 0)
542        idx += 1
543        if ctx['num'] == idx:
544            logger.info("Test: Identity subtype (different session id)")
545            return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
546                               4 + 1 + 3 + 4,
547                               EAP_TYPE_SAKE,
548                               EAP_SAKE_VERSION, 1, EAP_SAKE_SUBTYPE_IDENTITY,
549                               EAP_SAKE_AT_PERM_ID_REQ, 4, 0)
550
551        idx += 1
552        if ctx['num'] == idx:
553            logger.info("Test: Identity subtype with too short attribute")
554            return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
555                               4 + 1 + 3 + 2,
556                               EAP_TYPE_SAKE,
557                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
558                               EAP_SAKE_AT_ANY_ID_REQ, 2)
559
560        idx += 1
561        if ctx['num'] == idx:
562            logger.info("Test: Identity subtype with truncated attribute")
563            return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
564                               4 + 1 + 3 + 2,
565                               EAP_TYPE_SAKE,
566                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
567                               EAP_SAKE_AT_ANY_ID_REQ, 4)
568
569        idx += 1
570        if ctx['num'] == idx:
571            logger.info("Test: Identity subtype with too short attribute header")
572            payload = struct.pack("B", EAP_SAKE_AT_ANY_ID_REQ)
573            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
574                               4 + 1 + 3 + len(payload),
575                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
576                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
577
578        idx += 1
579        if ctx['num'] == idx:
580            logger.info("Test: Identity subtype with AT_IV but not AT_ENCR_DATA")
581            payload = struct.pack("BB", EAP_SAKE_AT_IV, 2)
582            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
583                               4 + 1 + 3 + len(payload),
584                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
585                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
586
587        idx += 1
588        if ctx['num'] == idx:
589            logger.info("Test: Identity subtype with skippable and non-skippable unknown attribute")
590            payload = struct.pack("BBBB", 255, 2, 127, 2)
591            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
592                               4 + 1 + 3 + len(payload),
593                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
594                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
595
596        idx += 1
597        if ctx['num'] == idx:
598            logger.info("Test: Identity subtype: AT_RAND_P with invalid payload length")
599            payload = struct.pack("BB", EAP_SAKE_AT_RAND_P, 2)
600            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
601                               4 + 1 + 3 + len(payload),
602                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
603                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
604
605        idx += 1
606        if ctx['num'] == idx:
607            logger.info("Test: Identity subtype: AT_MIC_P with invalid payload length")
608            payload = struct.pack("BB", EAP_SAKE_AT_MIC_P, 2)
609            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
610                               4 + 1 + 3 + len(payload),
611                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
612                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
613
614        idx += 1
615        if ctx['num'] == idx:
616            logger.info("Test: Identity subtype: AT_PERM_ID_REQ with invalid payload length")
617            payload = struct.pack("BBBBBBBBBBBBBB",
618                                  EAP_SAKE_AT_SPI_S, 2,
619                                  EAP_SAKE_AT_SPI_P, 2,
620                                  EAP_SAKE_AT_ENCR_DATA, 2,
621                                  EAP_SAKE_AT_NEXT_TMPID, 2,
622                                  EAP_SAKE_AT_PERM_ID_REQ, 4, 0, 0,
623                                  EAP_SAKE_AT_PERM_ID_REQ, 2)
624            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
625                               4 + 1 + 3 + len(payload),
626                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
627                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
628
629        idx += 1
630        if ctx['num'] == idx:
631            logger.info("Test: Identity subtype: AT_PADDING")
632            payload = struct.pack("BBBBBB",
633                                  EAP_SAKE_AT_PADDING, 3, 0,
634                                  EAP_SAKE_AT_PADDING, 3, 1)
635            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
636                               4 + 1 + 3 + len(payload),
637                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
638                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
639
640        idx += 1
641        if ctx['num'] == idx:
642            logger.info("Test: Identity subtype: AT_MSK_LIFE")
643            payload = struct.pack(">BBLBBH",
644                                  EAP_SAKE_AT_MSK_LIFE, 6, 0,
645                                  EAP_SAKE_AT_MSK_LIFE, 4, 0)
646            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
647                               4 + 1 + 3 + len(payload),
648                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
649                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
650
651        idx += 1
652        if ctx['num'] == idx:
653            logger.info("Test: Identity subtype with invalid attribute length")
654            payload = struct.pack("BB", EAP_SAKE_AT_ANY_ID_REQ, 0)
655            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
656                               4 + 1 + 3 + len(payload),
657                               EAP_TYPE_SAKE, EAP_SAKE_VERSION, 0,
658                               EAP_SAKE_SUBTYPE_IDENTITY) + payload
659
660        idx += 1
661        if ctx['num'] == idx:
662            logger.info("Test: Unknown subtype")
663            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
664                               4 + 1 + 3,
665                               EAP_TYPE_SAKE,
666                               EAP_SAKE_VERSION, 0, 123)
667
668        idx += 1
669        if ctx['num'] == idx:
670            logger.info("Test: Challenge subtype without any attributes")
671            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
672                               4 + 1 + 3,
673                               EAP_TYPE_SAKE,
674                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE)
675
676        idx += 1
677        if ctx['num'] == idx:
678            logger.info("Test: Challenge subtype with too short AT_RAND_S")
679            return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
680                               4 + 1 + 3 + 2,
681                               EAP_TYPE_SAKE,
682                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE,
683                               EAP_SAKE_AT_RAND_S, 2)
684
685        idx += 1
686        if ctx['num'] == idx:
687            return sake_challenge(ctx)
688        idx += 1
689        if ctx['num'] == idx:
690            logger.info("Test: Unexpected Identity subtype")
691            return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
692                               4 + 1 + 3 + 4,
693                               EAP_TYPE_SAKE,
694                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
695                               EAP_SAKE_AT_ANY_ID_REQ, 4, 0)
696
697        idx += 1
698        if ctx['num'] == idx:
699            return sake_challenge(ctx)
700        idx += 1
701        if ctx['num'] == idx:
702            logger.info("Test: Unexpected Challenge subtype")
703            return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
704                               4 + 1 + 3 + 18,
705                               EAP_TYPE_SAKE,
706                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE,
707                               EAP_SAKE_AT_RAND_S, 18, 0, 0, 0, 0)
708
709        idx += 1
710        if ctx['num'] == idx:
711            return sake_challenge(ctx)
712        idx += 1
713        if ctx['num'] == idx:
714            logger.info("Test: Confirm subtype without any attributes")
715            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
716                               4 + 1 + 3,
717                               EAP_TYPE_SAKE,
718                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM)
719
720        idx += 1
721        if ctx['num'] == idx:
722            return sake_challenge(ctx)
723        idx += 1
724        if ctx['num'] == idx:
725            logger.info("Test: Confirm subtype with too short AT_MIC_S")
726            return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
727                               4 + 1 + 3 + 2,
728                               EAP_TYPE_SAKE,
729                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM,
730                               EAP_SAKE_AT_MIC_S, 2)
731
732        idx += 1
733        if ctx['num'] == idx:
734            logger.info("Test: Unexpected Confirm subtype")
735            return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
736                               4 + 1 + 3 + 18,
737                               EAP_TYPE_SAKE,
738                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM,
739                               EAP_SAKE_AT_MIC_S, 18, 0, 0, 0, 0)
740
741        idx += 1
742        if ctx['num'] == idx:
743            return sake_challenge(ctx)
744        idx += 1
745        if ctx['num'] == idx:
746            logger.info("Test: Confirm subtype with incorrect AT_MIC_S")
747            return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
748                               4 + 1 + 3 + 18,
749                               EAP_TYPE_SAKE,
750                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM,
751                               EAP_SAKE_AT_MIC_S, 18, 0, 0, 0, 0)
752
753        global eap_proto_sake_test_done
754        if eap_proto_sake_test_done:
755            return sake_challenge(ctx)
756
757        logger.info("No more test responses available - test case completed")
758        eap_proto_sake_test_done = True
759        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
760
761    srv = start_radius_server(sake_handler)
762
763    try:
764        hapd = start_ap(apdev[0])
765        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
766
767        while not eap_proto_sake_test_done:
768            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
769                           eap="SAKE", identity="sake user",
770                           password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
771                           wait_connect=False)
772            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
773            if ev is None:
774                raise Exception("Timeout on EAP start")
775            time.sleep(0.1)
776            dev[0].request("REMOVE_NETWORK all")
777            dev[0].dump_monitor()
778
779        logger.info("Too short password")
780        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
781                       eap="SAKE", identity="sake user",
782                       password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd",
783                       wait_connect=False)
784        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
785        if ev is None:
786            raise Exception("Timeout on EAP start")
787        start = os.times()[4]
788        while True:
789            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
790                                   timeout=0.1)
791            if ev is None:
792                break
793            now = os.times()[4]
794            if now - start > 0.1:
795                break
796            dev[0].dump_monitor()
797
798        dev[0].request("REMOVE_NETWORK all")
799        time.sleep(0.1)
800        dev[0].dump_monitor()
801    finally:
802        stop_radius_server(srv)
803
804def test_eap_proto_sake_errors(dev, apdev):
805    """EAP-SAKE local error cases"""
806    check_eap_capa(dev[0], "SAKE")
807    params = hostapd.wpa2_eap_params(ssid="eap-test")
808    hapd = hostapd.add_ap(apdev[0], params)
809    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
810
811    for i in range(1, 3):
812        with alloc_fail(dev[0], i, "eap_sake_init"):
813            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
814                           eap="SAKE", identity="sake user",
815                           password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
816                           wait_connect=False)
817            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
818                                   timeout=15)
819            if ev is None:
820                raise Exception("Timeout on EAP start")
821            dev[0].request("REMOVE_NETWORK all")
822            dev[0].wait_disconnected()
823            dev[0].dump_monitor()
824
825    tests = [(1, "eap_msg_alloc;eap_sake_build_msg;eap_sake_process_challenge"),
826             (1, "=eap_sake_process_challenge"),
827             (1, "eap_sake_compute_mic;eap_sake_process_challenge"),
828             (1, "eap_sake_build_msg;eap_sake_process_confirm"),
829             (1, "eap_sake_compute_mic;eap_sake_process_confirm"),
830             (2, "eap_sake_compute_mic;=eap_sake_process_confirm"),
831             (1, "eap_sake_getKey"),
832             (1, "eap_sake_get_emsk"),
833             (1, "eap_sake_get_session_id")]
834    for count, func in tests:
835        with alloc_fail(dev[0], count, func):
836            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
837                           eap="SAKE", identity="sake user@domain",
838                           password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
839                           erp="1",
840                           wait_connect=False)
841            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
842                                   timeout=15)
843            if ev is None:
844                raise Exception("Timeout on EAP start")
845            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
846            dev[0].request("REMOVE_NETWORK all")
847            dev[0].wait_disconnected()
848            dev[0].dump_monitor()
849
850    tests = [(1, "os_get_random;eap_sake_process_challenge"),
851             (1, "eap_sake_derive_keys;eap_sake_process_challenge"),
852             (2, "eap_sake_derive_keys;eap_sake_process_challenge"),
853             (3, "eap_sake_derive_keys;eap_sake_process_challenge"),
854             (4, "eap_sake_derive_keys;eap_sake_process_challenge"),
855             (5, "eap_sake_derive_keys;eap_sake_process_challenge"),
856             (6, "eap_sake_derive_keys;eap_sake_process_challenge")]
857    for count, func in tests:
858        with fail_test(dev[0], count, func):
859            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
860                           eap="SAKE", identity="sake user",
861                           password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
862                           wait_connect=False)
863            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
864            if ev is None:
865                raise Exception("Timeout on EAP start")
866            wait_fail_trigger(dev[0], "GET_FAIL")
867            dev[0].request("REMOVE_NETWORK all")
868            dev[0].wait_disconnected()
869            dev[0].dump_monitor()
870
871def test_eap_proto_sake_errors2(dev, apdev):
872    """EAP-SAKE protocol tests (2)"""
873    def sake_handler(ctx, req):
874        logger.info("sake_handler - RX " + binascii.hexlify(req).decode())
875        if 'num' not in ctx:
876            ctx['num'] = 0
877        ctx['num'] += 1
878        if 'id' not in ctx:
879            ctx['id'] = 1
880        ctx['id'] = (ctx['id'] + 1) % 256
881        idx = 0
882
883        idx += 1
884        if ctx['num'] == idx:
885            logger.info("Test: Identity subtype")
886            return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
887                               4 + 1 + 3 + 4,
888                               EAP_TYPE_SAKE,
889                               EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
890                               EAP_SAKE_AT_ANY_ID_REQ, 4, 0)
891
892    srv = start_radius_server(sake_handler)
893
894    try:
895        hapd = start_ap(apdev[0])
896        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
897
898        with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_sake_build_msg;eap_sake_process_identity"):
899            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
900                           eap="SAKE", identity="sake user",
901                           password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
902                           wait_connect=False)
903            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
904                                   timeout=15)
905            if ev is None:
906                raise Exception("Timeout on EAP start")
907                dev[0].request("REMOVE_NETWORK all")
908                dev[0].wait_disconnected()
909
910    finally:
911        stop_radius_server(srv)
912
913def run_eap_sake_connect(dev):
914    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
915                eap="SAKE", identity="sake user",
916                password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
917                wait_connect=False)
918    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
919                         "CTRL-EVENT-DISCONNECTED"],
920                        timeout=1)
921    dev.request("REMOVE_NETWORK all")
922    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
923        dev.wait_disconnected()
924    dev.dump_monitor()
925
926def test_eap_proto_sake_errors_server(dev, apdev):
927    """EAP-SAKE local error cases on server"""
928    check_eap_capa(dev[0], "SAKE")
929    params = int_eap_server_params()
930    params['erp_domain'] = 'example.com'
931    params['eap_server_erp'] = '1'
932    hapd = hostapd.add_ap(apdev[0], params)
933    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
934
935    tests = [(1, "eap_sake_init"),
936             (1, "eap_sake_build_msg;eap_sake_build_challenge"),
937             (1, "eap_sake_build_msg;eap_sake_build_confirm"),
938             (1, "eap_sake_compute_mic;eap_sake_build_confirm"),
939             (1, "eap_sake_process_challenge"),
940             (1, "eap_sake_getKey"),
941             (1, "eap_sake_get_emsk"),
942             (1, "eap_sake_get_session_id")]
943    for count, func in tests:
944        with alloc_fail(hapd, count, func):
945            run_eap_sake_connect(dev[0])
946
947    tests = [(1, "eap_sake_init"),
948             (1, "eap_sake_build_challenge"),
949             (1, "eap_sake_build_confirm"),
950             (1, "eap_sake_derive_keys;eap_sake_process_challenge"),
951             (1, "eap_sake_compute_mic;eap_sake_process_challenge"),
952             (1, "eap_sake_compute_mic;eap_sake_process_confirm"),
953             (1, "eap_sake_compute_mic;eap_sake_build_confirm"),
954             (1, "eap_sake_process_confirm")]
955    for count, func in tests:
956        with fail_test(hapd, count, func):
957            run_eap_sake_connect(dev[0])
958
959def start_sake_assoc(dev, hapd):
960    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
961                eap="SAKE", identity="sake user",
962                password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
963                wait_connect=False)
964    proxy_msg(hapd, dev) # EAP-Identity/Request
965    proxy_msg(dev, hapd) # EAP-Identity/Response
966    proxy_msg(hapd, dev) # SAKE/Challenge/Request
967
968def stop_sake_assoc(dev, hapd):
969    dev.request("REMOVE_NETWORK all")
970    dev.wait_disconnected()
971    dev.dump_monitor()
972    hapd.dump_monitor()
973
974def test_eap_proto_sake_server(dev, apdev):
975    """EAP-SAKE protocol testing for the server"""
976    check_eap_capa(dev[0], "SAKE")
977    params = int_eap_server_params()
978    params['erp_domain'] = 'example.com'
979    params['eap_server_erp'] = '1'
980    hapd = hostapd.add_ap(apdev[0], params)
981    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
982    hapd.request("SET ext_eapol_frame_io 1")
983    dev[0].request("SET ext_eapol_frame_io 1")
984
985    # Successful exchange to verify proxying mechanism
986    start_sake_assoc(dev[0], hapd)
987    proxy_msg(dev[0], hapd) # SAKE/Challenge/Response
988    proxy_msg(hapd, dev[0]) # SAKE/Confirm/Request
989    proxy_msg(dev[0], hapd) # SAKE/Confirm/Response
990    proxy_msg(hapd, dev[0]) # EAP-Success
991    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 1/4
992    proxy_msg(dev[0], hapd) # EAPOL-Key msg 2/4
993    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 3/4
994    proxy_msg(dev[0], hapd) # EAPOL-Key msg 4/4
995    dev[0].wait_connected()
996    stop_sake_assoc(dev[0], hapd)
997
998    start_sake_assoc(dev[0], hapd)
999    resp = rx_msg(dev[0])
1000    # Too short EAP-SAKE header
1001    # --> EAP-SAKE: Invalid frame
1002    msg = resp[0:4] + "0007" + resp[8:12] + "0007" + "300200"
1003    tx_msg(dev[0], hapd, msg)
1004    # Unknown version
1005    # --> EAP-SAKE: Unknown version 1
1006    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "30010000"
1007    tx_msg(dev[0], hapd, msg)
1008    # Unknown session
1009    # --> EAP-SAKE: Session ID mismatch
1010    sess, = struct.unpack('B', binascii.unhexlify(resp[20:22]))
1011    sess = binascii.hexlify(struct.pack('B', (sess + 1) % 256)).decode()
1012    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "3002" + sess + "00"
1013    tx_msg(dev[0], hapd, msg)
1014    # Unknown subtype
1015    # --> EAP-SAKE: Unexpected subtype=5 in state=1
1016    msg = resp[0:22] + "05" + resp[24:]
1017    tx_msg(dev[0], hapd, msg)
1018    # Empty challenge
1019    # --> EAP-SAKE: Response/Challenge did not include AT_RAND_P or AT_MIC_P
1020    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + resp[16:24]
1021    tx_msg(dev[0], hapd, msg)
1022    rx_msg(hapd)
1023    stop_sake_assoc(dev[0], hapd)
1024
1025    start_sake_assoc(dev[0], hapd)
1026    resp = rx_msg(dev[0])
1027    # Invalid attribute in challenge
1028    # --> EAP-SAKE: Too short attribute
1029    msg = resp[0:4] + "0009" + resp[8:12] + "0009" + resp[16:26]
1030    tx_msg(dev[0], hapd, msg)
1031    rx_msg(hapd)
1032    stop_sake_assoc(dev[0], hapd)
1033
1034    start_sake_assoc(dev[0], hapd)
1035    proxy_msg(dev[0], hapd) # SAKE/Challenge/Response
1036    proxy_msg(hapd, dev[0]) # SAKE/Confirm/Request
1037    resp = rx_msg(dev[0])
1038    # Empty confirm
1039    # --> EAP-SAKE: Response/Confirm did not include AT_MIC_P
1040    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + resp[16:26]
1041    tx_msg(dev[0], hapd, msg)
1042    rx_msg(hapd)
1043    stop_sake_assoc(dev[0], hapd)
1044
1045    start_sake_assoc(dev[0], hapd)
1046    proxy_msg(dev[0], hapd) # SAKE/Challenge/Response
1047    proxy_msg(hapd, dev[0]) # SAKE/Confirm/Request
1048    resp = rx_msg(dev[0])
1049    # Invalid attribute in confirm
1050    # --> EAP-SAKE: Too short attribute
1051    msg = resp[0:4] + "0009" + resp[8:12] + "0009" + resp[16:26]
1052    tx_msg(dev[0], hapd, msg)
1053    rx_msg(hapd)
1054    stop_sake_assoc(dev[0], hapd)
1055
1056    start_sake_assoc(dev[0], hapd)
1057    proxy_msg(dev[0], hapd) # SAKE/Challenge/Response
1058    proxy_msg(hapd, dev[0]) # SAKE/Confirm/Request
1059    resp = rx_msg(dev[0])
1060    # Corrupted AT_MIC_P value
1061    # --> EAP-SAKE: Incorrect AT_MIC_P
1062    msg = resp[0:30] + "000000000000" + resp[42:]
1063    tx_msg(dev[0], hapd, msg)
1064    rx_msg(hapd)
1065    stop_sake_assoc(dev[0], hapd)
1066
1067def test_eap_proto_leap(dev, apdev):
1068    """EAP-LEAP protocol tests"""
1069    check_eap_capa(dev[0], "LEAP")
1070    def leap_handler(ctx, req):
1071        logger.info("leap_handler - RX " + binascii.hexlify(req).decode())
1072        if 'num' not in ctx:
1073            ctx['num'] = 0
1074        ctx['num'] = ctx['num'] + 1
1075        if 'id' not in ctx:
1076            ctx['id'] = 1
1077        ctx['id'] = (ctx['id'] + 1) % 256
1078
1079        if ctx['num'] == 1:
1080            logger.info("Test: Missing payload")
1081            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
1082                               4 + 1,
1083                               EAP_TYPE_LEAP)
1084
1085        if ctx['num'] == 2:
1086            logger.info("Test: Unexpected version")
1087            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
1088                               4 + 1 + 3,
1089                               EAP_TYPE_LEAP,
1090                               0, 0, 0)
1091
1092        if ctx['num'] == 3:
1093            logger.info("Test: Invalid challenge length")
1094            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
1095                               4 + 1 + 3,
1096                               EAP_TYPE_LEAP,
1097                               1, 0, 0)
1098
1099        if ctx['num'] == 4:
1100            logger.info("Test: Truncated challenge")
1101            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
1102                               4 + 1 + 3,
1103                               EAP_TYPE_LEAP,
1104                               1, 0, 8)
1105
1106        if ctx['num'] == 5:
1107            logger.info("Test: Valid challenge")
1108            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1109                               4 + 1 + 3 + 8,
1110                               EAP_TYPE_LEAP,
1111                               1, 0, 8, 0, 0)
1112        if ctx['num'] == 6:
1113            logger.info("Test: Missing payload in Response")
1114            return struct.pack(">BBHB", EAP_CODE_RESPONSE, ctx['id'],
1115                               4 + 1,
1116                               EAP_TYPE_LEAP)
1117
1118        if ctx['num'] == 7:
1119            logger.info("Test: Valid challenge")
1120            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1121                               4 + 1 + 3 + 8,
1122                               EAP_TYPE_LEAP,
1123                               1, 0, 8, 0, 0)
1124        if ctx['num'] == 8:
1125            logger.info("Test: Unexpected version in Response")
1126            return struct.pack(">BBHBBBB", EAP_CODE_RESPONSE, ctx['id'],
1127                               4 + 1 + 3,
1128                               EAP_TYPE_LEAP,
1129                               0, 0, 8)
1130
1131        if ctx['num'] == 9:
1132            logger.info("Test: Valid challenge")
1133            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1134                               4 + 1 + 3 + 8,
1135                               EAP_TYPE_LEAP,
1136                               1, 0, 8, 0, 0)
1137        if ctx['num'] == 10:
1138            logger.info("Test: Invalid challenge length in Response")
1139            return struct.pack(">BBHBBBB", EAP_CODE_RESPONSE, ctx['id'],
1140                               4 + 1 + 3,
1141                               EAP_TYPE_LEAP,
1142                               1, 0, 0)
1143
1144        if ctx['num'] == 11:
1145            logger.info("Test: Valid challenge")
1146            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1147                               4 + 1 + 3 + 8,
1148                               EAP_TYPE_LEAP,
1149                               1, 0, 8, 0, 0)
1150        if ctx['num'] == 12:
1151            logger.info("Test: Truncated challenge in Response")
1152            return struct.pack(">BBHBBBB", EAP_CODE_RESPONSE, ctx['id'],
1153                               4 + 1 + 3,
1154                               EAP_TYPE_LEAP,
1155                               1, 0, 24)
1156
1157        if ctx['num'] == 13:
1158            logger.info("Test: Valid challenge")
1159            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1160                               4 + 1 + 3 + 8,
1161                               EAP_TYPE_LEAP,
1162                               1, 0, 8, 0, 0)
1163        if ctx['num'] == 14:
1164            logger.info("Test: Invalid challange value in Response")
1165            return struct.pack(">BBHBBBB6L", EAP_CODE_RESPONSE, ctx['id'],
1166                               4 + 1 + 3 + 24,
1167                               EAP_TYPE_LEAP,
1168                               1, 0, 24,
1169                               0, 0, 0, 0, 0, 0)
1170
1171        if ctx['num'] == 15:
1172            logger.info("Test: Valid challenge")
1173            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1174                               4 + 1 + 3 + 8,
1175                               EAP_TYPE_LEAP,
1176                               1, 0, 8, 0, 0)
1177        if ctx['num'] == 16:
1178            logger.info("Test: Valid challange value in Response")
1179            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1180                               4 + 1 + 3 + 24,
1181                               EAP_TYPE_LEAP,
1182                               1, 0, 24,
1183                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1184                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1185                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1186
1187        if ctx['num'] == 17:
1188            logger.info("Test: Valid challenge")
1189            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1190                               4 + 1 + 3 + 8,
1191                               EAP_TYPE_LEAP,
1192                               1, 0, 8, 0, 0)
1193        if ctx['num'] == 18:
1194            logger.info("Test: Success")
1195            return struct.pack(">BBHB", EAP_CODE_SUCCESS, ctx['id'],
1196                               4 + 1,
1197                               EAP_TYPE_LEAP)
1198        # hostapd will drop the next frame in the sequence
1199
1200        if ctx['num'] == 19:
1201            logger.info("Test: Valid challenge")
1202            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1203                               4 + 1 + 3 + 8,
1204                               EAP_TYPE_LEAP,
1205                               1, 0, 8, 0, 0)
1206        if ctx['num'] == 20:
1207            logger.info("Test: Failure")
1208            return struct.pack(">BBHB", EAP_CODE_FAILURE, ctx['id'],
1209                               4 + 1,
1210                               EAP_TYPE_LEAP)
1211
1212        return None
1213
1214    srv = start_radius_server(leap_handler)
1215
1216    try:
1217        hapd = start_ap(apdev[0])
1218        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1219
1220        for i in range(0, 12):
1221            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1222                           eap="LEAP", identity="user", password="password",
1223                           wait_connect=False)
1224            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
1225            if ev is None:
1226                raise Exception("Timeout on EAP start")
1227            time.sleep(0.1)
1228            if i == 10:
1229                logger.info("Wait for additional roundtrip")
1230                time.sleep(1)
1231            dev[0].request("REMOVE_NETWORK all")
1232    finally:
1233        stop_radius_server(srv)
1234
1235def test_eap_proto_leap_errors(dev, apdev):
1236    """EAP-LEAP protocol tests (error paths)"""
1237    check_eap_capa(dev[0], "LEAP")
1238
1239    def leap_handler2(ctx, req):
1240        logger.info("leap_handler2 - RX " + binascii.hexlify(req).decode())
1241        if 'num' not in ctx:
1242            ctx['num'] = 0
1243        ctx['num'] = ctx['num'] + 1
1244        if 'id' not in ctx:
1245            ctx['id'] = 1
1246        ctx['id'] = (ctx['id'] + 1) % 256
1247        idx = 0
1248
1249        idx += 1
1250        if ctx['num'] == idx:
1251            logger.info("Test: Valid challenge")
1252            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1253                               4 + 1 + 3 + 8,
1254                               EAP_TYPE_LEAP,
1255                               1, 0, 8, 0, 0)
1256        idx += 1
1257        if ctx['num'] == idx:
1258            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
1259
1260        idx += 1
1261        if ctx['num'] == idx:
1262            logger.info("Test: Valid challenge")
1263            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1264                               4 + 1 + 3 + 8,
1265                               EAP_TYPE_LEAP,
1266                               1, 0, 8, 0, 0)
1267
1268        idx += 1
1269        if ctx['num'] == idx:
1270            logger.info("Test: Valid challenge")
1271            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1272                               4 + 1 + 3 + 8,
1273                               EAP_TYPE_LEAP,
1274                               1, 0, 8, 0, 0)
1275        idx += 1
1276        if ctx['num'] == idx:
1277            logger.info("Test: Success")
1278            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
1279
1280        idx += 1
1281        if ctx['num'] == idx:
1282            logger.info("Test: Valid challenge")
1283            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1284                               4 + 1 + 3 + 8,
1285                               EAP_TYPE_LEAP,
1286                               1, 0, 8, 0, 0)
1287        idx += 1
1288        if ctx['num'] == idx:
1289            logger.info("Test: Success")
1290            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
1291
1292        idx += 1
1293        if ctx['num'] == idx:
1294            logger.info("Test: Valid challenge")
1295            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1296                               4 + 1 + 3 + 8,
1297                               EAP_TYPE_LEAP,
1298                               1, 0, 8, 0, 0)
1299        idx += 1
1300        if ctx['num'] == idx:
1301            logger.info("Test: Valid challange value in Response")
1302            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1303                               4 + 1 + 3 + 24,
1304                               EAP_TYPE_LEAP,
1305                               1, 0, 24,
1306                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1307                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1308                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1309
1310        idx += 1
1311        if ctx['num'] == idx:
1312            logger.info("Test: Valid challenge")
1313            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1314                               4 + 1 + 3 + 8,
1315                               EAP_TYPE_LEAP,
1316                               1, 0, 8, 0, 0)
1317        idx += 1
1318        if ctx['num'] == idx:
1319            logger.info("Test: Valid challange value in Response")
1320            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1321                               4 + 1 + 3 + 24,
1322                               EAP_TYPE_LEAP,
1323                               1, 0, 24,
1324                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1325                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1326                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1327
1328        idx += 1
1329        if ctx['num'] == idx:
1330            logger.info("Test: Valid challenge")
1331            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1332                               4 + 1 + 3 + 8,
1333                               EAP_TYPE_LEAP,
1334                               1, 0, 8, 0, 0)
1335        idx += 1
1336        if ctx['num'] == idx:
1337            logger.info("Test: Valid challange value in Response")
1338            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1339                               4 + 1 + 3 + 24,
1340                               EAP_TYPE_LEAP,
1341                               1, 0, 24,
1342                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1343                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1344                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1345
1346        idx += 1
1347        if ctx['num'] == idx:
1348            logger.info("Test: Valid challenge")
1349            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1350                               4 + 1 + 3 + 8,
1351                               EAP_TYPE_LEAP,
1352                               1, 0, 8, 0, 0)
1353        idx += 1
1354        if ctx['num'] == idx:
1355            logger.info("Test: Valid challange value in Response")
1356            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1357                               4 + 1 + 3 + 24,
1358                               EAP_TYPE_LEAP,
1359                               1, 0, 24,
1360                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1361                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1362                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1363
1364        idx += 1
1365        if ctx['num'] == idx:
1366            logger.info("Test: Valid challenge")
1367            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1368                               4 + 1 + 3 + 8,
1369                               EAP_TYPE_LEAP,
1370                               1, 0, 8, 0, 0)
1371        idx += 1
1372        if ctx['num'] == idx:
1373            logger.info("Test: Valid challange value in Response")
1374            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1375                               4 + 1 + 3 + 24,
1376                               EAP_TYPE_LEAP,
1377                               1, 0, 24,
1378                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1379                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1380                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1381
1382        idx += 1
1383        if ctx['num'] == idx:
1384            logger.info("Test: Valid challenge")
1385            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1386                               4 + 1 + 3 + 8,
1387                               EAP_TYPE_LEAP,
1388                               1, 0, 8, 0, 0)
1389        idx += 1
1390        if ctx['num'] == idx:
1391            logger.info("Test: Valid challange value in Response")
1392            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1393                               4 + 1 + 3 + 24,
1394                               EAP_TYPE_LEAP,
1395                               1, 0, 24,
1396                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1397                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1398                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1399
1400        idx += 1
1401        if ctx['num'] == idx:
1402            logger.info("Test: Valid challenge")
1403            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1404                               4 + 1 + 3 + 8,
1405                               EAP_TYPE_LEAP,
1406                               1, 0, 8, 0, 0)
1407        idx += 1
1408        if ctx['num'] == idx:
1409            logger.info("Test: Valid challange value in Response")
1410            return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
1411                               4 + 1 + 3 + 24,
1412                               EAP_TYPE_LEAP,
1413                               1, 0, 24,
1414                               0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
1415                               0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
1416                               0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
1417
1418        idx += 1
1419        if ctx['num'] == idx:
1420            logger.info("Test: Valid challenge")
1421            return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
1422                               4 + 1 + 3 + 8,
1423                               EAP_TYPE_LEAP,
1424                               1, 0, 8, 0, 0)
1425
1426        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
1427
1428    srv = start_radius_server(leap_handler2)
1429
1430    try:
1431        hapd = start_ap(apdev[0])
1432        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1433
1434        with alloc_fail(dev[0], 1, "eap_leap_init"):
1435            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1436                           eap="LEAP", identity="user", password="password",
1437                           wait_connect=False)
1438            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1439            dev[0].request("REMOVE_NETWORK all")
1440            dev[0].wait_disconnected()
1441
1442        with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_leap_process_request"):
1443            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1444                           eap="LEAP", identity="user",
1445                           password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
1446                           wait_connect=False)
1447            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1448            dev[0].request("REMOVE_NETWORK all")
1449            dev[0].wait_disconnected()
1450
1451        with alloc_fail(dev[0], 1, "eap_leap_process_success"):
1452            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1453                           eap="LEAP", identity="user", password="password",
1454                           wait_connect=False)
1455            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1456            dev[0].request("REMOVE_NETWORK all")
1457            dev[0].wait_disconnected()
1458
1459        with fail_test(dev[0], 1, "os_get_random;eap_leap_process_success"):
1460            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1461                           eap="LEAP", identity="user", password="password",
1462                           wait_connect=False)
1463            wait_fail_trigger(dev[0], "GET_FAIL")
1464            dev[0].request("REMOVE_NETWORK all")
1465            dev[0].wait_disconnected()
1466
1467        with fail_test(dev[0], 1, "eap_leap_process_response"):
1468            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1469                           eap="LEAP", identity="user",
1470                           password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
1471                           wait_connect=False)
1472            wait_fail_trigger(dev[0], "GET_FAIL")
1473            dev[0].request("REMOVE_NETWORK all")
1474            dev[0].wait_disconnected()
1475
1476        with fail_test(dev[0], 1, "nt_password_hash;eap_leap_process_response"):
1477            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1478                           eap="LEAP", identity="user", password="password",
1479                           wait_connect=False)
1480            wait_fail_trigger(dev[0], "GET_FAIL")
1481            dev[0].request("REMOVE_NETWORK all")
1482            dev[0].wait_disconnected()
1483
1484        with fail_test(dev[0], 1, "hash_nt_password_hash;eap_leap_process_response"):
1485            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1486                           eap="LEAP", identity="user", password="password",
1487                           wait_connect=False)
1488            wait_fail_trigger(dev[0], "GET_FAIL")
1489            dev[0].request("REMOVE_NETWORK all")
1490            dev[0].wait_disconnected()
1491
1492        with alloc_fail(dev[0], 1, "eap_leap_getKey"):
1493            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1494                           eap="LEAP", identity="user",
1495                           password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
1496                           wait_connect=False)
1497            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1498            dev[0].request("REMOVE_NETWORK all")
1499            dev[0].wait_disconnected()
1500
1501        with fail_test(dev[0], 1, "eap_leap_getKey"):
1502            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1503                           eap="LEAP", identity="user",
1504                           password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
1505                           wait_connect=False)
1506            wait_fail_trigger(dev[0], "GET_FAIL")
1507            dev[0].request("REMOVE_NETWORK all")
1508            dev[0].wait_disconnected()
1509
1510        with fail_test(dev[0], 1, "nt_password_hash;eap_leap_getKey"):
1511            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1512                           eap="LEAP", identity="user", password="password",
1513                           wait_connect=False)
1514            wait_fail_trigger(dev[0], "GET_FAIL")
1515            dev[0].request("REMOVE_NETWORK all")
1516            dev[0].wait_disconnected()
1517
1518        with fail_test(dev[0], 1, "hash_nt_password_hash;eap_leap_getKey"):
1519            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1520                           eap="LEAP", identity="user", password="password",
1521                           wait_connect=False)
1522            wait_fail_trigger(dev[0], "GET_FAIL")
1523            dev[0].request("REMOVE_NETWORK all")
1524            dev[0].wait_disconnected()
1525
1526        with fail_test(dev[0], 1,
1527                       "nt_challenge_response;eap_leap_process_request"):
1528            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1529                           eap="LEAP", identity="user", password="password",
1530                           wait_connect=False)
1531            wait_fail_trigger(dev[0], "GET_FAIL")
1532            dev[0].request("REMOVE_NETWORK all")
1533            dev[0].wait_disconnected()
1534    finally:
1535        stop_radius_server(srv)
1536
1537def test_eap_proto_md5(dev, apdev):
1538    """EAP-MD5 protocol tests"""
1539    check_eap_capa(dev[0], "MD5")
1540
1541    def md5_handler(ctx, req):
1542        logger.info("md5_handler - RX " + binascii.hexlify(req).decode())
1543        if 'num' not in ctx:
1544            ctx['num'] = 0
1545        ctx['num'] = ctx['num'] + 1
1546        if 'id' not in ctx:
1547            ctx['id'] = 1
1548        ctx['id'] = (ctx['id'] + 1) % 256
1549
1550        if ctx['num'] == 1:
1551            logger.info("Test: Missing payload")
1552            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
1553                               4 + 1,
1554                               EAP_TYPE_MD5)
1555
1556        if ctx['num'] == 2:
1557            logger.info("Test: Zero-length challenge")
1558            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1559                               4 + 1 + 1,
1560                               EAP_TYPE_MD5,
1561                               0)
1562
1563        if ctx['num'] == 3:
1564            logger.info("Test: Truncated challenge")
1565            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1566                               4 + 1 + 1,
1567                               EAP_TYPE_MD5,
1568                               1)
1569
1570        if ctx['num'] == 4:
1571            logger.info("Test: Shortest possible challenge and name")
1572            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
1573                               4 + 1 + 3,
1574                               EAP_TYPE_MD5,
1575                               1, 0xaa, ord('n'))
1576
1577        return None
1578
1579    srv = start_radius_server(md5_handler)
1580
1581    try:
1582        hapd = start_ap(apdev[0])
1583        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1584
1585        for i in range(0, 4):
1586            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1587                           eap="MD5", identity="user", password="password",
1588                           wait_connect=False)
1589            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
1590            if ev is None:
1591                raise Exception("Timeout on EAP start")
1592            time.sleep(0.1)
1593            dev[0].request("REMOVE_NETWORK all")
1594    finally:
1595        stop_radius_server(srv)
1596
1597def test_eap_proto_md5_errors(dev, apdev):
1598    """EAP-MD5 local error cases"""
1599    check_eap_capa(dev[0], "MD5")
1600    params = hostapd.wpa2_eap_params(ssid="eap-test")
1601    hapd = hostapd.add_ap(apdev[0], params)
1602    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1603
1604    with fail_test(dev[0], 1, "chap_md5"):
1605        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1606                       eap="MD5", identity="phase1-user", password="password",
1607                       wait_connect=False)
1608        ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
1609        if ev is None:
1610            raise Exception("Timeout on EAP start")
1611        dev[0].request("REMOVE_NETWORK all")
1612        dev[0].wait_disconnected()
1613
1614    with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_md5_process"):
1615        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1616                       eap="MD5", identity="phase1-user", password="password",
1617                       wait_connect=False)
1618        ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
1619        if ev is None:
1620            raise Exception("Timeout on EAP start")
1621        time.sleep(0.1)
1622        dev[0].request("REMOVE_NETWORK all")
1623
1624def run_eap_md5_connect(dev):
1625    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
1626                eap="MD5", identity="phase1-user", password="password",
1627                wait_connect=False)
1628    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
1629                         "CTRL-EVENT-DISCONNECTED"],
1630                        timeout=1)
1631    dev.request("REMOVE_NETWORK all")
1632    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
1633        dev.wait_disconnected()
1634    dev.dump_monitor()
1635
1636def test_eap_proto_md5_errors_server(dev, apdev):
1637    """EAP-MD5 local error cases on server"""
1638    check_eap_capa(dev[0], "MD5")
1639    params = int_eap_server_params()
1640    params['erp_domain'] = 'example.com'
1641    params['eap_server_erp'] = '1'
1642    hapd = hostapd.add_ap(apdev[0], params)
1643    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1644
1645    tests = [(1, "eap_md5_init")]
1646    for count, func in tests:
1647        with alloc_fail(hapd, count, func):
1648            run_eap_md5_connect(dev[0])
1649
1650    tests = [(1, "os_get_random;eap_md5_buildReq"),
1651             (1, "chap_md5;eap_md5_process")]
1652    for count, func in tests:
1653        with fail_test(hapd, count, func):
1654            run_eap_md5_connect(dev[0])
1655
1656def start_md5_assoc(dev, hapd):
1657    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
1658                eap="MD5", identity="phase1-user", password="password",
1659                wait_connect=False)
1660    proxy_msg(hapd, dev) # EAP-Identity/Request
1661    proxy_msg(dev, hapd) # EAP-Identity/Response
1662    proxy_msg(hapd, dev) # MSCHAPV2/Request
1663    proxy_msg(dev, hapd) # NAK
1664    proxy_msg(hapd, dev) # MD5 Request
1665
1666def stop_md5_assoc(dev, hapd, wait=True):
1667    dev.request("REMOVE_NETWORK all")
1668    if wait:
1669        dev.wait_disconnected()
1670    dev.dump_monitor()
1671    hapd.dump_monitor()
1672
1673def test_eap_proto_md5_server(dev, apdev):
1674    """EAP-MD5 protocol testing for the server"""
1675    check_eap_capa(dev[0], "MD5")
1676    params = int_eap_server_params()
1677    params['erp_domain'] = 'example.com'
1678    params['eap_server_erp'] = '1'
1679    hapd = hostapd.add_ap(apdev[0], params)
1680    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1681    hapd.request("SET ext_eapol_frame_io 1")
1682    dev[0].request("SET ext_eapol_frame_io 1")
1683
1684    # Successful exchange to verify proxying mechanism
1685    start_md5_assoc(dev[0], hapd)
1686    proxy_msg(dev[0], hapd) # MD5 Response
1687    proxy_msg(hapd, dev[0]) # EAP-Success
1688    # Accept both EAP-Success and disconnection indication since it is possible
1689    # for disconnection from the AP (due to EAP-MD5 not deriving keys) to be
1690    # processed more quickly.
1691    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS",
1692                            "CTRL-EVENT-DISCONNECTED"], timeout=5)
1693    if ev is None:
1694        raise Exception("No EAP-Success reported")
1695    stop_md5_assoc(dev[0], hapd, wait="CTRL-EVENT-EAP-SUCCESS" in ev)
1696
1697    start_md5_assoc(dev[0], hapd)
1698    resp = rx_msg(dev[0])
1699    # Too short EAP-MD5 header (no length field)
1700    hapd.note("EAP-MD5: Invalid frame")
1701    msg = resp[0:4] + "0005" + resp[8:12] + "0005" + "04"
1702    tx_msg(dev[0], hapd, msg)
1703    # Too short EAP-MD5 header (no length field)
1704    hapd.note("EAP-MD5: Invalid response (response_len=0 payload_len=1")
1705    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "0400"
1706    tx_msg(dev[0], hapd, msg)
1707    stop_md5_assoc(dev[0], hapd)
1708
1709def test_eap_proto_otp(dev, apdev):
1710    """EAP-OTP protocol tests"""
1711    def otp_handler(ctx, req):
1712        logger.info("otp_handler - RX " + binascii.hexlify(req).decode())
1713        if 'num' not in ctx:
1714            ctx['num'] = 0
1715        ctx['num'] = ctx['num'] + 1
1716        if 'id' not in ctx:
1717            ctx['id'] = 1
1718        ctx['id'] = (ctx['id'] + 1) % 256
1719
1720        if ctx['num'] == 1:
1721            logger.info("Test: Empty payload")
1722            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
1723                               4 + 1,
1724                               EAP_TYPE_OTP)
1725        if ctx['num'] == 2:
1726            logger.info("Test: Success")
1727            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'],
1728                               4)
1729
1730        if ctx['num'] == 3:
1731            logger.info("Test: Challenge included")
1732            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1733                               4 + 1 + 1,
1734                               EAP_TYPE_OTP,
1735                               ord('A'))
1736        if ctx['num'] == 4:
1737            logger.info("Test: Success")
1738            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'],
1739                               4)
1740
1741        return None
1742
1743    srv = start_radius_server(otp_handler)
1744
1745    try:
1746        hapd = start_ap(apdev[0])
1747        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1748
1749        for i in range(0, 1):
1750            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1751                           eap="OTP", identity="user", password="password",
1752                           wait_connect=False)
1753            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
1754                                   timeout=15)
1755            if ev is None:
1756                raise Exception("Timeout on EAP start")
1757            time.sleep(0.1)
1758            dev[0].request("REMOVE_NETWORK all")
1759
1760        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1761                       eap="OTP", identity="user", wait_connect=False)
1762        ev = dev[0].wait_event(["CTRL-REQ-OTP"])
1763        if ev is None:
1764            raise Exception("Request for password timed out")
1765        id = ev.split(':')[0].split('-')[-1]
1766        dev[0].request("CTRL-RSP-OTP-" + id + ":password")
1767        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"])
1768        if ev is None:
1769            raise Exception("Success not reported")
1770    finally:
1771        stop_radius_server(srv)
1772
1773def test_eap_proto_otp_errors(dev, apdev):
1774    """EAP-OTP local error cases"""
1775    def otp_handler2(ctx, req):
1776        logger.info("otp_handler2 - RX " + binascii.hexlify(req).decode())
1777        if 'num' not in ctx:
1778            ctx['num'] = 0
1779        ctx['num'] = ctx['num'] + 1
1780        if 'id' not in ctx:
1781            ctx['id'] = 1
1782        ctx['id'] = (ctx['id'] + 1) % 256
1783        idx = 0
1784
1785        idx += 1
1786        if ctx['num'] == idx:
1787            logger.info("Test: Challenge included")
1788            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1789                               4 + 1 + 1,
1790                               EAP_TYPE_OTP,
1791                               ord('A'))
1792
1793        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
1794
1795    srv = start_radius_server(otp_handler2)
1796
1797    try:
1798        hapd = start_ap(apdev[0])
1799        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
1800
1801        with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_otp_process"):
1802            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
1803                           eap="OTP", identity="user", password="password",
1804                           wait_connect=False)
1805            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
1806            dev[0].request("REMOVE_NETWORK all")
1807            dev[0].wait_disconnected()
1808    finally:
1809        stop_radius_server(srv)
1810
1811EAP_GPSK_OPCODE_GPSK_1 = 1
1812EAP_GPSK_OPCODE_GPSK_2 = 2
1813EAP_GPSK_OPCODE_GPSK_3 = 3
1814EAP_GPSK_OPCODE_GPSK_4 = 4
1815EAP_GPSK_OPCODE_FAIL = 5
1816EAP_GPSK_OPCODE_PROTECTED_FAIL = 6
1817
1818def test_eap_proto_gpsk(dev, apdev):
1819    """EAP-GPSK protocol tests"""
1820    def gpsk_handler(ctx, req):
1821        logger.info("gpsk_handler - RX " + binascii.hexlify(req).decode())
1822        if 'num' not in ctx:
1823            ctx['num'] = 0
1824        ctx['num'] = ctx['num'] + 1
1825        if 'id' not in ctx:
1826            ctx['id'] = 1
1827        ctx['id'] = (ctx['id'] + 1) % 256
1828
1829        idx = 0
1830
1831        idx += 1
1832        if ctx['num'] == idx:
1833            logger.info("Test: Missing payload")
1834            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
1835                               4 + 1,
1836                               EAP_TYPE_GPSK)
1837
1838        idx += 1
1839        if ctx['num'] == idx:
1840            logger.info("Test: Unknown opcode")
1841            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1842                               4 + 1 + 1,
1843                               EAP_TYPE_GPSK,
1844                               255)
1845
1846        idx += 1
1847        if ctx['num'] == idx:
1848            logger.info("Test: Unexpected GPSK-3")
1849            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1850                               4 + 1 + 1,
1851                               EAP_TYPE_GPSK,
1852                               EAP_GPSK_OPCODE_GPSK_3)
1853
1854        idx += 1
1855        if ctx['num'] == idx:
1856            logger.info("Test: GPSK-1 Too short GPSK-1")
1857            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1858                               4 + 1 + 1,
1859                               EAP_TYPE_GPSK,
1860                               EAP_GPSK_OPCODE_GPSK_1)
1861
1862        idx += 1
1863        if ctx['num'] == idx:
1864            logger.info("Test: GPSK-1 Truncated ID_Server")
1865            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
1866                               4 + 1 + 1 + 2,
1867                               EAP_TYPE_GPSK,
1868                               EAP_GPSK_OPCODE_GPSK_1, 1)
1869
1870        idx += 1
1871        if ctx['num'] == idx:
1872            logger.info("Test: GPSK-1 Missing RAND_Server")
1873            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
1874                               4 + 1 + 1 + 2,
1875                               EAP_TYPE_GPSK,
1876                               EAP_GPSK_OPCODE_GPSK_1, 0)
1877
1878        idx += 1
1879        if ctx['num'] == idx:
1880            logger.info("Test: GPSK-1 Missing CSuite_List")
1881            return struct.pack(">BBHBBH8L", EAP_CODE_REQUEST, ctx['id'],
1882                               4 + 1 + 1 + 2 + 32,
1883                               EAP_TYPE_GPSK,
1884                               EAP_GPSK_OPCODE_GPSK_1, 0,
1885                               0, 0, 0, 0, 0, 0, 0, 0)
1886
1887        idx += 1
1888        if ctx['num'] == idx:
1889            logger.info("Test: GPSK-1 Truncated CSuite_List")
1890            return struct.pack(">BBHBBH8LH", EAP_CODE_REQUEST, ctx['id'],
1891                               4 + 1 + 1 + 2 + 32 + 2,
1892                               EAP_TYPE_GPSK,
1893                               EAP_GPSK_OPCODE_GPSK_1, 0,
1894                               0, 0, 0, 0, 0, 0, 0, 0,
1895                               1)
1896
1897        idx += 1
1898        if ctx['num'] == idx:
1899            logger.info("Test: GPSK-1 Empty CSuite_List")
1900            return struct.pack(">BBHBBH8LH", EAP_CODE_REQUEST, ctx['id'],
1901                               4 + 1 + 1 + 2 + 32 + 2,
1902                               EAP_TYPE_GPSK,
1903                               EAP_GPSK_OPCODE_GPSK_1, 0,
1904                               0, 0, 0, 0, 0, 0, 0, 0,
1905                               0)
1906
1907        idx += 1
1908        if ctx['num'] == idx:
1909            logger.info("Test: GPSK-1 Invalid CSuite_List")
1910            return struct.pack(">BBHBBH8LHB", EAP_CODE_REQUEST, ctx['id'],
1911                               4 + 1 + 1 + 2 + 32 + 2 + 1,
1912                               EAP_TYPE_GPSK,
1913                               EAP_GPSK_OPCODE_GPSK_1, 0,
1914                               0, 0, 0, 0, 0, 0, 0, 0,
1915                               1, 0)
1916
1917        idx += 1
1918        if ctx['num'] == idx:
1919            logger.info("Test: GPSK-1 No supported CSuite")
1920            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1921                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1922                               EAP_TYPE_GPSK,
1923                               EAP_GPSK_OPCODE_GPSK_1, 0,
1924                               0, 0, 0, 0, 0, 0, 0, 0,
1925                               6, 0, 0)
1926
1927        idx += 1
1928        if ctx['num'] == idx:
1929            logger.info("Test: GPSK-1 Supported CSuite")
1930            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1931                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1932                               EAP_TYPE_GPSK,
1933                               EAP_GPSK_OPCODE_GPSK_1, 0,
1934                               0, 0, 0, 0, 0, 0, 0, 0,
1935                               6, 0, 1)
1936        idx += 1
1937        if ctx['num'] == idx:
1938            logger.info("Test: Unexpected GPSK-1")
1939            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1940                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1941                               EAP_TYPE_GPSK,
1942                               EAP_GPSK_OPCODE_GPSK_1, 0,
1943                               0, 0, 0, 0, 0, 0, 0, 0,
1944                               6, 0, 1)
1945
1946        idx += 1
1947        if ctx['num'] == idx:
1948            logger.info("Test: GPSK-1 Supported CSuite but too short key")
1949            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1950                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1951                               EAP_TYPE_GPSK,
1952                               EAP_GPSK_OPCODE_GPSK_1, 0,
1953                               0, 0, 0, 0, 0, 0, 0, 0,
1954                               6, 0, 1)
1955
1956        idx += 1
1957        if ctx['num'] == idx:
1958            logger.info("Test: GPSK-1 Supported CSuite")
1959            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1960                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1961                               EAP_TYPE_GPSK,
1962                               EAP_GPSK_OPCODE_GPSK_1, 0,
1963                               0, 0, 0, 0, 0, 0, 0, 0,
1964                               6, 0, 1)
1965        idx += 1
1966        if ctx['num'] == idx:
1967            logger.info("Test: Too short GPSK-3")
1968            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
1969                               4 + 1 + 1,
1970                               EAP_TYPE_GPSK,
1971                               EAP_GPSK_OPCODE_GPSK_3)
1972
1973        idx += 1
1974        if ctx['num'] == idx:
1975            logger.info("Test: GPSK-1 Supported CSuite")
1976            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1977                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1978                               EAP_TYPE_GPSK,
1979                               EAP_GPSK_OPCODE_GPSK_1, 0,
1980                               0, 0, 0, 0, 0, 0, 0, 0,
1981                               6, 0, 1)
1982        idx += 1
1983        if ctx['num'] == idx:
1984            logger.info("Test: GPSK-3 Mismatch in RAND_Peer")
1985            return struct.pack(">BBHBB8L", EAP_CODE_REQUEST, ctx['id'],
1986                               4 + 1 + 1 + 32,
1987                               EAP_TYPE_GPSK,
1988                               EAP_GPSK_OPCODE_GPSK_3,
1989                               0, 0, 0, 0, 0, 0, 0, 0)
1990
1991        idx += 1
1992        if ctx['num'] == idx:
1993            logger.info("Test: GPSK-1 Supported CSuite")
1994            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
1995                               4 + 1 + 1 + 2 + 32 + 2 + 6,
1996                               EAP_TYPE_GPSK,
1997                               EAP_GPSK_OPCODE_GPSK_1, 0,
1998                               0, 0, 0, 0, 0, 0, 0, 0,
1999                               6, 0, 1)
2000        idx += 1
2001        if ctx['num'] == idx:
2002            logger.info("Test: GPSK-3 Missing RAND_Server")
2003            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2004                              4 + 1 + 1 + 32,
2005                              EAP_TYPE_GPSK,
2006                              EAP_GPSK_OPCODE_GPSK_3)
2007            msg += req[14:46]
2008            return msg
2009
2010        idx += 1
2011        if ctx['num'] == idx:
2012            logger.info("Test: GPSK-1 Supported CSuite")
2013            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2014                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2015                               EAP_TYPE_GPSK,
2016                               EAP_GPSK_OPCODE_GPSK_1, 0,
2017                               0, 0, 0, 0, 0, 0, 0, 0,
2018                               6, 0, 1)
2019        idx += 1
2020        if ctx['num'] == idx:
2021            logger.info("Test: GPSK-3 Mismatch in RAND_Server")
2022            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2023                              4 + 1 + 1 + 32 + 32,
2024                              EAP_TYPE_GPSK,
2025                              EAP_GPSK_OPCODE_GPSK_3)
2026            msg += req[14:46]
2027            msg += struct.pack(">8L", 1, 1, 1, 1, 1, 1, 1, 1)
2028            return msg
2029
2030        idx += 1
2031        if ctx['num'] == idx:
2032            logger.info("Test: GPSK-1 Supported CSuite")
2033            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2034                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2035                               EAP_TYPE_GPSK,
2036                               EAP_GPSK_OPCODE_GPSK_1, 0,
2037                               0, 0, 0, 0, 0, 0, 0, 0,
2038                               6, 0, 1)
2039        idx += 1
2040        if ctx['num'] == idx:
2041            logger.info("Test: GPSK-3 Missing ID_Server")
2042            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2043                              4 + 1 + 1 + 32 + 32,
2044                              EAP_TYPE_GPSK,
2045                              EAP_GPSK_OPCODE_GPSK_3)
2046            msg += req[14:46]
2047            msg += struct.pack(">8L", 0, 0, 0, 0, 0, 0, 0, 0)
2048            return msg
2049
2050        idx += 1
2051        if ctx['num'] == idx:
2052            logger.info("Test: GPSK-1 Supported CSuite")
2053            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2054                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2055                               EAP_TYPE_GPSK,
2056                               EAP_GPSK_OPCODE_GPSK_1, 0,
2057                               0, 0, 0, 0, 0, 0, 0, 0,
2058                               6, 0, 1)
2059        idx += 1
2060        if ctx['num'] == idx:
2061            logger.info("Test: GPSK-3 Truncated ID_Server")
2062            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2063                              4 + 1 + 1 + 32 + 32 + 2,
2064                              EAP_TYPE_GPSK,
2065                              EAP_GPSK_OPCODE_GPSK_3)
2066            msg += req[14:46]
2067            msg += struct.pack(">8LH", 0, 0, 0, 0, 0, 0, 0, 0, 1)
2068            return msg
2069
2070        idx += 1
2071        if ctx['num'] == idx:
2072            logger.info("Test: GPSK-1 Supported CSuite")
2073            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2074                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2075                               EAP_TYPE_GPSK,
2076                               EAP_GPSK_OPCODE_GPSK_1, 0,
2077                               0, 0, 0, 0, 0, 0, 0, 0,
2078                               6, 0, 1)
2079        idx += 1
2080        if ctx['num'] == idx:
2081            logger.info("Test: GPSK-3 Mismatch in ID_Server")
2082            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2083                              4 + 1 + 1 + 32 + 32 + 3,
2084                              EAP_TYPE_GPSK,
2085                              EAP_GPSK_OPCODE_GPSK_3)
2086            msg += req[14:46]
2087            msg += struct.pack(">8LHB", 0, 0, 0, 0, 0, 0, 0, 0, 1, ord('B'))
2088            return msg
2089
2090        idx += 1
2091        if ctx['num'] == idx:
2092            logger.info("Test: GPSK-1 Supported CSuite")
2093            return struct.pack(">BBHBBHB8LHLH", EAP_CODE_REQUEST, ctx['id'],
2094                               4 + 1 + 1 + 3 + 32 + 2 + 6,
2095                               EAP_TYPE_GPSK,
2096                               EAP_GPSK_OPCODE_GPSK_1, 1, ord('A'),
2097                               0, 0, 0, 0, 0, 0, 0, 0,
2098                               6, 0, 1)
2099        idx += 1
2100        if ctx['num'] == idx:
2101            logger.info("Test: GPSK-3 Mismatch in ID_Server (same length)")
2102            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2103                              4 + 1 + 1 + 32 + 32 + 3,
2104                              EAP_TYPE_GPSK,
2105                              EAP_GPSK_OPCODE_GPSK_3)
2106            msg += req[15:47]
2107            msg += struct.pack(">8LHB", 0, 0, 0, 0, 0, 0, 0, 0, 1, ord('B'))
2108            return msg
2109
2110        idx += 1
2111        if ctx['num'] == idx:
2112            logger.info("Test: GPSK-1 Supported CSuite")
2113            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2114                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2115                               EAP_TYPE_GPSK,
2116                               EAP_GPSK_OPCODE_GPSK_1, 0,
2117                               0, 0, 0, 0, 0, 0, 0, 0,
2118                               6, 0, 1)
2119        idx += 1
2120        if ctx['num'] == idx:
2121            logger.info("Test: GPSK-3 Missing CSuite_Sel")
2122            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2123                              4 + 1 + 1 + 32 + 32 + 2,
2124                              EAP_TYPE_GPSK,
2125                              EAP_GPSK_OPCODE_GPSK_3)
2126            msg += req[14:46]
2127            msg += struct.pack(">8LH", 0, 0, 0, 0, 0, 0, 0, 0, 0)
2128            return msg
2129
2130        idx += 1
2131        if ctx['num'] == idx:
2132            logger.info("Test: GPSK-1 Supported CSuite")
2133            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2134                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2135                               EAP_TYPE_GPSK,
2136                               EAP_GPSK_OPCODE_GPSK_1, 0,
2137                               0, 0, 0, 0, 0, 0, 0, 0,
2138                               6, 0, 1)
2139        idx += 1
2140        if ctx['num'] == idx:
2141            logger.info("Test: GPSK-3 Mismatch in CSuite_Sel")
2142            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2143                              4 + 1 + 1 + 32 + 32 + 2 + 6,
2144                              EAP_TYPE_GPSK,
2145                              EAP_GPSK_OPCODE_GPSK_3)
2146            msg += req[14:46]
2147            msg += struct.pack(">8LHLH", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2)
2148            return msg
2149
2150        idx += 1
2151        if ctx['num'] == idx:
2152            logger.info("Test: GPSK-1 Supported CSuite")
2153            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2154                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2155                               EAP_TYPE_GPSK,
2156                               EAP_GPSK_OPCODE_GPSK_1, 0,
2157                               0, 0, 0, 0, 0, 0, 0, 0,
2158                               6, 0, 1)
2159        idx += 1
2160        if ctx['num'] == idx:
2161            logger.info("Test: GPSK-3 Missing len(PD_Payload_Block)")
2162            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2163                              4 + 1 + 1 + 32 + 32 + 2 + 6,
2164                              EAP_TYPE_GPSK,
2165                              EAP_GPSK_OPCODE_GPSK_3)
2166            msg += req[14:46]
2167            msg += struct.pack(">8LHLH", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)
2168            return msg
2169
2170        idx += 1
2171        if ctx['num'] == idx:
2172            logger.info("Test: GPSK-1 Supported CSuite")
2173            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2174                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2175                               EAP_TYPE_GPSK,
2176                               EAP_GPSK_OPCODE_GPSK_1, 0,
2177                               0, 0, 0, 0, 0, 0, 0, 0,
2178                               6, 0, 1)
2179        idx += 1
2180        if ctx['num'] == idx:
2181            logger.info("Test: GPSK-3 Truncated PD_Payload_Block")
2182            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2183                              4 + 1 + 1 + 32 + 32 + 2 + 6 + 2,
2184                              EAP_TYPE_GPSK,
2185                              EAP_GPSK_OPCODE_GPSK_3)
2186            msg += req[14:46]
2187            msg += struct.pack(">8LHLHH", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1)
2188            return msg
2189
2190        idx += 1
2191        if ctx['num'] == idx:
2192            logger.info("Test: GPSK-1 Supported CSuite")
2193            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2194                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2195                               EAP_TYPE_GPSK,
2196                               EAP_GPSK_OPCODE_GPSK_1, 0,
2197                               0, 0, 0, 0, 0, 0, 0, 0,
2198                               6, 0, 1)
2199        idx += 1
2200        if ctx['num'] == idx:
2201            logger.info("Test: GPSK-3 Missing MAC")
2202            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2203                              4 + 1 + 1 + 32 + 32 + 2 + 6 + 3,
2204                              EAP_TYPE_GPSK,
2205                              EAP_GPSK_OPCODE_GPSK_3)
2206            msg += req[14:46]
2207            msg += struct.pack(">8LHLHHB",
2208                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 123)
2209            return msg
2210
2211        idx += 1
2212        if ctx['num'] == idx:
2213            logger.info("Test: GPSK-1 Supported CSuite")
2214            return struct.pack(">BBHBBH8LHLH", EAP_CODE_REQUEST, ctx['id'],
2215                               4 + 1 + 1 + 2 + 32 + 2 + 6,
2216                               EAP_TYPE_GPSK,
2217                               EAP_GPSK_OPCODE_GPSK_1, 0,
2218                               0, 0, 0, 0, 0, 0, 0, 0,
2219                               6, 0, 1)
2220        idx += 1
2221        if ctx['num'] == idx:
2222            logger.info("Test: GPSK-3 Incorrect MAC")
2223            msg = struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2224                              4 + 1 + 1 + 32 + 32 + 2 + 6 + 3 + 16,
2225                              EAP_TYPE_GPSK,
2226                              EAP_GPSK_OPCODE_GPSK_3)
2227            msg += req[14:46]
2228            msg += struct.pack(">8LHLHHB4L",
2229                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 123,
2230                               0, 0, 0, 0)
2231            return msg
2232
2233        return None
2234
2235    srv = start_radius_server(gpsk_handler)
2236
2237    try:
2238        hapd = start_ap(apdev[0])
2239        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
2240
2241        for i in range(0, 27):
2242            if i == 12:
2243                pw = "short"
2244            else:
2245                pw = "abcdefghijklmnop0123456789abcdef"
2246            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
2247                           eap="GPSK", identity="user", password=pw,
2248                           wait_connect=False)
2249            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
2250                                   timeout=15)
2251            if ev is None:
2252                raise Exception("Timeout on EAP start")
2253            time.sleep(0.05)
2254            dev[0].request("REMOVE_NETWORK all")
2255    finally:
2256        stop_radius_server(srv)
2257
2258def run_eap_gpsk_connect(dev):
2259    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
2260                eap="GPSK", identity="gpsk user",
2261                password="abcdefghijklmnop0123456789abcdef",
2262                wait_connect=False)
2263    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
2264                         "CTRL-EVENT-DISCONNECTED"],
2265                        timeout=1)
2266    dev.request("REMOVE_NETWORK all")
2267    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
2268        dev.wait_disconnected()
2269    dev.dump_monitor()
2270
2271def test_eap_proto_gpsk_errors_server(dev, apdev):
2272    """EAP-GPSK local error cases on server"""
2273    check_eap_capa(dev[0], "GPSK")
2274    params = int_eap_server_params()
2275    params['erp_domain'] = 'example.com'
2276    params['eap_server_erp'] = '1'
2277    hapd = hostapd.add_ap(apdev[0], params)
2278    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
2279
2280    tests = [(1, "eap_gpsk_init"),
2281             (1, "eap_msg_alloc;eap_gpsk_build_gpsk_1"),
2282             (1, "eap_msg_alloc;eap_gpsk_build_gpsk_3"),
2283             (1, "eap_gpsk_process_gpsk_2"),
2284             (1, "eap_gpsk_derive_keys;eap_gpsk_process_gpsk_2"),
2285             (1, "eap_gpsk_derive_session_id;eap_gpsk_process_gpsk_2"),
2286             (1, "eap_gpsk_getKey"),
2287             (1, "eap_gpsk_get_emsk"),
2288             (1, "eap_gpsk_get_session_id")]
2289    for count, func in tests:
2290        with alloc_fail(hapd, count, func):
2291            run_eap_gpsk_connect(dev[0])
2292
2293    tests = [(1, "os_get_random;eap_gpsk_build_gpsk_1"),
2294             (1, "eap_gpsk_compute_mic;eap_gpsk_build_gpsk_3"),
2295             (1, "eap_gpsk_derive_keys;eap_gpsk_process_gpsk_2"),
2296             (1, "eap_gpsk_derive_session_id;eap_gpsk_process_gpsk_2"),
2297             (1, "eap_gpsk_compute_mic;eap_gpsk_process_gpsk_2"),
2298             (1, "eap_gpsk_compute_mic;eap_gpsk_process_gpsk_4")]
2299    for count, func in tests:
2300        with fail_test(hapd, count, func):
2301            run_eap_gpsk_connect(dev[0])
2302
2303def start_gpsk_assoc(dev, hapd):
2304    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
2305                eap="GPSK", identity="gpsk user",
2306                password="abcdefghijklmnop0123456789abcdef",
2307                wait_connect=False)
2308    proxy_msg(hapd, dev) # EAP-Identity/Request
2309    proxy_msg(dev, hapd) # EAP-Identity/Response
2310    proxy_msg(hapd, dev) # GPSK-1
2311
2312def stop_gpsk_assoc(dev, hapd):
2313    dev.request("REMOVE_NETWORK all")
2314    dev.wait_disconnected()
2315    dev.dump_monitor()
2316    hapd.dump_monitor()
2317
2318def test_eap_proto_gpsk_server(dev, apdev):
2319    """EAP-GPSK protocol testing for the server"""
2320    check_eap_capa(dev[0], "GPSK")
2321    params = int_eap_server_params()
2322    params['erp_domain'] = 'example.com'
2323    params['eap_server_erp'] = '1'
2324    hapd = hostapd.add_ap(apdev[0], params)
2325    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
2326    hapd.request("SET ext_eapol_frame_io 1")
2327    dev[0].request("SET ext_eapol_frame_io 1")
2328
2329    # Successful exchange to verify proxying mechanism
2330    start_gpsk_assoc(dev[0], hapd)
2331    proxy_msg(dev[0], hapd) # GPSK-2
2332    proxy_msg(hapd, dev[0]) # GPSK-3
2333    proxy_msg(dev[0], hapd) # GPSK-4
2334    proxy_msg(hapd, dev[0]) # EAP-Success
2335    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 1/4
2336    proxy_msg(dev[0], hapd) # EAPOL-Key msg 2/4
2337    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 3/4
2338    proxy_msg(dev[0], hapd) # EAPOL-Key msg 4/4
2339    dev[0].wait_connected()
2340    stop_gpsk_assoc(dev[0], hapd)
2341
2342    start_gpsk_assoc(dev[0], hapd)
2343    resp = rx_msg(dev[0])
2344    # Too short EAP-GPSK header (no OP-Code)
2345    # --> EAP-GPSK: Invalid frame
2346    msg = resp[0:4] + "0005" + resp[8:12] + "0005" + "33"
2347    tx_msg(dev[0], hapd, msg)
2348    # Unknown OP-Code
2349    # --> EAP-GPSK: Unexpected opcode=7 in state=0
2350    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "3307"
2351    tx_msg(dev[0], hapd, msg)
2352    # Too short GPSK-2
2353    # --> EAP-GPSK: Too short message for ID_Peer length
2354    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "3302"
2355    tx_msg(dev[0], hapd, msg)
2356    rx_msg(hapd)
2357    stop_gpsk_assoc(dev[0], hapd)
2358
2359    start_gpsk_assoc(dev[0], hapd)
2360    resp = rx_msg(dev[0])
2361    # Too short GPSK-2
2362    # --> EAP-GPSK: Too short message for ID_Peer
2363    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "33020001"
2364    tx_msg(dev[0], hapd, msg)
2365    rx_msg(hapd)
2366    stop_gpsk_assoc(dev[0], hapd)
2367
2368    start_gpsk_assoc(dev[0], hapd)
2369    resp = rx_msg(dev[0])
2370    # Too short GPSK-2
2371    # --> EAP-GPSK: Too short message for ID_Server length
2372    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "33020000"
2373    tx_msg(dev[0], hapd, msg)
2374    rx_msg(hapd)
2375    stop_gpsk_assoc(dev[0], hapd)
2376
2377    start_gpsk_assoc(dev[0], hapd)
2378    resp = rx_msg(dev[0])
2379    # Too short GPSK-2
2380    # --> EAP-GPSK: Too short message for ID_Server
2381    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "330200000001"
2382    tx_msg(dev[0], hapd, msg)
2383    rx_msg(hapd)
2384    stop_gpsk_assoc(dev[0], hapd)
2385
2386    start_gpsk_assoc(dev[0], hapd)
2387    resp = rx_msg(dev[0])
2388    # ID_Server mismatch
2389    # --> EAP-GPSK: ID_Server in GPSK-1 and GPSK-2 did not match
2390    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "330200000000"
2391    tx_msg(dev[0], hapd, msg)
2392    rx_msg(hapd)
2393    stop_gpsk_assoc(dev[0], hapd)
2394
2395    start_gpsk_assoc(dev[0], hapd)
2396    resp = rx_msg(dev[0])
2397    # Too short GPSK-2
2398    # --> EAP-GPSK: Too short message for RAND_Peer
2399    msg = resp[0:4] + "0011" + resp[8:12] + "0011" + "330200000007" + binascii.hexlify(b"hostapd").decode()
2400    tx_msg(dev[0], hapd, msg)
2401    rx_msg(hapd)
2402    stop_gpsk_assoc(dev[0], hapd)
2403
2404    start_gpsk_assoc(dev[0], hapd)
2405    resp = rx_msg(dev[0])
2406    # Too short GPSK-2
2407    # --> EAP-GPSK: Too short message for RAND_Server
2408    msg = resp[0:4] + "0031" + resp[8:12] + "0031" + "330200000007" + binascii.hexlify(b"hostapd").decode() + 32*"00"
2409    tx_msg(dev[0], hapd, msg)
2410    rx_msg(hapd)
2411    stop_gpsk_assoc(dev[0], hapd)
2412
2413    start_gpsk_assoc(dev[0], hapd)
2414    resp = rx_msg(dev[0])
2415    # RAND_Server mismatch
2416    # --> EAP-GPSK: RAND_Server in GPSK-1 and GPSK-2 did not match
2417    msg = resp[0:4] + "0051" + resp[8:12] + "0051" + "330200000007" + binascii.hexlify(b"hostapd").decode() + 32*"00" + 32*"00"
2418    tx_msg(dev[0], hapd, msg)
2419    rx_msg(hapd)
2420    stop_gpsk_assoc(dev[0], hapd)
2421
2422    start_gpsk_assoc(dev[0], hapd)
2423    resp = rx_msg(dev[0])
2424    # Too short GPSK-2
2425    # --> EAP-GPSK: Too short message for CSuite_List length
2426    msg = resp[0:4] + "005a" + resp[8:12] + "005a" + resp[16:188]
2427    tx_msg(dev[0], hapd, msg)
2428    rx_msg(hapd)
2429    stop_gpsk_assoc(dev[0], hapd)
2430
2431    start_gpsk_assoc(dev[0], hapd)
2432    resp = rx_msg(dev[0])
2433    # Too short GPSK-2
2434    # --> EAP-GPSK: Too short message for CSuite_List
2435    msg = resp[0:4] + "005c" + resp[8:12] + "005c" + resp[16:192]
2436    tx_msg(dev[0], hapd, msg)
2437    rx_msg(hapd)
2438    stop_gpsk_assoc(dev[0], hapd)
2439
2440    start_gpsk_assoc(dev[0], hapd)
2441    resp = rx_msg(dev[0])
2442    # Too short GPSK-2
2443    # --> EAP-GPSK: CSuite_List in GPSK-1 and GPSK-2 did not match
2444    msg = resp[0:4] + "005c" + resp[8:12] + "005c" + resp[16:188] + "0000"
2445    tx_msg(dev[0], hapd, msg)
2446    rx_msg(hapd)
2447    stop_gpsk_assoc(dev[0], hapd)
2448
2449    start_gpsk_assoc(dev[0], hapd)
2450    resp = rx_msg(dev[0])
2451    # Too short GPSK-2
2452    # --> EAP-GPSK: Too short message for CSuite_Sel
2453    msg = resp[0:4] + "0068" + resp[8:12] + "0068" + resp[16:216]
2454    tx_msg(dev[0], hapd, msg)
2455    rx_msg(hapd)
2456    stop_gpsk_assoc(dev[0], hapd)
2457
2458    start_gpsk_assoc(dev[0], hapd)
2459    resp = rx_msg(dev[0])
2460    # Unsupported CSuite_Sel
2461    # --> EAP-GPSK: Peer selected unsupported ciphersuite 0:255
2462    msg = resp[0:4] + "006e" + resp[8:12] + "006e" + resp[16:226] + "ff"
2463    tx_msg(dev[0], hapd, msg)
2464    rx_msg(hapd)
2465    stop_gpsk_assoc(dev[0], hapd)
2466
2467    start_gpsk_assoc(dev[0], hapd)
2468    resp = rx_msg(dev[0])
2469    # Too short GPSK-2
2470    # --> EAP-GPSK: Too short message for PD_Payload_1 length
2471    msg = resp[0:4] + "006e" + resp[8:12] + "006e" + resp[16:228]
2472    tx_msg(dev[0], hapd, msg)
2473    rx_msg(hapd)
2474    stop_gpsk_assoc(dev[0], hapd)
2475
2476    start_gpsk_assoc(dev[0], hapd)
2477    resp = rx_msg(dev[0])
2478    # Too short GPSK-2
2479    # --> EAP-GPSK: Too short message for PD_Payload_1
2480    msg = resp[0:4] + "0070" + resp[8:12] + "0070" + resp[16:230] + "ff"
2481    tx_msg(dev[0], hapd, msg)
2482    rx_msg(hapd)
2483    stop_gpsk_assoc(dev[0], hapd)
2484
2485    start_gpsk_assoc(dev[0], hapd)
2486    resp = rx_msg(dev[0])
2487    # Too short GPSK-2
2488    # --> EAP-GPSK: Message too short for MIC (left=0 miclen=16)
2489    msg = resp[0:4] + "0070" + resp[8:12] + "0070" + resp[16:232]
2490    tx_msg(dev[0], hapd, msg)
2491    rx_msg(hapd)
2492    stop_gpsk_assoc(dev[0], hapd)
2493
2494    start_gpsk_assoc(dev[0], hapd)
2495    resp = rx_msg(dev[0])
2496    # Extra data in the end of GPSK-2
2497    # --> EAP-GPSK: Ignored 1 bytes of extra data in the end of GPSK-2
2498    msg = resp[0:4] + "0081" + resp[8:12] + "0081" + resp[16:264] + "00"
2499    tx_msg(dev[0], hapd, msg)
2500    proxy_msg(hapd, dev[0]) # GPSK-3
2501    resp = rx_msg(dev[0])
2502    # Too short GPSK-4
2503    # --> EAP-GPSK: Too short message for PD_Payload_1 length
2504    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "3304"
2505    tx_msg(dev[0], hapd, msg)
2506    rx_msg(hapd) # EAP-Failure
2507    stop_gpsk_assoc(dev[0], hapd)
2508
2509    start_gpsk_assoc(dev[0], hapd)
2510    proxy_msg(dev[0], hapd) # GPSK-2
2511    proxy_msg(hapd, dev[0]) # GPSK-3
2512    resp = rx_msg(dev[0])
2513    # Too short GPSK-4
2514    # --> EAP-GPSK: Too short message for PD_Payload_1
2515    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "33040001"
2516    tx_msg(dev[0], hapd, msg)
2517    rx_msg(hapd) # EAP-Failure
2518    stop_gpsk_assoc(dev[0], hapd)
2519
2520    start_gpsk_assoc(dev[0], hapd)
2521    proxy_msg(dev[0], hapd) # GPSK-2
2522    proxy_msg(hapd, dev[0]) # GPSK-3
2523    resp = rx_msg(dev[0])
2524    # Too short GPSK-4
2525    # --> EAP-GPSK: Message too short for MIC (left=0 miclen=16)
2526    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "33040000"
2527    tx_msg(dev[0], hapd, msg)
2528    rx_msg(hapd) # EAP-Failure
2529    stop_gpsk_assoc(dev[0], hapd)
2530
2531    start_gpsk_assoc(dev[0], hapd)
2532    proxy_msg(dev[0], hapd) # GPSK-2
2533    proxy_msg(hapd, dev[0]) # GPSK-3
2534    resp = rx_msg(dev[0])
2535    # Incorrect MIC in GPSK-4
2536    # --> EAP-GPSK: Incorrect MIC in GPSK-4
2537    msg = resp[0:4] + "0018" + resp[8:12] + "0018" + "33040000" + 16*"00"
2538    tx_msg(dev[0], hapd, msg)
2539    rx_msg(hapd) # EAP-Failure
2540    stop_gpsk_assoc(dev[0], hapd)
2541
2542    start_gpsk_assoc(dev[0], hapd)
2543    proxy_msg(dev[0], hapd) # GPSK-2
2544    proxy_msg(hapd, dev[0]) # GPSK-3
2545    resp = rx_msg(dev[0])
2546    # Incorrect MIC in GPSK-4
2547    # --> EAP-GPSK: Ignored 1 bytes of extra data in the end of GPSK-4
2548    msg = resp[0:4] + "0019" + resp[8:12] + "0019" + resp[16:] + "00"
2549    tx_msg(dev[0], hapd, msg)
2550    rx_msg(hapd) # EAP-Success
2551    stop_gpsk_assoc(dev[0], hapd)
2552
2553EAP_EKE_ID = 1
2554EAP_EKE_COMMIT = 2
2555EAP_EKE_CONFIRM = 3
2556EAP_EKE_FAILURE = 4
2557
2558def test_eap_proto_eke(dev, apdev):
2559    """EAP-EKE protocol tests"""
2560    def eke_handler(ctx, req):
2561        logger.info("eke_handler - RX " + binascii.hexlify(req).decode())
2562        if 'num' not in ctx:
2563            ctx['num'] = 0
2564        ctx['num'] = ctx['num'] + 1
2565        if 'id' not in ctx:
2566            ctx['id'] = 1
2567        ctx['id'] = (ctx['id'] + 1) % 256
2568
2569        idx = 0
2570
2571        idx += 1
2572        if ctx['num'] == idx:
2573            logger.info("Test: Missing payload")
2574            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
2575                               4 + 1,
2576                               EAP_TYPE_EKE)
2577
2578        idx += 1
2579        if ctx['num'] == idx:
2580            logger.info("Test: Unknown exchange")
2581            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2582                               4 + 1 + 1,
2583                               EAP_TYPE_EKE,
2584                               255)
2585
2586        idx += 1
2587        if ctx['num'] == idx:
2588            logger.info("Test: No NumProposals in EAP-EKE-ID/Request")
2589            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
2590                               4 + 1 + 1,
2591                               EAP_TYPE_EKE,
2592                               EAP_EKE_ID)
2593        idx += 1
2594        if ctx['num'] == idx:
2595            logger.info("Test: EAP-Failure")
2596            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2597
2598        idx += 1
2599        if ctx['num'] == idx:
2600            logger.info("Test: NumProposals=0 in EAP-EKE-ID/Request")
2601            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
2602                               4 + 1 + 1 + 1,
2603                               EAP_TYPE_EKE,
2604                               EAP_EKE_ID,
2605                               0)
2606        idx += 1
2607        if ctx['num'] == idx:
2608            logger.info("Test: EAP-Failure")
2609            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2610
2611        idx += 1
2612        if ctx['num'] == idx:
2613            logger.info("Test: Truncated Proposals list in EAP-EKE-ID/Request")
2614            return struct.pack(">BBHBBBB4B", EAP_CODE_REQUEST, ctx['id'],
2615                               4 + 1 + 1 + 2 + 4,
2616                               EAP_TYPE_EKE,
2617                               EAP_EKE_ID,
2618                               2, 0, 0, 0, 0, 0)
2619        idx += 1
2620        if ctx['num'] == idx:
2621            logger.info("Test: EAP-Failure")
2622            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2623
2624        idx += 1
2625        if ctx['num'] == idx:
2626            logger.info("Test: Unsupported proposals in EAP-EKE-ID/Request")
2627            return struct.pack(">BBHBBBB4B4B4B4B", EAP_CODE_REQUEST, ctx['id'],
2628                               4 + 1 + 1 + 2 + 4 * 4,
2629                               EAP_TYPE_EKE,
2630                               EAP_EKE_ID,
2631                               4, 0,
2632                               0, 0, 0, 0,
2633                               3, 0, 0, 0,
2634                               3, 1, 0, 0,
2635                               3, 1, 1, 0)
2636        idx += 1
2637        if ctx['num'] == idx:
2638            logger.info("Test: EAP-Failure")
2639            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2640
2641        idx += 1
2642        if ctx['num'] == idx:
2643            logger.info("Test: Missing IDType/Identity in EAP-EKE-ID/Request")
2644            return struct.pack(">BBHBBBB4B4B4B4B4B",
2645                               EAP_CODE_REQUEST, ctx['id'],
2646                               4 + 1 + 1 + 2 + 5 * 4,
2647                               EAP_TYPE_EKE,
2648                               EAP_EKE_ID,
2649                               5, 0,
2650                               0, 0, 0, 0,
2651                               3, 0, 0, 0,
2652                               3, 1, 0, 0,
2653                               3, 1, 1, 0,
2654                               3, 1, 1, 1)
2655        idx += 1
2656        if ctx['num'] == idx:
2657            logger.info("Test: EAP-Failure")
2658            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2659
2660        idx += 1
2661        if ctx['num'] == idx:
2662            logger.info("Test: Valid EAP-EKE-ID/Request")
2663            return struct.pack(">BBHBBBB4BB",
2664                               EAP_CODE_REQUEST, ctx['id'],
2665                               4 + 1 + 1 + 2 + 4 + 1,
2666                               EAP_TYPE_EKE,
2667                               EAP_EKE_ID,
2668                               1, 0,
2669                               3, 1, 1, 1,
2670                               255)
2671        idx += 1
2672        if ctx['num'] == idx:
2673            logger.info("Test: Unexpected EAP-EKE-ID/Request")
2674            return struct.pack(">BBHBBBB4BB",
2675                               EAP_CODE_REQUEST, ctx['id'],
2676                               4 + 1 + 1 + 2 + 4 + 1,
2677                               EAP_TYPE_EKE,
2678                               EAP_EKE_ID,
2679                               1, 0,
2680                               3, 1, 1, 1,
2681                               255)
2682        idx += 1
2683        if ctx['num'] == idx:
2684            logger.info("Test: EAP-Failure")
2685            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2686
2687        idx += 1
2688        if ctx['num'] == idx:
2689            logger.info("Test: Valid EAP-EKE-ID/Request")
2690            return struct.pack(">BBHBBBB4BB",
2691                               EAP_CODE_REQUEST, ctx['id'],
2692                               4 + 1 + 1 + 2 + 4 + 1,
2693                               EAP_TYPE_EKE,
2694                               EAP_EKE_ID,
2695                               1, 0,
2696                               3, 1, 1, 1,
2697                               255)
2698        idx += 1
2699        if ctx['num'] == idx:
2700            logger.info("Test: Unexpected EAP-EKE-Confirm/Request")
2701            return struct.pack(">BBHBB",
2702                               EAP_CODE_REQUEST, ctx['id'],
2703                               4 + 1 + 1,
2704                               EAP_TYPE_EKE,
2705                               EAP_EKE_CONFIRM)
2706        idx += 1
2707        if ctx['num'] == idx:
2708            logger.info("Test: EAP-Failure")
2709            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2710
2711        idx += 1
2712        if ctx['num'] == idx:
2713            logger.info("Test: Too short EAP-EKE-Failure/Request")
2714            return struct.pack(">BBHBB",
2715                               EAP_CODE_REQUEST, ctx['id'],
2716                               4 + 1 + 1,
2717                               EAP_TYPE_EKE,
2718                               EAP_EKE_FAILURE)
2719        idx += 1
2720        if ctx['num'] == idx:
2721            logger.info("Test: EAP-Failure")
2722            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2723
2724        idx += 1
2725        if ctx['num'] == idx:
2726            logger.info("Test: Unexpected EAP-EKE-Commit/Request")
2727            return struct.pack(">BBHBB",
2728                               EAP_CODE_REQUEST, ctx['id'],
2729                               4 + 1 + 1,
2730                               EAP_TYPE_EKE,
2731                               EAP_EKE_COMMIT)
2732        idx += 1
2733        if ctx['num'] == idx:
2734            logger.info("Test: EAP-Failure")
2735            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2736
2737        idx += 1
2738        if ctx['num'] == idx:
2739            logger.info("Test: Valid EAP-EKE-ID/Request")
2740            return struct.pack(">BBHBBBB4BB",
2741                               EAP_CODE_REQUEST, ctx['id'],
2742                               4 + 1 + 1 + 2 + 4 + 1,
2743                               EAP_TYPE_EKE,
2744                               EAP_EKE_ID,
2745                               1, 0,
2746                               3, 1, 1, 1,
2747                               255)
2748        idx += 1
2749        if ctx['num'] == idx:
2750            logger.info("Test: Too short EAP-EKE-Commit/Request")
2751            return struct.pack(">BBHBB",
2752                               EAP_CODE_REQUEST, ctx['id'],
2753                               4 + 1 + 1,
2754                               EAP_TYPE_EKE,
2755                               EAP_EKE_COMMIT)
2756        idx += 1
2757        if ctx['num'] == idx:
2758            logger.info("Test: EAP-Failure")
2759            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2760
2761        idx += 1
2762        if ctx['num'] == idx:
2763            logger.info("Test: Valid EAP-EKE-ID/Request")
2764            return struct.pack(">BBHBBBB4BB",
2765                               EAP_CODE_REQUEST, ctx['id'],
2766                               4 + 1 + 1 + 2 + 4 + 1,
2767                               EAP_TYPE_EKE,
2768                               EAP_EKE_ID,
2769                               1, 0,
2770                               1, 1, 1, 1,
2771                               255)
2772        idx += 1
2773        if ctx['num'] == idx:
2774            logger.info("Test: All zeroes DHComponent_S and empty CBvalue in EAP-EKE-Commit/Request")
2775            return struct.pack(">BBHBB4L32L",
2776                               EAP_CODE_REQUEST, ctx['id'],
2777                               4 + 1 + 1 + 16 + 128,
2778                               EAP_TYPE_EKE,
2779                               EAP_EKE_COMMIT,
2780                               0, 0, 0, 0,
2781                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2782                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
2783        idx += 1
2784        if ctx['num'] == idx:
2785            logger.info("Test: Too short EAP-EKE-Confirm/Request")
2786            return struct.pack(">BBHBB",
2787                               EAP_CODE_REQUEST, ctx['id'],
2788                               4 + 1 + 1,
2789                               EAP_TYPE_EKE,
2790                               EAP_EKE_CONFIRM)
2791        idx += 1
2792        if ctx['num'] == idx:
2793            logger.info("Test: EAP-Failure")
2794            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2795
2796        idx += 1
2797        if ctx['num'] == idx:
2798            logger.info("Test: Valid EAP-EKE-ID/Request")
2799            return struct.pack(">BBHBBBB4BB",
2800                               EAP_CODE_REQUEST, ctx['id'],
2801                               4 + 1 + 1 + 2 + 4 + 1,
2802                               EAP_TYPE_EKE,
2803                               EAP_EKE_ID,
2804                               1, 0,
2805                               1, 1, 1, 1,
2806                               255)
2807        idx += 1
2808        if ctx['num'] == idx:
2809            logger.info("Test: All zeroes DHComponent_S and empty CBvalue in EAP-EKE-Commit/Request")
2810            return struct.pack(">BBHBB4L32L",
2811                               EAP_CODE_REQUEST, ctx['id'],
2812                               4 + 1 + 1 + 16 + 128,
2813                               EAP_TYPE_EKE,
2814                               EAP_EKE_COMMIT,
2815                               0, 0, 0, 0,
2816                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2817                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
2818        idx += 1
2819        if ctx['num'] == idx:
2820            logger.info("Test: Invalid PNonce_PS and Auth_S values in EAP-EKE-Confirm/Request")
2821            return struct.pack(">BBHBB4L8L5L5L",
2822                               EAP_CODE_REQUEST, ctx['id'],
2823                               4 + 1 + 1 + 16 + 2 * 16 + 20 + 20,
2824                               EAP_TYPE_EKE,
2825                               EAP_EKE_CONFIRM,
2826                               0, 0, 0, 0,
2827                               0, 0, 0, 0, 0, 0, 0, 0,
2828                               0, 0, 0, 0, 0,
2829                               0, 0, 0, 0, 0)
2830        idx += 1
2831        if ctx['num'] == idx:
2832            logger.info("Test: EAP-Failure")
2833            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
2834
2835        return None
2836
2837    srv = start_radius_server(eke_handler)
2838
2839    try:
2840        hapd = start_ap(apdev[0])
2841        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
2842
2843        for i in range(0, 14):
2844            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
2845                           eap="EKE", identity="user", password="password",
2846                           wait_connect=False)
2847            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
2848                                   timeout=15)
2849            if ev is None:
2850                raise Exception("Timeout on EAP start")
2851            if i in [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]:
2852                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
2853                                       timeout=10)
2854                if ev is None:
2855                    raise Exception("Timeout on EAP failure")
2856            else:
2857                time.sleep(0.05)
2858            dev[0].request("REMOVE_NETWORK all")
2859            dev[0].dump_monitor()
2860    finally:
2861        stop_radius_server(srv)
2862
2863def eap_eke_test_fail(dev, phase1=None, success=False):
2864    dev.connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
2865                eap="EKE", identity="eke user@domain", password="hello",
2866                phase1=phase1, erp="1", wait_connect=False)
2867    ev = dev.wait_event(["CTRL-EVENT-EAP-FAILURE",
2868                         "CTRL-EVENT-EAP-SUCCESS"], timeout=5)
2869    if ev is None:
2870        raise Exception("Timeout on EAP failure")
2871    if not success and "CTRL-EVENT-EAP-FAILURE" not in ev:
2872        raise Exception("EAP did not fail during failure test")
2873    dev.request("REMOVE_NETWORK all")
2874    dev.wait_disconnected()
2875
2876def test_eap_proto_eke_errors(dev, apdev):
2877    """EAP-EKE local error cases"""
2878    check_eap_capa(dev[0], "EKE")
2879    params = hostapd.wpa2_eap_params(ssid="eap-test")
2880    hapd = hostapd.add_ap(apdev[0], params)
2881    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
2882
2883    for i in range(1, 3):
2884        with alloc_fail(dev[0], i, "eap_eke_init"):
2885            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
2886                           eap="EKE", identity="eke user", password="hello",
2887                           wait_connect=False)
2888            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
2889                                   timeout=15)
2890            if ev is None:
2891                raise Exception("Timeout on EAP start")
2892            dev[0].request("REMOVE_NETWORK all")
2893            dev[0].wait_disconnected()
2894
2895    tests = [(1, "eap_eke_dh_init", None),
2896             (1, "eap_eke_prf_hmac_sha1", "dhgroup=3 encr=1 prf=1 mac=1"),
2897             (1, "eap_eke_prf_hmac_sha256", "dhgroup=5 encr=1 prf=2 mac=2"),
2898             (1, "eap_eke_prf_*", None),
2899             (1, "os_get_random;eap_eke_dhcomp", None),
2900             (1, "aes_128_cbc_encrypt;eap_eke_dhcomp", None),
2901             (1, "aes_128_cbc_decrypt;eap_eke_shared_secret", None),
2902             (1, "hmac_sha256_vector;eap_eke_shared_secret", None),
2903             (1, "eap_eke_prf_hmac_sha256;eap_eke_derive_ke_ki", None),
2904             (1, "eap_eke_prf_hmac_sha256;eap_eke_derive_ka", None),
2905             (1, "eap_eke_prf_hmac_sha256;eap_eke_derive_msk", None),
2906             (1, "os_get_random;eap_eke_prot", None),
2907             (1, "aes_128_cbc_decrypt;eap_eke_decrypt_prot", None),
2908             (1, "eap_eke_derive_key;eap_eke_process_commit", None),
2909             (1, "eap_eke_dh_init;eap_eke_process_commit", None),
2910             (1, "eap_eke_shared_secret;eap_eke_process_commit", None),
2911             (1, "eap_eke_derive_ke_ki;eap_eke_process_commit", None),
2912             (1, "eap_eke_dhcomp;eap_eke_process_commit", None),
2913             (1, "os_get_random;eap_eke_process_commit", None),
2914             (1, "os_get_random;=eap_eke_process_commit", None),
2915             (1, "eap_eke_prot;eap_eke_process_commit", None),
2916             (1, "eap_eke_decrypt_prot;eap_eke_process_confirm", None),
2917             (1, "eap_eke_derive_ka;eap_eke_process_confirm", None),
2918             (1, "eap_eke_auth;eap_eke_process_confirm", None),
2919             (2, "eap_eke_auth;eap_eke_process_confirm", None),
2920             (1, "eap_eke_prot;eap_eke_process_confirm", None),
2921             (1, "aes_128_cbc_encrypt;eap_eke_prot;eap_eke_process_confirm", None),
2922             (1, "hmac_sha256;eap_eke_prot;eap_eke_process_confirm", None),
2923             (1, "eap_eke_derive_msk;eap_eke_process_confirm", None)]
2924    for count, func, phase1 in tests:
2925        with fail_test(dev[0], count, func):
2926            eap_eke_test_fail(dev[0], phase1)
2927
2928    tests = [(1, "=eap_eke_derive_ke_ki", None),
2929             (1, "=eap_eke_derive_ka", None),
2930             (1, "=eap_eke_derive_msk", None),
2931             (1, "eap_eke_build_msg;eap_eke_process_id", None),
2932             (1, "wpabuf_alloc;eap_eke_process_id", None),
2933             (1, "=eap_eke_process_id", None),
2934             (1, "wpabuf_alloc;=eap_eke_process_id", None),
2935             (1, "wpabuf_alloc;eap_eke_process_id", None),
2936             (1, "eap_eke_build_msg;eap_eke_process_commit", None),
2937             (1, "wpabuf_resize;eap_eke_process_commit", None),
2938             (1, "eap_eke_build_msg;eap_eke_process_confirm", None)]
2939    for count, func, phase1 in tests:
2940        with alloc_fail(dev[0], count, func):
2941            eap_eke_test_fail(dev[0], phase1)
2942
2943    tests = [(1, "eap_eke_getKey", None),
2944             (1, "eap_eke_get_emsk", None),
2945             (1, "eap_eke_get_session_id", None)]
2946    for count, func, phase1 in tests:
2947        with alloc_fail(dev[0], count, func):
2948            eap_eke_test_fail(dev[0], phase1, success=True)
2949
2950EAP_PAX_OP_STD_1 = 0x01
2951EAP_PAX_OP_STD_2 = 0x02
2952EAP_PAX_OP_STD_3 = 0x03
2953EAP_PAX_OP_SEC_1 = 0x11
2954EAP_PAX_OP_SEC_2 = 0x12
2955EAP_PAX_OP_SEC_3 = 0x13
2956EAP_PAX_OP_SEC_4 = 0x14
2957EAP_PAX_OP_SEC_5 = 0x15
2958EAP_PAX_OP_ACK = 0x21
2959
2960EAP_PAX_FLAGS_MF = 0x01
2961EAP_PAX_FLAGS_CE = 0x02
2962EAP_PAX_FLAGS_AI = 0x04
2963
2964EAP_PAX_MAC_HMAC_SHA1_128 = 0x01
2965EAP_PAX_HMAC_SHA256_128 = 0x02
2966
2967EAP_PAX_DH_GROUP_NONE = 0x00
2968EAP_PAX_DH_GROUP_2048_MODP = 0x01
2969EAP_PAX_DH_GROUP_3072_MODP = 0x02
2970EAP_PAX_DH_GROUP_NIST_ECC_P_256 = 0x03
2971
2972EAP_PAX_PUBLIC_KEY_NONE = 0x00
2973EAP_PAX_PUBLIC_KEY_RSAES_OAEP = 0x01
2974EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5 = 0x02
2975EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC = 0x03
2976
2977EAP_PAX_ADE_VENDOR_SPECIFIC = 0x01
2978EAP_PAX_ADE_CLIENT_CHANNEL_BINDING = 0x02
2979EAP_PAX_ADE_SERVER_CHANNEL_BINDING = 0x03
2980
2981def test_eap_proto_pax(dev, apdev):
2982    """EAP-PAX protocol tests"""
2983    def pax_std_1(ctx):
2984            logger.info("Test: STD-1")
2985            ctx['id'] = 10
2986            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
2987                               4 + 1 + 5 + 2 + 32 + 16,
2988                               EAP_TYPE_PAX,
2989                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
2990                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
2991                               32, 0, 0, 0, 0, 0, 0, 0, 0,
2992                               0x16, 0xc9, 0x08, 0x9d, 0x98, 0xa5, 0x6e, 0x1f,
2993                               0xf0, 0xac, 0xcf, 0xc4, 0x66, 0xcd, 0x2d, 0xbf)
2994
2995    def pax_handler(ctx, req):
2996        logger.info("pax_handler - RX " + binascii.hexlify(req).decode())
2997        if 'num' not in ctx:
2998            ctx['num'] = 0
2999        ctx['num'] = ctx['num'] + 1
3000        if 'id' not in ctx:
3001            ctx['id'] = 1
3002        ctx['id'] = (ctx['id'] + 1) % 256
3003
3004        idx = 0
3005
3006        idx += 1
3007        if ctx['num'] == idx:
3008            logger.info("Test: Missing payload")
3009            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
3010                               4 + 1,
3011                               EAP_TYPE_PAX)
3012
3013        idx += 1
3014        if ctx['num'] == idx:
3015            logger.info("Test: Minimum length payload")
3016            return struct.pack(">BBHB4L", EAP_CODE_REQUEST, ctx['id'],
3017                               4 + 1 + 16,
3018                               EAP_TYPE_PAX,
3019                               0, 0, 0, 0)
3020
3021        idx += 1
3022        if ctx['num'] == idx:
3023            logger.info("Test: Unsupported MAC ID")
3024            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
3025                               4 + 1 + 5 + 16,
3026                               EAP_TYPE_PAX,
3027                               EAP_PAX_OP_STD_1, 0, 255, EAP_PAX_DH_GROUP_NONE,
3028                               EAP_PAX_PUBLIC_KEY_NONE,
3029                               0, 0, 0, 0)
3030
3031        idx += 1
3032        if ctx['num'] == idx:
3033            logger.info("Test: Unsupported DH Group ID")
3034            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
3035                               4 + 1 + 5 + 16,
3036                               EAP_TYPE_PAX,
3037                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3038                               255, EAP_PAX_PUBLIC_KEY_NONE,
3039                               0, 0, 0, 0)
3040
3041        idx += 1
3042        if ctx['num'] == idx:
3043            logger.info("Test: Unsupported Public Key ID")
3044            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
3045                               4 + 1 + 5 + 16,
3046                               EAP_TYPE_PAX,
3047                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3048                               EAP_PAX_DH_GROUP_NONE, 255,
3049                               0, 0, 0, 0)
3050
3051        idx += 1
3052        if ctx['num'] == idx:
3053            logger.info("Test: More fragments")
3054            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
3055                               4 + 1 + 5 + 16,
3056                               EAP_TYPE_PAX,
3057                               EAP_PAX_OP_STD_1, EAP_PAX_FLAGS_MF,
3058                               EAP_PAX_MAC_HMAC_SHA1_128,
3059                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3060                               0, 0, 0, 0)
3061
3062        idx += 1
3063        if ctx['num'] == idx:
3064            logger.info("Test: Invalid ICV")
3065            return struct.pack(">BBHBBBBBB4L", EAP_CODE_REQUEST, ctx['id'],
3066                               4 + 1 + 5 + 16,
3067                               EAP_TYPE_PAX,
3068                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3069                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3070                               0, 0, 0, 0)
3071
3072        idx += 1
3073        if ctx['num'] == idx:
3074            logger.info("Test: Invalid ICV in short frame")
3075            return struct.pack(">BBHBBBBBB3L", EAP_CODE_REQUEST, ctx['id'],
3076                               4 + 1 + 5 + 12,
3077                               EAP_TYPE_PAX,
3078                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3079                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3080                               0, 0, 0)
3081
3082        idx += 1
3083        if ctx['num'] == idx:
3084            logger.info("Test: Correct ICV - unsupported op_code")
3085            ctx['id'] = 10
3086            return struct.pack(">BBHBBBBBB16B", EAP_CODE_REQUEST, ctx['id'],
3087                               4 + 1 + 5 + 16,
3088                               EAP_TYPE_PAX,
3089                               255, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3090                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3091                               0x90, 0x78, 0x97, 0x38, 0x29, 0x94, 0x32, 0xd4,
3092                               0x81, 0x27, 0xe0, 0xf6, 0x3b, 0x0d, 0xb2, 0xb2)
3093
3094        idx += 1
3095        if ctx['num'] == idx:
3096            logger.info("Test: Correct ICV - CE flag in STD-1")
3097            ctx['id'] = 10
3098            return struct.pack(">BBHBBBBBB16B", EAP_CODE_REQUEST, ctx['id'],
3099                               4 + 1 + 5 + 16,
3100                               EAP_TYPE_PAX,
3101                               EAP_PAX_OP_STD_1, EAP_PAX_FLAGS_CE,
3102                               EAP_PAX_MAC_HMAC_SHA1_128,
3103                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3104                               0x9c, 0x98, 0xb4, 0x0b, 0x94, 0x90, 0xde, 0x88,
3105                               0xb7, 0x72, 0x63, 0x44, 0x1d, 0xe3, 0x7c, 0x5c)
3106
3107        idx += 1
3108        if ctx['num'] == idx:
3109            logger.info("Test: Correct ICV - too short STD-1 payload")
3110            ctx['id'] = 10
3111            return struct.pack(">BBHBBBBBB16B", EAP_CODE_REQUEST, ctx['id'],
3112                               4 + 1 + 5 + 16,
3113                               EAP_TYPE_PAX,
3114                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3115                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3116                               0xda, 0xab, 0x2c, 0xe7, 0x84, 0x41, 0xb5, 0x5c,
3117                               0xee, 0xcf, 0x62, 0x03, 0xc5, 0x69, 0xcb, 0xf4)
3118
3119        idx += 1
3120        if ctx['num'] == idx:
3121            logger.info("Test: Correct ICV - incorrect A length in STD-1")
3122            ctx['id'] = 10
3123            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3124                               4 + 1 + 5 + 2 + 32 + 16,
3125                               EAP_TYPE_PAX,
3126                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3127                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3128                               0, 0, 0, 0, 0, 0, 0, 0, 0,
3129                               0xc4, 0xb0, 0x81, 0xe4, 0x6c, 0x8c, 0x20, 0x23,
3130                               0x60, 0x46, 0x89, 0xea, 0x94, 0x60, 0xf3, 0x2a)
3131
3132        idx += 1
3133        if ctx['num'] == idx:
3134            logger.info("Test: Correct ICV - extra data in STD-1")
3135            ctx['id'] = 10
3136            return struct.pack(">BBHBBBBBBH8LB16B", EAP_CODE_REQUEST, ctx['id'],
3137                               4 + 1 + 5 + 2 + 32 + 1 + 16,
3138                               EAP_TYPE_PAX,
3139                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3140                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3141                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3142                               1,
3143                               0x61, 0x49, 0x65, 0x37, 0x21, 0xe8, 0xd8, 0xbf,
3144                               0xf3, 0x02, 0x01, 0xe5, 0x42, 0x51, 0xd3, 0x34)
3145        idx += 1
3146        if ctx['num'] == idx:
3147            logger.info("Test: Unexpected STD-1")
3148            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3149                               4 + 1 + 5 + 2 + 32 + 16,
3150                               EAP_TYPE_PAX,
3151                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3152                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3153                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3154                               0xe5, 0x1d, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
3155                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
3156
3157        idx += 1
3158        if ctx['num'] == idx:
3159            return pax_std_1(ctx)
3160        idx += 1
3161        if ctx['num'] == idx:
3162            logger.info("Test: MAC ID changed during session")
3163            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3164                               4 + 1 + 5 + 2 + 32 + 16,
3165                               EAP_TYPE_PAX,
3166                               EAP_PAX_OP_STD_1, 0, EAP_PAX_HMAC_SHA256_128,
3167                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3168                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3169                               0xee, 0x00, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
3170                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
3171
3172        idx += 1
3173        if ctx['num'] == idx:
3174            return pax_std_1(ctx)
3175        idx += 1
3176        if ctx['num'] == idx:
3177            logger.info("Test: DH Group ID changed during session")
3178            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3179                               4 + 1 + 5 + 2 + 32 + 16,
3180                               EAP_TYPE_PAX,
3181                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3182                               EAP_PAX_DH_GROUP_2048_MODP,
3183                               EAP_PAX_PUBLIC_KEY_NONE,
3184                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3185                               0xee, 0x01, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
3186                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
3187
3188        idx += 1
3189        if ctx['num'] == idx:
3190            return pax_std_1(ctx)
3191        idx += 1
3192        if ctx['num'] == idx:
3193            logger.info("Test: Public Key ID changed during session")
3194            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3195                               4 + 1 + 5 + 2 + 32 + 16,
3196                               EAP_TYPE_PAX,
3197                               EAP_PAX_OP_STD_1, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3198                               EAP_PAX_DH_GROUP_NONE,
3199                               EAP_PAX_PUBLIC_KEY_RSAES_OAEP,
3200                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3201                               0xee, 0x02, 0xbf, 0xb8, 0x70, 0x20, 0x5c, 0xba,
3202                               0x41, 0xbb, 0x34, 0xda, 0x1a, 0x08, 0xe6, 0x8d)
3203
3204        idx += 1
3205        if ctx['num'] == idx:
3206            logger.info("Test: Unexpected STD-3")
3207            ctx['id'] = 10
3208            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3209                               4 + 1 + 5 + 2 + 32 + 16,
3210                               EAP_TYPE_PAX,
3211                               EAP_PAX_OP_STD_3, 0, EAP_PAX_MAC_HMAC_SHA1_128,
3212                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3213                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3214                               0x47, 0xbb, 0xc0, 0xf9, 0xb9, 0x69, 0xf5, 0xcb,
3215                               0x3a, 0xe8, 0xe7, 0xd6, 0x80, 0x28, 0xf2, 0x59)
3216
3217        idx += 1
3218        if ctx['num'] == idx:
3219            return pax_std_1(ctx)
3220        idx += 1
3221        if ctx['num'] == idx:
3222            # TODO: MAC calculation; for now, this gets dropped due to incorrect
3223            # ICV
3224            logger.info("Test: STD-3 with CE flag")
3225            return struct.pack(">BBHBBBBBBH8L16B", EAP_CODE_REQUEST, ctx['id'],
3226                               4 + 1 + 5 + 2 + 32 + 16,
3227                               EAP_TYPE_PAX,
3228                               EAP_PAX_OP_STD_3, EAP_PAX_FLAGS_CE,
3229                               EAP_PAX_MAC_HMAC_SHA1_128,
3230                               EAP_PAX_DH_GROUP_NONE, EAP_PAX_PUBLIC_KEY_NONE,
3231                               32, 0, 0, 0, 0, 0, 0, 0, 0,
3232                               0x8a, 0xc2, 0xf9, 0xf4, 0x8b, 0x75, 0x72, 0xa2,
3233                               0x4d, 0xd3, 0x1e, 0x54, 0x77, 0x04, 0x05, 0xe2)
3234
3235        idx += 1
3236        if ctx['num'] & 0x1 == idx & 0x1:
3237            logger.info("Test: Default request")
3238            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
3239                               4 + 1,
3240                               EAP_TYPE_PAX)
3241        else:
3242            logger.info("Test: Default EAP-Failure")
3243            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
3244
3245    srv = start_radius_server(pax_handler)
3246
3247    try:
3248        hapd = start_ap(apdev[0])
3249        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3250
3251        for i in range(0, 18):
3252            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3253                           eap="PAX", identity="user",
3254                           password_hex="0123456789abcdef0123456789abcdef",
3255                           wait_connect=False)
3256            logger.info("Waiting for EAP method to start")
3257            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
3258                                   timeout=15)
3259            if ev is None:
3260                raise Exception("Timeout on EAP start")
3261            time.sleep(0.05)
3262            dev[0].request("REMOVE_NETWORK all")
3263            dev[0].dump_monitor()
3264
3265        logger.info("Too short password")
3266        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3267                       eap="PAX", identity="user",
3268                       password_hex="0123456789abcdef0123456789abcd",
3269                       wait_connect=False)
3270        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
3271        if ev is None:
3272            raise Exception("Timeout on EAP start")
3273        time.sleep(0.1)
3274        dev[0].request("REMOVE_NETWORK all")
3275        dev[0].dump_monitor()
3276
3277        logger.info("No password")
3278        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3279                       eap="PAX", identity="user",
3280                       wait_connect=False)
3281        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
3282        if ev is None:
3283            raise Exception("Timeout on EAP start")
3284        time.sleep(0.1)
3285        dev[0].request("REMOVE_NETWORK all")
3286        dev[0].dump_monitor()
3287    finally:
3288        stop_radius_server(srv)
3289
3290def test_eap_proto_pax_errors(dev, apdev):
3291    """EAP-PAX local error cases"""
3292    check_eap_capa(dev[0], "PAX")
3293    params = hostapd.wpa2_eap_params(ssid="eap-test")
3294    hapd = hostapd.add_ap(apdev[0], params)
3295    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3296
3297    for i in range(1, 3):
3298        with alloc_fail(dev[0], i, "eap_pax_init"):
3299            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3300                           eap="PAX", identity="pax.user@example.com",
3301                           password_hex="0123456789abcdef0123456789abcdef",
3302                           wait_connect=False)
3303            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
3304                                   timeout=15)
3305            if ev is None:
3306                raise Exception("Timeout on EAP start")
3307            dev[0].request("REMOVE_NETWORK all")
3308            dev[0].wait_disconnected()
3309
3310    tests = ["eap_msg_alloc;eap_pax_alloc_resp;eap_pax_process_std_1",
3311             "eap_msg_alloc;eap_pax_alloc_resp;eap_pax_process_std_3",
3312             "eap_pax_getKey",
3313             "eap_pax_get_emsk",
3314             "eap_pax_get_session_id"]
3315    for func in tests:
3316        with alloc_fail(dev[0], 1, func):
3317            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3318                           eap="PAX", identity="pax.user@example.com",
3319                           password_hex="0123456789abcdef0123456789abcdef",
3320                           erp="1", wait_connect=False)
3321            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
3322            dev[0].request("REMOVE_NETWORK all")
3323            dev[0].wait_disconnected()
3324
3325    tests = [(1, "os_get_random;eap_pax_process_std_1"),
3326             (1, "eap_pax_initial_key_derivation"),
3327             (1, "eap_pax_mac;eap_pax_process_std_3"),
3328             (2, "eap_pax_mac;eap_pax_process_std_3"),
3329             (1, "eap_pax_kdf;eap_pax_getKey"),
3330             (1, "eap_pax_kdf;eap_pax_get_emsk")]
3331    for count, func in tests:
3332        with fail_test(dev[0], count, func):
3333            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3334                           eap="PAX", identity="pax.user@example.com",
3335                           password_hex="0123456789abcdef0123456789abcdef",
3336                           erp="1", wait_connect=False)
3337            wait_fail_trigger(dev[0], "GET_FAIL")
3338            dev[0].request("REMOVE_NETWORK all")
3339            dev[0].wait_disconnected()
3340
3341def run_eap_pax_connect(dev):
3342    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
3343                eap="PAX", identity="pax.user@example.com",
3344                password_hex="0123456789abcdef0123456789abcdef",
3345                wait_connect=False)
3346    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
3347                         "CTRL-EVENT-DISCONNECTED"],
3348                        timeout=1)
3349    dev.request("REMOVE_NETWORK all")
3350    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
3351        dev.wait_disconnected()
3352    dev.dump_monitor()
3353
3354def test_eap_proto_pax_errors_server(dev, apdev):
3355    """EAP-PAX local error cases on server"""
3356    check_eap_capa(dev[0], "PAX")
3357    params = int_eap_server_params()
3358    params['erp_domain'] = 'example.com'
3359    params['eap_server_erp'] = '1'
3360    hapd = hostapd.add_ap(apdev[0], params)
3361    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3362
3363    tests = [(1, "eap_pax_init"),
3364             (1, "eap_msg_alloc;eap_pax_build_std_1"),
3365             (1, "eap_msg_alloc;eap_pax_build_std_3"),
3366             (1, "=eap_pax_process_std_2"),
3367             (1, "eap_pax_getKey"),
3368             (1, "eap_pax_get_emsk"),
3369             (1, "eap_pax_get_session_id")]
3370    for count, func in tests:
3371        with alloc_fail(hapd, count, func):
3372            run_eap_pax_connect(dev[0])
3373
3374    tests = [(1, "os_get_random;eap_pax_build_std_1"),
3375             (1, "eap_pax_mac;eap_pax_build_std_1"),
3376             (1, "eap_pax_mac;eap_pax_build_std_3"),
3377             (2, "eap_pax_mac;=eap_pax_build_std_3"),
3378             (1, "eap_pax_initial_key_derivation;eap_pax_process_std_2"),
3379             (1, "eap_pax_mac;eap_pax_process_std_2"),
3380             (2, "eap_pax_mac;=eap_pax_process_std_2"),
3381             (1, "eap_pax_mac;eap_pax_check")]
3382    for count, func in tests:
3383        with fail_test(hapd, count, func):
3384            run_eap_pax_connect(dev[0])
3385
3386def start_pax_assoc(dev, hapd):
3387    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
3388                eap="PAX", identity="pax.user@example.com",
3389                password_hex="0123456789abcdef0123456789abcdef",
3390                wait_connect=False)
3391    proxy_msg(hapd, dev) # EAP-Identity/Request
3392    proxy_msg(dev, hapd) # EAP-Identity/Response
3393    proxy_msg(hapd, dev) # PAX_STD-1
3394
3395def stop_pax_assoc(dev, hapd):
3396    dev.request("REMOVE_NETWORK all")
3397    dev.wait_disconnected()
3398    dev.dump_monitor()
3399    hapd.dump_monitor()
3400
3401def test_eap_proto_pax_server(dev, apdev):
3402    """EAP-PAX protocol testing for the server"""
3403    check_eap_capa(dev[0], "PAX")
3404    params = int_eap_server_params()
3405    params['erp_domain'] = 'example.com'
3406    params['eap_server_erp'] = '1'
3407    hapd = hostapd.add_ap(apdev[0], params)
3408    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3409    hapd.request("SET ext_eapol_frame_io 1")
3410    dev[0].request("SET ext_eapol_frame_io 1")
3411
3412    # Successful exchange to verify proxying mechanism
3413    start_pax_assoc(dev[0], hapd)
3414    proxy_msg(dev[0], hapd) # PAX_STD-2
3415    proxy_msg(hapd, dev[0]) # PAX_STD-3
3416    proxy_msg(dev[0], hapd) # PAX-ACK
3417    proxy_msg(hapd, dev[0]) # EAP-Success
3418    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 1/4
3419    proxy_msg(dev[0], hapd) # EAPOL-Key msg 2/4
3420    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 3/4
3421    proxy_msg(dev[0], hapd) # EAPOL-Key msg 4/4
3422    dev[0].wait_connected()
3423    stop_pax_assoc(dev[0], hapd)
3424
3425    start_pax_assoc(dev[0], hapd)
3426    resp = rx_msg(dev[0])
3427    # Too short EAP-PAX header (no OP-Code)
3428    hapd.note("EAP-PAX: Invalid frame")
3429    msg = resp[0:4] + "0005" + resp[8:12] + "0005" + "2e"
3430    tx_msg(dev[0], hapd, msg)
3431    # Too short EAP-PAX message (no payload)
3432    hapd.note("EAP-PAX: Invalid frame")
3433    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "2e1100000000"
3434    tx_msg(dev[0], hapd, msg)
3435    # Unexpected PAX_SEC-2
3436    hapd.note("EAP-PAX: Expected PAX_STD-2 - ignore op 17")
3437    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e1100000000" + 16*"00"
3438    tx_msg(dev[0], hapd, msg)
3439    # Unexpected MAC ID
3440    hapd.note("EAP-PAX: Expected MAC ID 0x1, received 0xff")
3441    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e0200ff0000" + 16*"00"
3442    tx_msg(dev[0], hapd, msg)
3443    # Unexpected DH Group ID
3444    hapd.note("EAP-PAX: Expected DH Group ID 0x0, received 0xff")
3445    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e020001ff00" + 16*"00"
3446    tx_msg(dev[0], hapd, msg)
3447    # Unexpected Public Key ID
3448    hapd.note("EAP-PAX: Expected Public Key ID 0x0, received 0xff")
3449    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e02000100ff" + 16*"00"
3450    tx_msg(dev[0], hapd, msg)
3451    # Unsupported Flags - MF
3452    hapd.note("EAP-PAX: fragmentation not supported")
3453    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e0201010000" + 16*"00"
3454    tx_msg(dev[0], hapd, msg)
3455    # Unsupported Flags - CE
3456    hapd.note("EAP-PAX: Unexpected CE flag")
3457    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e0202010000" + 16*"00"
3458    tx_msg(dev[0], hapd, msg)
3459    # Too short Payload in PAX_STD-2
3460    hapd.note("EAP-PAX: Too short PAX_STD-2 (B)")
3461    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e0200010000" + 16*"00"
3462    tx_msg(dev[0], hapd, msg)
3463    rx_msg(hapd)
3464    stop_pax_assoc(dev[0], hapd)
3465
3466    start_pax_assoc(dev[0], hapd)
3467    resp = rx_msg(dev[0])
3468    # Too short Payload in PAX_STD-2
3469    hapd.note("EAP-PAX: Too short PAX_STD-2 (CID)")
3470    msg = resp[0:4] + "002c" + resp[8:12] + "002c" + "2e0200010000" + "0020" + 32*"00"
3471    tx_msg(dev[0], hapd, msg)
3472    rx_msg(hapd)
3473    stop_pax_assoc(dev[0], hapd)
3474
3475    start_pax_assoc(dev[0], hapd)
3476    resp = rx_msg(dev[0])
3477    # Too short Payload in PAX_STD-2
3478    hapd.note("EAP-PAX: Too short PAX_STD-2 (CID)")
3479    msg = resp[0:4] + "002e" + resp[8:12] + "002e" + "2e0200010000" + "0020" + 32*"00" + "ffff"
3480    tx_msg(dev[0], hapd, msg)
3481    rx_msg(hapd)
3482    stop_pax_assoc(dev[0], hapd)
3483
3484    start_pax_assoc(dev[0], hapd)
3485    resp = rx_msg(dev[0])
3486    # Too long CID in PAX_STD-2
3487    hapd.note("EAP-PAX: Too long CID")
3488    msg = resp[0:4] + "062e" + resp[8:12] + "062e" + "2e0200010000" + "0020" + 32*"00" + "0600" + 1536*"00"
3489    tx_msg(dev[0], hapd, msg)
3490    rx_msg(hapd)
3491    stop_pax_assoc(dev[0], hapd)
3492
3493    start_pax_assoc(dev[0], hapd)
3494    resp = rx_msg(dev[0])
3495    # Too short Payload in PAX_STD-2
3496    hapd.note("EAP-PAX: Too short PAX_STD-2 (MAC_CK)")
3497    msg = resp[0:4] + "003c" + resp[8:12] + "003c" + "2e0200010000" + "0020" + 32*"00" + 16*"00"
3498    tx_msg(dev[0], hapd, msg)
3499    rx_msg(hapd)
3500    stop_pax_assoc(dev[0], hapd)
3501
3502    start_pax_assoc(dev[0], hapd)
3503    resp = rx_msg(dev[0])
3504    # Unknown CID for PAX
3505    hapd.note("EAP-PAX: EAP-PAX not enabled for CID")
3506    msg = resp[0:4] + "0041" + resp[8:12] + "0041" + "2e0200010000" + "0020" + 32*"00" + "0001" + "00" + "0010" + 16*"00"
3507    tx_msg(dev[0], hapd, msg)
3508    rx_msg(hapd)
3509    stop_pax_assoc(dev[0], hapd)
3510
3511    start_pax_assoc(dev[0], hapd)
3512    resp = rx_msg(dev[0])
3513    # Too short ICV
3514    hapd.note("EAP-PAX: Too short ICV (15) in PAX_STD-2")
3515    msg = resp[0:4] + "0063" + resp[8:12] + "0063" + resp[16:206]
3516    tx_msg(dev[0], hapd, msg)
3517    rx_msg(hapd)
3518    stop_pax_assoc(dev[0], hapd)
3519
3520    start_pax_assoc(dev[0], hapd)
3521    proxy_msg(dev[0], hapd) # PAX_STD-2
3522    proxy_msg(hapd, dev[0]) # PAX_STD-3
3523    resp = rx_msg(dev[0])
3524    # Unexpected PAX_STD-2
3525    hapd.note("EAP-PAX: Expected PAX-ACK - ignore op 1")
3526    msg = resp[0:4] + "001a" + resp[8:12] + "001a" + "2e0100000000" + 16*"00"
3527    tx_msg(dev[0], hapd, msg)
3528    stop_pax_assoc(dev[0], hapd)
3529
3530def test_eap_proto_psk(dev, apdev):
3531    """EAP-PSK protocol tests"""
3532    def psk_handler(ctx, req):
3533        logger.info("psk_handler - RX " + binascii.hexlify(req).decode())
3534        if 'num' not in ctx:
3535            ctx['num'] = 0
3536        ctx['num'] = ctx['num'] + 1
3537        if 'id' not in ctx:
3538            ctx['id'] = 1
3539        ctx['id'] = (ctx['id'] + 1) % 256
3540
3541        idx = 0
3542
3543        idx += 1
3544        if ctx['num'] == idx:
3545            logger.info("Test: Missing payload")
3546            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
3547                               4 + 1,
3548                               EAP_TYPE_PSK)
3549
3550        idx += 1
3551        if ctx['num'] == idx:
3552            logger.info("Test: Non-zero T in first message")
3553            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
3554                               4 + 1 + 1 + 16,
3555                               EAP_TYPE_PSK, 0xc0, 0, 0, 0, 0)
3556
3557        idx += 1
3558        if ctx['num'] == idx:
3559            logger.info("Test: Valid first message")
3560            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
3561                               4 + 1 + 1 + 16,
3562                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
3563        idx += 1
3564        if ctx['num'] == idx:
3565            logger.info("Test: Too short third message")
3566            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
3567                               4 + 1,
3568                               EAP_TYPE_PSK)
3569
3570        idx += 1
3571        if ctx['num'] == idx:
3572            logger.info("Test: Valid first message")
3573            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
3574                               4 + 1 + 1 + 16,
3575                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
3576        idx += 1
3577        if ctx['num'] == idx:
3578            logger.info("Test: Incorrect T in third message")
3579            return struct.pack(">BBHBB4L4L", EAP_CODE_REQUEST, ctx['id'],
3580                               4 + 1 + 1 + 16 + 16,
3581                               EAP_TYPE_PSK, 0, 0, 0, 0, 0, 0, 0, 0, 0)
3582
3583        idx += 1
3584        if ctx['num'] == idx:
3585            logger.info("Test: Valid first message")
3586            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
3587                               4 + 1 + 1 + 16,
3588                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
3589        idx += 1
3590        if ctx['num'] == idx:
3591            logger.info("Test: Missing PCHANNEL in third message")
3592            return struct.pack(">BBHBB4L4L", EAP_CODE_REQUEST, ctx['id'],
3593                               4 + 1 + 1 + 16 + 16,
3594                               EAP_TYPE_PSK, 0x80, 0, 0, 0, 0, 0, 0, 0, 0)
3595
3596        idx += 1
3597        if ctx['num'] == idx:
3598            logger.info("Test: Valid first message")
3599            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
3600                               4 + 1 + 1 + 16,
3601                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
3602        idx += 1
3603        if ctx['num'] == idx:
3604            logger.info("Test: Invalic MAC_S in third message")
3605            return struct.pack(">BBHBB4L4L5LB", EAP_CODE_REQUEST, ctx['id'],
3606                               4 + 1 + 1 + 16 + 16 + 21,
3607                               EAP_TYPE_PSK, 0x80, 0, 0, 0, 0, 0, 0, 0, 0,
3608                               0, 0, 0, 0, 0, 0)
3609
3610        idx += 1
3611        if ctx['num'] == idx:
3612            logger.info("Test: Valid first message")
3613            return struct.pack(">BBHBB4L", EAP_CODE_REQUEST, ctx['id'],
3614                               4 + 1 + 1 + 16,
3615                               EAP_TYPE_PSK, 0, 0, 0, 0, 0)
3616        idx += 1
3617        if ctx['num'] == idx:
3618            logger.info("Test: EAP-Failure")
3619            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
3620
3621        return None
3622
3623    srv = start_radius_server(psk_handler)
3624
3625    try:
3626        hapd = start_ap(apdev[0])
3627        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3628
3629        for i in range(0, 6):
3630            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3631                           eap="PSK", identity="user",
3632                           password_hex="0123456789abcdef0123456789abcdef",
3633                           wait_connect=False)
3634            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
3635                                   timeout=15)
3636            if ev is None:
3637                raise Exception("Timeout on EAP start")
3638            time.sleep(0.1)
3639            dev[0].request("REMOVE_NETWORK all")
3640
3641        logger.info("Test: Invalid PSK length")
3642        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3643                       eap="PSK", identity="user",
3644                       password_hex="0123456789abcdef0123456789abcd",
3645                       wait_connect=False)
3646        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
3647                               timeout=15)
3648        if ev is None:
3649            raise Exception("Timeout on EAP start")
3650        time.sleep(0.1)
3651        dev[0].request("REMOVE_NETWORK all")
3652    finally:
3653        stop_radius_server(srv)
3654
3655def test_eap_proto_psk_errors(dev, apdev):
3656    """EAP-PSK local error cases"""
3657    check_eap_capa(dev[0], "PSK")
3658    params = hostapd.wpa2_eap_params(ssid="eap-test")
3659    hapd = hostapd.add_ap(apdev[0], params)
3660    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3661
3662    for i in range(1, 3):
3663        with alloc_fail(dev[0], i, "eap_psk_init"):
3664            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3665                           eap="PSK", identity="psk.user@example.com",
3666                           password_hex="0123456789abcdef0123456789abcdef",
3667                           wait_connect=False)
3668            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
3669                                   timeout=15)
3670            if ev is None:
3671                raise Exception("Timeout on EAP start")
3672            dev[0].request("REMOVE_NETWORK all")
3673            dev[0].wait_disconnected()
3674
3675    for i in range(1, 4):
3676        with fail_test(dev[0], i, "eap_psk_key_setup;eap_psk_init"):
3677            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3678                           eap="PSK", identity="psk.user@example.com",
3679                           password_hex="0123456789abcdef0123456789abcdef",
3680                           wait_connect=False)
3681            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
3682                                   timeout=15)
3683            if ev is None:
3684                raise Exception("Timeout on EAP start")
3685            dev[0].request("REMOVE_NETWORK all")
3686            dev[0].wait_disconnected()
3687
3688    tests = [(1, "=eap_psk_process_1"),
3689             (2, "=eap_psk_process_1"),
3690             (1, "eap_msg_alloc;eap_psk_process_1"),
3691             (1, "=eap_psk_process_3"),
3692             (2, "=eap_psk_process_3"),
3693             (1, "eap_msg_alloc;eap_psk_process_3"),
3694             (1, "eap_psk_getKey"),
3695             (1, "eap_psk_get_session_id"),
3696             (1, "eap_psk_get_emsk")]
3697    for count, func in tests:
3698        with alloc_fail(dev[0], count, func):
3699            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3700                           eap="PSK", identity="psk.user@example.com",
3701                           password_hex="0123456789abcdef0123456789abcdef",
3702                           erp="1", wait_connect=False)
3703            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
3704                                   timeout=15)
3705            if ev is None:
3706                raise Exception("Timeout on EAP start")
3707            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL",
3708                              note="No allocation failure seen for %d:%s" % (count, func))
3709            dev[0].request("REMOVE_NETWORK all")
3710            dev[0].wait_disconnected()
3711
3712    tests = [(1, "os_get_random;eap_psk_process_1"),
3713             (1, "omac1_aes_128;eap_psk_process_3"),
3714             (1, "=omac1_aes_vector;omac1_aes_128;aes_128_eax_encrypt"),
3715             (2, "=omac1_aes_vector;omac1_aes_128;aes_128_eax_encrypt"),
3716             (3, "=omac1_aes_vector;omac1_aes_128;aes_128_eax_encrypt"),
3717             (1, "=omac1_aes_vector;omac1_aes_128;aes_128_eax_decrypt"),
3718             (2, "=omac1_aes_vector;omac1_aes_128;aes_128_eax_decrypt"),
3719             (3, "=omac1_aes_vector;omac1_aes_128;aes_128_eax_decrypt"),
3720             (1, "aes_128_eax_decrypt;eap_psk_process_3"),
3721             (2, "aes_128_eax_decrypt;eap_psk_process_3"),
3722             (3, "aes_128_eax_decrypt;eap_psk_process_3"),
3723             (1, "aes_128_eax_encrypt;eap_psk_process_3"),
3724             (2, "aes_128_eax_encrypt;eap_psk_process_3"),
3725             (3, "aes_128_eax_encrypt;eap_psk_process_3"),
3726             (1, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3727             (2, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3728             (3, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3729             (4, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3730             (5, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3731             (6, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3732             (7, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3733             (8, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3734             (9, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3735             (10, "aes_128_encrypt_block;eap_psk_derive_keys;eap_psk_process_3"),
3736             (1, "aes_ctr_encrypt;aes_128_eax_decrypt;eap_psk_process_3"),
3737             (1, "aes_ctr_encrypt;aes_128_eax_encrypt;eap_psk_process_3")]
3738    for count, func in tests:
3739        with fail_test(dev[0], count, func):
3740            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
3741                           eap="PSK", identity="psk.user@example.com",
3742                           password_hex="0123456789abcdef0123456789abcdef",
3743                           wait_connect=False)
3744            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
3745                                   timeout=15)
3746            if ev is None:
3747                raise Exception("Timeout on EAP start")
3748            wait_fail_trigger(dev[0], "GET_FAIL",
3749                              note="No failure seen for %d:%s" % (count, func))
3750            dev[0].request("REMOVE_NETWORK all")
3751            dev[0].wait_disconnected()
3752            dev[0].dump_monitor()
3753
3754def run_eap_psk_connect(dev):
3755    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
3756                eap="PSK", identity="psk.user@example.com",
3757                password_hex="0123456789abcdef0123456789abcdef",
3758                wait_connect=False)
3759    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
3760                         "CTRL-EVENT-DISCONNECTED"],
3761                        timeout=1)
3762    dev.request("REMOVE_NETWORK all")
3763    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
3764        dev.wait_disconnected()
3765    dev.dump_monitor()
3766
3767def test_eap_proto_psk_errors_server(dev, apdev):
3768    """EAP-PSK local error cases on server"""
3769    check_eap_capa(dev[0], "PSK")
3770    params = int_eap_server_params()
3771    params['erp_domain'] = 'example.com'
3772    params['eap_server_erp'] = '1'
3773    hapd = hostapd.add_ap(apdev[0], params)
3774    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3775
3776    tests = [(1, "eap_psk_init"),
3777             (1, "eap_msg_alloc;eap_psk_build_1"),
3778             (1, "eap_msg_alloc;eap_psk_build_3"),
3779             (1, "=eap_psk_build_3"),
3780             (1, "=eap_psk_process_2"),
3781             (2, "=eap_psk_process_2"),
3782             (1, "=eap_psk_process_4"),
3783             (1, "aes_128_eax_decrypt;eap_psk_process_4"),
3784             (1, "eap_psk_getKey"),
3785             (1, "eap_psk_get_emsk"),
3786             (1, "eap_psk_get_session_id")]
3787    for count, func in tests:
3788        with alloc_fail(hapd, count, func):
3789            run_eap_psk_connect(dev[0])
3790
3791    tests = [(1, "os_get_random;eap_psk_build_1"),
3792             (1, "omac1_aes_128;eap_psk_build_3"),
3793             (1, "eap_psk_derive_keys;eap_psk_build_3"),
3794             (1, "aes_128_eax_encrypt;eap_psk_build_3"),
3795             (1, "eap_psk_key_setup;eap_psk_process_2"),
3796             (1, "omac1_aes_128;eap_psk_process_2"),
3797             (1, "aes_128_eax_decrypt;eap_psk_process_4")]
3798    for count, func in tests:
3799        with fail_test(hapd, count, func):
3800            run_eap_psk_connect(dev[0])
3801
3802def start_psk_assoc(dev, hapd):
3803    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
3804                eap="PSK", identity="psk.user@example.com",
3805                password_hex="0123456789abcdef0123456789abcdef",
3806                wait_connect=False)
3807    proxy_msg(hapd, dev) # EAP-Identity/Request
3808    proxy_msg(dev, hapd) # EAP-Identity/Response
3809    proxy_msg(hapd, dev) # PSK-1
3810
3811def stop_psk_assoc(dev, hapd):
3812    dev.request("REMOVE_NETWORK all")
3813    dev.wait_disconnected()
3814    dev.dump_monitor()
3815    hapd.dump_monitor()
3816
3817def test_eap_proto_psk_server(dev, apdev):
3818    """EAP-PSK protocol testing for the server"""
3819    check_eap_capa(dev[0], "PSK")
3820    params = int_eap_server_params()
3821    params['erp_domain'] = 'example.com'
3822    params['eap_server_erp'] = '1'
3823    hapd = hostapd.add_ap(apdev[0], params)
3824    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
3825    hapd.request("SET ext_eapol_frame_io 1")
3826    dev[0].request("SET ext_eapol_frame_io 1")
3827
3828    # Successful exchange to verify proxying mechanism
3829    start_psk_assoc(dev[0], hapd)
3830    proxy_msg(dev[0], hapd) # PSK-2
3831    proxy_msg(hapd, dev[0]) # PSK-3
3832    proxy_msg(dev[0], hapd) # PSK-4
3833    proxy_msg(hapd, dev[0]) # EAP-Success
3834    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 1/4
3835    proxy_msg(dev[0], hapd) # EAPOL-Key msg 2/4
3836    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 3/4
3837    proxy_msg(dev[0], hapd) # EAPOL-Key msg 4/4
3838    dev[0].wait_connected()
3839    stop_psk_assoc(dev[0], hapd)
3840
3841    start_psk_assoc(dev[0], hapd)
3842    resp = rx_msg(dev[0])
3843    # Too short EAP-PSK header (no Flags)
3844    hapd.note("EAP-PSK: Invalid frame")
3845    msg = resp[0:4] + "0005" + resp[8:12] + "0005" + "2f"
3846    tx_msg(dev[0], hapd, msg)
3847    # Unexpected PSK-1
3848    hapd.note("EAP-PSK: Expected PSK-2 - ignore T=0")
3849    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "2f00"
3850    tx_msg(dev[0], hapd, msg)
3851    # Too short PSK-2
3852    hapd.note("EAP-PSK: Too short frame")
3853    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "2f40"
3854    tx_msg(dev[0], hapd, msg)
3855    # PSK-2 with unknown ID_P
3856    hapd.note("EAP-PSK: EAP-PSK not enabled for ID_P")
3857    msg = resp[0:4] + "004a" + resp[8:12] + "004a" + "2f40" + 3*16*"00" + 20*"00"
3858    tx_msg(dev[0], hapd, msg)
3859    rx_msg(hapd) # EAP-Failure
3860    stop_psk_assoc(dev[0], hapd)
3861
3862    start_psk_assoc(dev[0], hapd)
3863    proxy_msg(dev[0], hapd) # PSK-2
3864    proxy_msg(hapd, dev[0]) # PSK-3
3865    resp = rx_msg(dev[0])
3866    # Unexpected PSK-2
3867    hapd.note("EAP-PSK: Expected PSK-4 - ignore T=1")
3868    msg = resp[0:4] + "0016" + resp[8:12] + "0016" + "2f40" + 16*"00"
3869    tx_msg(dev[0], hapd, msg)
3870    # Too short PSK-4 (no PCHANNEL)
3871    hapd.note("EAP-PSK: Too short PCHANNEL data in PSK-4 (len=0, expected 21)")
3872    msg = resp[0:4] + "0016" + resp[8:12] + "0016" + "2fc0" + 16*"00"
3873    tx_msg(dev[0], hapd, msg)
3874    rx_msg(hapd) # PSK-3 retry
3875    stop_psk_assoc(dev[0], hapd)
3876
3877    start_psk_assoc(dev[0], hapd)
3878    proxy_msg(dev[0], hapd) # PSK-2
3879    proxy_msg(hapd, dev[0]) # PSK-3
3880    resp = rx_msg(dev[0])
3881    # PCHANNEL Nonce did not increase
3882    hapd.note("EAP-PSK: Nonce did not increase")
3883    msg = resp[0:4] + "002b" + resp[8:12] + "002b" + "2fc0" + 16*"00" + 21*"00"
3884    tx_msg(dev[0], hapd, msg)
3885    rx_msg(hapd) # PSK-3 retry
3886    stop_psk_assoc(dev[0], hapd)
3887
3888    start_psk_assoc(dev[0], hapd)
3889    proxy_msg(dev[0], hapd) # PSK-2
3890    proxy_msg(hapd, dev[0]) # PSK-3
3891    resp = rx_msg(dev[0])
3892    # Invalid PCHANNEL encryption
3893    hapd.note("EAP-PSK: PCHANNEL decryption failed")
3894    msg = resp[0:4] + "002b" + resp[8:12] + "002b" + "2fc0" + 16*"00" + 21*"11"
3895    tx_msg(dev[0], hapd, msg)
3896    rx_msg(hapd) # PSK-3 retry
3897    stop_psk_assoc(dev[0], hapd)
3898
3899EAP_SIM_SUBTYPE_START = 10
3900EAP_SIM_SUBTYPE_CHALLENGE = 11
3901EAP_SIM_SUBTYPE_NOTIFICATION = 12
3902EAP_SIM_SUBTYPE_REAUTHENTICATION = 13
3903EAP_SIM_SUBTYPE_CLIENT_ERROR = 14
3904
3905EAP_AKA_SUBTYPE_CHALLENGE = 1
3906EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT = 2
3907EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE = 4
3908EAP_AKA_SUBTYPE_IDENTITY = 5
3909EAP_AKA_SUBTYPE_NOTIFICATION = 12
3910EAP_AKA_SUBTYPE_REAUTHENTICATION = 13
3911EAP_AKA_SUBTYPE_CLIENT_ERROR = 14
3912
3913EAP_SIM_AT_RAND = 1
3914EAP_SIM_AT_AUTN = 2
3915EAP_SIM_AT_RES = 3
3916EAP_SIM_AT_AUTS = 4
3917EAP_SIM_AT_PADDING = 6
3918EAP_SIM_AT_NONCE_MT = 7
3919EAP_SIM_AT_PERMANENT_ID_REQ = 10
3920EAP_SIM_AT_MAC = 11
3921EAP_SIM_AT_NOTIFICATION = 12
3922EAP_SIM_AT_ANY_ID_REQ = 13
3923EAP_SIM_AT_IDENTITY = 14
3924EAP_SIM_AT_VERSION_LIST = 15
3925EAP_SIM_AT_SELECTED_VERSION = 16
3926EAP_SIM_AT_FULLAUTH_ID_REQ = 17
3927EAP_SIM_AT_COUNTER = 19
3928EAP_SIM_AT_COUNTER_TOO_SMALL = 20
3929EAP_SIM_AT_NONCE_S = 21
3930EAP_SIM_AT_CLIENT_ERROR_CODE = 22
3931EAP_SIM_AT_KDF_INPUT = 23
3932EAP_SIM_AT_KDF = 24
3933EAP_SIM_AT_IV = 129
3934EAP_SIM_AT_ENCR_DATA = 130
3935EAP_SIM_AT_NEXT_PSEUDONYM = 132
3936EAP_SIM_AT_NEXT_REAUTH_ID = 133
3937EAP_SIM_AT_CHECKCODE = 134
3938EAP_SIM_AT_RESULT_IND = 135
3939EAP_SIM_AT_BIDDING = 136
3940
3941def test_eap_proto_aka(dev, apdev):
3942    """EAP-AKA protocol tests"""
3943    def aka_handler(ctx, req):
3944        logger.info("aka_handler - RX " + binascii.hexlify(req).decode())
3945        if 'num' not in ctx:
3946            ctx['num'] = 0
3947        ctx['num'] = ctx['num'] + 1
3948        if 'id' not in ctx:
3949            ctx['id'] = 1
3950        ctx['id'] = (ctx['id'] + 1) % 256
3951
3952        idx = 0
3953
3954        idx += 1
3955        if ctx['num'] == idx:
3956            logger.info("Test: Missing payload")
3957            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
3958                               4 + 1,
3959                               EAP_TYPE_AKA)
3960
3961        idx += 1
3962        if ctx['num'] == idx:
3963            logger.info("Test: Unknown subtype")
3964            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
3965                               4 + 1 + 3,
3966                               EAP_TYPE_AKA, 255, 0)
3967        idx += 1
3968        if ctx['num'] == idx:
3969            logger.info("Test: EAP-Failure")
3970            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
3971
3972        idx += 1
3973        if ctx['num'] == idx:
3974            logger.info("Test: Client Error")
3975            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
3976                               4 + 1 + 3,
3977                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CLIENT_ERROR, 0)
3978        idx += 1
3979        if ctx['num'] == idx:
3980            logger.info("Test: EAP-Failure")
3981            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
3982
3983        idx += 1
3984        if ctx['num'] == idx:
3985            logger.info("Test: Too short attribute header")
3986            return struct.pack(">BBHBBHB", EAP_CODE_REQUEST, ctx['id'],
3987                               4 + 1 + 1 + 3,
3988                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0, 255)
3989        idx += 1
3990        if ctx['num'] == idx:
3991            logger.info("Test: EAP-Failure")
3992            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
3993
3994        idx += 1
3995        if ctx['num'] == idx:
3996            logger.info("Test: Truncated attribute")
3997            return struct.pack(">BBHBBHBB", EAP_CODE_REQUEST, ctx['id'],
3998                               4 + 1 + 1 + 4,
3999                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0, 255,
4000                               255)
4001        idx += 1
4002        if ctx['num'] == idx:
4003            logger.info("Test: EAP-Failure")
4004            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4005
4006        idx += 1
4007        if ctx['num'] == idx:
4008            logger.info("Test: Too short attribute data")
4009            return struct.pack(">BBHBBHBB", EAP_CODE_REQUEST, ctx['id'],
4010                               4 + 1 + 1 + 4,
4011                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0, 255,
4012                               0)
4013        idx += 1
4014        if ctx['num'] == idx:
4015            logger.info("Test: EAP-Failure")
4016            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4017
4018        idx += 1
4019        if ctx['num'] == idx:
4020            logger.info("Test: Skippable/non-skippable unrecognzized attribute")
4021            return struct.pack(">BBHBBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4022                               4 + 1 + 1 + 10,
4023                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4024                               255, 1, 0, 127, 1, 0)
4025        idx += 1
4026        if ctx['num'] == idx:
4027            logger.info("Test: EAP-Failure")
4028            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4029
4030        idx += 1
4031        if ctx['num'] == idx:
4032            logger.info("Test: Identity request without ID type")
4033            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
4034                               4 + 1 + 3,
4035                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0)
4036        idx += 1
4037        if ctx['num'] == idx:
4038            logger.info("Test: Identity request ANY_ID")
4039            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4040                               4 + 1 + 3 + 4,
4041                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4042                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
4043        idx += 1
4044        if ctx['num'] == idx:
4045            logger.info("Test: Identity request ANY_ID (duplicate)")
4046            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4047                               4 + 1 + 3 + 4,
4048                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4049                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
4050        idx += 1
4051        if ctx['num'] == idx:
4052            logger.info("Test: EAP-Failure")
4053            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4054
4055        idx += 1
4056        if ctx['num'] == idx:
4057            logger.info("Test: Identity request ANY_ID")
4058            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4059                               4 + 1 + 3 + 4,
4060                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4061                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
4062        idx += 1
4063        if ctx['num'] == idx:
4064            logger.info("Test: Identity request FULLAUTH_ID")
4065            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4066                               4 + 1 + 3 + 4,
4067                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4068                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
4069        idx += 1
4070        if ctx['num'] == idx:
4071            logger.info("Test: Identity request FULLAUTH_ID (duplicate)")
4072            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4073                               4 + 1 + 3 + 4,
4074                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4075                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
4076        idx += 1
4077        if ctx['num'] == idx:
4078            logger.info("Test: EAP-Failure")
4079            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4080
4081        idx += 1
4082        if ctx['num'] == idx:
4083            logger.info("Test: Identity request ANY_ID")
4084            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4085                               4 + 1 + 3 + 4,
4086                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4087                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
4088        idx += 1
4089        if ctx['num'] == idx:
4090            logger.info("Test: Identity request FULLAUTH_ID")
4091            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4092                               4 + 1 + 3 + 4,
4093                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4094                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
4095        idx += 1
4096        if ctx['num'] == idx:
4097            logger.info("Test: Identity request PERMANENT_ID")
4098            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4099                               4 + 1 + 3 + 4,
4100                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4101                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
4102        idx += 1
4103        if ctx['num'] == idx:
4104            logger.info("Test: Identity request PERMANENT_ID (duplicate)")
4105            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4106                               4 + 1 + 3 + 4,
4107                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4108                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
4109        idx += 1
4110        if ctx['num'] == idx:
4111            logger.info("Test: EAP-Failure")
4112            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4113
4114        idx += 1
4115        if ctx['num'] == idx:
4116            logger.info("Test: Challenge with no attributes")
4117            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
4118                               4 + 1 + 3,
4119                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0)
4120        idx += 1
4121        if ctx['num'] == idx:
4122            logger.info("Test: EAP-Failure")
4123            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4124
4125        idx += 1
4126        if ctx['num'] == idx:
4127            logger.info("Test: AKA Challenge with BIDDING")
4128            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4129                               4 + 1 + 3 + 4,
4130                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4131                               EAP_SIM_AT_BIDDING, 1, 0x8000)
4132        idx += 1
4133        if ctx['num'] == idx:
4134            logger.info("Test: EAP-Failure")
4135            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4136
4137        idx += 1
4138        if ctx['num'] == idx:
4139            logger.info("Test: Notification with no attributes")
4140            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
4141                               4 + 1 + 3,
4142                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0)
4143        idx += 1
4144        if ctx['num'] == idx:
4145            logger.info("Test: EAP-Failure")
4146            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4147
4148        idx += 1
4149        if ctx['num'] == idx:
4150            logger.info("Test: Notification indicating success, but no MAC")
4151            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4152                               4 + 1 + 3 + 4,
4153                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4154                               EAP_SIM_AT_NOTIFICATION, 1, 32768)
4155        idx += 1
4156        if ctx['num'] == idx:
4157            logger.info("Test: EAP-Failure")
4158            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4159
4160        idx += 1
4161        if ctx['num'] == idx:
4162            logger.info("Test: Notification indicating success, but invalid MAC value")
4163            return struct.pack(">BBHBBHBBHBBH4L", EAP_CODE_REQUEST, ctx['id'],
4164                               4 + 1 + 3 + 4 + 20,
4165                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4166                               EAP_SIM_AT_NOTIFICATION, 1, 32768,
4167                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
4168        idx += 1
4169        if ctx['num'] == idx:
4170            logger.info("Test: EAP-Failure")
4171            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4172
4173        idx += 1
4174        if ctx['num'] == idx:
4175            logger.info("Test: Notification indicating success with zero-key MAC")
4176            return struct.pack(">BBHBBHBBHBBH16B", EAP_CODE_REQUEST,
4177                               ctx['id'] - 2,
4178                               4 + 1 + 3 + 4 + 20,
4179                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4180                               EAP_SIM_AT_NOTIFICATION, 1, 32768,
4181                               EAP_SIM_AT_MAC, 5, 0,
4182                               0xbe, 0x2e, 0xbb, 0xa9, 0xfa, 0x2e, 0x82, 0x36,
4183                               0x37, 0x8c, 0x32, 0x41, 0xb7, 0xc7, 0x58, 0xa3)
4184        idx += 1
4185        if ctx['num'] == idx:
4186            logger.info("Test: EAP-Success")
4187            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
4188
4189        idx += 1
4190        if ctx['num'] == idx:
4191            logger.info("Test: Notification before auth")
4192            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4193                               4 + 1 + 3 + 4,
4194                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4195                               EAP_SIM_AT_NOTIFICATION, 1, 16384)
4196        idx += 1
4197        if ctx['num'] == idx:
4198            logger.info("Test: EAP-Failure")
4199            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4200
4201        idx += 1
4202        if ctx['num'] == idx:
4203            logger.info("Test: Notification before auth")
4204            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4205                               4 + 1 + 3 + 4,
4206                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4207                               EAP_SIM_AT_NOTIFICATION, 1, 16385)
4208        idx += 1
4209        if ctx['num'] == idx:
4210            logger.info("Test: EAP-Failure")
4211            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4212
4213        idx += 1
4214        if ctx['num'] == idx:
4215            logger.info("Test: Notification with unrecognized non-failure")
4216            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4217                               4 + 1 + 3 + 4,
4218                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4219                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
4220        idx += 1
4221        if ctx['num'] == idx:
4222            logger.info("Test: Notification before auth (duplicate)")
4223            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4224                               4 + 1 + 3 + 4,
4225                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION, 0,
4226                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
4227        idx += 1
4228        if ctx['num'] == idx:
4229            logger.info("Test: EAP-Failure")
4230            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4231
4232        idx += 1
4233        if ctx['num'] == idx:
4234            logger.info("Test: Re-authentication (unexpected) with no attributes")
4235            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
4236                               4 + 1 + 3,
4237                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_REAUTHENTICATION,
4238                               0)
4239        idx += 1
4240        if ctx['num'] == idx:
4241            logger.info("Test: EAP-Failure")
4242            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4243
4244        idx += 1
4245        if ctx['num'] == idx:
4246            logger.info("Test: AKA Challenge with Checkcode claiming identity round was used")
4247            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
4248                               4 + 1 + 3 + 24,
4249                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4250                               EAP_SIM_AT_CHECKCODE, 6, 0, 0, 0, 0, 0, 0)
4251        idx += 1
4252        if ctx['num'] == idx:
4253            logger.info("Test: EAP-Failure")
4254            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4255
4256        idx += 1
4257        if ctx['num'] == idx:
4258            logger.info("Test: Identity request ANY_ID")
4259            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4260                               4 + 1 + 3 + 4,
4261                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4262                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
4263        idx += 1
4264        if ctx['num'] == idx:
4265            logger.info("Test: AKA Challenge with Checkcode claiming no identity round was used")
4266            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4267                               4 + 1 + 3 + 4,
4268                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4269                               EAP_SIM_AT_CHECKCODE, 1, 0)
4270        idx += 1
4271        if ctx['num'] == idx:
4272            logger.info("Test: EAP-Failure")
4273            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4274
4275        idx += 1
4276        if ctx['num'] == idx:
4277            logger.info("Test: Identity request ANY_ID")
4278            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4279                               4 + 1 + 3 + 4,
4280                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4281                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
4282        idx += 1
4283        if ctx['num'] == idx:
4284            logger.info("Test: AKA Challenge with mismatching Checkcode value")
4285            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
4286                               4 + 1 + 3 + 24,
4287                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4288                               EAP_SIM_AT_CHECKCODE, 6, 0, 0, 0, 0, 0, 0)
4289        idx += 1
4290        if ctx['num'] == idx:
4291            logger.info("Test: EAP-Failure")
4292            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4293
4294        idx += 1
4295        if ctx['num'] == idx:
4296            logger.info("Test: Re-authentication (unexpected) with Checkcode claimin identity round was used")
4297            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
4298                               4 + 1 + 3 + 24,
4299                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_REAUTHENTICATION,
4300                               0,
4301                               EAP_SIM_AT_CHECKCODE, 6, 0, 0, 0, 0, 0, 0)
4302        idx += 1
4303        if ctx['num'] == idx:
4304            logger.info("Test: EAP-Failure")
4305            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4306
4307        idx += 1
4308        if ctx['num'] == idx:
4309            logger.info("Test: Invalid AT_RAND length")
4310            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4311                               4 + 1 + 3 + 4,
4312                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4313                               EAP_SIM_AT_RAND, 1, 0)
4314        idx += 1
4315        if ctx['num'] == idx:
4316            logger.info("Test: EAP-Failure")
4317            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4318
4319        idx += 1
4320        if ctx['num'] == idx:
4321            logger.info("Test: Invalid AT_AUTN length")
4322            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4323                               4 + 1 + 3 + 4,
4324                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4325                               EAP_SIM_AT_AUTN, 1, 0)
4326        idx += 1
4327        if ctx['num'] == idx:
4328            logger.info("Test: EAP-Failure")
4329            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4330
4331        idx += 1
4332        if ctx['num'] == idx:
4333            logger.info("Test: Unencrypted AT_PADDING")
4334            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4335                               4 + 1 + 3 + 4,
4336                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4337                               EAP_SIM_AT_PADDING, 1, 0)
4338        idx += 1
4339        if ctx['num'] == idx:
4340            logger.info("Test: EAP-Failure")
4341            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4342
4343        idx += 1
4344        if ctx['num'] == idx:
4345            logger.info("Test: Invalid AT_NONCE_MT length")
4346            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4347                               4 + 1 + 3 + 4,
4348                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4349                               EAP_SIM_AT_NONCE_MT, 1, 0)
4350        idx += 1
4351        if ctx['num'] == idx:
4352            logger.info("Test: EAP-Failure")
4353            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4354
4355        idx += 1
4356        if ctx['num'] == idx:
4357            logger.info("Test: Invalid AT_MAC length")
4358            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4359                               4 + 1 + 3 + 4,
4360                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4361                               EAP_SIM_AT_MAC, 1, 0)
4362        idx += 1
4363        if ctx['num'] == idx:
4364            logger.info("Test: EAP-Failure")
4365            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4366
4367        idx += 1
4368        if ctx['num'] == idx:
4369            logger.info("Test: Invalid AT_NOTIFICATION length")
4370            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4371                               4 + 1 + 3 + 8,
4372                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4373                               EAP_SIM_AT_NOTIFICATION, 2, 0, 0)
4374        idx += 1
4375        if ctx['num'] == idx:
4376            logger.info("Test: EAP-Failure")
4377            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4378
4379        idx += 1
4380        if ctx['num'] == idx:
4381            logger.info("Test: AT_IDENTITY overflow")
4382            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4383                               4 + 1 + 3 + 4,
4384                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4385                               EAP_SIM_AT_IDENTITY, 1, 0xffff)
4386        idx += 1
4387        if ctx['num'] == idx:
4388            logger.info("Test: EAP-Failure")
4389            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4390
4391        idx += 1
4392        if ctx['num'] == idx:
4393            logger.info("Test: Unexpected AT_VERSION_LIST")
4394            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4395                               4 + 1 + 3 + 4,
4396                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4397                               EAP_SIM_AT_VERSION_LIST, 1, 0)
4398        idx += 1
4399        if ctx['num'] == idx:
4400            logger.info("Test: EAP-Failure")
4401            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4402
4403        idx += 1
4404        if ctx['num'] == idx:
4405            logger.info("Test: Invalid AT_SELECTED_VERSION length")
4406            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4407                               4 + 1 + 3 + 8,
4408                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4409                               EAP_SIM_AT_SELECTED_VERSION, 2, 0, 0)
4410        idx += 1
4411        if ctx['num'] == idx:
4412            logger.info("Test: EAP-Failure")
4413            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4414
4415        idx += 1
4416        if ctx['num'] == idx:
4417            logger.info("Test: Unencrypted AT_COUNTER")
4418            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4419                               4 + 1 + 3 + 4,
4420                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4421                               EAP_SIM_AT_COUNTER, 1, 0)
4422        idx += 1
4423        if ctx['num'] == idx:
4424            logger.info("Test: EAP-Failure")
4425            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4426
4427        idx += 1
4428        if ctx['num'] == idx:
4429            logger.info("Test: Unencrypted AT_COUNTER_TOO_SMALL")
4430            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4431                               4 + 1 + 3 + 4,
4432                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4433                               EAP_SIM_AT_COUNTER_TOO_SMALL, 1, 0)
4434        idx += 1
4435        if ctx['num'] == idx:
4436            logger.info("Test: EAP-Failure")
4437            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4438
4439        idx += 1
4440        if ctx['num'] == idx:
4441            logger.info("Test: Unencrypted AT_NONCE_S")
4442            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4443                               4 + 1 + 3 + 4,
4444                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4445                               EAP_SIM_AT_NONCE_S, 1, 0)
4446        idx += 1
4447        if ctx['num'] == idx:
4448            logger.info("Test: EAP-Failure")
4449            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4450
4451        idx += 1
4452        if ctx['num'] == idx:
4453            logger.info("Test: Invalid AT_CLIENT_ERROR_CODE length")
4454            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4455                               4 + 1 + 3 + 8,
4456                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4457                               EAP_SIM_AT_CLIENT_ERROR_CODE, 2, 0, 0)
4458        idx += 1
4459        if ctx['num'] == idx:
4460            logger.info("Test: EAP-Failure")
4461            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4462
4463        idx += 1
4464        if ctx['num'] == idx:
4465            logger.info("Test: Invalid AT_IV length")
4466            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4467                               4 + 1 + 3 + 4,
4468                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4469                               EAP_SIM_AT_IV, 1, 0)
4470        idx += 1
4471        if ctx['num'] == idx:
4472            logger.info("Test: EAP-Failure")
4473            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4474
4475        idx += 1
4476        if ctx['num'] == idx:
4477            logger.info("Test: Invalid AT_ENCR_DATA length")
4478            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4479                               4 + 1 + 3 + 8,
4480                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4481                               EAP_SIM_AT_ENCR_DATA, 2, 0, 0)
4482        idx += 1
4483        if ctx['num'] == idx:
4484            logger.info("Test: EAP-Failure")
4485            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4486
4487        idx += 1
4488        if ctx['num'] == idx:
4489            logger.info("Test: Unencrypted AT_NEXT_PSEUDONYM")
4490            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4491                               4 + 1 + 3 + 4,
4492                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4493                               EAP_SIM_AT_NEXT_PSEUDONYM, 1, 0)
4494        idx += 1
4495        if ctx['num'] == idx:
4496            logger.info("Test: EAP-Failure")
4497            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4498
4499        idx += 1
4500        if ctx['num'] == idx:
4501            logger.info("Test: Unencrypted AT_NEXT_REAUTH_ID")
4502            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4503                               4 + 1 + 3 + 4,
4504                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4505                               EAP_SIM_AT_NEXT_REAUTH_ID, 1, 0)
4506        idx += 1
4507        if ctx['num'] == idx:
4508            logger.info("Test: EAP-Failure")
4509            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4510
4511        idx += 1
4512        if ctx['num'] == idx:
4513            logger.info("Test: Invalid AT_RES length")
4514            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4515                               4 + 1 + 3 + 4,
4516                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4517                               EAP_SIM_AT_RES, 1, 0)
4518        idx += 1
4519        if ctx['num'] == idx:
4520            logger.info("Test: EAP-Failure")
4521            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4522
4523        idx += 1
4524        if ctx['num'] == idx:
4525            logger.info("Test: Invalid AT_RES length")
4526            return struct.pack(">BBHBBHBBH5L", EAP_CODE_REQUEST, ctx['id'],
4527                               4 + 1 + 3 + 24,
4528                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4529                               EAP_SIM_AT_RES, 6, 0xffff, 0, 0, 0, 0, 0)
4530        idx += 1
4531        if ctx['num'] == idx:
4532            logger.info("Test: EAP-Failure")
4533            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4534
4535        idx += 1
4536        if ctx['num'] == idx:
4537            logger.info("Test: Invalid AT_AUTS length")
4538            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4539                               4 + 1 + 3 + 8,
4540                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4541                               EAP_SIM_AT_AUTS, 2, 0, 0)
4542        idx += 1
4543        if ctx['num'] == idx:
4544            logger.info("Test: EAP-Failure")
4545            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4546
4547        idx += 1
4548        if ctx['num'] == idx:
4549            logger.info("Test: Invalid AT_CHECKCODE length")
4550            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4551                               4 + 1 + 3 + 8,
4552                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4553                               EAP_SIM_AT_CHECKCODE, 2, 0, 0)
4554        idx += 1
4555        if ctx['num'] == idx:
4556            logger.info("Test: EAP-Failure")
4557            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4558
4559        idx += 1
4560        if ctx['num'] == idx:
4561            logger.info("Test: Invalid AT_RESULT_IND length")
4562            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4563                               4 + 1 + 3 + 8,
4564                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4565                               EAP_SIM_AT_RESULT_IND, 2, 0, 0)
4566        idx += 1
4567        if ctx['num'] == idx:
4568            logger.info("Test: EAP-Failure")
4569            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4570
4571        idx += 1
4572        if ctx['num'] == idx:
4573            logger.info("Test: Unexpected AT_KDF_INPUT")
4574            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4575                               4 + 1 + 3 + 8,
4576                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4577                               EAP_SIM_AT_KDF_INPUT, 2, 0, 0)
4578        idx += 1
4579        if ctx['num'] == idx:
4580            logger.info("Test: EAP-Failure")
4581            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4582
4583        idx += 1
4584        if ctx['num'] == idx:
4585            logger.info("Test: Unexpected AT_KDF")
4586            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4587                               4 + 1 + 3 + 8,
4588                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4589                               EAP_SIM_AT_KDF, 2, 0, 0)
4590        idx += 1
4591        if ctx['num'] == idx:
4592            logger.info("Test: EAP-Failure")
4593            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4594
4595        idx += 1
4596        if ctx['num'] == idx:
4597            logger.info("Test: Invalid AT_BIDDING length")
4598            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4599                               4 + 1 + 3 + 8,
4600                               EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY, 0,
4601                               EAP_SIM_AT_BIDDING, 2, 0, 0)
4602        idx += 1
4603        if ctx['num'] == idx:
4604            logger.info("Test: EAP-Failure")
4605            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4606
4607        return None
4608
4609    srv = start_radius_server(aka_handler)
4610
4611    try:
4612        hapd = start_ap(apdev[0])
4613        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
4614
4615        for i in range(0, 49):
4616            eap = "AKA AKA'" if i == 11 else "AKA"
4617            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
4618                           eap=eap, identity="0232010000000000",
4619                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
4620                           wait_connect=False)
4621            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
4622                                   timeout=15)
4623            if ev is None:
4624                raise Exception("Timeout on EAP start")
4625            if i in [0, 15]:
4626                time.sleep(0.1)
4627            else:
4628                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
4629                                       timeout=10)
4630                if ev is None:
4631                    raise Exception("Timeout on EAP failure")
4632            dev[0].request("REMOVE_NETWORK all")
4633            dev[0].dump_monitor()
4634    finally:
4635        stop_radius_server(srv)
4636
4637def test_eap_proto_aka_prime(dev, apdev):
4638    """EAP-AKA' protocol tests"""
4639    def aka_prime_handler(ctx, req):
4640        logger.info("aka_prime_handler - RX " + binascii.hexlify(req).decode())
4641        if 'num' not in ctx:
4642            ctx['num'] = 0
4643        ctx['num'] = ctx['num'] + 1
4644        if 'id' not in ctx:
4645            ctx['id'] = 1
4646        ctx['id'] = (ctx['id'] + 1) % 256
4647
4648        idx = 0
4649
4650        idx += 1
4651        if ctx['num'] == idx:
4652            logger.info("Test: Missing payload")
4653            dev[0].note("Missing payload")
4654            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
4655                               4 + 1,
4656                               EAP_TYPE_AKA_PRIME)
4657
4658        idx += 1
4659        if ctx['num'] == idx:
4660            logger.info("Test: Challenge with no attributes")
4661            dev[0].note("Challenge with no attributes")
4662            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
4663                               4 + 1 + 3,
4664                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0)
4665        idx += 1
4666        if ctx['num'] == idx:
4667            logger.info("Test: EAP-Failure")
4668            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4669
4670        idx += 1
4671        if ctx['num'] == idx:
4672            logger.info("Test: Challenge with empty AT_KDF_INPUT")
4673            dev[0].note("Challenge with empty AT_KDF_INPUT")
4674            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
4675                               4 + 1 + 3 + 4,
4676                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4677                               EAP_SIM_AT_KDF_INPUT, 1, 0)
4678        idx += 1
4679        if ctx['num'] == idx:
4680            logger.info("Test: EAP-Failure")
4681            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4682
4683        idx += 1
4684        if ctx['num'] == idx:
4685            logger.info("Test: Challenge with AT_KDF_INPUT")
4686            dev[0].note("Test: Challenge with AT_KDF_INPUT")
4687            return struct.pack(">BBHBBHBBHBBBB", EAP_CODE_REQUEST, ctx['id'],
4688                               4 + 1 + 3 + 8,
4689                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4690                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4691                               ord('c'), ord('d'))
4692        idx += 1
4693        if ctx['num'] == idx:
4694            logger.info("Test: EAP-Failure")
4695            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4696
4697        idx += 1
4698        if ctx['num'] == idx:
4699            logger.info("Test: Challenge with duplicated KDF")
4700            dev[0].note("Challenge with duplicated KDF")
4701            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
4702                               EAP_CODE_REQUEST, ctx['id'],
4703                               4 + 1 + 3 + 8 + 3 * 4,
4704                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4705                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4706                               ord('c'), ord('d'),
4707                               EAP_SIM_AT_KDF, 1, 1,
4708                               EAP_SIM_AT_KDF, 1, 2,
4709                               EAP_SIM_AT_KDF, 1, 1)
4710        idx += 1
4711        if ctx['num'] == idx:
4712            logger.info("Test: EAP-Failure")
4713            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4714
4715        idx += 1
4716        if ctx['num'] == idx:
4717            logger.info("Test: Challenge with multiple KDF proposals")
4718            dev[0].note("Challenge with multiple KDF proposals (preparation)")
4719            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
4720                               EAP_CODE_REQUEST, ctx['id'],
4721                               4 + 1 + 3 + 8 + 3 * 4,
4722                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4723                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4724                               ord('c'), ord('d'),
4725                               EAP_SIM_AT_KDF, 1, 255,
4726                               EAP_SIM_AT_KDF, 1, 254,
4727                               EAP_SIM_AT_KDF, 1, 1)
4728        idx += 1
4729        if ctx['num'] == idx:
4730            logger.info("Test: Challenge with incorrect KDF selected")
4731            dev[0].note("Challenge with incorrect KDF selected")
4732            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBH",
4733                               EAP_CODE_REQUEST, ctx['id'],
4734                               4 + 1 + 3 + 8 + 4 * 4,
4735                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4736                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4737                               ord('c'), ord('d'),
4738                               EAP_SIM_AT_KDF, 1, 255,
4739                               EAP_SIM_AT_KDF, 1, 255,
4740                               EAP_SIM_AT_KDF, 1, 254,
4741                               EAP_SIM_AT_KDF, 1, 1)
4742        idx += 1
4743        if ctx['num'] == idx:
4744            logger.info("Test: EAP-Failure")
4745            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4746
4747        idx += 1
4748        if ctx['num'] == idx:
4749            logger.info("Test: Challenge with multiple KDF proposals")
4750            dev[0].note("Challenge with multiple KDF proposals (preparation)")
4751            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
4752                               EAP_CODE_REQUEST, ctx['id'],
4753                               4 + 1 + 3 + 8 + 3 * 4,
4754                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4755                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4756                               ord('c'), ord('d'),
4757                               EAP_SIM_AT_KDF, 1, 255,
4758                               EAP_SIM_AT_KDF, 1, 254,
4759                               EAP_SIM_AT_KDF, 1, 1)
4760        idx += 1
4761        if ctx['num'] == idx:
4762            logger.info("Test: Challenge with selected KDF not duplicated")
4763            dev[0].note("Challenge with selected KDF not duplicated")
4764            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
4765                               EAP_CODE_REQUEST, ctx['id'],
4766                               4 + 1 + 3 + 8 + 3 * 4,
4767                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4768                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4769                               ord('c'), ord('d'),
4770                               EAP_SIM_AT_KDF, 1, 1,
4771                               EAP_SIM_AT_KDF, 1, 255,
4772                               EAP_SIM_AT_KDF, 1, 254)
4773        idx += 1
4774        if ctx['num'] == idx:
4775            logger.info("Test: EAP-Failure")
4776            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4777
4778        idx += 1
4779        if ctx['num'] == idx:
4780            logger.info("Test: Challenge with multiple KDF proposals")
4781            dev[0].note("Challenge with multiple KDF proposals (preparation)")
4782            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
4783                               EAP_CODE_REQUEST, ctx['id'],
4784                               4 + 1 + 3 + 8 + 3 * 4,
4785                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4786                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4787                               ord('c'), ord('d'),
4788                               EAP_SIM_AT_KDF, 1, 255,
4789                               EAP_SIM_AT_KDF, 1, 254,
4790                               EAP_SIM_AT_KDF, 1, 1)
4791        idx += 1
4792        if ctx['num'] == idx:
4793            logger.info("Test: Challenge with selected KDF duplicated (missing MAC, RAND, AUTN)")
4794            dev[0].note("Challenge with selected KDF duplicated (missing MAC, RAND, AUTN)")
4795            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBH",
4796                               EAP_CODE_REQUEST, ctx['id'],
4797                               4 + 1 + 3 + 8 + 4 * 4,
4798                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4799                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4800                               ord('c'), ord('d'),
4801                               EAP_SIM_AT_KDF, 1, 1,
4802                               EAP_SIM_AT_KDF, 1, 255,
4803                               EAP_SIM_AT_KDF, 1, 254,
4804                               EAP_SIM_AT_KDF, 1, 1)
4805        idx += 1
4806        if ctx['num'] == idx:
4807            logger.info("Test: EAP-Failure")
4808            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4809
4810        idx += 1
4811        if ctx['num'] == idx:
4812            logger.info("Test: Challenge with multiple unsupported KDF proposals")
4813            dev[0].note("Challenge with multiple unsupported KDF proposals")
4814            return struct.pack(">BBHBBHBBHBBBBBBHBBH",
4815                               EAP_CODE_REQUEST, ctx['id'],
4816                               4 + 1 + 3 + 8 + 2 * 4,
4817                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4818                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4819                               ord('c'), ord('d'),
4820                               EAP_SIM_AT_KDF, 1, 255,
4821                               EAP_SIM_AT_KDF, 1, 254)
4822        idx += 1
4823        if ctx['num'] == idx:
4824            logger.info("Test: EAP-Failure")
4825            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4826
4827        idx += 1
4828        if ctx['num'] == idx:
4829            logger.info("Test: Challenge with multiple KDF proposals")
4830            dev[0].note("Challenge with multiple KDF proposals (preparation)")
4831            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
4832                               EAP_CODE_REQUEST, ctx['id'],
4833                               4 + 1 + 3 + 8 + 3 * 4,
4834                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4835                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4836                               ord('c'), ord('d'),
4837                               EAP_SIM_AT_KDF, 1, 255,
4838                               EAP_SIM_AT_KDF, 1, 254,
4839                               EAP_SIM_AT_KDF, 1, 1)
4840        idx += 1
4841        if ctx['num'] == idx:
4842            logger.info("Test: Challenge with invalid MAC, RAND, AUTN values)")
4843            dev[0].note("Challenge with invalid MAC, RAND, AUTN values)")
4844            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBHBBH4LBBH4LBBH4L",
4845                               EAP_CODE_REQUEST, ctx['id'],
4846                               4 + 1 + 3 + 8 + 4 * 4 + 20 + 20 + 20,
4847                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4848                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4849                               ord('c'), ord('d'),
4850                               EAP_SIM_AT_KDF, 1, 1,
4851                               EAP_SIM_AT_KDF, 1, 255,
4852                               EAP_SIM_AT_KDF, 1, 254,
4853                               EAP_SIM_AT_KDF, 1, 1,
4854                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0,
4855                               EAP_SIM_AT_RAND, 5, 0, 0, 0, 0, 0,
4856                               EAP_SIM_AT_AUTN, 5, 0, 0, 0, 0, 0)
4857        idx += 1
4858        if ctx['num'] == idx:
4859            logger.info("Test: EAP-Failure")
4860            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4861
4862        idx += 1
4863        if ctx['num'] == idx:
4864            logger.info("Test: Challenge - AMF separation bit not set)")
4865            dev[0].note("Challenge - AMF separation bit not set)")
4866            return struct.pack(">BBHBBHBBHBBBBBBHBBH4LBBH4LBBH4L",
4867                               EAP_CODE_REQUEST, ctx['id'],
4868                               4 + 1 + 3 + 8 + 4 + 20 + 20 + 20,
4869                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4870                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4871                               ord('c'), ord('d'),
4872                               EAP_SIM_AT_KDF, 1, 1,
4873                               EAP_SIM_AT_MAC, 5, 0, 1, 2, 3, 4,
4874                               EAP_SIM_AT_RAND, 5, 0, 5, 6, 7, 8,
4875                               EAP_SIM_AT_AUTN, 5, 0, 9, 10,
4876                               0x2fda8ef7, 0xbba518cc)
4877        idx += 1
4878        if ctx['num'] == idx:
4879            logger.info("Test: EAP-Failure")
4880            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4881
4882        idx += 1
4883        if ctx['num'] == idx:
4884            logger.info("Test: Challenge - Invalid MAC")
4885            dev[0].note("Challenge - Invalid MAC")
4886            return struct.pack(">BBHBBHBBHBBBBBBHBBH4LBBH4LBBH4L",
4887                               EAP_CODE_REQUEST, ctx['id'],
4888                               4 + 1 + 3 + 8 + 4 + 20 + 20 + 20,
4889                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4890                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4891                               ord('c'), ord('d'),
4892                               EAP_SIM_AT_KDF, 1, 1,
4893                               EAP_SIM_AT_MAC, 5, 0, 1, 2, 3, 4,
4894                               EAP_SIM_AT_RAND, 5, 0, 5, 6, 7, 8,
4895                               EAP_SIM_AT_AUTN, 5, 0, 0xffffffff, 0xffffffff,
4896                               0xd1f90322, 0x40514cb4)
4897        idx += 1
4898        if ctx['num'] == idx:
4899            logger.info("Test: EAP-Failure")
4900            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4901
4902        idx += 1
4903        if ctx['num'] == idx:
4904            logger.info("Test: Challenge - Valid MAC")
4905            dev[0].note("Challenge - Valid MAC")
4906            return struct.pack(">BBHBBHBBHBBBBBBHBBH4LBBH4LBBH4L",
4907                               EAP_CODE_REQUEST, ctx['id'],
4908                               4 + 1 + 3 + 8 + 4 + 20 + 20 + 20,
4909                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4910                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4911                               ord('c'), ord('d'),
4912                               EAP_SIM_AT_KDF, 1, 1,
4913                               EAP_SIM_AT_MAC, 5, 0,
4914                               0xf4a3c1d3, 0x7c901401, 0x34bd8b01, 0x6f7fa32f,
4915                               EAP_SIM_AT_RAND, 5, 0, 5, 6, 7, 8,
4916                               EAP_SIM_AT_AUTN, 5, 0, 0xffffffff, 0xffffffff,
4917                               0xd1f90322, 0x40514cb4)
4918        idx += 1
4919        if ctx['num'] == idx:
4920            logger.info("Test: EAP-Failure")
4921            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4922
4923        idx += 1
4924        if ctx['num'] == idx:
4925            logger.info("Test: Invalid AT_KDF_INPUT length")
4926            dev[0].note("Invalid AT_KDF_INPUT length")
4927            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4928                               4 + 1 + 3 + 8,
4929                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_IDENTITY, 0,
4930                               EAP_SIM_AT_KDF_INPUT, 2, 0xffff, 0)
4931        idx += 1
4932        if ctx['num'] == idx:
4933            logger.info("Test: EAP-Failure")
4934            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4935
4936        idx += 1
4937        if ctx['num'] == idx:
4938            logger.info("Test: Invalid AT_KDF length")
4939            dev[0].note("Invalid AT_KDF length")
4940            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
4941                               4 + 1 + 3 + 8,
4942                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_IDENTITY, 0,
4943                               EAP_SIM_AT_KDF, 2, 0, 0)
4944        idx += 1
4945        if ctx['num'] == idx:
4946            logger.info("Test: EAP-Failure")
4947            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4948
4949        idx += 1
4950        if ctx['num'] == idx:
4951            logger.info("Test: Challenge with large number of KDF proposals")
4952            dev[0].note("Challenge with large number of KDF proposals")
4953            return struct.pack(">BBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBHBBH",
4954                               EAP_CODE_REQUEST, ctx['id'],
4955                               4 + 1 + 3 + 12 * 4,
4956                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4957                               EAP_SIM_AT_KDF, 1, 255,
4958                               EAP_SIM_AT_KDF, 1, 254,
4959                               EAP_SIM_AT_KDF, 1, 253,
4960                               EAP_SIM_AT_KDF, 1, 252,
4961                               EAP_SIM_AT_KDF, 1, 251,
4962                               EAP_SIM_AT_KDF, 1, 250,
4963                               EAP_SIM_AT_KDF, 1, 249,
4964                               EAP_SIM_AT_KDF, 1, 248,
4965                               EAP_SIM_AT_KDF, 1, 247,
4966                               EAP_SIM_AT_KDF, 1, 246,
4967                               EAP_SIM_AT_KDF, 1, 245,
4968                               EAP_SIM_AT_KDF, 1, 244)
4969        idx += 1
4970        if ctx['num'] == idx:
4971            logger.info("Test: EAP-Failure")
4972            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
4973
4974        idx += 1
4975        if ctx['num'] == idx:
4976            logger.info("Test: Challenge with multiple KDF proposals")
4977            dev[0].note("Challenge with multiple KDF proposals (preparation)")
4978            return struct.pack(">BBHBBHBBHBBBBBBHBBH",
4979                               EAP_CODE_REQUEST, ctx['id'],
4980                               4 + 1 + 3 + 8 + 2 * 4,
4981                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4982                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4983                               ord('c'), ord('d'),
4984                               EAP_SIM_AT_KDF, 1, 2,
4985                               EAP_SIM_AT_KDF, 1, 1)
4986        idx += 1
4987        if ctx['num'] == idx:
4988            logger.info("Test: Challenge with an extra KDF appended")
4989            dev[0].note("Challenge with an extra KDF appended")
4990            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBHBBH",
4991                               EAP_CODE_REQUEST, ctx['id'],
4992                               4 + 1 + 3 + 8 + 4 * 4,
4993                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
4994                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
4995                               ord('c'), ord('d'),
4996                               EAP_SIM_AT_KDF, 1, 1,
4997                               EAP_SIM_AT_KDF, 1, 2,
4998                               EAP_SIM_AT_KDF, 1, 1,
4999                               EAP_SIM_AT_KDF, 1, 0)
5000        idx += 1
5001        if ctx['num'] == idx:
5002            logger.info("Test: EAP-Failure")
5003            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5004
5005        idx += 1
5006        if ctx['num'] == idx:
5007            logger.info("Test: Challenge with multiple KDF proposals")
5008            dev[0].note("Challenge with multiple KDF proposals (preparation)")
5009            return struct.pack(">BBHBBHBBHBBBBBBHBBH",
5010                               EAP_CODE_REQUEST, ctx['id'],
5011                               4 + 1 + 3 + 8 + 2 * 4,
5012                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
5013                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
5014                               ord('c'), ord('d'),
5015                               EAP_SIM_AT_KDF, 1, 2,
5016                               EAP_SIM_AT_KDF, 1, 1)
5017        idx += 1
5018        if ctx['num'] == idx:
5019            logger.info("Test: Challenge with a modified KDF")
5020            dev[0].note("Challenge with a modified KDF")
5021            return struct.pack(">BBHBBHBBHBBBBBBHBBHBBH",
5022                               EAP_CODE_REQUEST, ctx['id'],
5023                               4 + 1 + 3 + 8 + 3 * 4,
5024                               EAP_TYPE_AKA_PRIME, EAP_AKA_SUBTYPE_CHALLENGE, 0,
5025                               EAP_SIM_AT_KDF_INPUT, 2, 1, ord('a'), ord('b'),
5026                               ord('c'), ord('d'),
5027                               EAP_SIM_AT_KDF, 1, 1,
5028                               EAP_SIM_AT_KDF, 1, 0,
5029                               EAP_SIM_AT_KDF, 1, 1)
5030        idx += 1
5031        if ctx['num'] == idx:
5032            logger.info("Test: EAP-Failure")
5033            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5034
5035        return None
5036
5037    srv = start_radius_server(aka_prime_handler)
5038
5039    try:
5040        hapd = start_ap(apdev[0])
5041        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
5042
5043        for i in range(0, 18):
5044            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5045                           eap="AKA'", identity="6555444333222111",
5046                           password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
5047                           wait_connect=False)
5048            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
5049                                   timeout=15)
5050            if ev is None:
5051                raise Exception("Timeout on EAP start")
5052            if i in [0]:
5053                time.sleep(0.1)
5054            else:
5055                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
5056                                       timeout=10)
5057                if ev is None:
5058                    raise Exception("Timeout on EAP failure")
5059            dev[0].request("REMOVE_NETWORK all")
5060            dev[0].dump_monitor()
5061    finally:
5062        stop_radius_server(srv)
5063
5064def test_eap_proto_sim(dev, apdev):
5065    """EAP-SIM protocol tests"""
5066    def sim_handler(ctx, req):
5067        logger.info("sim_handler - RX " + binascii.hexlify(req).decode())
5068        if 'num' not in ctx:
5069            ctx['num'] = 0
5070        ctx['num'] = ctx['num'] + 1
5071        if 'id' not in ctx:
5072            ctx['id'] = 1
5073        ctx['id'] = (ctx['id'] + 1) % 256
5074
5075        idx = 0
5076
5077        idx += 1
5078        if ctx['num'] == idx:
5079            logger.info("Test: Missing payload")
5080            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
5081                               4 + 1,
5082                               EAP_TYPE_SIM)
5083
5084        idx += 1
5085        if ctx['num'] == idx:
5086            logger.info("Test: Unexpected AT_AUTN")
5087            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
5088                               4 + 1 + 3 + 8,
5089                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5090                               EAP_SIM_AT_AUTN, 2, 0, 0)
5091        idx += 1
5092        if ctx['num'] == idx:
5093            logger.info("Test: EAP-Failure")
5094            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5095
5096        idx += 1
5097        if ctx['num'] == idx:
5098            logger.info("Test: Too short AT_VERSION_LIST")
5099            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5100                               4 + 1 + 3 + 4,
5101                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5102                               EAP_SIM_AT_VERSION_LIST, 1, 0)
5103        idx += 1
5104        if ctx['num'] == idx:
5105            logger.info("Test: EAP-Failure")
5106            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5107
5108        idx += 1
5109        if ctx['num'] == idx:
5110            logger.info("Test: AT_VERSION_LIST overflow")
5111            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5112                               4 + 1 + 3 + 4,
5113                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5114                               EAP_SIM_AT_VERSION_LIST, 1, 0xffff)
5115        idx += 1
5116        if ctx['num'] == idx:
5117            logger.info("Test: EAP-Failure")
5118            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5119
5120        idx += 1
5121        if ctx['num'] == idx:
5122            logger.info("Test: Unexpected AT_AUTS")
5123            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
5124                               4 + 1 + 3 + 8,
5125                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5126                               EAP_SIM_AT_AUTS, 2, 0, 0)
5127        idx += 1
5128        if ctx['num'] == idx:
5129            logger.info("Test: EAP-Failure")
5130            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5131
5132        idx += 1
5133        if ctx['num'] == idx:
5134            logger.info("Test: Unexpected AT_CHECKCODE")
5135            return struct.pack(">BBHBBHBBHL", EAP_CODE_REQUEST, ctx['id'],
5136                               4 + 1 + 3 + 8,
5137                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5138                               EAP_SIM_AT_CHECKCODE, 2, 0, 0)
5139        idx += 1
5140        if ctx['num'] == idx:
5141            logger.info("Test: EAP-Failure")
5142            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5143
5144        idx += 1
5145        if ctx['num'] == idx:
5146            logger.info("Test: No AT_VERSION_LIST in Start")
5147            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
5148                               4 + 1 + 3,
5149                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0)
5150        idx += 1
5151        if ctx['num'] == idx:
5152            logger.info("Test: EAP-Failure")
5153            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5154
5155        idx += 1
5156        if ctx['num'] == idx:
5157            logger.info("Test: No support version in AT_VERSION_LIST")
5158            return struct.pack(">BBHBBHBBH4B", EAP_CODE_REQUEST, ctx['id'],
5159                               4 + 1 + 3 + 8,
5160                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5161                               EAP_SIM_AT_VERSION_LIST, 2, 3, 2, 3, 4, 5)
5162        idx += 1
5163        if ctx['num'] == idx:
5164            logger.info("Test: EAP-Failure")
5165            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5166
5167
5168        idx += 1
5169        if ctx['num'] == idx:
5170            logger.info("Test: Identity request without ID type")
5171            return struct.pack(">BBHBBHBBH2H", EAP_CODE_REQUEST, ctx['id'],
5172                               4 + 1 + 3 + 8,
5173                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5174                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0)
5175        idx += 1
5176        if ctx['num'] == idx:
5177            logger.info("Test: Identity request ANY_ID")
5178            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5179                               4 + 1 + 3 + 8 + 4,
5180                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5181                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5182                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
5183        idx += 1
5184        if ctx['num'] == idx:
5185            logger.info("Test: Identity request ANY_ID (duplicate)")
5186            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5187                               4 + 1 + 3 + 8 + 4,
5188                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5189                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5190                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
5191        idx += 1
5192        if ctx['num'] == idx:
5193            logger.info("Test: EAP-Failure")
5194            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5195
5196        idx += 1
5197        if ctx['num'] == idx:
5198            logger.info("Test: Identity request ANY_ID")
5199            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5200                               4 + 1 + 3 + 8 + 4,
5201                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5202                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5203                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
5204        idx += 1
5205        if ctx['num'] == idx:
5206            logger.info("Test: Identity request FULLAUTH_ID")
5207            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5208                               4 + 1 + 3 + 8 + 4,
5209                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5210                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5211                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
5212        idx += 1
5213        if ctx['num'] == idx:
5214            logger.info("Test: Identity request FULLAUTH_ID (duplicate)")
5215            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5216                               4 + 1 + 3 + 8 + 4,
5217                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5218                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5219                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
5220        idx += 1
5221        if ctx['num'] == idx:
5222            logger.info("Test: EAP-Failure")
5223            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5224
5225        idx += 1
5226        if ctx['num'] == idx:
5227            logger.info("Test: Identity request ANY_ID")
5228            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5229                               4 + 1 + 3 + 8 + 4,
5230                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5231                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5232                               EAP_SIM_AT_ANY_ID_REQ, 1, 0)
5233        idx += 1
5234        if ctx['num'] == idx:
5235            logger.info("Test: Identity request FULLAUTH_ID")
5236            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5237                               4 + 1 + 3 + 8 + 4,
5238                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5239                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5240                               EAP_SIM_AT_FULLAUTH_ID_REQ, 1, 0)
5241        idx += 1
5242        if ctx['num'] == idx:
5243            logger.info("Test: Identity request PERMANENT_ID")
5244            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5245                               4 + 1 + 3 + 8 + 4,
5246                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5247                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5248                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
5249        idx += 1
5250        if ctx['num'] == idx:
5251            logger.info("Test: Identity request PERMANENT_ID (duplicate)")
5252            return struct.pack(">BBHBBHBBH2HBBH", EAP_CODE_REQUEST, ctx['id'],
5253                               4 + 1 + 3 + 8 + 4,
5254                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START, 0,
5255                               EAP_SIM_AT_VERSION_LIST, 2, 2, 1, 0,
5256                               EAP_SIM_AT_PERMANENT_ID_REQ, 1, 0)
5257        idx += 1
5258        if ctx['num'] == idx:
5259            logger.info("Test: EAP-Failure")
5260            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5261
5262        idx += 1
5263        if ctx['num'] == idx:
5264            logger.info("Test: No AT_MAC and AT_RAND in Challenge")
5265            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
5266                               4 + 1 + 3,
5267                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0)
5268        idx += 1
5269        if ctx['num'] == idx:
5270            logger.info("Test: EAP-Failure")
5271            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5272
5273        idx += 1
5274        if ctx['num'] == idx:
5275            logger.info("Test: No AT_RAND in Challenge")
5276            return struct.pack(">BBHBBHBBH4L", EAP_CODE_REQUEST, ctx['id'],
5277                               4 + 1 + 3 + 20,
5278                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
5279                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
5280        idx += 1
5281        if ctx['num'] == idx:
5282            logger.info("Test: EAP-Failure")
5283            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5284
5285        idx += 1
5286        if ctx['num'] == idx:
5287            logger.info("Test: Insufficient number of challenges in Challenge")
5288            return struct.pack(">BBHBBHBBH4LBBH4L", EAP_CODE_REQUEST, ctx['id'],
5289                               4 + 1 + 3 + 20 + 20,
5290                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
5291                               EAP_SIM_AT_RAND, 5, 0, 0, 0, 0, 0,
5292                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
5293        idx += 1
5294        if ctx['num'] == idx:
5295            logger.info("Test: EAP-Failure")
5296            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5297
5298        idx += 1
5299        if ctx['num'] == idx:
5300            logger.info("Test: Too many challenges in Challenge")
5301            return struct.pack(">BBHBBHBBH4L4L4L4LBBH4L", EAP_CODE_REQUEST,
5302                               ctx['id'],
5303                               4 + 1 + 3 + 4 + 4 * 16 + 20,
5304                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
5305                               EAP_SIM_AT_RAND, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5306                               0, 0, 0, 0, 0, 0, 0, 0,
5307                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
5308        idx += 1
5309        if ctx['num'] == idx:
5310            logger.info("Test: EAP-Failure")
5311            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5312
5313        idx += 1
5314        if ctx['num'] == idx:
5315            logger.info("Test: Same RAND multiple times in Challenge")
5316            return struct.pack(">BBHBBHBBH4L4L4LBBH4L", EAP_CODE_REQUEST,
5317                               ctx['id'],
5318                               4 + 1 + 3 + 4 + 3 * 16 + 20,
5319                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE, 0,
5320                               EAP_SIM_AT_RAND, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1,
5321                               0, 0, 0, 0,
5322                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
5323        idx += 1
5324        if ctx['num'] == idx:
5325            logger.info("Test: EAP-Failure")
5326            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5327
5328        idx += 1
5329        if ctx['num'] == idx:
5330            logger.info("Test: Notification with no attributes")
5331            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
5332                               4 + 1 + 3,
5333                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0)
5334        idx += 1
5335        if ctx['num'] == idx:
5336            logger.info("Test: EAP-Failure")
5337            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5338
5339        idx += 1
5340        if ctx['num'] == idx:
5341            logger.info("Test: Notification indicating success, but no MAC")
5342            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5343                               4 + 1 + 3 + 4,
5344                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
5345                               EAP_SIM_AT_NOTIFICATION, 1, 32768)
5346        idx += 1
5347        if ctx['num'] == idx:
5348            logger.info("Test: EAP-Failure")
5349            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5350
5351        idx += 1
5352        if ctx['num'] == idx:
5353            logger.info("Test: Notification indicating success, but invalid MAC value")
5354            return struct.pack(">BBHBBHBBHBBH4L", EAP_CODE_REQUEST, ctx['id'],
5355                               4 + 1 + 3 + 4 + 20,
5356                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
5357                               EAP_SIM_AT_NOTIFICATION, 1, 32768,
5358                               EAP_SIM_AT_MAC, 5, 0, 0, 0, 0, 0)
5359        idx += 1
5360        if ctx['num'] == idx:
5361            logger.info("Test: EAP-Failure")
5362            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5363
5364        idx += 1
5365        if ctx['num'] == idx:
5366            logger.info("Test: Notification before auth")
5367            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5368                               4 + 1 + 3 + 4,
5369                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
5370                               EAP_SIM_AT_NOTIFICATION, 1, 16384)
5371        idx += 1
5372        if ctx['num'] == idx:
5373            logger.info("Test: EAP-Failure")
5374            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5375
5376        idx += 1
5377        if ctx['num'] == idx:
5378            logger.info("Test: Notification before auth")
5379            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5380                               4 + 1 + 3 + 4,
5381                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
5382                               EAP_SIM_AT_NOTIFICATION, 1, 16385)
5383        idx += 1
5384        if ctx['num'] == idx:
5385            logger.info("Test: EAP-Failure")
5386            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5387
5388        idx += 1
5389        if ctx['num'] == idx:
5390            logger.info("Test: Notification with unrecognized non-failure")
5391            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5392                               4 + 1 + 3 + 4,
5393                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
5394                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
5395        idx += 1
5396        if ctx['num'] == idx:
5397            logger.info("Test: Notification before auth (duplicate)")
5398            return struct.pack(">BBHBBHBBH", EAP_CODE_REQUEST, ctx['id'],
5399                               4 + 1 + 3 + 4,
5400                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION, 0,
5401                               EAP_SIM_AT_NOTIFICATION, 1, 0xc000)
5402        idx += 1
5403        if ctx['num'] == idx:
5404            logger.info("Test: EAP-Failure")
5405            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5406
5407        idx += 1
5408        if ctx['num'] == idx:
5409            logger.info("Test: Re-authentication (unexpected) with no attributes")
5410            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
5411                               4 + 1 + 3,
5412                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_REAUTHENTICATION,
5413                               0)
5414        idx += 1
5415        if ctx['num'] == idx:
5416            logger.info("Test: EAP-Failure")
5417            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5418
5419        idx += 1
5420        if ctx['num'] == idx:
5421            logger.info("Test: Client Error")
5422            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
5423                               4 + 1 + 3,
5424                               EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CLIENT_ERROR, 0)
5425        idx += 1
5426        if ctx['num'] == idx:
5427            logger.info("Test: EAP-Failure")
5428            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5429
5430        idx += 1
5431        if ctx['num'] == idx:
5432            logger.info("Test: Unknown subtype")
5433            return struct.pack(">BBHBBH", EAP_CODE_REQUEST, ctx['id'],
5434                               4 + 1 + 3,
5435                               EAP_TYPE_SIM, 255, 0)
5436        idx += 1
5437        if ctx['num'] == idx:
5438            logger.info("Test: EAP-Failure")
5439            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
5440
5441        return None
5442
5443    srv = start_radius_server(sim_handler)
5444
5445    try:
5446        hapd = start_ap(apdev[0])
5447        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
5448
5449        for i in range(0, 25):
5450            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5451                           eap="SIM", identity="1232010000000000",
5452                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
5453                           wait_connect=False)
5454            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
5455                                   timeout=15)
5456            if ev is None:
5457                raise Exception("Timeout on EAP start")
5458            if i in [0]:
5459                time.sleep(0.1)
5460            else:
5461                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
5462                                       timeout=10)
5463                if ev is None:
5464                    raise Exception("Timeout on EAP failure")
5465            dev[0].request("REMOVE_NETWORK all")
5466            dev[0].dump_monitor()
5467    finally:
5468        stop_radius_server(srv)
5469
5470def test_eap_proto_sim_errors(dev, apdev):
5471    """EAP-SIM protocol tests (error paths)"""
5472    check_hlr_auc_gw_support()
5473    params = hostapd.wpa2_eap_params(ssid="eap-test")
5474    hapd = hostapd.add_ap(apdev[0], params)
5475    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
5476
5477    with alloc_fail(dev[0], 1, "eap_sim_init"):
5478        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5479                       eap="SIM", identity="1232010000000000",
5480                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
5481                       wait_connect=False)
5482        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
5483                               timeout=15)
5484        if ev is None:
5485            raise Exception("Timeout on EAP start")
5486        dev[0].request("REMOVE_NETWORK all")
5487        dev[0].wait_disconnected()
5488
5489    with fail_test(dev[0], 1, "os_get_random;eap_sim_init"):
5490        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5491                       eap="SIM", identity="1232010000000000",
5492                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
5493                       wait_connect=False)
5494        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
5495                               timeout=15)
5496        if ev is None:
5497            raise Exception("Timeout on EAP start")
5498        dev[0].request("REMOVE_NETWORK all")
5499        dev[0].wait_disconnected()
5500
5501    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5502                   eap="SIM", identity="1232010000000000",
5503                   password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
5504
5505    with fail_test(dev[0], 1, "aes_128_cbc_encrypt;eap_sim_response_reauth"):
5506        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
5507        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
5508        if ev is None:
5509            raise Exception("EAP re-authentication did not start")
5510        wait_fail_trigger(dev[0], "GET_FAIL")
5511        dev[0].request("REMOVE_NETWORK all")
5512        dev[0].dump_monitor()
5513
5514    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5515                   eap="SIM", identity="1232010000000000",
5516                   password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
5517
5518    with fail_test(dev[0], 1, "os_get_random;eap_sim_msg_add_encr_start"):
5519        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
5520        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
5521        if ev is None:
5522            raise Exception("EAP re-authentication did not start")
5523        wait_fail_trigger(dev[0], "GET_FAIL")
5524        dev[0].request("REMOVE_NETWORK all")
5525        dev[0].dump_monitor()
5526
5527    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5528                   eap="SIM", identity="1232010000000000",
5529                   password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
5530
5531    with fail_test(dev[0], 1, "os_get_random;eap_sim_init_for_reauth"):
5532        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
5533        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
5534        if ev is None:
5535            raise Exception("EAP re-authentication did not start")
5536        wait_fail_trigger(dev[0], "GET_FAIL")
5537        dev[0].request("REMOVE_NETWORK all")
5538        dev[0].dump_monitor()
5539
5540    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5541                   eap="SIM", identity="1232010000000000",
5542                   password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
5543
5544    with alloc_fail(dev[0], 1, "eap_sim_parse_encr;eap_sim_process_reauthentication"):
5545        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
5546        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
5547        if ev is None:
5548            raise Exception("EAP re-authentication did not start")
5549        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5550        dev[0].request("REMOVE_NETWORK all")
5551        dev[0].dump_monitor()
5552
5553    tests = [(1, "eap_sim_verify_mac;eap_sim_process_challenge"),
5554             (1, "eap_sim_parse_encr;eap_sim_process_challenge"),
5555             (1, "eap_sim_msg_init;eap_sim_response_start"),
5556             (1, "wpabuf_alloc;eap_sim_msg_init;eap_sim_response_start"),
5557             (1, "=eap_sim_learn_ids"),
5558             (2, "=eap_sim_learn_ids"),
5559             (2, "eap_sim_learn_ids"),
5560             (3, "eap_sim_learn_ids"),
5561             (1, "eap_sim_process_start"),
5562             (1, "eap_sim_getKey"),
5563             (1, "eap_sim_get_emsk"),
5564             (1, "eap_sim_get_session_id")]
5565    for count, func in tests:
5566        with alloc_fail(dev[0], count, func):
5567            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5568                           eap="SIM", identity="1232010000000000@domain",
5569                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
5570                           erp="1", wait_connect=False)
5571            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5572            dev[0].request("REMOVE_NETWORK all")
5573            dev[0].dump_monitor()
5574
5575    tests = [(1, "aes_128_cbc_decrypt;eap_sim_parse_encr")]
5576    for count, func in tests:
5577        with fail_test(dev[0], count, func):
5578            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5579                           eap="SIM", identity="1232010000000000",
5580                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
5581                           wait_connect=False)
5582            wait_fail_trigger(dev[0], "GET_FAIL")
5583            dev[0].request("REMOVE_NETWORK all")
5584            dev[0].dump_monitor()
5585
5586    params = int_eap_server_params()
5587    params['eap_sim_db'] = "unix:/tmp/hlr_auc_gw.sock"
5588    params['eap_sim_aka_result_ind'] = "1"
5589    hapd2 = hostapd.add_ap(apdev[1], params)
5590    dev[0].scan_for_bss(hapd2.own_addr(), freq=2412)
5591
5592    with alloc_fail(dev[0], 1,
5593                    "eap_sim_msg_init;eap_sim_response_notification"):
5594        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
5595                       scan_freq="2412",
5596                       eap="SIM", identity="1232010000000000",
5597                       phase1="result_ind=1",
5598                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
5599                       wait_connect=False)
5600        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5601        dev[0].request("REMOVE_NETWORK all")
5602        dev[0].dump_monitor()
5603
5604    hapd2.dump_monitor()
5605    tests = ["eap_sim_msg_add_encr_start;eap_sim_response_notification",
5606             "aes_128_cbc_encrypt;eap_sim_response_notification"]
5607    for func in tests:
5608        with fail_test(dev[0], 1, func):
5609            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
5610                           scan_freq="2412",
5611                           eap="SIM", identity="1232010000000000",
5612                           phase1="result_ind=1",
5613                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
5614            hapd2.wait_sta()
5615            dev[0].request("REAUTHENTICATE")
5616            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
5617            if ev is None:
5618                raise Exception("EAP method not started on reauthentication")
5619            time.sleep(0.1)
5620            wait_fail_trigger(dev[0], "GET_FAIL")
5621            dev[0].request("REMOVE_NETWORK all")
5622            dev[0].dump_monitor()
5623            hapd2.wait_sta_disconnect()
5624
5625    hapd2.dump_monitor()
5626    tests = ["eap_sim_parse_encr;eap_sim_process_notification_reauth"]
5627    for func in tests:
5628        with alloc_fail(dev[0], 1, func):
5629            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
5630                           scan_freq="2412",
5631                           eap="SIM", identity="1232010000000000",
5632                           phase1="result_ind=1",
5633                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581")
5634            hapd2.wait_sta()
5635            dev[0].request("REAUTHENTICATE")
5636            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
5637            if ev is None:
5638                raise Exception("EAP method not started on reauthentication")
5639            time.sleep(0.1)
5640            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5641            dev[0].request("REMOVE_NETWORK all")
5642            dev[0].dump_monitor()
5643            hapd2.wait_sta_disconnect()
5644
5645def test_eap_proto_aka_errors(dev, apdev):
5646    """EAP-AKA protocol tests (error paths)"""
5647    check_hlr_auc_gw_support()
5648    params = hostapd.wpa2_eap_params(ssid="eap-test")
5649    hapd = hostapd.add_ap(apdev[0], params)
5650    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
5651
5652    with alloc_fail(dev[0], 1, "eap_aka_init"):
5653        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5654                       eap="AKA", identity="0232010000000000",
5655                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
5656                       wait_connect=False)
5657        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
5658                               timeout=15)
5659        if ev is None:
5660            raise Exception("Timeout on EAP start")
5661        dev[0].request("REMOVE_NETWORK all")
5662        dev[0].wait_disconnected()
5663
5664    tests = [(1, "=eap_aka_learn_ids"),
5665             (2, "=eap_aka_learn_ids"),
5666             (1, "eap_sim_parse_encr;eap_aka_process_challenge"),
5667             (1, "wpabuf_alloc;eap_aka_add_id_msg"),
5668             (1, "eap_aka_getKey"),
5669             (1, "eap_aka_get_emsk"),
5670             (1, "eap_aka_get_session_id")]
5671    for count, func in tests:
5672        with alloc_fail(dev[0], count, func):
5673            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5674                           eap="AKA", identity="0232010000000000@domain",
5675                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
5676                           erp="1", wait_connect=False)
5677            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5678            dev[0].request("REMOVE_NETWORK all")
5679            dev[0].dump_monitor()
5680
5681    params = int_eap_server_params()
5682    params['eap_sim_db'] = "unix:/tmp/hlr_auc_gw.sock"
5683    params['eap_sim_aka_result_ind'] = "1"
5684    hapd2 = hostapd.add_ap(apdev[1], params)
5685    dev[0].scan_for_bss(hapd2.own_addr(), freq=2412)
5686
5687    with alloc_fail(dev[0], 1,
5688                    "eap_sim_msg_init;eap_aka_response_notification"):
5689        dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
5690                       eap="AKA", identity="0232010000000000",
5691                       phase1="result_ind=1",
5692                       password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123",
5693                       wait_connect=False)
5694        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5695        dev[0].request("REMOVE_NETWORK all")
5696        dev[0].dump_monitor()
5697
5698    tests = [(1, "aes_128_encrypt_block;milenage_f1;milenage_check", None),
5699             (2, "aes_128_encrypt_block;milenage_f1;milenage_check", None),
5700             (1, "milenage_f2345;milenage_check", None),
5701             (7, "aes_128_encrypt_block;milenage_f2345;milenage_check",
5702              "ff0000000123"),
5703             (1, "aes_128_encrypt_block;milenage_f1;milenage_check",
5704              "fff000000123")]
5705    for count, func, seq in tests:
5706        if not seq:
5707            seq = "000000000123"
5708        with fail_test(dev[0], count, func):
5709            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
5710                           scan_freq="2412",
5711                           eap="AKA", identity="0232010000000000",
5712                           phase1="result_ind=1",
5713                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:" + seq,
5714                           wait_connect=False)
5715            wait_fail_trigger(dev[0], "GET_FAIL")
5716            dev[0].request("REMOVE_NETWORK all")
5717            dev[0].wait_disconnected()
5718            dev[0].dump_monitor()
5719
5720    hapd2.dump_monitor()
5721    tests = ["eap_sim_msg_add_encr_start;eap_aka_response_notification",
5722             "aes_128_cbc_encrypt;eap_aka_response_notification"]
5723    for func in tests:
5724        with fail_test(dev[0], 1, func):
5725            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
5726                           scan_freq="2412",
5727                           eap="AKA", identity="0232010000000000",
5728                           phase1="result_ind=1",
5729                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
5730            hapd2.wait_sta()
5731            dev[0].request("REAUTHENTICATE")
5732            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
5733            if ev is None:
5734                raise Exception("EAP method not started on reauthentication")
5735            time.sleep(0.1)
5736            wait_fail_trigger(dev[0], "GET_FAIL")
5737            dev[0].request("REMOVE_NETWORK all")
5738            dev[0].dump_monitor()
5739            hapd2.wait_sta_disconnect()
5740
5741    hapd2.dump_monitor()
5742    tests = ["eap_sim_parse_encr;eap_aka_process_notification_reauth"]
5743    for func in tests:
5744        with alloc_fail(dev[0], 1, func):
5745            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
5746                           scan_freq="2412",
5747                           eap="AKA", identity="0232010000000000",
5748                           phase1="result_ind=1",
5749                           password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123")
5750            hapd2.wait_sta()
5751            dev[0].request("REAUTHENTICATE")
5752            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
5753            if ev is None:
5754                raise Exception("EAP method not started on reauthentication")
5755            time.sleep(0.1)
5756            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5757            dev[0].request("REMOVE_NETWORK all")
5758            dev[0].dump_monitor()
5759            hapd2.wait_sta_disconnect()
5760
5761def test_eap_proto_aka_prime_errors(dev, apdev):
5762    """EAP-AKA' protocol tests (error paths)"""
5763    check_hlr_auc_gw_support()
5764    params = hostapd.wpa2_eap_params(ssid="eap-test")
5765    hapd = hostapd.add_ap(apdev[0], params)
5766    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
5767
5768    with alloc_fail(dev[0], 1, "eap_aka_init"):
5769        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5770                       eap="AKA'", identity="6555444333222111",
5771                       password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
5772                       wait_connect=False)
5773        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
5774                               timeout=15)
5775        if ev is None:
5776            raise Exception("Timeout on EAP start")
5777        dev[0].request("REMOVE_NETWORK all")
5778        dev[0].wait_disconnected()
5779
5780    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5781                   eap="AKA'", identity="6555444333222111",
5782                   password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
5783
5784    with fail_test(dev[0], 1, "aes_128_cbc_encrypt;eap_aka_response_reauth"):
5785        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
5786        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
5787        if ev is None:
5788            raise Exception("EAP re-authentication did not start")
5789        wait_fail_trigger(dev[0], "GET_FAIL")
5790        dev[0].request("REMOVE_NETWORK all")
5791        dev[0].dump_monitor()
5792
5793    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5794                   eap="AKA'", identity="6555444333222111",
5795                   password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123")
5796
5797    with alloc_fail(dev[0], 1, "eap_sim_parse_encr;eap_aka_process_reauthentication"):
5798        hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
5799        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
5800        if ev is None:
5801            raise Exception("EAP re-authentication did not start")
5802        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5803        dev[0].request("REMOVE_NETWORK all")
5804        dev[0].dump_monitor()
5805
5806    tests = [(1, "eap_sim_verify_mac_sha256"),
5807             (1, "=eap_aka_process_challenge")]
5808    for count, func in tests:
5809        with alloc_fail(dev[0], count, func):
5810            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
5811                           eap="AKA'", identity="6555444333222111",
5812                           password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
5813                           erp="1", wait_connect=False)
5814            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5815            dev[0].request("REMOVE_NETWORK all")
5816            dev[0].dump_monitor()
5817
5818def test_eap_proto_ikev2(dev, apdev):
5819    """EAP-IKEv2 protocol tests"""
5820    check_eap_capa(dev[0], "IKEV2")
5821
5822    global eap_proto_ikev2_test_done
5823    eap_proto_ikev2_test_done = False
5824
5825    def ikev2_handler(ctx, req):
5826        logger.info("ikev2_handler - RX " + binascii.hexlify(req).decode())
5827        if 'num' not in ctx:
5828            ctx['num'] = 0
5829        ctx['num'] = ctx['num'] + 1
5830        if 'id' not in ctx:
5831            ctx['id'] = 1
5832        ctx['id'] = (ctx['id'] + 1) % 256
5833
5834        idx = 0
5835
5836        idx += 1
5837        if ctx['num'] == idx:
5838            logger.info("Test: Missing payload")
5839            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
5840                               4 + 1,
5841                               EAP_TYPE_IKEV2)
5842
5843        idx += 1
5844        if ctx['num'] == idx:
5845            logger.info("Test: Truncated Message Length field")
5846            return struct.pack(">BBHBB3B", EAP_CODE_REQUEST, ctx['id'],
5847                               4 + 1 + 1 + 3,
5848                               EAP_TYPE_IKEV2, 0x80, 0, 0, 0)
5849
5850        idx += 1
5851        if ctx['num'] == idx:
5852            logger.info("Test: Too short Message Length value")
5853            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
5854                               4 + 1 + 1 + 4 + 1,
5855                               EAP_TYPE_IKEV2, 0x80, 0, 1)
5856
5857        idx += 1
5858        if ctx['num'] == idx:
5859            logger.info("Test: Truncated message")
5860            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
5861                               4 + 1 + 1 + 4,
5862                               EAP_TYPE_IKEV2, 0x80, 1)
5863
5864        idx += 1
5865        if ctx['num'] == idx:
5866            logger.info("Test: Truncated message(2)")
5867            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
5868                               4 + 1 + 1 + 4,
5869                               EAP_TYPE_IKEV2, 0x80, 0xffffffff)
5870
5871        idx += 1
5872        if ctx['num'] == idx:
5873            logger.info("Test: Truncated message(3)")
5874            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
5875                               4 + 1 + 1 + 4,
5876                               EAP_TYPE_IKEV2, 0xc0, 0xffffffff)
5877
5878        idx += 1
5879        if ctx['num'] == idx:
5880            logger.info("Test: Truncated message(4)")
5881            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
5882                               4 + 1 + 1 + 4,
5883                               EAP_TYPE_IKEV2, 0xc0, 10000000)
5884
5885        idx += 1
5886        if ctx['num'] == idx:
5887            logger.info("Test: Too long fragments (first fragment)")
5888            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
5889                               4 + 1 + 1 + 4 + 1,
5890                               EAP_TYPE_IKEV2, 0xc0, 2, 1)
5891
5892        idx += 1
5893        if ctx['num'] == idx:
5894            logger.info("Test: Too long fragments (second fragment)")
5895            return struct.pack(">BBHBB2B", EAP_CODE_REQUEST, ctx['id'],
5896                               4 + 1 + 1 + 2,
5897                               EAP_TYPE_IKEV2, 0x00, 2, 3)
5898
5899        idx += 1
5900        if ctx['num'] == idx:
5901            logger.info("Test: No Message Length field in first fragment")
5902            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
5903                               4 + 1 + 1 + 1,
5904                               EAP_TYPE_IKEV2, 0x40, 1)
5905
5906        idx += 1
5907        if ctx['num'] == idx:
5908            logger.info("Test: ICV before keys")
5909            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
5910                               4 + 1 + 1,
5911                               EAP_TYPE_IKEV2, 0x20)
5912
5913        idx += 1
5914        if ctx['num'] == idx:
5915            logger.info("Test: Unsupported IKEv2 header version")
5916            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5917                               4 + 1 + 1 + 28,
5918                               EAP_TYPE_IKEV2, 0x00,
5919                               0, 0, 0, 0,
5920                               0, 0, 0, 0, 0, 0)
5921
5922        idx += 1
5923        if ctx['num'] == idx:
5924            logger.info("Test: Incorrect IKEv2 header Length")
5925            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5926                               4 + 1 + 1 + 28,
5927                               EAP_TYPE_IKEV2, 0x00,
5928                               0, 0, 0, 0,
5929                               0, 0x20, 0, 0, 0, 0)
5930
5931        idx += 1
5932        if ctx['num'] == idx:
5933            logger.info("Test: Unexpected IKEv2 Exchange Type in SA_INIT state")
5934            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5935                               4 + 1 + 1 + 28,
5936                               EAP_TYPE_IKEV2, 0x00,
5937                               0, 0, 0, 0,
5938                               0, 0x20, 0, 0, 0, 28)
5939
5940        idx += 1
5941        if ctx['num'] == idx:
5942            logger.info("Test: Unexpected IKEv2 Message ID in SA_INIT state")
5943            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5944                               4 + 1 + 1 + 28,
5945                               EAP_TYPE_IKEV2, 0x00,
5946                               0, 0, 0, 0,
5947                               0, 0x20, 34, 0, 1, 28)
5948
5949        idx += 1
5950        if ctx['num'] == idx:
5951            logger.info("Test: Unexpected IKEv2 Flags value")
5952            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5953                               4 + 1 + 1 + 28,
5954                               EAP_TYPE_IKEV2, 0x00,
5955                               0, 0, 0, 0,
5956                               0, 0x20, 34, 0, 0, 28)
5957
5958        idx += 1
5959        if ctx['num'] == idx:
5960            logger.info("Test: Unexpected IKEv2 Flags value(2)")
5961            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5962                               4 + 1 + 1 + 28,
5963                               EAP_TYPE_IKEV2, 0x00,
5964                               0, 0, 0, 0,
5965                               0, 0x20, 34, 0x20, 0, 28)
5966
5967        idx += 1
5968        if ctx['num'] == idx:
5969            logger.info("Test: No SAi1 in SA_INIT")
5970            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, ctx['id'],
5971                               4 + 1 + 1 + 28,
5972                               EAP_TYPE_IKEV2, 0x00,
5973                               0, 0, 0, 0,
5974                               0, 0x20, 34, 0x08, 0, 28)
5975
5976        def build_ike(id, next=0, exch_type=34, flags=0x00, ike=b''):
5977            return struct.pack(">BBHBB2L2LBBBBLL", EAP_CODE_REQUEST, id,
5978                               4 + 1 + 1 + 28 + len(ike),
5979                               EAP_TYPE_IKEV2, flags,
5980                               0, 0, 0, 0,
5981                               next, 0x20, exch_type, 0x08, 0,
5982                               28 + len(ike)) + ike
5983
5984        idx += 1
5985        if ctx['num'] == idx:
5986            logger.info("Test: Unexpected extra data after payloads")
5987            return build_ike(ctx['id'], ike=struct.pack(">B", 1))
5988
5989        idx += 1
5990        if ctx['num'] == idx:
5991            logger.info("Test: Truncated payload header")
5992            return build_ike(ctx['id'], next=128, ike=struct.pack(">B", 1))
5993
5994        idx += 1
5995        if ctx['num'] == idx:
5996            logger.info("Test: Too small payload header length")
5997            ike = struct.pack(">BBH", 0, 0, 3)
5998            return build_ike(ctx['id'], next=128, ike=ike)
5999
6000        idx += 1
6001        if ctx['num'] == idx:
6002            logger.info("Test: Too large payload header length")
6003            ike = struct.pack(">BBH", 0, 0, 5)
6004            return build_ike(ctx['id'], next=128, ike=ike)
6005
6006        idx += 1
6007        if ctx['num'] == idx:
6008            logger.info("Test: Unsupported payload (non-critical and critical)")
6009            ike = struct.pack(">BBHBBH", 129, 0, 4, 0, 0x01, 4)
6010            return build_ike(ctx['id'], next=128, ike=ike)
6011
6012        idx += 1
6013        if ctx['num'] == idx:
6014            logger.info("Test: Certificate and empty SAi1")
6015            ike = struct.pack(">BBHBBH", 33, 0, 4, 0, 0, 4)
6016            return build_ike(ctx['id'], next=37, ike=ike)
6017
6018        idx += 1
6019        if ctx['num'] == idx:
6020            logger.info("Test: Too short proposal")
6021            ike = struct.pack(">BBHBBHBBB", 0, 0, 4 + 7,
6022                              0, 0, 7, 0, 0, 0)
6023            return build_ike(ctx['id'], next=33, ike=ike)
6024
6025        idx += 1
6026        if ctx['num'] == idx:
6027            logger.info("Test: Too small proposal length in SAi1")
6028            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6029                              0, 0, 7, 0, 0, 0, 0)
6030            return build_ike(ctx['id'], next=33, ike=ike)
6031
6032        idx += 1
6033        if ctx['num'] == idx:
6034            logger.info("Test: Too large proposal length in SAi1")
6035            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6036                              0, 0, 9, 0, 0, 0, 0)
6037            return build_ike(ctx['id'], next=33, ike=ike)
6038
6039        idx += 1
6040        if ctx['num'] == idx:
6041            logger.info("Test: Unexpected proposal type in SAi1")
6042            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6043                              1, 0, 8, 0, 0, 0, 0)
6044            return build_ike(ctx['id'], next=33, ike=ike)
6045
6046        idx += 1
6047        if ctx['num'] == idx:
6048            logger.info("Test: Unexpected Protocol ID in SAi1")
6049            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6050                              0, 0, 8, 0, 0, 0, 0)
6051            return build_ike(ctx['id'], next=33, ike=ike)
6052
6053        idx += 1
6054        if ctx['num'] == idx:
6055            logger.info("Test: Unexpected proposal number in SAi1")
6056            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6057                              0, 0, 8, 0, 1, 0, 0)
6058            return build_ike(ctx['id'], next=33, ike=ike)
6059
6060        idx += 1
6061        if ctx['num'] == idx:
6062            logger.info("Test: Not enough room for SPI in SAi1")
6063            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6064                              0, 0, 8, 1, 1, 1, 0)
6065            return build_ike(ctx['id'], next=33, ike=ike)
6066
6067        idx += 1
6068        if ctx['num'] == idx:
6069            logger.info("Test: Unexpected SPI in SAi1")
6070            ike = struct.pack(">BBHBBHBBBBB", 0, 0, 4 + 9,
6071                              0, 0, 9, 1, 1, 1, 0, 1)
6072            return build_ike(ctx['id'], next=33, ike=ike)
6073
6074        idx += 1
6075        if ctx['num'] == idx:
6076            logger.info("Test: No transforms in SAi1")
6077            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6078                              0, 0, 8, 1, 1, 0, 0)
6079            return build_ike(ctx['id'], next=33, ike=ike)
6080
6081        idx += 1
6082        if ctx['num'] == idx:
6083            logger.info("Test: Too short transform in SAi1")
6084            ike = struct.pack(">BBHBBHBBBB", 0, 0, 4 + 8,
6085                              0, 0, 8, 1, 1, 0, 1)
6086            return build_ike(ctx['id'], next=33, ike=ike)
6087
6088        idx += 1
6089        if ctx['num'] == idx:
6090            logger.info("Test: Too small transform length in SAi1")
6091            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
6092                              0, 0, 8 + 8, 1, 1, 0, 1,
6093                              0, 0, 7, 0, 0, 0)
6094            return build_ike(ctx['id'], next=33, ike=ike)
6095
6096        idx += 1
6097        if ctx['num'] == idx:
6098            logger.info("Test: Too large transform length in SAi1")
6099            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
6100                              0, 0, 8 + 8, 1, 1, 0, 1,
6101                              0, 0, 9, 0, 0, 0)
6102            return build_ike(ctx['id'], next=33, ike=ike)
6103
6104        idx += 1
6105        if ctx['num'] == idx:
6106            logger.info("Test: Unexpected Transform type in SAi1")
6107            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
6108                              0, 0, 8 + 8, 1, 1, 0, 1,
6109                              1, 0, 8, 0, 0, 0)
6110            return build_ike(ctx['id'], next=33, ike=ike)
6111
6112        idx += 1
6113        if ctx['num'] == idx:
6114            logger.info("Test: No transform attributes in SAi1")
6115            ike = struct.pack(">BBHBBHBBBBBBHBBH", 0, 0, 4 + 8 + 8,
6116                              0, 0, 8 + 8, 1, 1, 0, 1,
6117                              0, 0, 8, 0, 0, 0)
6118            return build_ike(ctx['id'], next=33, ike=ike)
6119
6120        idx += 1
6121        if ctx['num'] == idx:
6122            logger.info("Test: No transform attr for AES and unexpected data after transforms in SAi1")
6123            tlen1 = 8 + 3
6124            tlen2 = 8 + 4
6125            tlen3 = 8 + 4
6126            tlen = tlen1 + tlen2 + tlen3
6127            ike = struct.pack(">BBHBBHBBBBBBHBBH3BBBHBBHHHBBHBBHHHB",
6128                              0, 0, 4 + 8 + tlen + 1,
6129                              0, 0, 8 + tlen + 1, 1, 1, 0, 3,
6130                              3, 0, tlen1, 1, 0, 12, 1, 2, 3,
6131                              3, 0, tlen2, 1, 0, 12, 0, 128,
6132                              0, 0, tlen3, 1, 0, 12, 0x8000 | 14, 127,
6133                              1)
6134            return build_ike(ctx['id'], next=33, ike=ike)
6135
6136        def build_sa(next=0):
6137            tlen = 5 * 8
6138            return struct.pack(">BBHBBHBBBBBBHBBHBBHBBHBBHBBHBBHBBHBBHBBH",
6139                               next, 0, 4 + 8 + tlen,
6140                               0, 0, 8 + tlen, 1, 1, 0, 5,
6141                               3, 0, 8, 1, 0, 3,
6142                               3, 0, 8, 2, 0, 1,
6143                               3, 0, 8, 3, 0, 1,
6144                               3, 0, 8, 4, 0, 5,
6145                               0, 0, 8, 241, 0, 0)
6146
6147        idx += 1
6148        if ctx['num'] == idx:
6149            logger.info("Test: Valid proposal, but no KEi in SAi1")
6150            ike = build_sa()
6151            return build_ike(ctx['id'], next=33, ike=ike)
6152
6153        idx += 1
6154        if ctx['num'] == idx:
6155            logger.info("Test: Empty KEi in SAi1")
6156            ike = build_sa(next=34) + struct.pack(">BBH", 0, 0, 4)
6157            return build_ike(ctx['id'], next=33, ike=ike)
6158
6159        idx += 1
6160        if ctx['num'] == idx:
6161            logger.info("Test: Mismatch in DH Group in SAi1")
6162            ike = build_sa(next=34)
6163            ike += struct.pack(">BBHHH", 0, 0, 4 + 4 + 96, 12345, 0)
6164            ike += 96*b'\x00'
6165            return build_ike(ctx['id'], next=33, ike=ike)
6166        idx += 1
6167        if ctx['num'] == idx:
6168            logger.info("Test: EAP-Failure")
6169            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6170
6171        idx += 1
6172        if ctx['num'] == idx:
6173            logger.info("Test: Invalid DH public value length in SAi1")
6174            ike = build_sa(next=34)
6175            ike += struct.pack(">BBHHH", 0, 0, 4 + 4 + 96, 5, 0)
6176            ike += 96*b'\x00'
6177            return build_ike(ctx['id'], next=33, ike=ike)
6178
6179        def build_ke(next=0):
6180            ke = struct.pack(">BBHHH", next, 0, 4 + 4 + 192, 5, 0)
6181            ke += 191*b'\x00'+b'\x02'
6182            return ke
6183
6184        idx += 1
6185        if ctx['num'] == idx:
6186            logger.info("Test: Valid proposal and KEi, but no Ni in SAi1")
6187            ike = build_sa(next=34)
6188            ike += build_ke()
6189            return build_ike(ctx['id'], next=33, ike=ike)
6190
6191        idx += 1
6192        if ctx['num'] == idx:
6193            logger.info("Test: Too short Ni in SAi1")
6194            ike = build_sa(next=34)
6195            ike += build_ke(next=40)
6196            ike += struct.pack(">BBH", 0, 0, 4)
6197            return build_ike(ctx['id'], next=33, ike=ike)
6198
6199        idx += 1
6200        if ctx['num'] == idx:
6201            logger.info("Test: Too long Ni in SAi1")
6202            ike = build_sa(next=34)
6203            ike += build_ke(next=40)
6204            ike += struct.pack(">BBH", 0, 0, 4 + 257) + 257*b'\x00'
6205            return build_ike(ctx['id'], next=33, ike=ike)
6206
6207        def build_ni(next=0):
6208            return struct.pack(">BBH", next, 0, 4 + 256) + 256*b'\x00'
6209
6210        def build_sai1(id):
6211            ike = build_sa(next=34)
6212            ike += build_ke(next=40)
6213            ike += build_ni()
6214            return build_ike(ctx['id'], next=33, ike=ike)
6215
6216        idx += 1
6217        if ctx['num'] == idx:
6218            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
6219            return build_sai1(ctx['id'])
6220        idx += 1
6221        if ctx['num'] == idx:
6222            logger.info("Test: EAP-Failure")
6223            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6224
6225        idx += 1
6226        if ctx['num'] == idx:
6227            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
6228            return build_sai1(ctx['id'])
6229        idx += 1
6230        if ctx['num'] == idx:
6231            logger.info("Test: No integrity checksum")
6232            ike = b''
6233            return build_ike(ctx['id'], next=37, ike=ike)
6234
6235        idx += 1
6236        if ctx['num'] == idx:
6237            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
6238            return build_sai1(ctx['id'])
6239        idx += 1
6240        if ctx['num'] == idx:
6241            logger.info("Test: Truncated integrity checksum")
6242            return struct.pack(">BBHBB",
6243                               EAP_CODE_REQUEST, ctx['id'],
6244                               4 + 1 + 1,
6245                               EAP_TYPE_IKEV2, 0x20)
6246
6247        idx += 1
6248        if ctx['num'] == idx:
6249            logger.info("Test: Valid proposal, KEi, and Ni in SAi1")
6250            return build_sai1(ctx['id'])
6251        idx += 1
6252        if ctx['num'] == idx:
6253            logger.info("Test: Invalid integrity checksum")
6254            ike = b''
6255            return build_ike(ctx['id'], next=37, flags=0x20, ike=ike)
6256
6257        idx += 1
6258        if ctx['num'] == idx:
6259            logger.info("No more test responses available - test case completed")
6260            global eap_proto_ikev2_test_done
6261            eap_proto_ikev2_test_done = True
6262            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
6263                               4 + 1,
6264                               EAP_TYPE_IKEV2)
6265        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6266
6267    srv = start_radius_server(ikev2_handler)
6268
6269    try:
6270        hapd = start_ap(apdev[0])
6271        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
6272
6273        i = 0
6274        while not eap_proto_ikev2_test_done:
6275            i += 1
6276            logger.info("Running connection iteration %d" % i)
6277            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
6278                           eap="IKEV2", identity="user",
6279                           password="password",
6280                           wait_connect=False)
6281            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15)
6282            if ev is None:
6283                raise Exception("Timeout on EAP start")
6284            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
6285                                   timeout=15)
6286            if ev is None:
6287                raise Exception("Timeout on EAP method start")
6288            if i in [41, 46]:
6289                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
6290                                       timeout=10)
6291                if ev is None:
6292                    raise Exception("Timeout on EAP failure")
6293            else:
6294                time.sleep(0.05)
6295            dev[0].request("REMOVE_NETWORK all")
6296            dev[0].wait_disconnected()
6297            dev[0].dump_monitor()
6298            dev[1].dump_monitor()
6299            dev[2].dump_monitor()
6300    finally:
6301        stop_radius_server(srv)
6302
6303def NtPasswordHash(password):
6304    pw = password.encode('utf_16_le')
6305    return hashlib.new('md4', pw).digest()
6306
6307def HashNtPasswordHash(password_hash):
6308    return hashlib.new('md4', password_hash).digest()
6309
6310def ChallengeHash(peer_challenge, auth_challenge, username):
6311    data = peer_challenge + auth_challenge + username
6312    return hashlib.sha1(data).digest()[0:8]
6313
6314def GenerateAuthenticatorResponse(password, nt_response, peer_challenge,
6315                                  auth_challenge, username):
6316    magic1 = binascii.unhexlify("4D616769632073657276657220746F20636C69656E74207369676E696E6720636F6E7374616E74")
6317    magic2 = binascii.unhexlify("50616420746F206D616B6520697420646F206D6F7265207468616E206F6E6520697465726174696F6E")
6318
6319    password_hash = NtPasswordHash(password)
6320    password_hash_hash = HashNtPasswordHash(password_hash)
6321    data = password_hash_hash + nt_response + magic1
6322    digest = hashlib.sha1(data).digest()
6323
6324    challenge = ChallengeHash(peer_challenge, auth_challenge, username.encode())
6325
6326    data = digest + challenge + magic2
6327    resp = hashlib.sha1(data).digest()
6328    return resp
6329
6330def test_eap_proto_ikev2_errors(dev, apdev):
6331    """EAP-IKEv2 local error cases"""
6332    check_eap_capa(dev[0], "IKEV2")
6333    params = hostapd.wpa2_eap_params(ssid="eap-test")
6334    hapd = hostapd.add_ap(apdev[0], params)
6335    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
6336
6337    for i in range(1, 5):
6338        with alloc_fail(dev[0], i, "eap_ikev2_init"):
6339            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
6340                           eap="IKEV2", identity="ikev2 user",
6341                           password="ike password",
6342                           wait_connect=False)
6343            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
6344                                   timeout=15)
6345            if ev is None:
6346                raise Exception("Timeout on EAP start")
6347            dev[0].request("REMOVE_NETWORK all")
6348            dev[0].wait_disconnected()
6349
6350    tests = [(1, "ikev2_encr_encrypt"),
6351             (1, "ikev2_encr_decrypt"),
6352             (1, "ikev2_derive_auth_data"),
6353             (2, "ikev2_derive_auth_data"),
6354             (1, "=ikev2_decrypt_payload"),
6355             (1, "ikev2_encr_decrypt;ikev2_decrypt_payload"),
6356             (1, "ikev2_encr_encrypt;ikev2_build_encrypted"),
6357             (1, "ikev2_derive_sk_keys"),
6358             (2, "ikev2_derive_sk_keys"),
6359             (3, "ikev2_derive_sk_keys"),
6360             (4, "ikev2_derive_sk_keys"),
6361             (5, "ikev2_derive_sk_keys"),
6362             (6, "ikev2_derive_sk_keys"),
6363             (7, "ikev2_derive_sk_keys"),
6364             (8, "ikev2_derive_sk_keys"),
6365             (1, "eap_ikev2_derive_keymat;eap_ikev2_peer_keymat"),
6366             (1, "eap_msg_alloc;eap_ikev2_build_msg"),
6367             (1, "eap_ikev2_getKey"),
6368             (1, "eap_ikev2_get_emsk"),
6369             (1, "eap_ikev2_get_session_id"),
6370             (1, "=ikev2_derive_keys"),
6371             (2, "=ikev2_derive_keys"),
6372             (1, "wpabuf_alloc;ikev2_process_kei"),
6373             (1, "=ikev2_process_idi"),
6374             (1, "ikev2_derive_auth_data;ikev2_build_auth"),
6375             (1, "wpabuf_alloc;ikev2_build_sa_init"),
6376             (2, "wpabuf_alloc;ikev2_build_sa_init"),
6377             (3, "wpabuf_alloc;ikev2_build_sa_init"),
6378             (4, "wpabuf_alloc;ikev2_build_sa_init"),
6379             (5, "wpabuf_alloc;ikev2_build_sa_init"),
6380             (6, "wpabuf_alloc;ikev2_build_sa_init"),
6381             (1, "wpabuf_alloc;ikev2_build_sa_auth"),
6382             (2, "wpabuf_alloc;ikev2_build_sa_auth"),
6383             (1, "ikev2_build_auth;ikev2_build_sa_auth")]
6384    for count, func in tests:
6385        with alloc_fail(dev[0], count, func):
6386            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
6387                           eap="IKEV2", identity="ikev2 user@domain",
6388                           password="ike password", erp="1", wait_connect=False)
6389            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
6390                                   timeout=15)
6391            if ev is None:
6392                raise Exception("Timeout on EAP start")
6393            ok = False
6394            for j in range(10):
6395                state = dev[0].request('GET_ALLOC_FAIL')
6396                if state.startswith('0:'):
6397                    ok = True
6398                    break
6399                time.sleep(0.1)
6400            if not ok:
6401                raise Exception("No allocation failure seen for %d:%s" % (count, func))
6402            dev[0].request("REMOVE_NETWORK all")
6403            dev[0].wait_disconnected()
6404
6405    tests = [(1, "wpabuf_alloc;ikev2_build_notify"),
6406             (2, "wpabuf_alloc;ikev2_build_notify"),
6407             (1, "ikev2_build_encrypted;ikev2_build_notify")]
6408    for count, func in tests:
6409        with alloc_fail(dev[0], count, func):
6410            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
6411                           eap="IKEV2", identity="ikev2 user",
6412                           password="wrong password", erp="1",
6413                           wait_connect=False)
6414            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
6415                                   timeout=15)
6416            if ev is None:
6417                raise Exception("Timeout on EAP start")
6418            ok = False
6419            for j in range(10):
6420                state = dev[0].request('GET_ALLOC_FAIL')
6421                if state.startswith('0:'):
6422                    ok = True
6423                    break
6424                time.sleep(0.1)
6425            if not ok:
6426                raise Exception("No allocation failure seen for %d:%s" % (count, func))
6427            dev[0].request("REMOVE_NETWORK all")
6428            dev[0].wait_disconnected()
6429
6430    tests = [(1, "ikev2_integ_hash"),
6431             (1, "ikev2_integ_hash;ikev2_decrypt_payload"),
6432             (1, "os_get_random;ikev2_build_encrypted"),
6433             (1, "ikev2_prf_plus;ikev2_derive_sk_keys"),
6434             (1, "eap_ikev2_derive_keymat;eap_ikev2_peer_keymat"),
6435             (1, "os_get_random;ikev2_build_sa_init"),
6436             (2, "os_get_random;ikev2_build_sa_init"),
6437             (1, "ikev2_integ_hash;eap_ikev2_validate_icv"),
6438             (1, "hmac_sha1_vector;?ikev2_prf_hash;ikev2_derive_keys"),
6439             (1, "hmac_sha1_vector;?ikev2_prf_hash;ikev2_derive_auth_data"),
6440             (2, "hmac_sha1_vector;?ikev2_prf_hash;ikev2_derive_auth_data"),
6441             (3, "hmac_sha1_vector;?ikev2_prf_hash;ikev2_derive_auth_data")]
6442    for count, func in tests:
6443        with fail_test(dev[0], count, func):
6444            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
6445                           eap="IKEV2", identity="ikev2 user",
6446                           password="ike password", wait_connect=False)
6447            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
6448                                   timeout=15)
6449            if ev is None:
6450                raise Exception("Timeout on EAP start")
6451            ok = False
6452            for j in range(10):
6453                state = dev[0].request('GET_FAIL')
6454                if state.startswith('0:'):
6455                    ok = True
6456                    break
6457                time.sleep(0.1)
6458            if not ok:
6459                raise Exception("No failure seen for %d:%s" % (count, func))
6460            dev[0].request("REMOVE_NETWORK all")
6461            dev[0].wait_disconnected()
6462
6463    params = {"ssid": "eap-test2", "wpa": "2", "wpa_key_mgmt": "WPA-EAP",
6464              "rsn_pairwise": "CCMP", "ieee8021x": "1",
6465              "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf",
6466              "fragment_size": "50"}
6467    hapd2 = hostapd.add_ap(apdev[1], params)
6468    dev[0].scan_for_bss(hapd2.own_addr(), freq=2412)
6469
6470    tests = [(1, "eap_ikev2_build_frag_ack"),
6471             (1, "wpabuf_alloc;eap_ikev2_process_fragment")]
6472    for count, func in tests:
6473        with alloc_fail(dev[0], count, func):
6474            dev[0].connect("eap-test2", key_mgmt="WPA-EAP", scan_freq="2412",
6475                           eap="IKEV2", identity="ikev2 user",
6476                           password="ike password", erp="1", wait_connect=False)
6477            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
6478                                   timeout=15)
6479            if ev is None:
6480                raise Exception("Timeout on EAP start")
6481            ok = False
6482            for j in range(10):
6483                state = dev[0].request('GET_ALLOC_FAIL')
6484                if state.startswith('0:'):
6485                    ok = True
6486                    break
6487                time.sleep(0.1)
6488            if not ok:
6489                raise Exception("No allocation failure seen for %d:%s" % (count, func))
6490            dev[0].request("REMOVE_NETWORK all")
6491            dev[0].wait_disconnected()
6492
6493def run_eap_ikev2_connect(dev):
6494    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
6495                eap="IKEV2", identity="ikev2 user",
6496                password="ike password",
6497                fragment_size="30", wait_connect=False)
6498    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
6499                         "CTRL-EVENT-DISCONNECTED"],
6500                        timeout=1)
6501    dev.request("REMOVE_NETWORK all")
6502    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
6503        dev.wait_disconnected()
6504    ev = dev.wait_event(["CTRL-EVENT-NETWORK-REMOVED"], timeout=1)
6505    if ev is None:
6506        raise Exception("Network removal not reported")
6507    time.sleep(0.01)
6508    dev.dump_monitor()
6509
6510def test_eap_proto_ikev2_errors_server(dev, apdev):
6511    """EAP-IKEV2 local error cases on server"""
6512    check_eap_capa(dev[0], "IKEV2")
6513    params = int_eap_server_params()
6514    params['erp_domain'] = 'example.com'
6515    params['eap_server_erp'] = '1'
6516    hapd = hostapd.add_ap(apdev[0], params)
6517    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
6518
6519    tests = [(1, "eap_ikev2_init"),
6520             (2, "=eap_ikev2_init"),
6521             (3, "=eap_ikev2_init"),
6522             (1, "eap_msg_alloc;eap_ikev2_build_msg"),
6523             (1, "ikev2_initiator_build;eap_ikev2_buildReq"),
6524             (1, "eap_ikev2_process_fragment"),
6525             (1, "wpabuf_alloc_copy;ikev2_process_ker"),
6526             (1, "ikev2_process_idr"),
6527             (1, "ikev2_derive_auth_data;ikev2_process_auth_secret"),
6528             (1, "ikev2_decrypt_payload;ikev2_process_sa_auth"),
6529             (1, "ikev2_process_sa_auth_decrypted;ikev2_process_sa_auth"),
6530             (1, "dh_init;ikev2_build_kei"),
6531             (1, "ikev2_build_auth"),
6532             (1, "wpabuf_alloc;ikev2_build_sa_init"),
6533             (1, "ikev2_build_sa_auth"),
6534             (1, "=ikev2_build_sa_auth"),
6535             (2, "=ikev2_derive_auth_data"),
6536             (1, "wpabuf_alloc;ikev2_build_sa_auth"),
6537             (2, "wpabuf_alloc;=ikev2_build_sa_auth"),
6538             (1, "ikev2_decrypt_payload;ikev2_process_sa_init_encr"),
6539             (1, "dh_derive_shared;ikev2_derive_keys"),
6540             (1, "=ikev2_derive_keys"),
6541             (2, "=ikev2_derive_keys"),
6542             (1, "eap_ikev2_getKey"),
6543             (1, "eap_ikev2_get_emsk"),
6544             (1, "eap_ikev2_get_session_id")]
6545    for count, func in tests:
6546        with alloc_fail(hapd, count, func):
6547            run_eap_ikev2_connect(dev[0])
6548
6549    tests = [(1, "eap_ikev2_validate_icv;eap_ikev2_process_icv"),
6550             (1, "eap_ikev2_server_keymat"),
6551             (1, "ikev2_build_auth"),
6552             (1, "os_get_random;ikev2_build_sa_init"),
6553             (2, "os_get_random;ikev2_build_sa_init"),
6554             (1, "ikev2_derive_keys"),
6555             (2, "ikev2_derive_keys"),
6556             (3, "ikev2_derive_keys"),
6557             (4, "ikev2_derive_keys"),
6558             (5, "ikev2_derive_keys"),
6559             (6, "ikev2_derive_keys"),
6560             (7, "ikev2_derive_keys"),
6561             (8, "ikev2_derive_keys"),
6562             (1, "ikev2_decrypt_payload;ikev2_process_sa_auth"),
6563             (1, "eap_ikev2_process_icv;eap_ikev2_process")]
6564    for count, func in tests:
6565        with fail_test(hapd, count, func):
6566            run_eap_ikev2_connect(dev[0])
6567
6568def start_ikev2_assoc(dev, hapd):
6569    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
6570                eap="IKEV2", identity="ikev2 user",
6571                password="ike password", wait_connect=False)
6572    proxy_msg(hapd, dev) # EAP-Identity/Request
6573    proxy_msg(dev, hapd) # EAP-Identity/Response
6574    proxy_msg(hapd, dev) # IKEV2 1
6575
6576def stop_ikev2_assoc(dev, hapd):
6577    dev.request("REMOVE_NETWORK all")
6578    dev.wait_disconnected()
6579    dev.dump_monitor()
6580    hapd.dump_monitor()
6581
6582def test_eap_proto_ikev2_server(dev, apdev):
6583    """EAP-IKEV2 protocol testing for the server"""
6584    check_eap_capa(dev[0], "IKEV2")
6585    params = int_eap_server_params()
6586    params['erp_domain'] = 'example.com'
6587    params['eap_server_erp'] = '1'
6588    hapd = hostapd.add_ap(apdev[0], params)
6589    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
6590    hapd.request("SET ext_eapol_frame_io 1")
6591    dev[0].request("SET ext_eapol_frame_io 1")
6592
6593    # Successful exchange to verify proxying mechanism
6594    start_ikev2_assoc(dev[0], hapd)
6595    proxy_msg(dev[0], hapd) # IKEV2 2
6596    proxy_msg(hapd, dev[0]) # IKEV2 3
6597    proxy_msg(dev[0], hapd) # IKEV2 4
6598    proxy_msg(hapd, dev[0]) # EAP-Success
6599    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 1/4
6600    proxy_msg(dev[0], hapd) # EAPOL-Key msg 2/4
6601    proxy_msg(hapd, dev[0]) # EAPOL-Key msg 3/4
6602    proxy_msg(dev[0], hapd) # EAPOL-Key msg 4/4
6603    dev[0].wait_connected()
6604    stop_ikev2_assoc(dev[0], hapd)
6605
6606    start_ikev2_assoc(dev[0], hapd)
6607    resp = rx_msg(dev[0])
6608    # Too short EAP-IKEV2 header
6609    hapd.note("IKEV2: Too short frame to include HDR")
6610    msg = resp[0:4] + "0005" + resp[8:12] + "0005" + "31"
6611    tx_msg(dev[0], hapd, msg)
6612    rx_msg(hapd)
6613    stop_ikev2_assoc(dev[0], hapd)
6614
6615    start_ikev2_assoc(dev[0], hapd)
6616    resp = rx_msg(dev[0])
6617    # Too short EAP-IKEV2 header - missing Message Length field
6618    hapd.note("EAP-IKEV2: Message underflow")
6619    msg = resp[0:4] + "0006" + resp[8:12] + "0006" + "3180"
6620    tx_msg(dev[0], hapd, msg)
6621    rx_msg(hapd)
6622    stop_ikev2_assoc(dev[0], hapd)
6623
6624    start_ikev2_assoc(dev[0], hapd)
6625    resp = rx_msg(dev[0])
6626    # Too short EAP-IKEV2 header - too small Message Length
6627    hapd.note("EAP-IKEV2: Invalid Message Length (0; 1 remaining in this msg)")
6628    msg = resp[0:4] + "000b" + resp[8:12] + "000b" + "318000000000ff"
6629    tx_msg(dev[0], hapd, msg)
6630    rx_msg(hapd)
6631    stop_ikev2_assoc(dev[0], hapd)
6632
6633    start_ikev2_assoc(dev[0], hapd)
6634    resp = rx_msg(dev[0])
6635    # Too short EAP-IKEV2 header - too large Message Length
6636    hapd.note("EAP-IKEV2: Ignore too long message")
6637    msg = resp[0:4] + "000b" + resp[8:12] + "000b" + "31c0bbccddeeff"
6638    tx_msg(dev[0], hapd, msg)
6639    rx_msg(hapd)
6640    stop_ikev2_assoc(dev[0], hapd)
6641
6642    start_ikev2_assoc(dev[0], hapd)
6643    resp = rx_msg(dev[0])
6644    # No Message Length in first fragment
6645    hapd.note("EAP-IKEV2: No Message Length field in a fragmented packet")
6646    msg = resp[0:4] + "0007" + resp[8:12] + "0007" + "3140ff"
6647    tx_msg(dev[0], hapd, msg)
6648    rx_msg(hapd)
6649    stop_ikev2_assoc(dev[0], hapd)
6650
6651    start_ikev2_assoc(dev[0], hapd)
6652    resp = rx_msg(dev[0])
6653    # First fragment (valid)
6654    hapd.note("EAP-IKEV2: Received 1 bytes in first fragment, waiting for 255 bytes more")
6655    msg = resp[0:4] + "000b" + resp[8:12] + "000b" + "31c000000100ff"
6656    tx_msg(dev[0], hapd, msg)
6657    req = rx_msg(hapd)
6658    id, = struct.unpack('B', binascii.unhexlify(req)[5:6])
6659    hapd.note("EAP-IKEV2: Received 1 bytes in first fragment, waiting for 254 bytes more")
6660    payload = struct.pack('BBB', 49, 0x40, 0)
6661    msg = struct.pack('>BBHBBH', 1, 0, 4 + len(payload), 2, id, 4 + len(payload)) + payload
6662    tx_msg(dev[0], hapd, binascii.hexlify(msg).decode())
6663    req = rx_msg(hapd)
6664    id, = struct.unpack('B', binascii.unhexlify(req)[5:6])
6665    hapd.note("EAP-IKEV2: Fragment overflow")
6666    payload = struct.pack('BB', 49, 0x40) + 255*b'\x00'
6667    msg = struct.pack('>BBHBBH', 1, 0, 4 + len(payload), 2, id, 4 + len(payload)) + payload
6668    tx_msg(dev[0], hapd, binascii.hexlify(msg).decode())
6669    rx_msg(hapd)
6670    stop_ikev2_assoc(dev[0], hapd)
6671
6672    start_ikev2_assoc(dev[0], hapd)
6673    proxy_msg(dev[0], hapd) # IKEV2 2
6674    req = proxy_msg(hapd, dev[0]) # IKEV2 3
6675    id, = struct.unpack('B', binascii.unhexlify(req)[5:6])
6676    # Missing ICV
6677    hapd.note("EAP-IKEV2: The message should have included integrity checksum")
6678    payload = struct.pack('BB', 49, 0) + b'\x00'
6679    msg = struct.pack('>BBHBBH', 1, 0, 4 + len(payload), 2, id, 4 + len(payload)) + payload
6680    tx_msg(dev[0], hapd, binascii.hexlify(msg).decode())
6681    rx_msg(hapd)
6682    stop_ikev2_assoc(dev[0], hapd)
6683
6684    tests = [("Unsupported HDR version 0x0 (expected 0x20)",
6685              struct.pack('BB', 49, 0) + 16*b'\x00' +
6686              struct.pack('>BBBBLL', 0, 0, 0, 0, 0, 0)),
6687             ("IKEV2: Invalid length (HDR: 0 != RX: 28)",
6688              struct.pack('BB', 49, 0) + 16*b'\x00' +
6689              struct.pack('>BBBBLL', 0, 0x20, 0, 0, 0, 0)),
6690             ("IKEV2: Unexpected Exchange Type 0 in SA_INIT state",
6691              struct.pack('BB', 49, 0) + 16*b'\x00' +
6692              struct.pack('>BBBBLL', 0, 0x20, 0, 0, 0, 28)),
6693             ("IKEV2: Unexpected Flags value 0x0",
6694              struct.pack('BB', 49, 0) + 16*b'\x00' +
6695              struct.pack('>BBBBLL', 0, 0x20, 34, 0, 0, 28)),
6696             ("IKEV2: SAr1 not received",
6697              struct.pack('BB', 49, 0) + 16*b'\x00' +
6698              struct.pack('>BBBBLL', 0, 0x20, 34, 0x20, 0, 28))]
6699    for txt, payload in tests:
6700        start_ikev2_assoc(dev[0], hapd)
6701        resp = rx_msg(dev[0])
6702        id, = struct.unpack('B', binascii.unhexlify(resp)[5:6])
6703        hapd.note(txt)
6704        msg = struct.pack('>BBHBBH', 1, 0, 4 + len(payload), 2, id, 4 + len(payload)) + payload
6705        tx_msg(dev[0], hapd, binascii.hexlify(msg).decode())
6706        rx_msg(hapd)
6707        stop_ikev2_assoc(dev[0], hapd)
6708
6709def test_eap_proto_mschapv2(dev, apdev):
6710    """EAP-MSCHAPv2 protocol tests"""
6711    check_eap_capa(dev[0], "MSCHAPV2")
6712
6713    def mschapv2_handler(ctx, req):
6714        logger.info("mschapv2_handler - RX " + binascii.hexlify(req).decode())
6715        if 'num' not in ctx:
6716            ctx['num'] = 0
6717        ctx['num'] = ctx['num'] + 1
6718        if 'id' not in ctx:
6719            ctx['id'] = 1
6720        ctx['id'] = (ctx['id'] + 1) % 256
6721        idx = 0
6722
6723        idx += 1
6724        if ctx['num'] == idx:
6725            logger.info("Test: Missing payload")
6726            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
6727                               4 + 1,
6728                               EAP_TYPE_MSCHAPV2)
6729
6730        idx += 1
6731        if ctx['num'] == idx:
6732            logger.info("Test: Unknown MSCHAPv2 op_code")
6733            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6734                               4 + 1 + 4 + 1,
6735                               EAP_TYPE_MSCHAPV2,
6736                               0, 0, 5, 0)
6737
6738        idx += 1
6739        if ctx['num'] == idx:
6740            logger.info("Test: Invalid ms_len and unknown MSCHAPv2 op_code")
6741            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6742                               4 + 1 + 4 + 1,
6743                               EAP_TYPE_MSCHAPV2,
6744                               255, 0, 0, 0)
6745
6746        idx += 1
6747        if ctx['num'] == idx:
6748            logger.info("Test: Success before challenge")
6749            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6750                               4 + 1 + 4 + 1,
6751                               EAP_TYPE_MSCHAPV2,
6752                               3, 0, 5, 0)
6753
6754        idx += 1
6755        if ctx['num'] == idx:
6756            logger.info("Test: Failure before challenge - required challenge field not present")
6757            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6758                               4 + 1 + 4 + 1,
6759                               EAP_TYPE_MSCHAPV2,
6760                               4, 0, 5, 0)
6761        idx += 1
6762        if ctx['num'] == idx:
6763            logger.info("Test: Failure")
6764            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6765
6766        idx += 1
6767        if ctx['num'] == idx:
6768            logger.info("Test: Failure before challenge - invalid failure challenge len")
6769            payload = b'C=12'
6770            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6771                               4 + 1 + 4 + len(payload),
6772                               EAP_TYPE_MSCHAPV2,
6773                               4, 0, 4 + len(payload)) + payload
6774        idx += 1
6775        if ctx['num'] == idx:
6776            logger.info("Test: Failure")
6777            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6778
6779        idx += 1
6780        if ctx['num'] == idx:
6781            logger.info("Test: Failure before challenge - invalid failure challenge len")
6782            payload = b'C=12 V=3'
6783            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6784                               4 + 1 + 4 + len(payload),
6785                               EAP_TYPE_MSCHAPV2,
6786                               4, 0, 4 + len(payload)) + payload
6787        idx += 1
6788        if ctx['num'] == idx:
6789            logger.info("Test: Failure")
6790            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6791
6792        idx += 1
6793        if ctx['num'] == idx:
6794            logger.info("Test: Failure before challenge - invalid failure challenge")
6795            payload = b'C=00112233445566778899aabbccddeefQ '
6796            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6797                               4 + 1 + 4 + len(payload),
6798                               EAP_TYPE_MSCHAPV2,
6799                               4, 0, 4 + len(payload)) + payload
6800        idx += 1
6801        if ctx['num'] == idx:
6802            logger.info("Test: Failure")
6803            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6804
6805        idx += 1
6806        if ctx['num'] == idx:
6807            logger.info("Test: Failure before challenge - password expired")
6808            payload = b'E=648 R=1 C=00112233445566778899aabbccddeeff V=3 M=Password expired'
6809            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6810                               4 + 1 + 4 + len(payload),
6811                               EAP_TYPE_MSCHAPV2,
6812                               4, 0, 4 + len(payload)) + payload
6813        idx += 1
6814        if ctx['num'] == idx:
6815            logger.info("Test: Success after password change")
6816            payload = b"S=1122334455667788990011223344556677889900"
6817            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6818                               4 + 1 + 4 + len(payload),
6819                               EAP_TYPE_MSCHAPV2,
6820                               3, 0, 4 + len(payload)) + payload
6821
6822        idx += 1
6823        if ctx['num'] == idx:
6824            logger.info("Test: Invalid challenge length")
6825            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6826                               4 + 1 + 4 + 1,
6827                               EAP_TYPE_MSCHAPV2,
6828                               1, 0, 4 + 1, 0)
6829
6830        idx += 1
6831        if ctx['num'] == idx:
6832            logger.info("Test: Too short challenge packet")
6833            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6834                               4 + 1 + 4 + 1,
6835                               EAP_TYPE_MSCHAPV2,
6836                               1, 0, 4 + 1, 16)
6837
6838        idx += 1
6839        if ctx['num'] == idx:
6840            logger.info("Test: Challenge")
6841            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6842                               4 + 1 + 4 + 1 + 16 + 6,
6843                               EAP_TYPE_MSCHAPV2,
6844                               1, 0, 4 + 1 + 16 + 6, 16) + 16*b'A' + b'foobar'
6845        idx += 1
6846        if ctx['num'] == idx:
6847            logger.info("Test: Failure - password expired")
6848            payload = b'E=648 R=1 C=00112233445566778899aabbccddeeff V=3 M=Password expired'
6849            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6850                               4 + 1 + 4 + len(payload),
6851                               EAP_TYPE_MSCHAPV2,
6852                               4, 0, 4 + len(payload)) + payload
6853        idx += 1
6854        if ctx['num'] == idx:
6855            logger.info("Test: Success after password change")
6856            if len(req) != 591:
6857                logger.info("Unexpected Change-Password packet length: %s" % len(req))
6858                return None
6859            data = req[9:]
6860            enc_pw = data[0:516]
6861            data = data[516:]
6862            enc_hash = data[0:16]
6863            data = data[16:]
6864            peer_challenge = data[0:16]
6865            data = data[16:]
6866            # Reserved
6867            data = data[8:]
6868            nt_response = data[0:24]
6869            data = data[24:]
6870            flags = data
6871            logger.info("enc_hash: " + binascii.hexlify(enc_hash).decode())
6872            logger.info("peer_challenge: " + binascii.hexlify(peer_challenge).decode())
6873            logger.info("nt_response: " + binascii.hexlify(nt_response).decode())
6874            logger.info("flags: " + binascii.hexlify(flags).decode())
6875
6876            auth_challenge = binascii.unhexlify("00112233445566778899aabbccddeeff")
6877            logger.info("auth_challenge: " + binascii.hexlify(auth_challenge).decode())
6878
6879            auth_resp = GenerateAuthenticatorResponse("new-pw", nt_response,
6880                                                      peer_challenge,
6881                                                      auth_challenge, "user")
6882            payload = b"S=" + binascii.hexlify(auth_resp).decode().upper().encode()
6883            logger.info("Success message payload: " + payload.decode())
6884            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6885                               4 + 1 + 4 + len(payload),
6886                               EAP_TYPE_MSCHAPV2,
6887                               3, 0, 4 + len(payload)) + payload
6888        idx += 1
6889        if ctx['num'] == idx:
6890            logger.info("Test: EAP-Success")
6891            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
6892
6893        idx += 1
6894        if ctx['num'] == idx:
6895            logger.info("Test: Failure - password expired")
6896            payload = b'E=648 R=1 C=00112233445566778899aabbccddeeff V=3 M=Password expired'
6897            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6898                               4 + 1 + 4 + len(payload),
6899                               EAP_TYPE_MSCHAPV2,
6900                               4, 0, 4 + len(payload)) + payload
6901        idx += 1
6902        if ctx['num'] == idx:
6903            logger.info("Test: Success after password change")
6904            if len(req) != 591:
6905                logger.info("Unexpected Change-Password packet length: %s" % len(req))
6906                return None
6907            data = req[9:]
6908            enc_pw = data[0:516]
6909            data = data[516:]
6910            enc_hash = data[0:16]
6911            data = data[16:]
6912            peer_challenge = data[0:16]
6913            data = data[16:]
6914            # Reserved
6915            data = data[8:]
6916            nt_response = data[0:24]
6917            data = data[24:]
6918            flags = data
6919            logger.info("enc_hash: " + binascii.hexlify(enc_hash).decode())
6920            logger.info("peer_challenge: " + binascii.hexlify(peer_challenge).decode())
6921            logger.info("nt_response: " + binascii.hexlify(nt_response).decode())
6922            logger.info("flags: " + binascii.hexlify(flags).decode())
6923
6924            auth_challenge = binascii.unhexlify("00112233445566778899aabbccddeeff")
6925            logger.info("auth_challenge: " + binascii.hexlify(auth_challenge).decode())
6926
6927            auth_resp = GenerateAuthenticatorResponse("new-pw", nt_response,
6928                                                      peer_challenge,
6929                                                      auth_challenge, "user")
6930            payload = b"S=" + binascii.hexlify(auth_resp).decode().upper().encode()
6931            logger.info("Success message payload: " + payload.decode())
6932            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6933                               4 + 1 + 4 + len(payload),
6934                               EAP_TYPE_MSCHAPV2,
6935                               3, 0, 4 + len(payload)) + payload
6936        idx += 1
6937        if ctx['num'] == idx:
6938            logger.info("Test: EAP-Success")
6939            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
6940
6941        idx += 1
6942        if ctx['num'] == idx:
6943            logger.info("Test: Challenge")
6944            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6945                               4 + 1 + 4 + 1 + 16 + 6,
6946                               EAP_TYPE_MSCHAPV2,
6947                               1, 0, 4 + 1 + 16 + 6, 16) + 16*b'A' + b'foobar'
6948        idx += 1
6949        if ctx['num'] == idx:
6950            logger.info("Test: Failure - authentication failure")
6951            payload = b'E=691 R=1 C=00112233445566778899aabbccddeeff V=3 M=Authentication failed'
6952            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6953                               4 + 1 + 4 + len(payload),
6954                               EAP_TYPE_MSCHAPV2,
6955                               4, 0, 4 + len(payload)) + payload
6956
6957        idx += 1
6958        if ctx['num'] == idx:
6959            logger.info("Test: Challenge")
6960            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6961                               4 + 1 + 4 + 1 + 16 + 6,
6962                               EAP_TYPE_MSCHAPV2,
6963                               1, 0, 4 + 1 + 16 + 6, 16) + 16*b'A' + b'foobar'
6964        idx += 1
6965        if ctx['num'] == idx:
6966            logger.info("Test: Failure - authentication failure")
6967            payload = b'E=691 R=1 C=00112233445566778899aabbccddeeff V=3 M=Authentication failed (2)'
6968            return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
6969                               4 + 1 + 4 + len(payload),
6970                               EAP_TYPE_MSCHAPV2,
6971                               4, 0, 4 + len(payload)) + payload
6972        idx += 1
6973        if ctx['num'] == idx:
6974            logger.info("Test: Failure")
6975            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
6976
6977        idx += 1
6978        if ctx['num'] == idx:
6979            logger.info("Test: Challenge - invalid ms_len and workaround disabled")
6980            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
6981                               4 + 1 + 4 + 1 + 16 + 6,
6982                               EAP_TYPE_MSCHAPV2,
6983                               1, 0, 4 + 1 + 16 + 6 + 1, 16) + 16*b'A' + b'foobar'
6984
6985        return None
6986
6987    srv = start_radius_server(mschapv2_handler)
6988
6989    try:
6990        hapd = start_ap(apdev[0])
6991        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
6992
6993        for i in range(0, 16):
6994            logger.info("RUN: %d" % i)
6995            if i == 12:
6996                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
6997                               eap="MSCHAPV2", identity="user",
6998                               password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
6999                               wait_connect=False)
7000            elif i == 14:
7001                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7002                               eap="MSCHAPV2", identity="user",
7003                               phase2="mschapv2_retry=0",
7004                               password="password", wait_connect=False)
7005            elif i == 15:
7006                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7007                               eap="MSCHAPV2", identity="user",
7008                               eap_workaround="0",
7009                               password="password", wait_connect=False)
7010            else:
7011                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7012                               eap="MSCHAPV2", identity="user",
7013                               password="password", wait_connect=False)
7014            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
7015            if ev is None:
7016                raise Exception("Timeout on EAP start")
7017
7018            if i in [8, 11, 12]:
7019                ev = dev[0].wait_event(["CTRL-REQ-NEW_PASSWORD"],
7020                                       timeout=10)
7021                if ev is None:
7022                    raise Exception("Timeout on new password request")
7023                id = ev.split(':')[0].split('-')[-1]
7024                dev[0].request("CTRL-RSP-NEW_PASSWORD-" + id + ":new-pw")
7025                if i in [11, 12]:
7026                    ev = dev[0].wait_event(["CTRL-EVENT-PASSWORD-CHANGED"],
7027                                       timeout=10)
7028                    if ev is None:
7029                        raise Exception("Timeout on password change")
7030                    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"],
7031                                       timeout=10)
7032                    if ev is None:
7033                        raise Exception("Timeout on EAP success")
7034                else:
7035                    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
7036                                           timeout=10)
7037                    if ev is None:
7038                        raise Exception("Timeout on EAP failure")
7039
7040            if i in [13]:
7041                ev = dev[0].wait_event(["CTRL-REQ-IDENTITY"],
7042                                       timeout=10)
7043                if ev is None:
7044                    raise Exception("Timeout on identity request")
7045                id = ev.split(':')[0].split('-')[-1]
7046                dev[0].request("CTRL-RSP-IDENTITY-" + id + ":user")
7047
7048                ev = dev[0].wait_event(["CTRL-REQ-PASSWORD"],
7049                                       timeout=10)
7050                if ev is None:
7051                    raise Exception("Timeout on password request")
7052                id = ev.split(':')[0].split('-')[-1]
7053                dev[0].request("CTRL-RSP-PASSWORD-" + id + ":password")
7054
7055                # TODO: Does this work correctly?
7056
7057                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
7058                                       timeout=10)
7059                if ev is None:
7060                    raise Exception("Timeout on EAP failure")
7061
7062            if i in [4, 5, 6, 7, 14]:
7063                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"],
7064                                       timeout=10)
7065                if ev is None:
7066                    raise Exception("Timeout on EAP failure")
7067            else:
7068                time.sleep(0.05)
7069            dev[0].request("REMOVE_NETWORK all")
7070            dev[0].wait_disconnected(timeout=1)
7071    finally:
7072        stop_radius_server(srv)
7073
7074def test_eap_proto_mschapv2_errors(dev, apdev):
7075    """EAP-MSCHAPv2 protocol tests (error paths)"""
7076    check_eap_capa(dev[0], "MSCHAPV2")
7077
7078    def mschapv2_fail_password_expired(ctx):
7079        logger.info("Test: Failure before challenge - password expired")
7080        payload = b'E=648 R=1 C=00112233445566778899aabbccddeeff V=3 M=Password expired'
7081        return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
7082                           4 + 1 + 4 + len(payload),
7083                           EAP_TYPE_MSCHAPV2,
7084                           4, 0, 4 + len(payload)) + payload
7085
7086    def mschapv2_success_after_password_change(ctx, req=None):
7087        logger.info("Test: Success after password change")
7088        if req is None or len(req) != 591:
7089            payload = b"S=1122334455667788990011223344556677889900"
7090        else:
7091            data = req[9:]
7092            enc_pw = data[0:516]
7093            data = data[516:]
7094            enc_hash = data[0:16]
7095            data = data[16:]
7096            peer_challenge = data[0:16]
7097            data = data[16:]
7098            # Reserved
7099            data = data[8:]
7100            nt_response = data[0:24]
7101            data = data[24:]
7102            flags = data
7103            logger.info("enc_hash: " + binascii.hexlify(enc_hash).decode())
7104            logger.info("peer_challenge: " + binascii.hexlify(peer_challenge).decode())
7105            logger.info("nt_response: " + binascii.hexlify(nt_response).decode())
7106            logger.info("flags: " + binascii.hexlify(flags).decode())
7107
7108            auth_challenge = binascii.unhexlify("00112233445566778899aabbccddeeff")
7109            logger.info("auth_challenge: " + binascii.hexlify(auth_challenge).decode())
7110
7111            auth_resp = GenerateAuthenticatorResponse("new-pw", nt_response,
7112                                                      peer_challenge,
7113                                                      auth_challenge, "user")
7114            payload = b"S=" + binascii.hexlify(auth_resp).decode().upper().encode()
7115        return struct.pack(">BBHBBBH", EAP_CODE_REQUEST, ctx['id'],
7116                           4 + 1 + 4 + len(payload),
7117                           EAP_TYPE_MSCHAPV2,
7118                           3, 0, 4 + len(payload)) + payload
7119
7120    def mschapv2_handler(ctx, req):
7121        logger.info("mschapv2_handler - RX " + binascii.hexlify(req).decode())
7122        if 'num' not in ctx:
7123            ctx['num'] = 0
7124        ctx['num'] = ctx['num'] + 1
7125        if 'id' not in ctx:
7126            ctx['id'] = 1
7127        ctx['id'] = (ctx['id'] + 1) % 256
7128        idx = 0
7129
7130        idx += 1
7131        if ctx['num'] == idx:
7132            return mschapv2_fail_password_expired(ctx)
7133        idx += 1
7134        if ctx['num'] == idx:
7135            return mschapv2_success_after_password_change(ctx, req)
7136        idx += 1
7137        if ctx['num'] == idx:
7138            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7139
7140        idx += 1
7141        if ctx['num'] == idx:
7142            return mschapv2_fail_password_expired(ctx)
7143        idx += 1
7144        if ctx['num'] == idx:
7145            return mschapv2_success_after_password_change(ctx, req)
7146        idx += 1
7147        if ctx['num'] == idx:
7148            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7149
7150        idx += 1
7151        if ctx['num'] == idx:
7152            return mschapv2_fail_password_expired(ctx)
7153        idx += 1
7154        if ctx['num'] == idx:
7155            return mschapv2_success_after_password_change(ctx, req)
7156        idx += 1
7157        if ctx['num'] == idx:
7158            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7159
7160        idx += 1
7161        if ctx['num'] == idx:
7162            return mschapv2_fail_password_expired(ctx)
7163        idx += 1
7164        if ctx['num'] == idx:
7165            return mschapv2_success_after_password_change(ctx, req)
7166        idx += 1
7167        if ctx['num'] == idx:
7168            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7169
7170        idx += 1
7171        if ctx['num'] == idx:
7172            return mschapv2_fail_password_expired(ctx)
7173        idx += 1
7174        if ctx['num'] == idx:
7175            return mschapv2_success_after_password_change(ctx, req)
7176        idx += 1
7177        if ctx['num'] == idx:
7178            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7179
7180        idx += 1
7181        if ctx['num'] == idx:
7182            return mschapv2_fail_password_expired(ctx)
7183        idx += 1
7184        if ctx['num'] == idx:
7185            return mschapv2_success_after_password_change(ctx, req)
7186        idx += 1
7187        if ctx['num'] == idx:
7188            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7189
7190        idx += 1
7191        if ctx['num'] == idx:
7192            return mschapv2_fail_password_expired(ctx)
7193        idx += 1
7194        if ctx['num'] == idx:
7195            return mschapv2_success_after_password_change(ctx, req)
7196        idx += 1
7197        if ctx['num'] == idx:
7198            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7199
7200        idx += 1
7201        if ctx['num'] == idx:
7202            return mschapv2_fail_password_expired(ctx)
7203        idx += 1
7204        if ctx['num'] == idx:
7205            return mschapv2_success_after_password_change(ctx, req)
7206        idx += 1
7207        if ctx['num'] == idx:
7208            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7209
7210        idx += 1
7211        if ctx['num'] == idx:
7212            return mschapv2_fail_password_expired(ctx)
7213        idx += 1
7214        if ctx['num'] == idx:
7215            return mschapv2_success_after_password_change(ctx, req)
7216        idx += 1
7217        if ctx['num'] == idx:
7218            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7219
7220        return None
7221
7222    srv = start_radius_server(mschapv2_handler)
7223
7224    try:
7225        hapd = start_ap(apdev[0])
7226        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
7227
7228        tests = ["os_get_random;eap_mschapv2_change_password",
7229                 "generate_nt_response;eap_mschapv2_change_password",
7230                 "get_master_key;eap_mschapv2_change_password",
7231                 "nt_password_hash;eap_mschapv2_change_password",
7232                 "old_nt_password_hash_encrypted_with_new_nt_password_hash"]
7233        for func in tests:
7234            with fail_test(dev[0], 1, func):
7235                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7236                               eap="MSCHAPV2", identity="user",
7237                               password="password", wait_connect=False)
7238                ev = dev[0].wait_event(["CTRL-REQ-NEW_PASSWORD"], timeout=10)
7239                if ev is None:
7240                    raise Exception("Timeout on new password request")
7241                id = ev.split(':')[0].split('-')[-1]
7242                dev[0].request("CTRL-RSP-NEW_PASSWORD-" + id + ":new-pw")
7243                time.sleep(0.1)
7244                wait_fail_trigger(dev[0], "GET_FAIL")
7245                dev[0].request("REMOVE_NETWORK all")
7246                dev[0].wait_disconnected(timeout=1)
7247
7248        tests = ["encrypt_pw_block_with_password_hash;eap_mschapv2_change_password",
7249                 "nt_password_hash;eap_mschapv2_change_password",
7250                 "nt_password_hash;eap_mschapv2_success"]
7251        for func in tests:
7252            with fail_test(dev[0], 1, func):
7253                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7254                               eap="MSCHAPV2", identity="user",
7255                               password_hex="hash:8846f7eaee8fb117ad06bdd830b7586c",
7256                               wait_connect=False)
7257                ev = dev[0].wait_event(["CTRL-REQ-NEW_PASSWORD"], timeout=10)
7258                if ev is None:
7259                    raise Exception("Timeout on new password request")
7260                id = ev.split(':')[0].split('-')[-1]
7261                dev[0].request("CTRL-RSP-NEW_PASSWORD-" + id + ":new-pw")
7262                time.sleep(0.1)
7263                wait_fail_trigger(dev[0], "GET_FAIL")
7264                dev[0].request("REMOVE_NETWORK all")
7265                dev[0].wait_disconnected(timeout=1)
7266
7267        tests = ["eap_msg_alloc;eap_mschapv2_change_password"]
7268        for func in tests:
7269            with alloc_fail(dev[0], 1, func):
7270                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7271                               eap="MSCHAPV2", identity="user",
7272                               password="password", wait_connect=False)
7273                ev = dev[0].wait_event(["CTRL-REQ-NEW_PASSWORD"], timeout=10)
7274                if ev is None:
7275                    raise Exception("Timeout on new password request")
7276                id = ev.split(':')[0].split('-')[-1]
7277                dev[0].request("CTRL-RSP-NEW_PASSWORD-" + id + ":new-pw")
7278                time.sleep(0.1)
7279                wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
7280                dev[0].request("REMOVE_NETWORK all")
7281                dev[0].wait_disconnected(timeout=1)
7282    finally:
7283        stop_radius_server(srv)
7284
7285def test_eap_proto_pwd(dev, apdev):
7286    """EAP-pwd protocol tests"""
7287    check_eap_capa(dev[0], "PWD")
7288
7289    global eap_proto_pwd_test_done, eap_proto_pwd_test_wait
7290    eap_proto_pwd_test_done = False
7291    eap_proto_pwd_test_wait = False
7292
7293    def pwd_handler(ctx, req):
7294        logger.info("pwd_handler - RX " + binascii.hexlify(req).decode())
7295        if 'num' not in ctx:
7296            ctx['num'] = 0
7297        ctx['num'] = ctx['num'] + 1
7298        if 'id' not in ctx:
7299            ctx['id'] = 1
7300        ctx['id'] = (ctx['id'] + 1) % 256
7301        idx = 0
7302
7303        global eap_proto_pwd_test_wait
7304        eap_proto_pwd_test_wait = False
7305
7306        idx += 1
7307        if ctx['num'] == idx:
7308            logger.info("Test: Missing payload")
7309            # EAP-pwd: Got a frame but pos is not NULL and len is 0
7310            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'], 4 + 1,
7311                               EAP_TYPE_PWD)
7312
7313        idx += 1
7314        if ctx['num'] == idx:
7315            logger.info("Test: Missing Total-Length field")
7316            # EAP-pwd: Frame too short to contain Total-Length field
7317            payload = struct.pack("B", 0x80)
7318            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7319                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7320
7321        idx += 1
7322        if ctx['num'] == idx:
7323            logger.info("Test: Too large Total-Length")
7324            # EAP-pwd: Incoming fragments whose total length = 65535
7325            payload = struct.pack(">BH", 0x80, 65535)
7326            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7327                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7328
7329        idx += 1
7330        if ctx['num'] == idx:
7331            eap_proto_pwd_test_wait = True
7332            logger.info("Test: First fragment")
7333            # EAP-pwd: Incoming fragments whose total length = 10
7334            # EAP-pwd: ACKing a 0 byte fragment
7335            payload = struct.pack(">BH", 0xc0, 10)
7336            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7337                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7338        idx += 1
7339        if ctx['num'] == idx:
7340            logger.info("Test: Unexpected Total-Length value in the second fragment")
7341            # EAP-pwd: Incoming fragments whose total length = 0
7342            # EAP-pwd: Unexpected new fragment start when previous fragment is still in use
7343            payload = struct.pack(">BH", 0x80, 0)
7344            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7345                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7346
7347        idx += 1
7348        if ctx['num'] == idx:
7349            logger.info("Test: First and only fragment")
7350            # EAP-pwd: Incoming fragments whose total length = 0
7351            # EAP-pwd: processing frame: exch 0, len 0
7352            # EAP-pwd: Ignoring message with unknown opcode 128
7353            payload = struct.pack(">BH", 0x80, 0)
7354            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7355                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7356
7357        idx += 1
7358        if ctx['num'] == idx:
7359            logger.info("Test: First and only fragment with extra data")
7360            # EAP-pwd: Incoming fragments whose total length = 0
7361            # EAP-pwd: processing frame: exch 0, len 1
7362            # EAP-pwd: Ignoring message with unknown opcode 128
7363            payload = struct.pack(">BHB", 0x80, 0, 0)
7364            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7365                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7366
7367        idx += 1
7368        if ctx['num'] == idx:
7369            eap_proto_pwd_test_wait = True
7370            logger.info("Test: First fragment")
7371            # EAP-pwd: Incoming fragments whose total length = 2
7372            # EAP-pwd: ACKing a 1 byte fragment
7373            payload = struct.pack(">BHB", 0xc0, 2, 1)
7374            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7375                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7376        idx += 1
7377        if ctx['num'] == idx:
7378            logger.info("Test: Extra data in the second fragment")
7379            # EAP-pwd: Buffer overflow attack detected (3 vs. 1)!
7380            payload = struct.pack(">BBB", 0x0, 2, 3)
7381            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7382                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7383
7384        idx += 1
7385        if ctx['num'] == idx:
7386            logger.info("Test: Too short id exchange")
7387            # EAP-pwd: processing frame: exch 1, len 0
7388            # EAP-PWD: PWD-ID-Req -> FAILURE
7389            payload = struct.pack(">B", 0x01)
7390            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7391                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7392
7393        idx += 1
7394        if ctx['num'] == idx:
7395            logger.info("Test: Unsupported rand func in id exchange")
7396            # EAP-PWD: Server EAP-pwd-ID proposal: group=0 random=0 prf=0 prep=0
7397            # EAP-PWD: PWD-ID-Req -> FAILURE
7398            payload = struct.pack(">BHBBLB", 0x01, 0, 0, 0, 0, 0)
7399            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7400                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7401
7402        idx += 1
7403        if ctx['num'] == idx:
7404            logger.info("Test: Unsupported prf in id exchange")
7405            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=0 prep=0
7406            # EAP-PWD: PWD-ID-Req -> FAILURE
7407            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 0, 0, 0)
7408            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7409                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7410
7411        idx += 1
7412        if ctx['num'] == idx:
7413            logger.info("Test: Unsupported password pre-processing technique in id exchange")
7414            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=255
7415            # EAP-PWD: Unsupported password pre-processing technique (Prep=255)
7416            # EAP-PWD: PWD-ID-Req -> FAILURE
7417            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 255)
7418            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7419                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7420
7421        idx += 1
7422        if ctx['num'] == idx:
7423            eap_proto_pwd_test_wait = True
7424            logger.info("Test: Valid id exchange")
7425            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=0
7426            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7427            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7428                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7429        idx += 1
7430        if ctx['num'] == idx:
7431            logger.info("Test: Unexpected id exchange")
7432            # EAP-pwd: processing frame: exch 1, len 9
7433            # EAP-PWD: PWD-Commit-Req -> FAILURE
7434            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7435            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7436                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7437
7438        idx += 1
7439        if ctx['num'] == idx:
7440            logger.info("Test: Unexpected commit exchange")
7441            # EAP-pwd: processing frame: exch 2, len 0
7442            # EAP-PWD: PWD-ID-Req -> FAILURE
7443            payload = struct.pack(">B", 0x02)
7444            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7445                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7446
7447        idx += 1
7448        if ctx['num'] == idx:
7449            eap_proto_pwd_test_wait = True
7450            logger.info("Test: Valid id exchange")
7451            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=0
7452            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7453            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7454                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7455        idx += 1
7456        if ctx['num'] == idx:
7457            logger.info("Test: Unexpected Commit payload length (prep=None)")
7458            # EAP-pwd commit request, password prep is NONE
7459            # EAP-pwd: Unexpected Commit payload length 0 (expected 96)
7460            payload = struct.pack(">B", 0x02)
7461            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7462                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7463
7464        idx += 1
7465        if ctx['num'] == idx:
7466            eap_proto_pwd_test_wait = True
7467            logger.info("Test: Valid id exchange")
7468            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=0
7469            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7470            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7471                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7472        idx += 1
7473        if ctx['num'] == idx:
7474            logger.info("Test: Commit payload with all zeros values --> Shared key at infinity")
7475            # EAP-pwd: Invalid coordinate in element
7476            payload = struct.pack(">B", 0x02) + 96*b'\0'
7477            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7478                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7479
7480        idx += 1
7481        if ctx['num'] == idx:
7482            eap_proto_pwd_test_wait = True
7483            logger.info("Test: Valid id exchange")
7484            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=0
7485            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7486            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7487                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7488        idx += 1
7489        if ctx['num'] == idx:
7490            eap_proto_pwd_test_wait = True
7491            logger.info("Test: Commit payload with valid values")
7492            # EAP-pwd commit request, password prep is NONE
7493            element = binascii.unhexlify("8dcab2862c5396839a6bac0c689ff03d962863108e7c275bbf1d6eedf634ee832a214db99f0d0a1a6317733eecdd97f0fc4cda19f57e1bb9bb9c8dcf8c60ba6f")
7494            scalar = binascii.unhexlify("450f31e058cf2ac2636a5d6e2b3c70b1fcc301957f0716e77f13aa69f9a2e5bd")
7495            payload = struct.pack(">B", 0x02) + element + scalar
7496            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7497                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7498        idx += 1
7499        if ctx['num'] == idx:
7500            logger.info("Test: Unexpected Confirm payload length 0")
7501            # EAP-pwd: Unexpected Confirm payload length 0 (expected 32)
7502            payload = struct.pack(">B", 0x03)
7503            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7504                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7505
7506        idx += 1
7507        if ctx['num'] == idx:
7508            eap_proto_pwd_test_wait = True
7509            logger.info("Test: Valid id exchange")
7510            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=0
7511            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7512            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7513                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7514        idx += 1
7515        if ctx['num'] == idx:
7516            eap_proto_pwd_test_wait = True
7517            logger.info("Test: Commit payload with valid values")
7518            # EAP-pwd commit request, password prep is NONE
7519            element = binascii.unhexlify("8dcab2862c5396839a6bac0c689ff03d962863108e7c275bbf1d6eedf634ee832a214db99f0d0a1a6317733eecdd97f0fc4cda19f57e1bb9bb9c8dcf8c60ba6f")
7520            scalar = binascii.unhexlify("450f31e058cf2ac2636a5d6e2b3c70b1fcc301957f0716e77f13aa69f9a2e5bd")
7521            payload = struct.pack(">B", 0x02) + element + scalar
7522            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7523                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7524        idx += 1
7525        if ctx['num'] == idx:
7526            logger.info("Test: Confirm payload with incorrect value")
7527            # EAP-PWD (peer): confirm did not verify
7528            payload = struct.pack(">B", 0x03) + 32*b'\0'
7529            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7530                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7531
7532        idx += 1
7533        if ctx['num'] == idx:
7534            logger.info("Test: Unexpected confirm exchange")
7535            # EAP-pwd: processing frame: exch 3, len 0
7536            # EAP-PWD: PWD-ID-Req -> FAILURE
7537            payload = struct.pack(">B", 0x03)
7538            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7539                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7540
7541        idx += 1
7542        if ctx['num'] == idx:
7543            logger.info("Test: Unsupported password pre-processing technique SASLprep in id exchange")
7544            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=2
7545            # EAP-PWD: Unsupported password pre-processing technique (Prep=2)
7546            # EAP-PWD: PWD-ID-Req -> FAILURE
7547            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 2)
7548            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7549                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7550
7551        idx += 1
7552        if ctx['num'] == idx:
7553            eap_proto_pwd_test_wait = True
7554            logger.info("Test: Valid id exchange")
7555            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=1
7556            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 1)
7557            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7558                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7559        idx += 1
7560        if ctx['num'] == idx:
7561            logger.info("Test: Unexpected Commit payload length (prep=MS)")
7562            # EAP-pwd commit request, password prep is MS
7563            # EAP-pwd: Unexpected Commit payload length 0 (expected 96)
7564            payload = struct.pack(">B", 0x02)
7565            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7566                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7567
7568        idx += 1
7569        if ctx['num'] == idx:
7570            eap_proto_pwd_test_wait = True
7571            logger.info("Test: Valid id exchange")
7572            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=3
7573            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 3)
7574            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7575                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7576        idx += 1
7577        if ctx['num'] == idx:
7578            logger.info("Test: Unexpected Commit payload length (prep=ssha1)")
7579            # EAP-pwd commit request, password prep is salted sha1
7580            # EAP-pwd: Invalid Salt-len
7581            payload = struct.pack(">B", 0x02)
7582            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7583                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7584
7585        idx += 1
7586        if ctx['num'] == idx:
7587            eap_proto_pwd_test_wait = True
7588            logger.info("Test: Valid id exchange")
7589            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=3
7590            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 3)
7591            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7592                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7593        idx += 1
7594        if ctx['num'] == idx:
7595            logger.info("Test: Unexpected Commit payload length (prep=ssha1)")
7596            # EAP-pwd commit request, password prep is salted sha1
7597            # EAP-pwd: Invalid Salt-len
7598            payload = struct.pack(">BB", 0x02, 0)
7599            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7600                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7601
7602        idx += 1
7603        if ctx['num'] == idx:
7604            eap_proto_pwd_test_wait = True
7605            logger.info("Test: Valid id exchange")
7606            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=3
7607            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 3)
7608            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7609                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7610        idx += 1
7611        if ctx['num'] == idx:
7612            logger.info("Test: Unexpected Commit payload length (prep=ssha1)")
7613            # EAP-pwd commit request, password prep is salted sha1
7614            # EAP-pwd: Unexpected Commit payload length 1 (expected 98)
7615            payload = struct.pack(">BB", 0x02, 1)
7616            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7617                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7618
7619        idx += 1
7620        if ctx['num'] == idx:
7621            eap_proto_pwd_test_wait = True
7622            logger.info("Test: Valid id exchange")
7623            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=4
7624            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 4)
7625            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7626                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7627        idx += 1
7628        if ctx['num'] == idx:
7629            logger.info("Test: Unexpected Commit payload length (prep=ssha256)")
7630            # EAP-pwd commit request, password prep is salted sha256
7631            # EAP-pwd: Invalid Salt-len
7632            payload = struct.pack(">B", 0x02)
7633            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7634                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7635
7636        idx += 1
7637        if ctx['num'] == idx:
7638            eap_proto_pwd_test_wait = True
7639            logger.info("Test: Valid id exchange")
7640            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=4
7641            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 4)
7642            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7643                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7644        idx += 1
7645        if ctx['num'] == idx:
7646            logger.info("Test: Unexpected Commit payload length (prep=ssha256)")
7647            # EAP-pwd commit request, password prep is salted sha256
7648            # EAP-pwd: Invalid Salt-len
7649            payload = struct.pack(">BB", 0x02, 0)
7650            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7651                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7652
7653        idx += 1
7654        if ctx['num'] == idx:
7655            eap_proto_pwd_test_wait = True
7656            logger.info("Test: Valid id exchange")
7657            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=4
7658            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 4)
7659            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7660                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7661        idx += 1
7662        if ctx['num'] == idx:
7663            logger.info("Test: Unexpected Commit payload length (prep=ssha256)")
7664            # EAP-pwd commit request, password prep is salted sha256
7665            # EAP-pwd: Unexpected Commit payload length 1 (expected 98)
7666            payload = struct.pack(">BB", 0x02, 1)
7667            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7668                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7669
7670        idx += 1
7671        if ctx['num'] == idx:
7672            eap_proto_pwd_test_wait = True
7673            logger.info("Test: Valid id exchange")
7674            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=5
7675            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 5)
7676            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7677                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7678        idx += 1
7679        if ctx['num'] == idx:
7680            logger.info("Test: Unexpected Commit payload length (prep=ssha512)")
7681            # EAP-pwd commit request, password prep is salted sha512
7682            # EAP-pwd: Invalid Salt-len
7683            payload = struct.pack(">B", 0x02)
7684            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7685                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7686
7687        idx += 1
7688        if ctx['num'] == idx:
7689            eap_proto_pwd_test_wait = True
7690            logger.info("Test: Valid id exchange")
7691            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=5
7692            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 5)
7693            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7694                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7695        idx += 1
7696        if ctx['num'] == idx:
7697            logger.info("Test: Unexpected Commit payload length (prep=ssha512)")
7698            # EAP-pwd commit request, password prep is salted sha512
7699            # EAP-pwd: Invalid Salt-len
7700            payload = struct.pack(">BB", 0x02, 0)
7701            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7702                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7703
7704        idx += 1
7705        if ctx['num'] == idx:
7706            eap_proto_pwd_test_wait = True
7707            logger.info("Test: Valid id exchange")
7708            # EAP-PWD: Server EAP-pwd-ID proposal: group=19 random=1 prf=1 prep=5
7709            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 5)
7710            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7711                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7712        idx += 1
7713        if ctx['num'] == idx:
7714            logger.info("Test: Unexpected Commit payload length (prep=ssha512)")
7715            # EAP-pwd commit request, password prep is salted sha512
7716            # EAP-pwd: Unexpected Commit payload length 1 (expected 98)
7717            payload = struct.pack(">BB", 0x02, 1)
7718            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7719                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7720
7721        logger.info("No more test responses available - test case completed")
7722        global eap_proto_pwd_test_done
7723        eap_proto_pwd_test_done = True
7724        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7725
7726    srv = start_radius_server(pwd_handler)
7727
7728    try:
7729        hapd = start_ap(apdev[0])
7730        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
7731
7732        i = 0
7733        while not eap_proto_pwd_test_done:
7734            i += 1
7735            logger.info("Running connection iteration %d" % i)
7736            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7737                           eap="PWD", identity="pwd user",
7738                           password="secret password",
7739                           wait_connect=False)
7740            ok = False
7741            for j in range(5):
7742                ev = dev[0].wait_event(["CTRL-EVENT-EAP-STATUS",
7743                                        "CTRL-EVENT-EAP-PROPOSED-METHOD"],
7744                                       timeout=5)
7745                if ev is None:
7746                    raise Exception("Timeout on EAP start")
7747                if "CTRL-EVENT-EAP-PROPOSED-METHOD" in ev:
7748                    ok = True
7749                    break
7750                if "CTRL-EVENT-EAP-STATUS" in ev and "status='completion' parameter='failure'" in ev:
7751                    ok = True
7752                    break
7753            if not ok:
7754                raise Exception("Expected EAP event not seen")
7755            if eap_proto_pwd_test_wait:
7756                for k in range(20):
7757                    time.sleep(0.1)
7758                    if not eap_proto_pwd_test_wait:
7759                        break
7760                if eap_proto_pwd_test_wait:
7761                    raise Exception("eap_proto_pwd_test_wait not cleared")
7762            dev[0].request("REMOVE_NETWORK all")
7763            dev[0].wait_disconnected(timeout=1)
7764            dev[0].dump_monitor()
7765    finally:
7766        stop_radius_server(srv)
7767
7768def test_eap_proto_pwd_invalid_scalar(dev, apdev):
7769    """EAP-pwd protocol tests - invalid server scalar"""
7770    check_eap_capa(dev[0], "PWD")
7771    run_eap_proto_pwd_invalid_scalar(dev, apdev, 32*b'\0')
7772    run_eap_proto_pwd_invalid_scalar(dev, apdev, 31*b'\0' + b'\x01')
7773    # Group Order
7774    val = binascii.unhexlify("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")
7775    run_eap_proto_pwd_invalid_scalar(dev, apdev, val)
7776    # Group Order - 1
7777    val = binascii.unhexlify("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632550")
7778    run_eap_proto_pwd_invalid_scalar(dev, apdev, val, valid_scalar=True)
7779
7780def run_eap_proto_pwd_invalid_scalar(dev, apdev, scalar, valid_scalar=False):
7781    global eap_proto_pwd_invalid_scalar_fail
7782    eap_proto_pwd_invalid_scalar_fail = False
7783
7784    def pwd_handler(ctx, req):
7785        logger.info("pwd_handler - RX " + binascii.hexlify(req).decode())
7786        if 'num' not in ctx:
7787            ctx['num'] = 0
7788        ctx['num'] = ctx['num'] + 1
7789        if 'id' not in ctx:
7790            ctx['id'] = 1
7791        ctx['id'] = (ctx['id'] + 1) % 256
7792        idx = 0
7793
7794        idx += 1
7795        if ctx['num'] == idx:
7796            logger.info("Test: Valid id exchange")
7797            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7798            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7799                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7800        idx += 1
7801        if ctx['num'] == idx:
7802            logger.info("Test: Commit payload with invalid scalar")
7803            payload = struct.pack(">B", 0x02) + binascii.unhexlify("67feb2b46d59e6dd3af3a429ec9c04a949337564615d3a2c19bdf6826eb6f5efa303aed86af3a072ed819d518d620adb2659f0e84c4f8b739629db8c93088cfc") + scalar
7804            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7805                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7806        idx += 1
7807        if ctx['num'] == idx:
7808            logger.info("Confirm message next - should not get here")
7809            global eap_proto_pwd_invalid_scalar_fail
7810            eap_proto_pwd_invalid_scalar_fail = True
7811            payload = struct.pack(">B", 0x03) + 32*b'\0'
7812            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7813                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7814
7815        logger.info("No more test responses available - test case completed")
7816        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7817
7818    srv = start_radius_server(pwd_handler)
7819
7820    try:
7821        hapd = start_ap(apdev[0])
7822        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
7823
7824        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7825                       eap="PWD", identity="pwd user",
7826                       password="secret password",
7827                       wait_connect=False)
7828        ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
7829        if ev is None:
7830            raise Exception("EAP failure not reported")
7831        dev[0].request("REMOVE_NETWORK all")
7832        dev[0].wait_disconnected(timeout=1)
7833        dev[0].dump_monitor()
7834    finally:
7835        stop_radius_server(srv)
7836
7837    if valid_scalar and not eap_proto_pwd_invalid_scalar_fail:
7838        raise Exception("Peer did not accept valid EAP-pwd-Commit scalar")
7839    if not valid_scalar and eap_proto_pwd_invalid_scalar_fail:
7840        raise Exception("Peer did not stop after invalid EAP-pwd-Commit scalar")
7841
7842def test_eap_proto_pwd_invalid_element(dev, apdev):
7843    """EAP-pwd protocol tests - invalid server element"""
7844    check_eap_capa(dev[0], "PWD")
7845    # Invalid x,y coordinates
7846    run_eap_proto_pwd_invalid_element(dev, apdev, 64*b'\x00')
7847    run_eap_proto_pwd_invalid_element(dev, apdev, 32*b'\x00' + 32*b'\x01')
7848    run_eap_proto_pwd_invalid_element(dev, apdev, 32*b'\x01' + 32*b'\x00')
7849    run_eap_proto_pwd_invalid_element(dev, apdev, 32*b'\xff' + 32*b'\x01')
7850    run_eap_proto_pwd_invalid_element(dev, apdev, 32*b'\x01' + 32*b'\xff')
7851    run_eap_proto_pwd_invalid_element(dev, apdev, 64*b'\xff')
7852    # Not on curve
7853    run_eap_proto_pwd_invalid_element(dev, apdev, 64*b'\x01')
7854
7855def run_eap_proto_pwd_invalid_element(dev, apdev, element):
7856    global eap_proto_pwd_invalid_element_fail
7857    eap_proto_pwd_invalid_element_fail = False
7858
7859    def pwd_handler(ctx, req):
7860        logger.info("pwd_handler - RX " + binascii.hexlify(req).decode())
7861        if 'num' not in ctx:
7862            ctx['num'] = 0
7863        ctx['num'] = ctx['num'] + 1
7864        if 'id' not in ctx:
7865            ctx['id'] = 1
7866        ctx['id'] = (ctx['id'] + 1) % 256
7867        idx = 0
7868
7869        idx += 1
7870        if ctx['num'] == idx:
7871            logger.info("Test: Valid id exchange")
7872            payload = struct.pack(">BHBBLB", 0x01, 19, 1, 1, 0, 0)
7873            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7874                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7875        idx += 1
7876        if ctx['num'] == idx:
7877            logger.info("Test: Commit payload with invalid element")
7878            payload = struct.pack(">B", 0x02) + element + 31*b'\0' + b'\x02'
7879            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7880                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7881        idx += 1
7882        if ctx['num'] == idx:
7883            logger.info("Confirm message next - should not get here")
7884            global eap_proto_pwd_invalid_element_fail
7885            eap_proto_pwd_invalid_element_fail = True
7886            payload = struct.pack(">B", 0x03) + 32*b'\0'
7887            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
7888                               4 + 1 + len(payload), EAP_TYPE_PWD) + payload
7889
7890        logger.info("No more test responses available - test case completed")
7891        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
7892
7893    srv = start_radius_server(pwd_handler)
7894
7895    try:
7896        hapd = start_ap(apdev[0])
7897        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
7898
7899        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
7900                       eap="PWD", identity="pwd user",
7901                       password="secret password",
7902                       wait_connect=False)
7903        ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
7904        if ev is None:
7905            raise Exception("EAP failure not reported")
7906        dev[0].request("REMOVE_NETWORK all")
7907        dev[0].wait_disconnected(timeout=1)
7908        dev[0].dump_monitor()
7909    finally:
7910        stop_radius_server(srv)
7911
7912    if eap_proto_pwd_invalid_element_fail:
7913        raise Exception("Peer did not stop after invalid EAP-pwd-Commit element")
7914
7915def rx_msg(src):
7916    ev = src.wait_event(["EAPOL-TX"], timeout=5)
7917    if ev is None:
7918        raise Exception("No EAPOL-TX")
7919    return ev.split(' ')[2]
7920
7921def tx_msg(src, dst, msg):
7922    dst.request("EAPOL_RX " + src.own_addr() + " " + msg)
7923
7924def proxy_msg(src, dst):
7925    msg = rx_msg(src)
7926    tx_msg(src, dst, msg)
7927    return msg
7928
7929def start_pwd_exchange(dev, ap):
7930    check_eap_capa(dev, "PWD")
7931    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
7932    hapd = hostapd.add_ap(ap, params)
7933    hapd.request("SET ext_eapol_frame_io 1")
7934    dev.request("SET ext_eapol_frame_io 1")
7935    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP",
7936                   eap="PWD", identity="pwd user", password="secret password",
7937                   wait_connect=False, scan_freq="2412")
7938    proxy_msg(hapd, dev) # EAP-Identity/Request
7939    proxy_msg(dev, hapd) # EAP-Identity/Response
7940    proxy_msg(hapd, dev) # EAP-pwd-ID/Request
7941    proxy_msg(dev, hapd) # EAP-pwd-ID/Response
7942    return hapd
7943
7944def test_eap_proto_pwd_unexpected_fragment(dev, apdev):
7945    """EAP-pwd protocol tests - unexpected more-fragment frame"""
7946    hapd = start_pwd_exchange(dev[0], apdev[0])
7947
7948    # EAP-pwd-Commit/Request
7949    req = rx_msg(hapd)
7950    if req[18:20] != "02":
7951        raise Exception("Unexpected EAP-pwd-Commit/Request flag")
7952    msg = req[0:18] + "42" + req[20:]
7953    tx_msg(hapd, dev[0], msg)
7954
7955def test_eap_proto_pwd_reflection_attack(dev, apdev):
7956    """EAP-pwd protocol tests - reflection attack on the server"""
7957    hapd = start_pwd_exchange(dev[0], apdev[0])
7958
7959    # EAP-pwd-Commit/Request
7960    req = proxy_msg(hapd, dev[0])
7961    if len(req) != 212:
7962        raise Exception("Unexpected EAP-pwd-Commit/Response length")
7963
7964    # EAP-pwd-Commit/Response
7965    resp = rx_msg(dev[0])
7966    # Reflect same Element/Scalar back to the server
7967    msg = resp[0:20] + req[20:]
7968    tx_msg(dev[0], hapd, msg)
7969
7970    # EAP-pwd-Commit/Response or EAP-Failure
7971    req = rx_msg(hapd)
7972    if req[8:10] != "04":
7973        # reflect EAP-pwd-Confirm/Request
7974        msg = req[0:8] + "02" + req[10:]
7975        tx_msg(dev[0], hapd, msg)
7976        req = rx_msg(hapd)
7977        if req[8:10] == "03":
7978            raise Exception("EAP-Success after reflected Element/Scalar")
7979        raise Exception("No EAP-Failure to reject invalid EAP-pwd-Commit/Response")
7980
7981def test_eap_proto_pwd_invalid_scalar_peer(dev, apdev):
7982    """EAP-pwd protocol tests - invalid peer scalar"""
7983    run_eap_proto_pwd_invalid_scalar_peer(dev, apdev, 32*"00")
7984    run_eap_proto_pwd_invalid_scalar_peer(dev, apdev, 31*"00" + "01")
7985    # Group Order
7986    run_eap_proto_pwd_invalid_scalar_peer(dev, apdev,
7987                                          "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")
7988    # Group Order - 1
7989    run_eap_proto_pwd_invalid_scalar_peer(dev, apdev,
7990                                          "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632550",
7991                                          valid_scalar=True)
7992
7993def run_eap_proto_pwd_invalid_scalar_peer(dev, apdev, scalar,
7994                                          valid_scalar=False):
7995    hapd = start_pwd_exchange(dev[0], apdev[0])
7996    proxy_msg(hapd, dev[0]) # EAP-pwd-Commit/Request
7997
7998    # EAP-pwd-Commit/Response
7999    resp = rx_msg(dev[0])
8000    # Replace scalar with an invalid value
8001    msg = resp[0:20] + resp[20:148] + scalar
8002    tx_msg(dev[0], hapd, msg)
8003
8004    # EAP-pwd-Commit/Response or EAP-Failure
8005    req = rx_msg(hapd)
8006    if valid_scalar and req[8:10] == "04":
8007        raise Exception("Unexpected EAP-Failure with valid scalar")
8008    if not valid_scalar and req[8:10] != "04":
8009        raise Exception("No EAP-Failure to reject invalid scalar")
8010    dev[0].request("REMOVE_NETWORK all")
8011    dev[0].wait_disconnected(timeout=1)
8012    hapd.disable()
8013
8014def test_eap_proto_pwd_invalid_element_peer(dev, apdev):
8015    """EAP-pwd protocol tests - invalid peer element"""
8016    # Invalid x,y coordinates
8017    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 64*'00')
8018    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 32*'00' + 32*'01')
8019    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 32*'01' + 32*'00')
8020    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 32*'ff' + 32*'01')
8021    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 32*'01' + 32*'ff')
8022    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 64*'ff')
8023    # Not on curve
8024    run_eap_proto_pwd_invalid_element_peer(dev, apdev, 64*'01')
8025
8026def run_eap_proto_pwd_invalid_element_peer(dev, apdev, element):
8027    hapd = start_pwd_exchange(dev[0], apdev[0])
8028    proxy_msg(hapd, dev[0]) # EAP-pwd-Commit/Request
8029
8030    # EAP-pwd-Commit/Response
8031    resp = rx_msg(dev[0])
8032    # Replace element with an invalid value
8033    msg = resp[0:20] + element + resp[148:]
8034    tx_msg(dev[0], hapd, msg)
8035
8036    # EAP-pwd-Commit/Response or EAP-Failure
8037    req = rx_msg(hapd)
8038    if req[8:10] != "04":
8039        raise Exception("No EAP-Failure to reject invalid element")
8040    dev[0].request("REMOVE_NETWORK all")
8041    dev[0].wait_disconnected(timeout=1)
8042    hapd.disable()
8043
8044def test_eap_proto_pwd_errors(dev, apdev):
8045    """EAP-pwd local error cases"""
8046    check_eap_capa(dev[0], "PWD")
8047    params = hostapd.wpa2_eap_params(ssid="eap-test")
8048    hapd = hostapd.add_ap(apdev[0], params)
8049    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8050
8051    for i in range(1, 4):
8052        with alloc_fail(dev[0], i, "eap_pwd_init"):
8053            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8054                           eap="PWD", identity="pwd user",
8055                           password="secret password",
8056                           wait_connect=False)
8057            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
8058                                   timeout=15)
8059            if ev is None:
8060                raise Exception("Timeout on EAP start")
8061            dev[0].request("REMOVE_NETWORK all")
8062            dev[0].wait_disconnected()
8063
8064    with alloc_fail(dev[0], 1, "eap_pwd_get_session_id"):
8065        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8066                       eap="PWD", identity="pwd user",
8067                       fragment_size="0",
8068                       password="secret password")
8069        dev[0].request("REMOVE_NETWORK all")
8070        dev[0].wait_disconnected()
8071
8072    funcs = ["eap_pwd_getkey", "eap_pwd_get_emsk",
8073             "=wpabuf_alloc;eap_pwd_perform_commit_exchange",
8074             "=wpabuf_alloc;eap_pwd_perform_confirm_exchange"]
8075    for func in funcs:
8076        with alloc_fail(dev[0], 1, func):
8077            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8078                           eap="PWD", identity="pwd user@domain",
8079                           password="secret password", erp="1",
8080                           wait_connect=False)
8081            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8082            dev[0].request("REMOVE_NETWORK all")
8083            dev[0].wait_disconnected()
8084
8085    for i in range(1, 5):
8086        with alloc_fail(dev[0], i, "eap_pwd_perform_id_exchange"):
8087            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8088                           eap="PWD", identity="pwd user",
8089                           password="secret password",
8090                           wait_connect=False)
8091            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8092                                   timeout=15)
8093            if ev is None:
8094                raise Exception("Timeout on EAP start")
8095            ok = False
8096            for j in range(10):
8097                state = dev[0].request('GET_ALLOC_FAIL')
8098                if state.startswith('0:'):
8099                    ok = True
8100                    break
8101                time.sleep(0.1)
8102            if not ok:
8103                raise Exception("No allocation failure seen")
8104            dev[0].request("REMOVE_NETWORK all")
8105            dev[0].wait_disconnected()
8106
8107    with alloc_fail(dev[0], 1, "wpabuf_alloc;eap_pwd_perform_id_exchange"):
8108        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8109                       eap="PWD", identity="pwd user",
8110                       password="secret password",
8111                       wait_connect=False)
8112        ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8113                               timeout=15)
8114        if ev is None:
8115            raise Exception("Timeout on EAP start")
8116        dev[0].request("REMOVE_NETWORK all")
8117        dev[0].wait_disconnected()
8118
8119    for i in range(1, 9):
8120        with alloc_fail(dev[0], i, "eap_pwd_perform_commit_exchange"):
8121            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8122                           eap="PWD", identity="pwd user",
8123                           password="secret password",
8124                           wait_connect=False)
8125            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8126                                   timeout=15)
8127            if ev is None:
8128                raise Exception("Timeout on EAP start")
8129            ok = False
8130            for j in range(10):
8131                state = dev[0].request('GET_ALLOC_FAIL')
8132                if state.startswith('0:'):
8133                    ok = True
8134                    break
8135                time.sleep(0.1)
8136            if not ok:
8137                raise Exception("No allocation failure seen")
8138            dev[0].request("REMOVE_NETWORK all")
8139            dev[0].wait_disconnected()
8140
8141    for i in range(1, 12):
8142        with alloc_fail(dev[0], i, "eap_pwd_perform_confirm_exchange"):
8143            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8144                           eap="PWD", identity="pwd user",
8145                           password="secret password",
8146                           wait_connect=False)
8147            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8148                                   timeout=15)
8149            if ev is None:
8150                raise Exception("Timeout on EAP start")
8151            ok = False
8152            for j in range(10):
8153                state = dev[0].request('GET_ALLOC_FAIL')
8154                if state.startswith('0:'):
8155                    ok = True
8156                    break
8157                time.sleep(0.1)
8158            if not ok:
8159                raise Exception("No allocation failure seen")
8160            dev[0].request("REMOVE_NETWORK all")
8161            dev[0].wait_disconnected()
8162
8163    for i in range(1, 5):
8164        with alloc_fail(dev[0], i, "eap_msg_alloc;=eap_pwd_process"):
8165            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8166                           eap="PWD", identity="pwd user",
8167                           password="secret password", fragment_size="50",
8168                           wait_connect=False)
8169            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8170                                   timeout=15)
8171            if ev is None:
8172                raise Exception("Timeout on EAP start")
8173            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8174            dev[0].request("REMOVE_NETWORK all")
8175            dev[0].wait_disconnected()
8176
8177    # No password configured
8178    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8179                   eap="PWD", identity="pwd user",
8180                   wait_connect=False)
8181    ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=52"],
8182                           timeout=15)
8183    if ev is None:
8184        raise Exception("EAP-pwd not started")
8185    dev[0].request("REMOVE_NETWORK all")
8186    dev[0].wait_disconnected()
8187
8188    funcs = [(1, "hash_nt_password_hash;eap_pwd_perform_commit_exchange"),
8189             (1, "=crypto_bignum_init;eap_pwd_perform_commit_exchange"),
8190             (1, "=crypto_ec_point_init;eap_pwd_perform_commit_exchange"),
8191             (2, "=crypto_ec_point_init;eap_pwd_perform_commit_exchange"),
8192             (1, "=crypto_ec_point_mul;eap_pwd_perform_commit_exchange"),
8193             (2, "=crypto_ec_point_mul;eap_pwd_perform_commit_exchange"),
8194             (3, "=crypto_ec_point_mul;eap_pwd_perform_commit_exchange"),
8195             (1, "=crypto_ec_point_add;eap_pwd_perform_commit_exchange"),
8196             (1, "=crypto_ec_point_invert;eap_pwd_perform_commit_exchange"),
8197             (1, "=crypto_ec_point_to_bin;eap_pwd_perform_commit_exchange"),
8198             (1, "crypto_hash_finish;eap_pwd_kdf"),
8199             (1, "crypto_ec_point_from_bin;eap_pwd_get_element"),
8200             (3, "crypto_bignum_init;compute_password_element"),
8201             (4, "crypto_bignum_init;compute_password_element"),
8202             (1, "crypto_bignum_init_set;compute_password_element"),
8203             (2, "crypto_bignum_init_set;compute_password_element"),
8204             (3, "crypto_bignum_init_set;compute_password_element"),
8205             (1, "crypto_bignum_to_bin;compute_password_element"),
8206             (1, "crypto_ec_point_compute_y_sqr;compute_password_element"),
8207             (1, "crypto_bignum_rand;compute_password_element"),
8208             (1, "crypto_bignum_sub;compute_password_element")]
8209    for count, func in funcs:
8210        with fail_test(dev[0], count, func):
8211            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8212                           eap="PWD", identity="pwd-hash",
8213                           password_hex="hash:e3718ece8ab74792cbbfffd316d2d19a",
8214                           wait_connect=False)
8215            ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
8216            if ev is None:
8217                raise Exception("No EAP-Failure reported")
8218            dev[0].request("REMOVE_NETWORK all")
8219            dev[0].wait_disconnected()
8220
8221    params = {"ssid": "eap-test2", "wpa": "2", "wpa_key_mgmt": "WPA-EAP",
8222              "rsn_pairwise": "CCMP", "ieee8021x": "1",
8223              "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf",
8224              "pwd_group": "19", "fragment_size": "40"}
8225    hapd2 = hostapd.add_ap(apdev[1], params)
8226    dev[0].scan_for_bss(hapd2.own_addr(), freq=2412)
8227
8228    with alloc_fail(dev[0], 1, "wpabuf_alloc;=eap_pwd_process"):
8229        dev[0].connect("eap-test2", key_mgmt="WPA-EAP", scan_freq="2412",
8230                       eap="PWD", identity="pwd user",
8231                       password="secret password",
8232                       wait_connect=False)
8233        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8234        dev[0].request("REMOVE_NETWORK all")
8235        dev[0].wait_disconnected()
8236
8237    for i in range(1, 5):
8238        with fail_test(dev[0], i,
8239                       "=crypto_ec_point_to_bin;eap_pwd_perform_confirm_exchange"):
8240            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8241                           eap="PWD", identity="pwd-hash",
8242                           password_hex="hash:e3718ece8ab74792cbbfffd316d2d19a",
8243                           wait_connect=False)
8244            ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
8245            if ev is None:
8246                raise Exception("No EAP-Failure reported")
8247            dev[0].request("REMOVE_NETWORK all")
8248            dev[0].wait_disconnected()
8249            dev[0].dump_monitor()
8250
8251def run_eap_pwd_connect(dev, hash=True, fragment=2000):
8252    if hash:
8253        dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP",
8254                    fragment_size=str(fragment),
8255                    eap="PWD", identity="pwd-hash",
8256                    password_hex="hash:e3718ece8ab74792cbbfffd316d2d19a",
8257                    scan_freq="2412", wait_connect=False)
8258    else:
8259        dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP",
8260                    fragment_size=str(fragment),
8261                    eap="PWD", identity="pwd-hash-sha1",
8262                    password="secret password",
8263                    scan_freq="2412", wait_connect=False)
8264    ev = dev.wait_event(["CTRL-EVENT-EAP-SUCCESS", "CTRL-EVENT-EAP-FAILURE",
8265                         "CTRL-EVENT-DISCONNECTED"],
8266                        timeout=1)
8267    dev.request("REMOVE_NETWORK all")
8268    if not ev or "CTRL-EVENT-DISCONNECTED" not in ev:
8269        dev.wait_disconnected()
8270    dev.dump_monitor()
8271
8272def test_eap_proto_pwd_errors_server(dev, apdev):
8273    """EAP-pwd local error cases on server"""
8274    check_eap_capa(dev[0], "PWD")
8275    params = int_eap_server_params()
8276    params['erp_domain'] = 'example.com'
8277    params['eap_server_erp'] = '1'
8278    hapd = hostapd.add_ap(apdev[0], params)
8279    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8280
8281    tests = [(1, "eap_pwd_init"),
8282             (2, "eap_pwd_init"),
8283             (3, "eap_pwd_init"),
8284             (1, "eap_pwd_build_id_req"),
8285             (1, "eap_pwd_build_commit_req"),
8286             (1, "eap_pwd_build_confirm_req"),
8287             (1, "eap_pwd_h_init;eap_pwd_build_confirm_req"),
8288             (1, "wpabuf_alloc;eap_pwd_build_confirm_req"),
8289             (1, "eap_msg_alloc;eap_pwd_build_req"),
8290             (1, "eap_pwd_process_id_resp"),
8291             (1, "get_eap_pwd_group;eap_pwd_process_id_resp"),
8292             (1, "eap_pwd_process_confirm_resp"),
8293             (1, "eap_pwd_h_init;eap_pwd_process_confirm_resp"),
8294             (1, "compute_keys;eap_pwd_process_confirm_resp"),
8295             (1, "eap_pwd_getkey"),
8296             (1, "eap_pwd_get_emsk"),
8297             (1, "eap_pwd_get_session_id")]
8298    for count, func in tests:
8299        with alloc_fail(hapd, count, func):
8300            run_eap_pwd_connect(dev[0], hash=True)
8301
8302    tests = [(1, "eap_msg_alloc;eap_pwd_build_req"),
8303             (2, "eap_msg_alloc;eap_pwd_build_req"),
8304             (1, "wpabuf_alloc;eap_pwd_process")]
8305    for count, func in tests:
8306        with alloc_fail(hapd, count, func):
8307            run_eap_pwd_connect(dev[0], hash=True, fragment=13)
8308
8309    tests = [(4, "eap_pwd_init")]
8310    for count, func in tests:
8311        with alloc_fail(hapd, count, func):
8312            run_eap_pwd_connect(dev[0], hash=False)
8313
8314    tests = [(1, "eap_pwd_build_id_req"),
8315             (1, "eap_pwd_build_commit_req"),
8316             (1, "crypto_ec_point_mul;eap_pwd_build_commit_req"),
8317             (1, "crypto_ec_point_invert;eap_pwd_build_commit_req"),
8318             (1, "crypto_ec_point_to_bin;eap_pwd_build_commit_req"),
8319             (1, "crypto_ec_point_to_bin;eap_pwd_build_confirm_req"),
8320             (2, "=crypto_ec_point_to_bin;eap_pwd_build_confirm_req"),
8321             (1, "hash_nt_password_hash;eap_pwd_process_id_resp"),
8322             (1, "compute_password_element;eap_pwd_process_id_resp"),
8323             (1, "crypto_bignum_init;eap_pwd_process_commit_resp"),
8324             (1, "crypto_ec_point_mul;eap_pwd_process_commit_resp"),
8325             (2, "crypto_ec_point_mul;eap_pwd_process_commit_resp"),
8326             (1, "crypto_ec_point_add;eap_pwd_process_commit_resp"),
8327             (1, "crypto_ec_point_to_bin;eap_pwd_process_confirm_resp"),
8328             (2, "=crypto_ec_point_to_bin;eap_pwd_process_confirm_resp")]
8329    for count, func in tests:
8330        with fail_test(hapd, count, func):
8331            run_eap_pwd_connect(dev[0], hash=True)
8332
8333def start_pwd_assoc(dev, hapd):
8334    dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP",
8335                eap="PWD", identity="pwd user", password="secret password",
8336                wait_connect=False, scan_freq="2412")
8337    proxy_msg(hapd, dev) # EAP-Identity/Request
8338    proxy_msg(dev, hapd) # EAP-Identity/Response
8339    proxy_msg(hapd, dev) # EAP-pwd-Identity/Request
8340
8341def stop_pwd_assoc(dev, hapd):
8342    dev.request("REMOVE_NETWORK all")
8343    dev.wait_disconnected()
8344    dev.dump_monitor()
8345    hapd.dump_monitor()
8346
8347def test_eap_proto_pwd_server(dev, apdev):
8348    """EAP-pwd protocol testing for the server"""
8349    check_eap_capa(dev[0], "PWD")
8350    params = int_eap_server_params()
8351    hapd = hostapd.add_ap(apdev[0], params)
8352    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8353    hapd.request("SET ext_eapol_frame_io 1")
8354    dev[0].request("SET ext_eapol_frame_io 1")
8355
8356    start_pwd_assoc(dev[0], hapd)
8357    resp = rx_msg(dev[0])
8358    # Replace exch field with unexpected value
8359    # --> EAP-pwd: Unexpected opcode=4 in state=0
8360    msg = resp[0:18] + "04" + resp[20:]
8361    tx_msg(dev[0], hapd, msg)
8362
8363    # Too short EAP-pwd header (no flags/exch field)
8364    # --> EAP-pwd: Invalid frame
8365    msg = resp[0:4] + "0005" + resp[8:12] + "0005" + "34"
8366    tx_msg(dev[0], hapd, msg)
8367
8368    # Too short EAP-pwd header (L=1 but only one octet of total length field)
8369    # --> EAP-pwd: Frame too short to contain Total-Length field
8370    msg = resp[0:4] + "0007" + resp[8:12] + "0007" + "34" + "81ff"
8371    tx_msg(dev[0], hapd, msg)
8372    # server continues exchange, so start from scratch for the next step
8373    rx_msg(hapd)
8374    stop_pwd_assoc(dev[0], hapd)
8375
8376    start_pwd_assoc(dev[0], hapd)
8377    resp = rx_msg(dev[0])
8378    # Too large total length
8379    msg = resp[0:4] + "0008" + resp[8:12] + "0008" + "34" + "c1ffff"
8380    tx_msg(dev[0], hapd, msg)
8381    # server continues exchange, so start from scratch for the next step
8382    rx_msg(hapd)
8383    stop_pwd_assoc(dev[0], hapd)
8384
8385    start_pwd_assoc(dev[0], hapd)
8386    resp = rx_msg(dev[0])
8387    # First fragment
8388    msg = resp[0:4] + "0009" + resp[8:12] + "0009" + "34" + "c100ff" + "aa"
8389    tx_msg(dev[0], hapd, msg)
8390    # Ack
8391    req = rx_msg(hapd)
8392    # Unexpected first fragment
8393    # --> EAP-pwd: Unexpected new fragment start when previous fragment is still in use
8394    msg = resp[0:4] + "0009" + resp[8:10] + req[10:12] + "0009" + "34" + "c100ee" + "bb"
8395    tx_msg(dev[0], hapd, msg)
8396    # server continues exchange, so start from scratch for the next step
8397    rx_msg(hapd)
8398    stop_pwd_assoc(dev[0], hapd)
8399
8400    start_pwd_assoc(dev[0], hapd)
8401    resp = rx_msg(dev[0])
8402    # Too much data in first fragment
8403    # --> EAP-pwd: Buffer overflow attack detected! (0+2 > 1)
8404    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "34" + "c10001" + "aabb"
8405    tx_msg(dev[0], hapd, msg)
8406    # EAP-Failure
8407    rx_msg(hapd)
8408    stop_pwd_assoc(dev[0], hapd)
8409
8410    start_pwd_assoc(dev[0], hapd)
8411    resp = rx_msg(dev[0])
8412    # Change parameters
8413    # --> EAP-pwd: peer changed parameters
8414    msg = resp[0:20] + "ff" + resp[22:]
8415    tx_msg(dev[0], hapd, msg)
8416    # EAP-Failure
8417    rx_msg(hapd)
8418    stop_pwd_assoc(dev[0], hapd)
8419
8420    start_pwd_assoc(dev[0], hapd)
8421    resp = rx_msg(dev[0])
8422    # Too short ID response
8423    # --> EAP-pwd: Invalid ID response
8424    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "34" + "01ffeeddcc"
8425    tx_msg(dev[0], hapd, msg)
8426    # server continues exchange, so start from scratch for the next step
8427    rx_msg(hapd)
8428    stop_pwd_assoc(dev[0], hapd)
8429
8430    start_pwd_assoc(dev[0], hapd)
8431    # EAP-pwd-Identity/Response
8432    resp = rx_msg(dev[0])
8433    tx_msg(dev[0], hapd, resp)
8434    # EAP-pwd-Commit/Request
8435    req = rx_msg(hapd)
8436    # Unexpected EAP-pwd-Identity/Response
8437    # --> EAP-pwd: Unexpected opcode=1 in state=1
8438    msg = resp[0:10] + req[10:12] + resp[12:]
8439    tx_msg(dev[0], hapd, msg)
8440    # server continues exchange, so start from scratch for the next step
8441    rx_msg(hapd)
8442    stop_pwd_assoc(dev[0], hapd)
8443
8444    start_pwd_assoc(dev[0], hapd)
8445    proxy_msg(dev[0], hapd) # EAP-pwd-Identity/Response
8446    proxy_msg(hapd, dev[0]) # EAP-pwd-Commit/Request
8447    # EAP-pwd-Commit/Response
8448    resp = rx_msg(dev[0])
8449    # Too short Commit response
8450    # --> EAP-pwd: Unexpected Commit payload length 4 (expected 96)
8451    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "34" + "02ffeeddcc"
8452    tx_msg(dev[0], hapd, msg)
8453    # EAP-Failure
8454    rx_msg(hapd)
8455    stop_pwd_assoc(dev[0], hapd)
8456
8457    start_pwd_assoc(dev[0], hapd)
8458    proxy_msg(dev[0], hapd) # EAP-pwd-Identity/Response
8459    proxy_msg(hapd, dev[0]) # EAP-pwd-Commit/Request
8460    proxy_msg(dev[0], hapd) # EAP-pwd-Commit/Response
8461    proxy_msg(hapd, dev[0]) # EAP-pwd-Confirm/Request
8462    # EAP-pwd-Confirm/Response
8463    resp = rx_msg(dev[0])
8464    # Too short Confirm response
8465    # --> EAP-pwd: Unexpected Confirm payload length 4 (expected 32)
8466    msg = resp[0:4] + "000a" + resp[8:12] + "000a" + "34" + "03ffeeddcc"
8467    tx_msg(dev[0], hapd, msg)
8468    # EAP-Failure
8469    rx_msg(hapd)
8470    stop_pwd_assoc(dev[0], hapd)
8471
8472    start_pwd_assoc(dev[0], hapd)
8473    resp = rx_msg(dev[0])
8474    # Set M=1
8475    # --> EAP-pwd: No buffer for reassembly
8476    msg = resp[0:18] + "41" + resp[20:]
8477    tx_msg(dev[0], hapd, msg)
8478    # EAP-Failure
8479    rx_msg(hapd)
8480    stop_pwd_assoc(dev[0], hapd)
8481
8482def test_eap_proto_erp(dev, apdev):
8483    """ERP protocol tests"""
8484    check_erp_capa(dev[0])
8485
8486    global eap_proto_erp_test_done
8487    eap_proto_erp_test_done = False
8488
8489    def erp_handler(ctx, req):
8490        logger.info("erp_handler - RX " + binascii.hexlify(req).decode())
8491        if 'num' not in ctx:
8492            ctx['num'] = 0
8493        ctx['num'] += 1
8494        if 'id' not in ctx:
8495            ctx['id'] = 1
8496        ctx['id'] = (ctx['id'] + 1) % 256
8497        idx = 0
8498
8499        idx += 1
8500        if ctx['num'] == idx:
8501            logger.info("Test: Missing type")
8502            return struct.pack(">BBH", EAP_CODE_INITIATE, ctx['id'], 4)
8503
8504        idx += 1
8505        if ctx['num'] == idx:
8506            logger.info("Test: Unexpected type")
8507            return struct.pack(">BBHB", EAP_CODE_INITIATE, ctx['id'], 4 + 1,
8508                               255)
8509
8510        idx += 1
8511        if ctx['num'] == idx:
8512            logger.info("Test: Missing Reserved field")
8513            return struct.pack(">BBHB", EAP_CODE_INITIATE, ctx['id'], 4 + 1,
8514                               EAP_ERP_TYPE_REAUTH_START)
8515
8516        idx += 1
8517        if ctx['num'] == idx:
8518            logger.info("Test: Zero-length TVs/TLVs")
8519            payload = b""
8520            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8521                               4 + 1 + 1 + len(payload),
8522                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8523
8524        idx += 1
8525        if ctx['num'] == idx:
8526            logger.info("Test: Too short TLV")
8527            payload = struct.pack("B", 191)
8528            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8529                               4 + 1 + 1 + len(payload),
8530                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8531
8532        idx += 1
8533        if ctx['num'] == idx:
8534            logger.info("Test: Truncated TLV")
8535            payload = struct.pack("BB", 191, 1)
8536            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8537                               4 + 1 + 1 + len(payload),
8538                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8539
8540        idx += 1
8541        if ctx['num'] == idx:
8542            logger.info("Test: Ignored unknown TLV and unknown TV/TLV terminating parsing")
8543            payload = struct.pack("BBB", 191, 0, 192)
8544            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8545                               4 + 1 + 1 + len(payload),
8546                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8547
8548        idx += 1
8549        if ctx['num'] == idx:
8550            logger.info("Test: More than one keyName-NAI")
8551            payload = struct.pack("BBBB", EAP_ERP_TLV_KEYNAME_NAI, 0,
8552                                  EAP_ERP_TLV_KEYNAME_NAI, 0)
8553            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8554                               4 + 1 + 1 + len(payload),
8555                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8556
8557        idx += 1
8558        if ctx['num'] == idx:
8559            logger.info("Test: Too short TLV keyName-NAI")
8560            payload = struct.pack("B", EAP_ERP_TLV_KEYNAME_NAI)
8561            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8562                               4 + 1 + 1 + len(payload),
8563                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8564
8565        idx += 1
8566        if ctx['num'] == idx:
8567            logger.info("Test: Truncated TLV keyName-NAI")
8568            payload = struct.pack("BB", EAP_ERP_TLV_KEYNAME_NAI, 1)
8569            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8570                               4 + 1 + 1 + len(payload),
8571                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8572
8573        idx += 1
8574        if ctx['num'] == idx:
8575            logger.info("Test: Valid rRK lifetime TV followed by too short rMSK lifetime TV")
8576            payload = struct.pack(">BLBH", EAP_ERP_TV_RRK_LIFETIME, 0,
8577                                  EAP_ERP_TV_RMSK_LIFETIME, 0)
8578            return struct.pack(">BBHBB", EAP_CODE_INITIATE, ctx['id'],
8579                               4 + 1 + 1 + len(payload),
8580                               EAP_ERP_TYPE_REAUTH_START, 0) + payload
8581
8582        idx += 1
8583        if ctx['num'] == idx:
8584            logger.info("Test: Missing type (Finish)")
8585            return struct.pack(">BBH", EAP_CODE_FINISH, ctx['id'], 4)
8586
8587        idx += 1
8588        if ctx['num'] == idx:
8589            logger.info("Test: Unexpected type (Finish)")
8590            return struct.pack(">BBHB", EAP_CODE_FINISH, ctx['id'], 4 + 1,
8591                               255)
8592
8593        idx += 1
8594        if ctx['num'] == idx:
8595            logger.info("Test: Missing fields (Finish)")
8596            return struct.pack(">BBHB", EAP_CODE_FINISH, ctx['id'], 4 + 1,
8597                               EAP_ERP_TYPE_REAUTH)
8598
8599        idx += 1
8600        if ctx['num'] == idx:
8601            logger.info("Test: Unexpected SEQ (Finish)")
8602            return struct.pack(">BBHBBHB", EAP_CODE_FINISH, ctx['id'],
8603                               4 + 1 + 4,
8604                               EAP_ERP_TYPE_REAUTH, 0, 0xffff, 0)
8605
8606        logger.info("No more test responses available - test case completed")
8607        global eap_proto_erp_test_done
8608        eap_proto_erp_test_done = True
8609        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
8610
8611    srv = start_radius_server(erp_handler)
8612
8613    try:
8614        hapd = start_ap(apdev[0])
8615        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8616
8617        i = 0
8618        while not eap_proto_erp_test_done:
8619            i += 1
8620            logger.info("Running connection iteration %d" % i)
8621            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8622                           eap="PAX", identity="pax.user@example.com",
8623                           password_hex="0123456789abcdef0123456789abcdef",
8624                           wait_connect=False)
8625            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
8626            if ev is None:
8627                raise Exception("Timeout on EAP start")
8628            time.sleep(0.1)
8629            dev[0].request("REMOVE_NETWORK all")
8630            dev[0].wait_disconnected(timeout=1)
8631            dev[0].dump_monitor()
8632    finally:
8633        stop_radius_server(srv)
8634
8635def test_eap_proto_fast_errors(dev, apdev):
8636    """EAP-FAST local error cases"""
8637    check_eap_capa(dev[0], "FAST")
8638    params = hostapd.wpa2_eap_params(ssid="eap-test")
8639    hapd = hostapd.add_ap(apdev[0], params)
8640    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8641
8642    for i in range(1, 5):
8643        with alloc_fail(dev[0], i, "eap_fast_init"):
8644            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8645                           eap="FAST", anonymous_identity="FAST",
8646                           identity="user", password="password",
8647                           ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
8648                           phase1="fast_provisioning=2",
8649                           pac_file="blob://fast_pac_auth",
8650                           wait_connect=False)
8651            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
8652                                   timeout=5)
8653            if ev is None:
8654                raise Exception("Timeout on EAP start")
8655            dev[0].request("REMOVE_NETWORK all")
8656            dev[0].wait_disconnected()
8657
8658    tests = [(1, "wpabuf_alloc;eap_fast_tlv_eap_payload"),
8659             (1, "eap_fast_derive_key;eap_fast_derive_key_auth"),
8660             (1, "eap_msg_alloc;eap_peer_tls_phase2_nak"),
8661             (1, "wpabuf_alloc;eap_fast_tlv_result"),
8662             (1, "wpabuf_alloc;eap_fast_tlv_pac_ack"),
8663             (1, "=eap_peer_tls_derive_session_id;eap_fast_process_crypto_binding"),
8664             (1, "eap_peer_tls_decrypt;eap_fast_decrypt"),
8665             (1, "eap_fast_getKey"),
8666             (1, "eap_fast_get_session_id"),
8667             (1, "eap_fast_get_emsk")]
8668    for count, func in tests:
8669        dev[0].request("SET blob fast_pac_auth_errors ")
8670        with alloc_fail(dev[0], count, func):
8671            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8672                           eap="FAST", anonymous_identity="FAST",
8673                           identity="user@example.com", password="password",
8674                           ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
8675                           phase1="fast_provisioning=2",
8676                           pac_file="blob://fast_pac_auth_errors",
8677                           erp="1",
8678                           wait_connect=False)
8679            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8680                                   timeout=15)
8681            if ev is None:
8682                raise Exception("Timeout on EAP start")
8683            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8684            dev[0].request("REMOVE_NETWORK all")
8685            dev[0].wait_disconnected()
8686
8687    tests = [(1, "eap_fast_derive_key;eap_fast_derive_key_provisioning"),
8688             (1, "eap_mschapv2_getKey;eap_fast_get_phase2_key"),
8689             (1, "=eap_fast_use_pac_opaque"),
8690             (1, "eap_fast_copy_buf"),
8691             (1, "=eap_fast_add_pac"),
8692             (1, "=eap_fast_init_pac_data"),
8693             (1, "=eap_fast_write_pac"),
8694             (2, "=eap_fast_write_pac")]
8695    for count, func in tests:
8696        dev[0].request("SET blob fast_pac_errors ")
8697        with alloc_fail(dev[0], count, func):
8698            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8699                           eap="FAST", anonymous_identity="FAST",
8700                           identity="user", password="password",
8701                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8702                           phase1="fast_provisioning=1",
8703                           pac_file="blob://fast_pac_errors",
8704                           erp="1",
8705                           wait_connect=False)
8706            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8707                                   timeout=15)
8708            if ev is None:
8709                raise Exception("Timeout on EAP start")
8710            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8711            dev[0].request("REMOVE_NETWORK all")
8712            dev[0].wait_disconnected()
8713
8714    tests = [(1, "eap_fast_get_cmk;eap_fast_process_crypto_binding"),
8715             (1, "eap_fast_derive_eap_msk;eap_fast_process_crypto_binding"),
8716             (1, "eap_fast_derive_eap_emsk;eap_fast_process_crypto_binding")]
8717    for count, func in tests:
8718        dev[0].request("SET blob fast_pac_auth_errors ")
8719        with fail_test(dev[0], count, func):
8720            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8721                           eap="FAST", anonymous_identity="FAST",
8722                           identity="user", password="password",
8723                           ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
8724                           phase1="fast_provisioning=2",
8725                           pac_file="blob://fast_pac_auth_errors",
8726                           erp="1",
8727                           wait_connect=False)
8728            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8729                                   timeout=15)
8730            if ev is None:
8731                raise Exception("Timeout on EAP start")
8732            wait_fail_trigger(dev[0], "GET_FAIL")
8733            dev[0].request("REMOVE_NETWORK all")
8734            dev[0].wait_disconnected()
8735
8736    dev[0].request("SET blob fast_pac_errors ")
8737    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8738                   eap="FAST", anonymous_identity="FAST",
8739                   identity="user", password="password",
8740                   ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
8741                   phase1="fast_provisioning=1",
8742                   pac_file="blob://fast_pac_errors",
8743                   wait_connect=False)
8744    ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
8745    if ev is None:
8746        raise Exception("Timeout on EAP start")
8747    # EAP-FAST: Only EAP-MSCHAPv2 is allowed during unauthenticated
8748    # provisioning; reject phase2 type 6
8749    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
8750    if ev is None:
8751        raise Exception("Timeout on EAP failure")
8752    dev[0].request("REMOVE_NETWORK all")
8753    dev[0].wait_disconnected()
8754
8755    logger.info("Wrong password in Phase 2")
8756    dev[0].request("SET blob fast_pac_errors ")
8757    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8758                   eap="FAST", anonymous_identity="FAST",
8759                   identity="user", password="wrong password",
8760                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8761                   phase1="fast_provisioning=1",
8762                   pac_file="blob://fast_pac_errors",
8763                   wait_connect=False)
8764    ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
8765    if ev is None:
8766        raise Exception("Timeout on EAP start")
8767    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
8768    if ev is None:
8769        raise Exception("Timeout on EAP failure")
8770    dev[0].request("REMOVE_NETWORK all")
8771    dev[0].wait_disconnected()
8772
8773    tests = ["FOOBAR\n",
8774             "wpa_supplicant EAP-FAST PAC file - version 1\nFOOBAR\n",
8775             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\n",
8776             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nSTART\n",
8777             "wpa_supplicant EAP-FAST PAC file - version 1\nEND\n",
8778             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Type=12345\nEND\n"
8779             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Key=12\nEND\n",
8780             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Key=1\nEND\n",
8781             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Key=1q\nEND\n",
8782             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nPAC-Opaque=1\nEND\n",
8783             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nA-ID=1\nEND\n",
8784             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nI-ID=1\nEND\n",
8785             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nA-ID-Info=1\nEND\n"]
8786    for pac in tests:
8787        blob = binascii.hexlify(pac.encode()).decode()
8788        dev[0].request("SET blob fast_pac_errors " + blob)
8789        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8790                       eap="FAST", anonymous_identity="FAST",
8791                       identity="user", password="password",
8792                       ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
8793                       phase1="fast_provisioning=2",
8794                       pac_file="blob://fast_pac_errors",
8795                       wait_connect=False)
8796        ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
8797                               timeout=5)
8798        if ev is None:
8799            raise Exception("Timeout on EAP start")
8800        dev[0].request("REMOVE_NETWORK all")
8801        dev[0].wait_disconnected()
8802
8803    tests = ["wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nEND\n",
8804             "wpa_supplicant EAP-FAST PAC file - version 1\nSTART\nEND\nSTART\nEND\nSTART\nEND\n"]
8805    for pac in tests:
8806        blob = binascii.hexlify(pac.encode()).decode()
8807        dev[0].request("SET blob fast_pac_errors " + blob)
8808        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8809                       eap="FAST", anonymous_identity="FAST",
8810                       identity="user", password="password",
8811                       ca_cert="auth_serv/ca.pem", phase2="auth=GTC",
8812                       phase1="fast_provisioning=2",
8813                       pac_file="blob://fast_pac_errors")
8814        dev[0].request("REMOVE_NETWORK all")
8815        dev[0].wait_disconnected()
8816
8817    dev[0].request("SET blob fast_pac_errors ")
8818
8819def test_eap_proto_peap_errors_server(dev, apdev):
8820    """EAP-PEAP local error cases on server"""
8821    params = int_eap_server_params()
8822    hapd = hostapd.add_ap(apdev[0], params)
8823    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8824
8825    tests = [(1, "get_asymetric_start_key;eap_mschapv2_getKey"),
8826             (1, "generate_authenticator_response_pwhash;eap_mschapv2_process_response"),
8827             (1, "hash_nt_password_hash;eap_mschapv2_process_response"),
8828             (1, "get_master_key;eap_mschapv2_process_response")]
8829    for count, func in tests:
8830        with fail_test(hapd, count, func):
8831            dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP",
8832                           scan_freq="2412",
8833                           eap="PEAP", anonymous_identity="peap",
8834                           identity="user", password="password",
8835                           phase1="peapver=0 crypto_binding=2",
8836                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8837                           erp="1", wait_connect=False)
8838            ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
8839            if ev is None:
8840                raise Exception("EAP-Failure not reported")
8841            dev[0].request("REMOVE_NETWORK all")
8842            dev[0].wait_disconnected()
8843
8844def test_eap_proto_peap_errors(dev, apdev):
8845    """EAP-PEAP local error cases"""
8846    check_eap_capa(dev[0], "PEAP")
8847    check_eap_capa(dev[0], "MSCHAPV2")
8848    params = hostapd.wpa2_eap_params(ssid="eap-test")
8849    hapd = hostapd.add_ap(apdev[0], params)
8850    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8851
8852    for i in range(1, 5):
8853        with alloc_fail(dev[0], i, "eap_peap_init"):
8854            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8855                           eap="PEAP", anonymous_identity="peap",
8856                           identity="user", password="password",
8857                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8858                           wait_connect=False)
8859            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
8860                                   timeout=5)
8861            if ev is None:
8862                raise Exception("Timeout on EAP start")
8863            dev[0].request("REMOVE_NETWORK all")
8864            dev[0].wait_disconnected()
8865
8866    tests = [(1, "eap_mschapv2_getKey;eap_peap_get_isk;eap_peap_derive_cmk"),
8867             (1, "eap_msg_alloc;eap_tlv_build_result"),
8868             (1, "eap_mschapv2_init;eap_peap_phase2_request"),
8869             (1, "eap_peer_tls_decrypt;eap_peap_decrypt"),
8870             (1, "wpabuf_alloc;=eap_peap_decrypt"),
8871             (1, "eap_peer_tls_encrypt;eap_peap_decrypt"),
8872             (1, "eap_peer_tls_process_helper;eap_peap_process"),
8873             (1, "eap_peer_tls_derive_key;eap_peap_process"),
8874             (1, "eap_peer_tls_derive_session_id;eap_peap_process"),
8875             (1, "eap_peap_getKey"),
8876             (1, "eap_peap_get_session_id")]
8877    for count, func in tests:
8878        with alloc_fail(dev[0], count, func):
8879            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8880                           eap="PEAP", anonymous_identity="peap",
8881                           identity="user", password="password",
8882                           phase1="peapver=0 crypto_binding=2",
8883                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8884                           erp="1", wait_connect=False)
8885            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8886                                   timeout=15)
8887            if ev is None:
8888                raise Exception("Timeout on EAP start")
8889            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8890            dev[0].request("REMOVE_NETWORK all")
8891            dev[0].wait_disconnected()
8892
8893    tests = [(1, "peap_prfplus;eap_peap_derive_cmk"),
8894             (1, "eap_tlv_add_cryptobinding;eap_tlv_build_result"),
8895             (1, "peap_prfplus;eap_peap_getKey"),
8896             (1, "get_asymetric_start_key;eap_mschapv2_getKey")]
8897    for count, func in tests:
8898        with fail_test(dev[0], count, func):
8899            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8900                           eap="PEAP", anonymous_identity="peap",
8901                           identity="user", password="password",
8902                           phase1="peapver=0 crypto_binding=2",
8903                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8904                           erp="1", wait_connect=False)
8905            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
8906                                   timeout=15)
8907            if ev is None:
8908                raise Exception("Timeout on EAP start")
8909            wait_fail_trigger(dev[0], "GET_FAIL")
8910            dev[0].request("REMOVE_NETWORK all")
8911            dev[0].wait_disconnected()
8912
8913    with alloc_fail(dev[0], 1,
8914                    "eap_peer_tls_phase2_nak;eap_peap_phase2_request"):
8915        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8916                       eap="PEAP", anonymous_identity="peap",
8917                       identity="cert user", password="password",
8918                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
8919                       wait_connect=False)
8920        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
8921        dev[0].request("REMOVE_NETWORK all")
8922        dev[0].wait_disconnected()
8923
8924def test_eap_proto_ttls_errors(dev, apdev):
8925    """EAP-TTLS local error cases"""
8926    check_eap_capa(dev[0], "TTLS")
8927    check_eap_capa(dev[0], "MSCHAPV2")
8928    params = hostapd.wpa2_eap_params(ssid="eap-test")
8929    hapd = hostapd.add_ap(apdev[0], params)
8930    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
8931
8932    for i in range(1, 5):
8933        with alloc_fail(dev[0], i, "eap_ttls_init"):
8934            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
8935                           eap="TTLS", anonymous_identity="ttls",
8936                           identity="user", password="password",
8937                           ca_cert="auth_serv/ca.pem",
8938                           phase2="autheap=MSCHAPV2",
8939                           wait_connect=False)
8940            ev = dev[0].wait_event(["EAP: Failed to initialize EAP method"],
8941                                   timeout=5)
8942            if ev is None:
8943                raise Exception("Timeout on EAP start")
8944            dev[0].request("REMOVE_NETWORK all")
8945            dev[0].wait_disconnected()
8946
8947    tests = [(1, "eap_peer_tls_derive_key;eap_ttls_v0_derive_key",
8948              "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
8949             (1, "eap_peer_tls_derive_session_id;eap_ttls_v0_derive_key",
8950              "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
8951             (1, "wpabuf_alloc;eap_ttls_phase2_request_mschapv2",
8952              "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
8953             (1, "eap_peer_tls_derive_key;eap_ttls_phase2_request_mschapv2",
8954              "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
8955             (1, "eap_peer_tls_encrypt;eap_ttls_encrypt_response;eap_ttls_implicit_identity_request",
8956              "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
8957             (1, "eap_peer_tls_decrypt;eap_ttls_decrypt",
8958              "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
8959             (1, "eap_ttls_getKey",
8960              "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
8961             (1, "eap_ttls_get_session_id",
8962              "DOMAIN\mschapv2 user", "auth=MSCHAPV2"),
8963             (1, "eap_ttls_get_emsk",
8964              "mschapv2 user@domain", "auth=MSCHAPV2"),
8965             (1, "wpabuf_alloc;eap_ttls_phase2_request_mschap",
8966              "mschap user", "auth=MSCHAP"),
8967             (1, "eap_peer_tls_derive_key;eap_ttls_phase2_request_mschap",
8968              "mschap user", "auth=MSCHAP"),
8969             (1, "wpabuf_alloc;eap_ttls_phase2_request_chap",
8970              "chap user", "auth=CHAP"),
8971             (1, "eap_peer_tls_derive_key;eap_ttls_phase2_request_chap",
8972              "chap user", "auth=CHAP"),
8973             (1, "wpabuf_alloc;eap_ttls_phase2_request_pap",
8974              "pap user", "auth=PAP"),
8975             (1, "wpabuf_alloc;eap_ttls_avp_encapsulate",
8976              "user", "autheap=MSCHAPV2"),
8977             (1, "eap_mschapv2_init;eap_ttls_phase2_request_eap_method",
8978              "user", "autheap=MSCHAPV2"),
8979             (1, "eap_sm_buildIdentity;eap_ttls_phase2_request_eap",
8980              "user", "autheap=MSCHAPV2"),
8981             (1, "eap_ttls_avp_encapsulate;eap_ttls_phase2_request_eap",
8982              "user", "autheap=MSCHAPV2"),
8983             (1, "eap_ttls_parse_attr_eap",
8984              "user", "autheap=MSCHAPV2"),
8985             (1, "eap_peer_tls_encrypt;eap_ttls_encrypt_response;eap_ttls_process_decrypted",
8986              "user", "autheap=MSCHAPV2"),
8987             (1, "eap_ttls_fake_identity_request",
8988              "user", "autheap=MSCHAPV2"),
8989             (1, "eap_msg_alloc;eap_tls_process_output",
8990              "user", "autheap=MSCHAPV2"),
8991             (1, "eap_msg_alloc;eap_peer_tls_build_ack",
8992              "user", "autheap=MSCHAPV2"),
8993             (1, "eap_peer_tls_phase2_nak;eap_ttls_phase2_request_eap_method",
8994              "cert user", "autheap=MSCHAPV2")]
8995    tls = dev[0].request("GET tls_library")
8996    if tls.startswith("internal"):
8997        tests += [(1, "tlsv1_client_decrypt;eap_peer_tls_decrypt",
8998                   "user", "autheap=MSCHAPV2")]
8999    else:
9000        tests += [(1, "tls_connection_decrypt;eap_peer_tls_decrypt",
9001                   "user", "autheap=MSCHAPV2")]
9002    for count, func, identity, phase2 in tests:
9003        with alloc_fail(dev[0], count, func):
9004            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9005                           eap="TTLS", anonymous_identity="ttls",
9006                           identity=identity, password="password",
9007                           ca_cert="auth_serv/ca.pem", phase2=phase2,
9008                           erp="1", wait_connect=False)
9009            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
9010                                   timeout=15)
9011            if ev is None:
9012                raise Exception("Timeout on EAP start")
9013            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL",
9014                              note="Allocation failure not triggered for: %d:%s" % (count, func))
9015            dev[0].request("REMOVE_NETWORK all")
9016            dev[0].wait_disconnected()
9017
9018    tests = [(1, "os_get_random;eap_ttls_phase2_request_mschapv2"),
9019             (1, "mschapv2_derive_response;eap_ttls_phase2_request_mschapv2")]
9020    for count, func in tests:
9021        with fail_test(dev[0], count, func):
9022            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9023                           eap="TTLS", anonymous_identity="ttls",
9024                           identity="DOMAIN\mschapv2 user", password="password",
9025                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
9026                           erp="1", wait_connect=False)
9027            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
9028                                   timeout=15)
9029            if ev is None:
9030                raise Exception("Timeout on EAP start")
9031            wait_fail_trigger(dev[0], "GET_FAIL",
9032                              note="Test failure not triggered for: %d:%s" % (count, func))
9033            dev[0].request("REMOVE_NETWORK all")
9034            dev[0].wait_disconnected()
9035
9036    tests = [(1, "nt_challenge_response;eap_ttls_phase2_request_mschap")]
9037    for count, func in tests:
9038        with fail_test(dev[0], count, func):
9039            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9040                           eap="TTLS", anonymous_identity="ttls",
9041                           identity="mschap user", password="password",
9042                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAP",
9043                           erp="1", wait_connect=False)
9044            ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
9045                                   timeout=15)
9046            if ev is None:
9047                raise Exception("Timeout on EAP start")
9048            wait_fail_trigger(dev[0], "GET_FAIL",
9049                              note="Test failure not triggered for: %d:%s" % (count, func))
9050            dev[0].request("REMOVE_NETWORK all")
9051            dev[0].wait_disconnected()
9052
9053def test_eap_proto_expanded(dev, apdev):
9054    """EAP protocol tests with expanded header"""
9055    global eap_proto_expanded_test_done
9056    eap_proto_expanded_test_done = False
9057
9058    def expanded_handler(ctx, req):
9059        logger.info("expanded_handler - RX " + binascii.hexlify(req).decode())
9060        if 'num' not in ctx:
9061            ctx['num'] = 0
9062        ctx['num'] += 1
9063        if 'id' not in ctx:
9064            ctx['id'] = 1
9065        ctx['id'] = (ctx['id'] + 1) % 256
9066        idx = 0
9067
9068        idx += 1
9069        if ctx['num'] == idx:
9070            logger.info("Test: MD5 challenge in expanded header")
9071            return struct.pack(">BBHB3BLBBB", EAP_CODE_REQUEST, ctx['id'],
9072                               4 + 1 + 3 + 4 + 3,
9073                               EAP_TYPE_EXPANDED, 0, 0, 0, EAP_TYPE_MD5,
9074                               1, 0xaa, ord('n'))
9075        idx += 1
9076        if ctx['num'] == idx:
9077            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9078
9079        idx += 1
9080        if ctx['num'] == idx:
9081            logger.info("Test: Invalid expanded EAP length")
9082            return struct.pack(">BBHB3BH", EAP_CODE_REQUEST, ctx['id'],
9083                               4 + 1 + 3 + 2,
9084                               EAP_TYPE_EXPANDED, 0, 0, 0, EAP_TYPE_MD5)
9085        idx += 1
9086        if ctx['num'] == idx:
9087            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9088
9089        idx += 1
9090        if ctx['num'] == idx:
9091            logger.info("Test: Invalid expanded frame type")
9092            return struct.pack(">BBHB3BL", EAP_CODE_REQUEST, ctx['id'],
9093                               4 + 1 + 3 + 4,
9094                               EAP_TYPE_EXPANDED, 0, 0, 1, EAP_TYPE_MD5)
9095        idx += 1
9096        if ctx['num'] == idx:
9097            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9098
9099        idx += 1
9100        if ctx['num'] == idx:
9101            logger.info("Test: MSCHAPv2 Challenge")
9102            return struct.pack(">BBHBBBHB", EAP_CODE_REQUEST, ctx['id'],
9103                               4 + 1 + 4 + 1 + 16 + 6,
9104                               EAP_TYPE_MSCHAPV2,
9105                               1, 0, 4 + 1 + 16 + 6, 16) + 16*b'A' + b'foobar'
9106        idx += 1
9107        if ctx['num'] == idx:
9108            logger.info("Test: Invalid expanded frame type")
9109            return struct.pack(">BBHB3BL", EAP_CODE_REQUEST, ctx['id'],
9110                               4 + 1 + 3 + 4,
9111                               EAP_TYPE_EXPANDED, 0, 0, 1, EAP_TYPE_MSCHAPV2)
9112
9113        logger.info("No more test responses available - test case completed")
9114        global eap_proto_expanded_test_done
9115        eap_proto_expanded_test_done = True
9116        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9117
9118    srv = start_radius_server(expanded_handler)
9119
9120    try:
9121        hapd = start_ap(apdev[0])
9122        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9123
9124        i = 0
9125        while not eap_proto_expanded_test_done:
9126            i += 1
9127            logger.info("Running connection iteration %d" % i)
9128            if i == 4:
9129                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9130                               eap="MSCHAPV2", identity="user",
9131                               password="password",
9132                               wait_connect=False)
9133            else:
9134                dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9135                               eap="MD5", identity="user", password="password",
9136                               wait_connect=False)
9137            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
9138            if ev is None:
9139                raise Exception("Timeout on EAP start")
9140            if i in [1]:
9141                ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
9142                if ev is None:
9143                    raise Exception("Timeout on EAP method start")
9144                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
9145                if ev is None:
9146                    raise Exception("Timeout on EAP failure")
9147            elif i in [2, 3]:
9148                ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"],
9149                                       timeout=5)
9150                if ev is None:
9151                    raise Exception("Timeout on EAP proposed method")
9152                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
9153                if ev is None:
9154                    raise Exception("Timeout on EAP failure")
9155            else:
9156                time.sleep(0.1)
9157            dev[0].request("REMOVE_NETWORK all")
9158            dev[0].wait_disconnected(timeout=1)
9159            dev[0].dump_monitor()
9160    finally:
9161        stop_radius_server(srv)
9162
9163def test_eap_proto_tls(dev, apdev):
9164    """EAP-TLS protocol tests"""
9165    check_eap_capa(dev[0], "TLS")
9166    global eap_proto_tls_test_done, eap_proto_tls_test_wait
9167    eap_proto_tls_test_done = False
9168    eap_proto_tls_test_wait = False
9169
9170    def tls_handler(ctx, req):
9171        logger.info("tls_handler - RX " + binascii.hexlify(req).decode())
9172        if 'num' not in ctx:
9173            ctx['num'] = 0
9174        ctx['num'] += 1
9175        if 'id' not in ctx:
9176            ctx['id'] = 1
9177        ctx['id'] = (ctx['id'] + 1) % 256
9178        idx = 0
9179
9180        global eap_proto_tls_test_wait
9181
9182        idx += 1
9183        if ctx['num'] == idx:
9184            logger.info("Test: Too much payload in TLS/Start: TLS Message Length (0 bytes) smaller than this fragment (1 bytes)")
9185            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
9186                               4 + 1 + 1 + 4 + 1,
9187                               EAP_TYPE_TLS, 0xa0, 0, 1)
9188
9189        idx += 1
9190        if ctx['num'] == idx:
9191            logger.info("Test: Fragmented TLS/Start")
9192            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
9193                               4 + 1 + 1 + 4 + 1,
9194                               EAP_TYPE_TLS, 0xe0, 2, 1)
9195        idx += 1
9196        if ctx['num'] == idx:
9197            logger.info("Test: Too long fragment of TLS/Start: Invalid reassembly state: tls_in_left=2 tls_in_len=0 in_len=0")
9198            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
9199                               4 + 1 + 1 + 2,
9200                               EAP_TYPE_TLS, 0x00, 2, 3)
9201        idx += 1
9202        if ctx['num'] == idx:
9203            logger.info("Test: EAP-Failure")
9204            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9205
9206        idx += 1
9207        if ctx['num'] == idx:
9208            logger.info("Test: TLS/Start")
9209            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9210                               4 + 1 + 1,
9211                               EAP_TYPE_TLS, 0x20)
9212        idx += 1
9213        if ctx['num'] == idx:
9214            logger.info("Test: Fragmented TLS message")
9215            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
9216                               4 + 1 + 1 + 4 + 1,
9217                               EAP_TYPE_TLS, 0xc0, 2, 1)
9218        idx += 1
9219        if ctx['num'] == idx:
9220            logger.info("Test: Invalid TLS message: no Flags octet included + workaround")
9221            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
9222                               4 + 1,
9223                               EAP_TYPE_TLS)
9224        idx += 1
9225        if ctx['num'] == idx:
9226            logger.info("Test: Too long fragment of TLS message: more data than TLS message length indicated")
9227            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
9228                               4 + 1 + 1 + 2,
9229                               EAP_TYPE_TLS, 0x00, 2, 3)
9230        idx += 1
9231        if ctx['num'] == idx:
9232            logger.info("Test: EAP-Failure")
9233            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9234
9235        idx += 1
9236        if ctx['num'] == idx:
9237            logger.info("Test: Fragmented TLS/Start and truncated Message Length field")
9238            return struct.pack(">BBHBB3B", EAP_CODE_REQUEST, ctx['id'],
9239                               4 + 1 + 1 + 3,
9240                               EAP_TYPE_TLS, 0xe0, 1, 2, 3)
9241
9242        idx += 1
9243        if ctx['num'] == idx:
9244            logger.info("Test: TLS/Start")
9245            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9246                               4 + 1 + 1,
9247                               EAP_TYPE_TLS, 0x20)
9248        idx += 1
9249        if ctx['num'] == idx:
9250            logger.info("Test: Fragmented TLS message")
9251            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
9252                               4 + 1 + 1 + 4 + 1,
9253                               EAP_TYPE_TLS, 0xc0, 2, 1)
9254        idx += 1
9255        if ctx['num'] == idx:
9256            logger.info("Test: Invalid TLS message: no Flags octet included + workaround disabled")
9257            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
9258                               4 + 1,
9259                               EAP_TYPE_TLS)
9260
9261        idx += 1
9262        if ctx['num'] == idx:
9263            logger.info("Test: TLS/Start")
9264            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9265                               4 + 1 + 1,
9266                               EAP_TYPE_TLS, 0x20)
9267        idx += 1
9268        if ctx['num'] == idx:
9269            logger.info("Test: Fragmented TLS message (long; first)")
9270            payload = 1450*b'A'
9271            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
9272                               4 + 1 + 1 + 4 + len(payload),
9273                               EAP_TYPE_TLS, 0xc0, 65536) + payload
9274        # "Too long TLS fragment (size over 64 kB)" on the last one
9275        for i in range(44):
9276            idx += 1
9277            if ctx['num'] == idx:
9278                logger.info("Test: Fragmented TLS message (long; cont %d)" % i)
9279                eap_proto_tls_test_wait = True
9280                payload = 1470*b'A'
9281                return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9282                                   4 + 1 + 1 + len(payload),
9283                                   EAP_TYPE_TLS, 0x40) + payload
9284        eap_proto_tls_test_wait = False
9285        idx += 1
9286        if ctx['num'] == idx:
9287            logger.info("Test: EAP-Failure")
9288            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9289
9290        idx += 1
9291        if ctx['num'] == idx:
9292            logger.info("Test: TLS/Start")
9293            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9294                               4 + 1 + 1,
9295                               EAP_TYPE_TLS, 0x20)
9296        idx += 1
9297        if ctx['num'] == idx:
9298            logger.info("Test: Non-ACK to more-fragment message")
9299            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
9300                               4 + 1 + 1 + 1,
9301                               EAP_TYPE_TLS, 0x00, 255)
9302        idx += 1
9303        if ctx['num'] == idx:
9304            logger.info("Test: EAP-Failure")
9305            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9306
9307        logger.info("No more test responses available - test case completed")
9308        global eap_proto_tls_test_done
9309        eap_proto_tls_test_done = True
9310        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9311
9312    srv = start_radius_server(tls_handler)
9313
9314    try:
9315        hapd = start_ap(apdev[0])
9316        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9317
9318        i = 0
9319        while not eap_proto_tls_test_done:
9320            i += 1
9321            logger.info("Running connection iteration %d" % i)
9322            workaround = "0" if i == 6 else "1"
9323            fragment_size = "100" if i == 8 else "1400"
9324            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9325                           eap="TLS", identity="tls user",
9326                           ca_cert="auth_serv/ca.pem",
9327                           client_cert="auth_serv/user.pem",
9328                           private_key="auth_serv/user.key",
9329                           eap_workaround=workaround,
9330                           fragment_size=fragment_size,
9331                           wait_connect=False)
9332            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
9333            if ev is None:
9334                raise Exception("Timeout on EAP start")
9335            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD",
9336                                    "CTRL-EVENT-EAP-STATUS"], timeout=5)
9337            if ev is None:
9338                raise Exception("Timeout on EAP method start")
9339            time.sleep(0.1)
9340            start = os.times()[4]
9341            while eap_proto_tls_test_wait:
9342                now = os.times()[4]
9343                if now - start > 10:
9344                    break
9345                time.sleep(0.1)
9346            dev[0].request("REMOVE_NETWORK all")
9347            dev[0].wait_disconnected(timeout=1)
9348            dev[0].dump_monitor()
9349    finally:
9350        stop_radius_server(srv)
9351
9352def test_eap_proto_tnc(dev, apdev):
9353    """EAP-TNC protocol tests"""
9354    check_eap_capa(dev[0], "TNC")
9355    global eap_proto_tnc_test_done
9356    eap_proto_tnc_test_done = False
9357
9358    def tnc_handler(ctx, req):
9359        logger.info("tnc_handler - RX " + binascii.hexlify(req).decode())
9360        if 'num' not in ctx:
9361            ctx['num'] = 0
9362        ctx['num'] += 1
9363        if 'id' not in ctx:
9364            ctx['id'] = 1
9365        ctx['id'] = (ctx['id'] + 1) % 256
9366        idx = 0
9367
9368        idx += 1
9369        if ctx['num'] == idx:
9370            logger.info("Test: TNC start with unsupported version")
9371            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9372                               4 + 1 + 1,
9373                               EAP_TYPE_TNC, 0x20)
9374
9375        idx += 1
9376        if ctx['num'] == idx:
9377            logger.info("Test: TNC without Flags field")
9378            return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
9379                               4 + 1,
9380                               EAP_TYPE_TNC)
9381
9382        idx += 1
9383        if ctx['num'] == idx:
9384            logger.info("Test: Message underflow due to missing Message Length")
9385            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9386                               4 + 1 + 1,
9387                               EAP_TYPE_TNC, 0xa1)
9388
9389        idx += 1
9390        if ctx['num'] == idx:
9391            logger.info("Test: Invalid Message Length")
9392            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
9393                               4 + 1 + 1 + 4 + 1,
9394                               EAP_TYPE_TNC, 0xa1, 0, 0)
9395
9396        idx += 1
9397        if ctx['num'] == idx:
9398            logger.info("Test: Invalid Message Length")
9399            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
9400                               4 + 1 + 1 + 4,
9401                               EAP_TYPE_TNC, 0xe1, 75001)
9402
9403        idx += 1
9404        if ctx['num'] == idx:
9405            logger.info("Test: Start with Message Length")
9406            return struct.pack(">BBHBBL", EAP_CODE_REQUEST, ctx['id'],
9407                               4 + 1 + 1 + 4,
9408                               EAP_TYPE_TNC, 0xa1, 1)
9409        idx += 1
9410        if ctx['num'] == idx:
9411            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9412
9413        idx += 1
9414        if ctx['num'] == idx:
9415            logger.info("Test: Server used start flag again")
9416            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9417                               4 + 1 + 1,
9418                               EAP_TYPE_TNC, 0x21)
9419        idx += 1
9420        if ctx['num'] == idx:
9421            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9422                               4 + 1 + 1,
9423                               EAP_TYPE_TNC, 0x21)
9424
9425        idx += 1
9426        if ctx['num'] == idx:
9427            logger.info("Test: Fragmentation and unexpected payload in ack")
9428            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9429                               4 + 1 + 1,
9430                               EAP_TYPE_TNC, 0x21)
9431        idx += 1
9432        if ctx['num'] == idx:
9433            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9434                               4 + 1 + 1,
9435                               EAP_TYPE_TNC, 0x01)
9436        idx += 1
9437        if ctx['num'] == idx:
9438            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
9439                               4 + 1 + 1 + 1,
9440                               EAP_TYPE_TNC, 0x01, 0)
9441
9442        idx += 1
9443        if ctx['num'] == idx:
9444            logger.info("Test: Server fragmenting and fragment overflow")
9445            return struct.pack(">BBHBBLB", EAP_CODE_REQUEST, ctx['id'],
9446                               4 + 1 + 1 + 4 + 1,
9447                               EAP_TYPE_TNC, 0xe1, 2, 1)
9448        idx += 1
9449        if ctx['num'] == idx:
9450            return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
9451                               4 + 1 + 1 + 2,
9452                               EAP_TYPE_TNC, 0x01, 2, 3)
9453
9454        idx += 1
9455        if ctx['num'] == idx:
9456            logger.info("Test: Server fragmenting and no message length in a fragment")
9457            return struct.pack(">BBHBBB", EAP_CODE_REQUEST, ctx['id'],
9458                               4 + 1 + 1 + 1,
9459                               EAP_TYPE_TNC, 0x61, 2)
9460
9461        idx += 1
9462        if ctx['num'] == idx:
9463            logger.info("Test: TNC start followed by invalid TNCCS-Batch")
9464            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9465                               4 + 1 + 1,
9466                               EAP_TYPE_TNC, 0x21)
9467        idx += 1
9468        if ctx['num'] == idx:
9469            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9470            resp = b"FOO"
9471            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9472                               4 + 1 + 1 + len(resp),
9473                               EAP_TYPE_TNC, 0x01) + resp
9474
9475        idx += 1
9476        if ctx['num'] == idx:
9477            logger.info("Test: TNC start followed by invalid TNCCS-Batch (2)")
9478            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9479                               4 + 1 + 1,
9480                               EAP_TYPE_TNC, 0x21)
9481        idx += 1
9482        if ctx['num'] == idx:
9483            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9484            resp = b"</TNCCS-Batch><TNCCS-Batch>"
9485            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9486                               4 + 1 + 1 + len(resp),
9487                               EAP_TYPE_TNC, 0x01) + resp
9488
9489        idx += 1
9490        if ctx['num'] == idx:
9491            logger.info("Test: TNCCS-Batch missing BatchId attribute")
9492            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9493                               4 + 1 + 1,
9494                               EAP_TYPE_TNC, 0x21)
9495        idx += 1
9496        if ctx['num'] == idx:
9497            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9498            resp = b"<TNCCS-Batch    foo=3></TNCCS-Batch>"
9499            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9500                               4 + 1 + 1 + len(resp),
9501                               EAP_TYPE_TNC, 0x01) + resp
9502
9503        idx += 1
9504        if ctx['num'] == idx:
9505            logger.info("Test: Unexpected IF-TNCCS BatchId")
9506            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9507                               4 + 1 + 1,
9508                               EAP_TYPE_TNC, 0x21)
9509        idx += 1
9510        if ctx['num'] == idx:
9511            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9512            resp = b"<TNCCS-Batch    BatchId=123456789></TNCCS-Batch>"
9513            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9514                               4 + 1 + 1 + len(resp),
9515                               EAP_TYPE_TNC, 0x01) + resp
9516
9517        idx += 1
9518        if ctx['num'] == idx:
9519            logger.info("Test: Missing IMC-IMV-Message and TNCC-TNCS-Message end tags")
9520            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9521                               4 + 1 + 1,
9522                               EAP_TYPE_TNC, 0x21)
9523        idx += 1
9524        if ctx['num'] == idx:
9525            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9526            resp = b"<TNCCS-Batch BatchId=2><IMC-IMV-Message><TNCC-TNCS-Message></TNCCS-Batch>"
9527            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9528                               4 + 1 + 1 + len(resp),
9529                               EAP_TYPE_TNC, 0x01) + resp
9530        idx += 1
9531        if ctx['num'] == idx:
9532            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9533
9534        idx += 1
9535        if ctx['num'] == idx:
9536            logger.info("Test: Missing IMC-IMV-Message and TNCC-TNCS-Message Type")
9537            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9538                               4 + 1 + 1,
9539                               EAP_TYPE_TNC, 0x21)
9540        idx += 1
9541        if ctx['num'] == idx:
9542            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9543            resp = b"<TNCCS-Batch BatchId=2><IMC-IMV-Message></IMC-IMV-Message><TNCC-TNCS-Message></TNCC-TNCS-Message></TNCCS-Batch>"
9544            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9545                               4 + 1 + 1 + len(resp),
9546                               EAP_TYPE_TNC, 0x01) + resp
9547        idx += 1
9548        if ctx['num'] == idx:
9549            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9550
9551        idx += 1
9552        if ctx['num'] == idx:
9553            logger.info("Test: Missing TNCC-TNCS-Message XML end tag")
9554            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9555                               4 + 1 + 1,
9556                               EAP_TYPE_TNC, 0x21)
9557        idx += 1
9558        if ctx['num'] == idx:
9559            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9560            resp = b"<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><XML></TNCC-TNCS-Message></TNCCS-Batch>"
9561            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9562                               4 + 1 + 1 + len(resp),
9563                               EAP_TYPE_TNC, 0x01) + resp
9564        idx += 1
9565        if ctx['num'] == idx:
9566            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9567
9568        idx += 1
9569        if ctx['num'] == idx:
9570            logger.info("Test: Missing TNCC-TNCS-Message Base64 start tag")
9571            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9572                               4 + 1 + 1,
9573                               EAP_TYPE_TNC, 0x21)
9574        idx += 1
9575        if ctx['num'] == idx:
9576            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9577            resp = b"<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type></TNCC-TNCS-Message></TNCCS-Batch>"
9578            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9579                               4 + 1 + 1 + len(resp),
9580                               EAP_TYPE_TNC, 0x01) + resp
9581        idx += 1
9582        if ctx['num'] == idx:
9583            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9584
9585        idx += 1
9586        if ctx['num'] == idx:
9587            logger.info("Test: Missing TNCC-TNCS-Message Base64 end tag")
9588            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9589                               4 + 1 + 1,
9590                               EAP_TYPE_TNC, 0x21)
9591        idx += 1
9592        if ctx['num'] == idx:
9593            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9594            resp = b"<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><Base64>abc</TNCC-TNCS-Message></TNCCS-Batch>"
9595            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9596                               4 + 1 + 1 + len(resp),
9597                               EAP_TYPE_TNC, 0x01) + resp
9598        idx += 1
9599        if ctx['num'] == idx:
9600            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9601
9602        idx += 1
9603        if ctx['num'] == idx:
9604            logger.info("Test: TNCC-TNCS-Message Base64 message")
9605            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9606                               4 + 1 + 1,
9607                               EAP_TYPE_TNC, 0x21)
9608        idx += 1
9609        if ctx['num'] == idx:
9610            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9611            resp = b"<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><Base64>aGVsbG8=</Base64></TNCC-TNCS-Message></TNCCS-Batch>"
9612            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9613                               4 + 1 + 1 + len(resp),
9614                               EAP_TYPE_TNC, 0x01) + resp
9615        idx += 1
9616        if ctx['num'] == idx:
9617            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9618
9619        idx += 1
9620        if ctx['num'] == idx:
9621            logger.info("Test: Invalid TNCC-TNCS-Message XML message")
9622            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9623                               4 + 1 + 1,
9624                               EAP_TYPE_TNC, 0x21)
9625        idx += 1
9626        if ctx['num'] == idx:
9627            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9628            resp = b"<TNCCS-Batch BatchId=2><TNCC-TNCS-Message><Type>00000001</Type><XML>hello</XML></TNCC-TNCS-Message></TNCCS-Batch>"
9629            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9630                               4 + 1 + 1 + len(resp),
9631                               EAP_TYPE_TNC, 0x01) + resp
9632        idx += 1
9633        if ctx['num'] == idx:
9634            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9635
9636        idx += 1
9637        if ctx['num'] == idx:
9638            logger.info("Test: Missing TNCCS-Recommendation type")
9639            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9640                               4 + 1 + 1,
9641                               EAP_TYPE_TNC, 0x21)
9642        idx += 1
9643        if ctx['num'] == idx:
9644            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9645            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>'
9646            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9647                               4 + 1 + 1 + len(resp),
9648                               EAP_TYPE_TNC, 0x01) + resp
9649        idx += 1
9650        if ctx['num'] == idx:
9651            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9652
9653        idx += 1
9654        if ctx['num'] == idx:
9655            logger.info("Test: TNCCS-Recommendation type=none")
9656            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9657                               4 + 1 + 1,
9658                               EAP_TYPE_TNC, 0x21)
9659        idx += 1
9660        if ctx['num'] == idx:
9661            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9662            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>'
9663            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9664                               4 + 1 + 1 + len(resp),
9665                               EAP_TYPE_TNC, 0x01) + resp
9666        idx += 1
9667        if ctx['num'] == idx:
9668            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9669
9670        idx += 1
9671        if ctx['num'] == idx:
9672            logger.info("Test: TNCCS-Recommendation type=isolate")
9673            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9674                               4 + 1 + 1,
9675                               EAP_TYPE_TNC, 0x21)
9676        idx += 1
9677        if ctx['num'] == idx:
9678            logger.info("Received TNCCS-Batch: " + binascii.hexlify(req[6:]).decode())
9679            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>'
9680            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
9681                               4 + 1 + 1 + len(resp),
9682                               EAP_TYPE_TNC, 0x01) + resp
9683        idx += 1
9684        if ctx['num'] == idx:
9685            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9686
9687        logger.info("No more test responses available - test case completed")
9688        global eap_proto_tnc_test_done
9689        eap_proto_tnc_test_done = True
9690        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9691
9692    srv = start_radius_server(tnc_handler)
9693
9694    try:
9695        hapd = start_ap(apdev[0])
9696        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9697
9698        i = 0
9699        while not eap_proto_tnc_test_done:
9700            i += 1
9701            logger.info("Running connection iteration %d" % i)
9702            frag = 1400
9703            if i == 8:
9704                frag = 150
9705            dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9706                           eap="TNC", identity="tnc", fragment_size=str(frag),
9707                           wait_connect=False)
9708            ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
9709            if ev is None:
9710                raise Exception("Timeout on EAP start")
9711            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD",
9712                                    "CTRL-EVENT-EAP-STATUS"], timeout=5)
9713            if ev is None:
9714                raise Exception("Timeout on EAP method start")
9715            time.sleep(0.1)
9716            dev[0].request("REMOVE_NETWORK all")
9717            dev[0].wait_disconnected(timeout=1)
9718            dev[0].dump_monitor()
9719    finally:
9720        stop_radius_server(srv)
9721
9722def test_eap_canned_success_after_identity(dev, apdev):
9723    """EAP protocol tests for canned EAP-Success after identity"""
9724    check_eap_capa(dev[0], "MD5")
9725    def eap_canned_success_handler(ctx, req):
9726        logger.info("eap_canned_success_handler - RX " + binascii.hexlify(req).decode())
9727        if 'num' not in ctx:
9728            ctx['num'] = 0
9729        ctx['num'] = ctx['num'] + 1
9730        if 'id' not in ctx:
9731            ctx['id'] = 1
9732        ctx['id'] = (ctx['id'] + 1) % 256
9733        idx = 0
9734
9735        idx += 1
9736        if ctx['num'] == idx:
9737            logger.info("Test: EAP-Success")
9738            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
9739
9740        idx += 1
9741        if ctx['num'] == idx:
9742            logger.info("Test: EAP-Success")
9743            return struct.pack(">BBH", EAP_CODE_SUCCESS, ctx['id'], 4)
9744
9745        return None
9746
9747    srv = start_radius_server(eap_canned_success_handler)
9748
9749    try:
9750        hapd = start_ap(apdev[0])
9751        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9752
9753        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9754                       phase1="allow_canned_success=1",
9755                       eap="MD5", identity="user", password="password",
9756                       wait_connect=False)
9757        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
9758        if ev is None:
9759            raise Exception("Timeout on EAP success")
9760        dev[0].request("REMOVE_NETWORK all")
9761        dev[0].wait_disconnected()
9762
9763        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
9764                       eap="MD5", identity="user", password="password",
9765                       wait_connect=False)
9766        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
9767        if ev is None:
9768            raise Exception("Timeout on EAP start")
9769        ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=0.1)
9770        if ev is not None:
9771            raise Exception("Unexpected EAP success")
9772        dev[0].request("REMOVE_NETWORK all")
9773        dev[0].wait_disconnected()
9774    finally:
9775        stop_radius_server(srv)
9776
9777def test_eap_proto_wsc(dev, apdev):
9778    """EAP-WSC protocol tests"""
9779    global eap_proto_wsc_test_done, eap_proto_wsc_wait_failure
9780    eap_proto_wsc_test_done = False
9781
9782    def wsc_handler(ctx, req):
9783        logger.info("wsc_handler - RX " + binascii.hexlify(req).decode())
9784        if 'num' not in ctx:
9785            ctx['num'] = 0
9786        ctx['num'] += 1
9787        if 'id' not in ctx:
9788            ctx['id'] = 1
9789        ctx['id'] = (ctx['id'] + 1) % 256
9790        idx = 0
9791
9792        global eap_proto_wsc_wait_failure
9793        eap_proto_wsc_wait_failure = False
9794
9795        idx += 1
9796        if ctx['num'] == idx:
9797            logger.info("Test: Missing Flags field")
9798            return struct.pack(">BBHB3BLB", EAP_CODE_REQUEST, ctx['id'],
9799                               4 + 1 + 3 + 4 + 1,
9800                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9801                               1)
9802
9803        idx += 1
9804        if ctx['num'] == idx:
9805            logger.info("Test: Message underflow (missing Message Length field)")
9806            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9807                               4 + 1 + 3 + 4 + 2,
9808                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9809                               1, 0x02)
9810
9811        idx += 1
9812        if ctx['num'] == idx:
9813            logger.info("Test: Invalid Message Length (> 50000)")
9814            return struct.pack(">BBHB3BLBBH", EAP_CODE_REQUEST, ctx['id'],
9815                               4 + 1 + 3 + 4 + 4,
9816                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9817                               1, 0x02, 65535)
9818
9819        idx += 1
9820        if ctx['num'] == idx:
9821            logger.info("Test: Invalid Message Length (< current payload)")
9822            return struct.pack(">BBHB3BLBBHB", EAP_CODE_REQUEST, ctx['id'],
9823                               4 + 1 + 3 + 4 + 5,
9824                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9825                               1, 0x02, 0, 0xff)
9826
9827        idx += 1
9828        if ctx['num'] == idx:
9829            logger.info("Test: Unexpected Op-Code 5 in WAIT_START state")
9830            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9831                               4 + 1 + 3 + 4 + 2,
9832                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9833                               5, 0x00)
9834
9835        idx += 1
9836        if ctx['num'] == idx:
9837            logger.info("Test: Valid WSC Start to start the sequence")
9838            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9839                               4 + 1 + 3 + 4 + 2,
9840                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9841                               1, 0x00)
9842        idx += 1
9843        if ctx['num'] == idx:
9844            logger.info("Test: No Message Length field in a fragmented packet")
9845            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9846                               4 + 1 + 3 + 4 + 2,
9847                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9848                               4, 0x01)
9849
9850        idx += 1
9851        if ctx['num'] == idx:
9852            logger.info("Test: Valid WSC Start to start the sequence")
9853            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9854                               4 + 1 + 3 + 4 + 2,
9855                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9856                               1, 0x00)
9857        idx += 1
9858        if ctx['num'] == idx:
9859            logger.info("Test: Valid first fragmented packet")
9860            return struct.pack(">BBHB3BLBBHB", EAP_CODE_REQUEST, ctx['id'],
9861                               4 + 1 + 3 + 4 + 5,
9862                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9863                               4, 0x03, 10, 1)
9864        idx += 1
9865        if ctx['num'] == idx:
9866            logger.info("Test: Unexpected Op-Code 5 in fragment (expected 4)")
9867            return struct.pack(">BBHB3BLBBB", EAP_CODE_REQUEST, ctx['id'],
9868                               4 + 1 + 3 + 4 + 3,
9869                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9870                               5, 0x01, 2)
9871
9872        idx += 1
9873        if ctx['num'] == idx:
9874            logger.info("Test: Valid WSC Start to start the sequence")
9875            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9876                               4 + 1 + 3 + 4 + 2,
9877                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9878                               1, 0x00)
9879        idx += 1
9880        if ctx['num'] == idx:
9881            logger.info("Test: Valid first fragmented packet")
9882            return struct.pack(">BBHB3BLBBHB", EAP_CODE_REQUEST, ctx['id'],
9883                               4 + 1 + 3 + 4 + 5,
9884                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9885                               4, 0x03, 2, 1)
9886        idx += 1
9887        if ctx['num'] == idx:
9888            logger.info("Test: Fragment overflow")
9889            return struct.pack(">BBHB3BLBBBB", EAP_CODE_REQUEST, ctx['id'],
9890                               4 + 1 + 3 + 4 + 4,
9891                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9892                               4, 0x01, 2, 3)
9893
9894        idx += 1
9895        if ctx['num'] == idx:
9896            logger.info("Test: Valid WSC Start to start the sequence")
9897            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9898                               4 + 1 + 3 + 4 + 2,
9899                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9900                               1, 0x00)
9901        idx += 1
9902        if ctx['num'] == idx:
9903            logger.info("Test: Unexpected Op-Code 5 in WAIT_FRAG_ACK state")
9904            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9905                               4 + 1 + 3 + 4 + 2,
9906                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9907                               5, 0x00)
9908
9909        idx += 1
9910        if ctx['num'] == idx:
9911            logger.info("Test: Valid WSC Start")
9912            return struct.pack(">BBHB3BLBB", EAP_CODE_REQUEST, ctx['id'],
9913                               4 + 1 + 3 + 4 + 2,
9914                               EAP_TYPE_EXPANDED, 0x00, 0x37, 0x2a, 1,
9915                               1, 0x00)
9916        idx += 1
9917        if ctx['num'] == idx:
9918            logger.info("No more test responses available - test case completed")
9919            global eap_proto_wsc_test_done
9920            eap_proto_wsc_test_done = True
9921            eap_proto_wsc_wait_failure = True
9922            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9923
9924        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
9925
9926    srv = start_radius_server(wsc_handler)
9927
9928    try:
9929        hapd = start_ap(apdev[0])
9930        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9931
9932        i = 0
9933        while not eap_proto_wsc_test_done:
9934            i += 1
9935            logger.info("Running connection iteration %d" % i)
9936            fragment_size = 1398 if i != 9 else 50
9937            dev[0].connect("eap-test", key_mgmt="WPA-EAP", eap="WSC",
9938                           fragment_size=str(fragment_size),
9939                           identity="WFA-SimpleConfig-Enrollee-1-0",
9940                           phase1="pin=12345670",
9941                           scan_freq="2412", wait_connect=False)
9942            ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
9943            if ev is None:
9944                raise Exception("Timeout on EAP method start")
9945            if eap_proto_wsc_wait_failure:
9946                ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
9947                if ev is None:
9948                    raise Exception("Timeout on EAP failure")
9949            else:
9950                time.sleep(0.1)
9951            dev[0].request("REMOVE_NETWORK all")
9952            dev[0].wait_disconnected(timeout=1)
9953            dev[0].dump_monitor()
9954    finally:
9955        stop_radius_server(srv)
9956
9957def test_eap_canned_success_before_method(dev, apdev):
9958    """EAP protocol tests for canned EAP-Success before any method"""
9959    params = int_eap_server_params()
9960    hapd = hostapd.add_ap(apdev[0], params)
9961    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9962    bssid = apdev[0]['bssid']
9963    hapd.request("SET ext_eapol_frame_io 1")
9964
9965    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
9966                   phase1="allow_canned_success=1",
9967                   eap="MD5", identity="user", password="password",
9968                   wait_connect=False)
9969
9970    ev = hapd.wait_event(["EAPOL-TX"], timeout=10)
9971    if ev is None:
9972        raise Exception("Timeout on EAPOL-TX from hostapd")
9973
9974    res = dev[0].request("EAPOL_RX " + bssid + " 0200000403020004")
9975    if "OK" not in res:
9976        raise Exception("EAPOL_RX to wpa_supplicant failed")
9977
9978    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=5)
9979    if ev is None:
9980        raise Exception("Timeout on EAP success")
9981    dev[0].request("REMOVE_NETWORK all")
9982    dev[0].wait_disconnected()
9983
9984def test_eap_canned_failure_before_method(dev, apdev):
9985    """EAP protocol tests for canned EAP-Failure before any method"""
9986    params = int_eap_server_params()
9987    hapd = hostapd.add_ap(apdev[0], params)
9988    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
9989    bssid = apdev[0]['bssid']
9990    hapd.request("SET ext_eapol_frame_io 1")
9991    dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", scan_freq="2412",
9992                   phase1="allow_canned_success=1",
9993                   eap="MD5", identity="user", password="password",
9994                   wait_connect=False)
9995
9996    ev = hapd.wait_event(["EAPOL-TX"], timeout=10)
9997    if ev is None:
9998        raise Exception("Timeout on EAPOL-TX from hostapd")
9999
10000    res = dev[0].request("EAPOL_RX " + bssid + " 0200000404020004")
10001    if "OK" not in res:
10002        raise Exception("EAPOL_RX to wpa_supplicant failed")
10003
10004    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=5)
10005    if ev is None:
10006        raise Exception("Timeout on EAP failure")
10007    dev[0].request("REMOVE_NETWORK all")
10008    dev[0].wait_disconnected()
10009
10010def test_eap_nak_oom(dev, apdev):
10011    """EAP-Nak OOM"""
10012    check_eap_capa(dev[0], "MD5")
10013    params = hostapd.wpa2_eap_params(ssid="eap-test")
10014    hapd = hostapd.add_ap(apdev[0], params)
10015    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
10016    with alloc_fail(dev[0], 1, "eap_msg_alloc;eap_sm_buildNak"):
10017        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
10018                       eap="MD5", identity="sake user", password="password",
10019                       wait_connect=False)
10020        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
10021        dev[0].request("REMOVE_NETWORK all")
10022        dev[0].wait_disconnected()
10023
10024def test_eap_nak_expanded(dev, apdev):
10025    """EAP-Nak with expanded method"""
10026    check_eap_capa(dev[0], "MD5")
10027    check_eap_capa(dev[0], "VENDOR-TEST")
10028    params = hostapd.wpa2_eap_params(ssid="eap-test")
10029    hapd = hostapd.add_ap(apdev[0], params)
10030    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
10031    dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
10032                   eap="VENDOR-TEST WSC",
10033                   identity="sake user", password="password",
10034                   wait_connect=False)
10035    ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=10)
10036    if ev is None or "NAK" not in ev:
10037        raise Exception("No NAK event seen")
10038
10039    ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
10040    if ev is None:
10041        raise Exception("No EAP-Failure seen")
10042
10043    dev[0].request("REMOVE_NETWORK all")
10044    dev[0].wait_disconnected()
10045
10046EAP_TLV_RESULT_TLV = 3
10047EAP_TLV_NAK_TLV = 4
10048EAP_TLV_ERROR_CODE_TLV = 5
10049EAP_TLV_CONNECTION_BINDING_TLV = 6
10050EAP_TLV_VENDOR_SPECIFIC_TLV = 7
10051EAP_TLV_URI_TLV = 8
10052EAP_TLV_EAP_PAYLOAD_TLV = 9
10053EAP_TLV_INTERMEDIATE_RESULT_TLV = 10
10054EAP_TLV_PAC_TLV = 11
10055EAP_TLV_CRYPTO_BINDING_TLV = 12
10056EAP_TLV_CALLING_STATION_ID_TLV = 13
10057EAP_TLV_CALLED_STATION_ID_TLV = 14
10058EAP_TLV_NAS_PORT_TYPE_TLV = 15
10059EAP_TLV_SERVER_IDENTIFIER_TLV = 16
10060EAP_TLV_IDENTITY_TYPE_TLV = 17
10061EAP_TLV_SERVER_TRUSTED_ROOT_TLV = 18
10062EAP_TLV_REQUEST_ACTION_TLV = 19
10063EAP_TLV_PKCS7_TLV = 20
10064
10065EAP_TLV_RESULT_SUCCESS = 1
10066EAP_TLV_RESULT_FAILURE = 2
10067
10068EAP_TLV_TYPE_MANDATORY = 0x8000
10069EAP_TLV_TYPE_MASK = 0x3fff
10070
10071PAC_TYPE_PAC_KEY = 1
10072PAC_TYPE_PAC_OPAQUE = 2
10073PAC_TYPE_CRED_LIFETIME = 3
10074PAC_TYPE_A_ID = 4
10075PAC_TYPE_I_ID = 5
10076PAC_TYPE_A_ID_INFO = 7
10077PAC_TYPE_PAC_ACKNOWLEDGEMENT = 8
10078PAC_TYPE_PAC_INFO = 9
10079PAC_TYPE_PAC_TYPE = 10
10080
10081def eap_fast_start(ctx):
10082    logger.info("Send EAP-FAST/Start")
10083    return struct.pack(">BBHBBHH", EAP_CODE_REQUEST, ctx['id'],
10084                       4 + 1 + 1 + 4 + 16,
10085                       EAP_TYPE_FAST, 0x21, 4, 16) + 16*b'A'
10086
10087def test_eap_fast_proto(dev, apdev):
10088    """EAP-FAST Phase protocol testing"""
10089    check_eap_capa(dev[0], "FAST")
10090    global eap_fast_proto_ctx
10091    eap_fast_proto_ctx = None
10092
10093    def eap_handler(ctx, req):
10094        logger.info("eap_handler - RX " + binascii.hexlify(req).decode())
10095        if 'num' not in ctx:
10096            ctx['num'] = 0
10097        ctx['num'] = ctx['num'] + 1
10098        if 'id' not in ctx:
10099            ctx['id'] = 1
10100        ctx['id'] = (ctx['id'] + 1) % 256
10101        idx = 0
10102
10103        global eap_fast_proto_ctx
10104        eap_fast_proto_ctx = ctx
10105        ctx['test_done'] = False
10106
10107        idx += 1
10108        if ctx['num'] == idx:
10109            return eap_fast_start(ctx)
10110        idx += 1
10111        if ctx['num'] == idx:
10112            logger.info("EAP-FAST: TLS processing failed")
10113            data = b'ABCDEFGHIK'
10114            return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
10115                               4 + 1 + 1 + len(data),
10116                               EAP_TYPE_FAST, 0x01) + data
10117        idx += 1
10118        if ctx['num'] == idx:
10119            ctx['test_done'] = True
10120            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
10121
10122        logger.info("Past last test case")
10123        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
10124
10125    srv = start_radius_server(eap_handler)
10126    try:
10127        hapd = start_ap(apdev[0])
10128        dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
10129        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
10130                       eap="FAST", anonymous_identity="FAST",
10131                       identity="user", password="password",
10132                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
10133                       phase1="fast_provisioning=1",
10134                       pac_file="blob://fast_pac_proto",
10135                       wait_connect=False)
10136        ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
10137        if ev is None:
10138            raise Exception("Could not start EAP-FAST")
10139        ok = False
10140        for i in range(100):
10141            if eap_fast_proto_ctx:
10142                if eap_fast_proto_ctx['test_done']:
10143                    ok = True
10144                    break
10145            time.sleep(0.05)
10146        dev[0].request("REMOVE_NETWORK all")
10147        dev[0].wait_disconnected()
10148    finally:
10149        stop_radius_server(srv)
10150
10151def run_eap_fast_phase2(dev, test_payload, test_failure=True):
10152    global eap_fast_proto_ctx
10153    eap_fast_proto_ctx = None
10154
10155    def ssl_info_callback(conn, where, ret):
10156        logger.debug("SSL: info where=%d ret=%d" % (where, ret))
10157
10158    def log_conn_state(conn):
10159        try:
10160            state = conn.state_string()
10161        except AttributeError:
10162            state = conn.get_state_string()
10163        if state:
10164            logger.info("State: " + str(state))
10165
10166    def process_clienthello(ctx, payload):
10167        logger.info("Process ClientHello")
10168        ctx['sslctx'] = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
10169        ctx['sslctx'].set_info_callback(ssl_info_callback)
10170        ctx['sslctx'].load_tmp_dh("auth_serv/dh.conf")
10171        if OpenSSL.SSL.OPENSSL_VERSION_NUMBER >= 0x10100000:
10172            ctx['sslctx'].set_cipher_list("ADH-AES128-SHA:@SECLEVEL=0")
10173        else:
10174            ctx['sslctx'].set_cipher_list("ADH-AES128-SHA")
10175        ctx['conn'] = OpenSSL.SSL.Connection(ctx['sslctx'], None)
10176        ctx['conn'].set_accept_state()
10177        log_conn_state(ctx['conn'])
10178        ctx['conn'].bio_write(payload)
10179        try:
10180            ctx['conn'].do_handshake()
10181        except OpenSSL.SSL.WantReadError:
10182            pass
10183        log_conn_state(ctx['conn'])
10184        data = ctx['conn'].bio_read(4096)
10185        log_conn_state(ctx['conn'])
10186        return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
10187                           4 + 1 + 1 + len(data),
10188                           EAP_TYPE_FAST, 0x01) + data
10189
10190    def process_clientkeyexchange(ctx, payload, appl_data):
10191        logger.info("Process ClientKeyExchange")
10192        log_conn_state(ctx['conn'])
10193        ctx['conn'].bio_write(payload)
10194        try:
10195            ctx['conn'].do_handshake()
10196        except OpenSSL.SSL.WantReadError:
10197            pass
10198        ctx['conn'].send(appl_data)
10199        log_conn_state(ctx['conn'])
10200        data = ctx['conn'].bio_read(4096)
10201        log_conn_state(ctx['conn'])
10202        return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
10203                           4 + 1 + 1 + len(data),
10204                           EAP_TYPE_FAST, 0x01) + data
10205
10206    def eap_handler(ctx, req):
10207        logger.info("eap_handler - RX " + binascii.hexlify(req).decode())
10208        if 'num' not in ctx:
10209            ctx['num'] = 0
10210        ctx['num'] = ctx['num'] + 1
10211        if 'id' not in ctx:
10212            ctx['id'] = 1
10213        ctx['id'] = (ctx['id'] + 1) % 256
10214        idx = 0
10215
10216        global eap_fast_proto_ctx
10217        eap_fast_proto_ctx = ctx
10218        ctx['test_done'] = False
10219        logger.debug("ctx['num']=%d" % ctx['num'])
10220
10221        idx += 1
10222        if ctx['num'] == idx:
10223            return eap_fast_start(ctx)
10224        idx += 1
10225        if ctx['num'] == idx:
10226            return process_clienthello(ctx, req[6:])
10227        idx += 1
10228        if ctx['num'] == idx:
10229            if not test_failure:
10230                ctx['test_done'] = True
10231            return process_clientkeyexchange(ctx, req[6:], test_payload)
10232        idx += 1
10233        if ctx['num'] == idx:
10234            ctx['test_done'] = True
10235            return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
10236
10237        logger.info("Past last test case")
10238        return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
10239
10240    srv = start_radius_server(eap_handler)
10241    try:
10242        dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
10243                       eap="FAST", anonymous_identity="FAST",
10244                       identity="user", password="password",
10245                       ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
10246                       phase1="fast_provisioning=1",
10247                       pac_file="blob://fast_pac_proto",
10248                       wait_connect=False)
10249        ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
10250        if ev is None:
10251            raise Exception("Could not start EAP-FAST")
10252        dev[0].dump_monitor()
10253        ok = False
10254        for i in range(100):
10255            if eap_fast_proto_ctx:
10256                if eap_fast_proto_ctx['test_done']:
10257                    ok = True
10258                    break
10259            time.sleep(0.05)
10260        time.sleep(0.1)
10261        dev[0].request("REMOVE_NETWORK all")
10262        dev[0].wait_disconnected()
10263        if not ok:
10264            raise Exception("EAP-FAST TLS exchange did not complete")
10265        for i in range(3):
10266            dev[i].dump_monitor()
10267    finally:
10268        stop_radius_server(srv)
10269
10270def test_eap_fast_proto_phase2(dev, apdev):
10271    """EAP-FAST Phase 2 protocol testing"""
10272    if not openssl_imported:
10273        raise HwsimSkip("OpenSSL python method not available")
10274    check_eap_capa(dev[0], "FAST")
10275    hapd = start_ap(apdev[0])
10276    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
10277
10278    tests = [("Too short Phase 2 TLV frame (len=3)",
10279              "ABC",
10280              False),
10281             ("EAP-FAST: TLV overflow",
10282              struct.pack(">HHB", 0, 2, 0xff),
10283              False),
10284             ("EAP-FAST: Unknown TLV (optional and mandatory)",
10285              struct.pack(">HHB", 0, 1, 0xff) +
10286              struct.pack(">HHB", EAP_TLV_TYPE_MANDATORY, 1, 0xff),
10287              True),
10288             ("EAP-FAST: More than one EAP-Payload TLV in the message",
10289              struct.pack(">HHBHHB",
10290                          EAP_TLV_EAP_PAYLOAD_TLV, 1, 0xff,
10291                          EAP_TLV_EAP_PAYLOAD_TLV, 1, 0xff),
10292              True),
10293             ("EAP-FAST: Unknown Result 255 and More than one Result TLV in the message",
10294              struct.pack(">HHHHHH",
10295                          EAP_TLV_RESULT_TLV, 2, 0xff,
10296                          EAP_TLV_RESULT_TLV, 2, 0xff),
10297              True),
10298             ("EAP-FAST: Too short Result TLV",
10299              struct.pack(">HHB", EAP_TLV_RESULT_TLV, 1, 0xff),
10300              True),
10301             ("EAP-FAST: Unknown Intermediate Result 255 and More than one Intermediate-Result TLV in the message",
10302              struct.pack(">HHHHHH",
10303                          EAP_TLV_INTERMEDIATE_RESULT_TLV, 2, 0xff,
10304                          EAP_TLV_INTERMEDIATE_RESULT_TLV, 2, 0xff),
10305              True),
10306             ("EAP-FAST: Too short Intermediate-Result TLV",
10307              struct.pack(">HHB", EAP_TLV_INTERMEDIATE_RESULT_TLV, 1, 0xff),
10308              True),
10309             ("EAP-FAST: More than one Crypto-Binding TLV in the message",
10310              struct.pack(">HH", EAP_TLV_CRYPTO_BINDING_TLV, 60) + 60*b'A' +
10311              struct.pack(">HH", EAP_TLV_CRYPTO_BINDING_TLV, 60) + 60*b'A',
10312              True),
10313             ("EAP-FAST: Too short Crypto-Binding TLV",
10314              struct.pack(">HHB", EAP_TLV_CRYPTO_BINDING_TLV, 1, 0xff),
10315              True),
10316             ("EAP-FAST: More than one Request-Action TLV in the message",
10317              struct.pack(">HHBBHHBB",
10318                          EAP_TLV_REQUEST_ACTION_TLV, 2, 0xff, 0xff,
10319                          EAP_TLV_REQUEST_ACTION_TLV, 2, 0xff, 0xff),
10320              True),
10321             ("EAP-FAST: Too short Request-Action TLV",
10322              struct.pack(">HHB", EAP_TLV_REQUEST_ACTION_TLV, 1, 0xff),
10323              True),
10324             ("EAP-FAST: More than one PAC TLV in the message",
10325              struct.pack(">HHBHHB",
10326                          EAP_TLV_PAC_TLV, 1, 0xff,
10327                          EAP_TLV_PAC_TLV, 1, 0xff),
10328              True),
10329             ("EAP-FAST: Too short EAP Payload TLV (Len=3)",
10330              struct.pack(">HH3B",
10331                          EAP_TLV_EAP_PAYLOAD_TLV, 3, 0, 0, 0),
10332              False),
10333             ("EAP-FAST: Too short Phase 2 request (Len=0)",
10334              struct.pack(">HHBBH",
10335                          EAP_TLV_EAP_PAYLOAD_TLV, 4,
10336                          EAP_CODE_REQUEST, 0, 0),
10337              False),
10338             ("EAP-FAST: EAP packet overflow in EAP Payload TLV",
10339              struct.pack(">HHBBH",
10340                          EAP_TLV_EAP_PAYLOAD_TLV, 4,
10341                          EAP_CODE_REQUEST, 0, 4 + 1),
10342              False),
10343             ("EAP-FAST: Unexpected code=0 in Phase 2 EAP header",
10344              struct.pack(">HHBBH",
10345                          EAP_TLV_EAP_PAYLOAD_TLV, 4,
10346                          0, 0, 0),
10347              False),
10348             ("EAP-FAST: PAC TLV without Result TLV acknowledging success",
10349              struct.pack(">HHB", EAP_TLV_PAC_TLV, 1, 0xff),
10350              True),
10351             ("EAP-FAST: PAC TLV does not include all the required fields",
10352              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10353                          EAP_TLV_RESULT_SUCCESS) +
10354              struct.pack(">HHB", EAP_TLV_PAC_TLV, 1, 0xff),
10355              True),
10356             ("EAP-FAST: Invalid PAC-Key length 0, Ignored unknown PAC type 0, and PAC TLV overrun (type=0 len=2 left=1)",
10357              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10358                          EAP_TLV_RESULT_SUCCESS) +
10359              struct.pack(">HHHHHHHHB", EAP_TLV_PAC_TLV, 4 + 4 + 5,
10360                          PAC_TYPE_PAC_KEY, 0, 0, 0, 0, 2, 0),
10361              True),
10362             ("EAP-FAST: PAC-Info does not include all the required fields",
10363              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10364                          EAP_TLV_RESULT_SUCCESS) +
10365              struct.pack(">HHHHHHHH", EAP_TLV_PAC_TLV, 4 + 4 + 4 + 32,
10366                          PAC_TYPE_PAC_OPAQUE, 0,
10367                          PAC_TYPE_PAC_INFO, 0,
10368                          PAC_TYPE_PAC_KEY, 32) + 32*b'A',
10369              True),
10370             ("EAP-FAST: Invalid CRED_LIFETIME length, Ignored unknown PAC-Info type 0, and Invalid PAC-Type length 1",
10371              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10372                          EAP_TLV_RESULT_SUCCESS) +
10373              struct.pack(">HHHHHHHHHHHHBHH", EAP_TLV_PAC_TLV, 4 + 4 + 13 + 4 + 32,
10374                          PAC_TYPE_PAC_OPAQUE, 0,
10375                          PAC_TYPE_PAC_INFO, 13, PAC_TYPE_CRED_LIFETIME, 0,
10376                          0, 0, PAC_TYPE_PAC_TYPE, 1, 0,
10377                          PAC_TYPE_PAC_KEY, 32) + 32*b'A',
10378              True),
10379             ("EAP-FAST: Unsupported PAC-Type 0",
10380              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10381                          EAP_TLV_RESULT_SUCCESS) +
10382              struct.pack(">HHHHHHHHHHH", EAP_TLV_PAC_TLV, 4 + 4 + 6 + 4 + 32,
10383                          PAC_TYPE_PAC_OPAQUE, 0,
10384                          PAC_TYPE_PAC_INFO, 6, PAC_TYPE_PAC_TYPE, 2, 0,
10385                          PAC_TYPE_PAC_KEY, 32) + 32*b'A',
10386              True),
10387             ("EAP-FAST: PAC-Info overrun (type=0 len=2 left=1)",
10388              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10389                          EAP_TLV_RESULT_SUCCESS) +
10390              struct.pack(">HHHHHHHHBHH", EAP_TLV_PAC_TLV, 4 + 4 + 5 + 4 + 32,
10391                          PAC_TYPE_PAC_OPAQUE, 0,
10392                          PAC_TYPE_PAC_INFO, 5, 0, 2, 1,
10393                          PAC_TYPE_PAC_KEY, 32) + 32*b'A',
10394              True),
10395             ("EAP-FAST: Valid PAC",
10396              struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
10397                          EAP_TLV_RESULT_SUCCESS) +
10398              struct.pack(">HHHHHHHHBHHBHH", EAP_TLV_PAC_TLV,
10399                          4 + 4 + 10 + 4 + 32,
10400                          PAC_TYPE_PAC_OPAQUE, 0,
10401                          PAC_TYPE_PAC_INFO, 10, PAC_TYPE_A_ID, 1, 0x41,
10402                          PAC_TYPE_A_ID_INFO, 1, 0x42,
10403                          PAC_TYPE_PAC_KEY, 32) + 32*b'A',
10404              True),
10405             ("EAP-FAST: Invalid version/subtype in Crypto-Binding TLV",
10406              struct.pack(">HH", EAP_TLV_CRYPTO_BINDING_TLV, 60) + 60*b'A',
10407              True)]
10408    for title, payload, failure in tests:
10409        logger.info("Phase 2 test: " + title)
10410        run_eap_fast_phase2(dev, payload, failure)
10411
10412def test_eap_fast_tlv_nak_oom(dev, apdev):
10413    """EAP-FAST Phase 2 TLV NAK OOM"""
10414    if not openssl_imported:
10415        raise HwsimSkip("OpenSSL python method not available")
10416    check_eap_capa(dev[0], "FAST")
10417    hapd = start_ap(apdev[0])
10418    dev[0].scan_for_bss(hapd.own_addr(), freq=2412)
10419
10420    with alloc_fail(dev[0], 1, "eap_fast_tlv_nak"):
10421        run_eap_fast_phase2(dev, struct.pack(">HHB", EAP_TLV_TYPE_MANDATORY,
10422                                             1, 0xff), False)
10423