]> git.ipfire.org Git - thirdparty/hostap.git/blob - tests/hwsim/test_eap_proto.py
tests: EAP-MD5 protocol tests
[thirdparty/hostap.git] / tests / hwsim / test_eap_proto.py
1 # EAP protocol tests
2 # Copyright (c) 2014, 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
7 import hmac
8 import logging
9 logger = logging.getLogger()
10 import select
11 import struct
12 import threading
13 import time
14
15 import hostapd
16
17 EAP_CODE_REQUEST = 1
18 EAP_CODE_RESPONSE = 2
19 EAP_CODE_SUCCESS = 3
20 EAP_CODE_FAILURE = 4
21
22 EAP_TYPE_IDENTITY = 1
23 EAP_TYPE_NOTIFICATION = 2
24 EAP_TYPE_NAK = 3
25 EAP_TYPE_MD5 = 4
26 EAP_TYPE_OTP = 5
27 EAP_TYPE_GTC = 6
28 EAP_TYPE_TLS = 13
29 EAP_TYPE_LEAP = 17
30 EAP_TYPE_SIM = 18
31 EAP_TYPE_TTLS = 21
32 EAP_TYPE_AKA = 23
33 EAP_TYPE_PEAP = 25
34 EAP_TYPE_MSCHAPV2 = 26
35 EAP_TYPE_TLV = 33
36 EAP_TYPE_TNC = 38
37 EAP_TYPE_FAST = 43
38 EAP_TYPE_PAX = 46
39 EAP_TYPE_PSK = 47
40 EAP_TYPE_SAKE = 48
41 EAP_TYPE_IKEV2 = 49
42 EAP_TYPE_AKA_PRIME = 50
43 EAP_TYPE_GPSK = 51
44 EAP_TYPE_PWD = 52
45 EAP_TYPE_EKE = 53
46
47 def run_pyrad_server(srv, t_stop, eap_handler):
48 srv.RunWithStop(t_stop, eap_handler)
49
50 def start_radius_server(eap_handler):
51 try:
52 import pyrad.server
53 import pyrad.packet
54 import pyrad.dictionary
55 except ImportError:
56 return None
57
58 class TestServer(pyrad.server.Server):
59 def _HandleAuthPacket(self, pkt):
60 pyrad.server.Server._HandleAuthPacket(self, pkt)
61 if len(pkt[79]) > 1:
62 logger.info("Multiple EAP-Message attributes")
63 # TODO: reassemble
64 eap = pkt[79][0]
65 eap_req = self.eap_handler(self.ctx, eap)
66 reply = self.CreateReplyPacket(pkt)
67 if eap_req:
68 if len(eap_req) > 253:
69 logger.info("Need to fragment EAP-Message")
70 # TODO: fragment
71 reply.AddAttribute("EAP-Message", eap_req)
72 else:
73 logger.info("No EAP request available")
74 reply.code = pyrad.packet.AccessChallenge
75
76 hmac_obj = hmac.new(reply.secret)
77 hmac_obj.update(struct.pack("B", reply.code))
78 hmac_obj.update(struct.pack("B", reply.id))
79
80 # reply attributes
81 reply.AddAttribute("Message-Authenticator",
82 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
83 attrs = reply._PktEncodeAttributes()
84
85 # Length
86 flen = 4 + 16 + len(attrs)
87 hmac_obj.update(struct.pack(">H", flen))
88 hmac_obj.update(pkt.authenticator)
89 hmac_obj.update(attrs)
90 del reply[80]
91 reply.AddAttribute("Message-Authenticator", hmac_obj.digest())
92
93 self.SendReplyPacket(pkt.fd, reply)
94
95 def RunWithStop(self, t_stop, eap_handler):
96 self._poll = select.poll()
97 self._fdmap = {}
98 self._PrepareSockets()
99 self.t_stop = t_stop
100 self.eap_handler = eap_handler
101 self.ctx = {}
102
103 while not t_stop.is_set():
104 for (fd, event) in self._poll.poll(1000):
105 if event == select.POLLIN:
106 try:
107 fdo = self._fdmap[fd]
108 self._ProcessInput(fdo)
109 except pyrad.server.ServerPacketError as err:
110 logger.info("pyrad server dropping packet: " + str(err))
111 except pyrad.packet.PacketError as err:
112 logger.info("pyrad server received invalid packet: " + str(err))
113 else:
114 logger.error("Unexpected event in pyrad server main loop")
115
116 srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"),
117 authport=18138, acctport=18139)
118 srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1",
119 "radius",
120 "localhost")
121 srv.BindToAddress("")
122 t_stop = threading.Event()
123 t = threading.Thread(target=run_pyrad_server, args=(srv, t_stop, eap_handler))
124 t.start()
125
126 return { 'srv': srv, 'stop': t_stop, 'thread': t }
127
128 def stop_radius_server(srv):
129 srv['stop'].set()
130 srv['thread'].join()
131
132 def start_ap(ifname):
133 params = hostapd.wpa2_eap_params(ssid="eap-test")
134 params['auth_server_port'] = "18138"
135 hapd = hostapd.add_ap(ifname, params)
136 return hapd
137
138 EAP_SAKE_VERSION = 2
139
140 EAP_SAKE_SUBTYPE_CHALLENGE = 1
141 EAP_SAKE_SUBTYPE_CONFIRM = 2
142 EAP_SAKE_SUBTYPE_AUTH_REJECT = 3
143 EAP_SAKE_SUBTYPE_IDENTITY = 4
144
145 EAP_SAKE_AT_RAND_S = 1
146 EAP_SAKE_AT_RAND_P = 2
147 EAP_SAKE_AT_MIC_S = 3
148 EAP_SAKE_AT_MIC_P = 4
149 EAP_SAKE_AT_SERVERID = 5
150 EAP_SAKE_AT_PEERID = 6
151 EAP_SAKE_AT_SPI_S = 7
152 EAP_SAKE_AT_SPI_P = 8
153 EAP_SAKE_AT_ANY_ID_REQ = 9
154 EAP_SAKE_AT_PERM_ID_REQ = 10
155 EAP_SAKE_AT_ENCR_DATA = 128
156 EAP_SAKE_AT_IV = 129
157 EAP_SAKE_AT_PADDING = 130
158 EAP_SAKE_AT_NEXT_TMPID = 131
159 EAP_SAKE_AT_MSK_LIFE = 132
160
161 def test_eap_proto_sake(dev, apdev):
162 """EAP-SAKE protocol tests"""
163 def sake_challenge(ctx):
164 logger.info("Test: Challenge subtype")
165 return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
166 4 + 1 + 3 + 18,
167 EAP_TYPE_SAKE,
168 EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE,
169 EAP_SAKE_AT_RAND_S, 18, 0, 0, 0, 0)
170
171 def sake_handler(ctx, req):
172 logger.info("sake_handler - RX " + req.encode("hex"))
173 if 'num' not in ctx:
174 ctx['num'] = 0
175 ctx['num'] = ctx['num'] + 1
176 if 'id' not in ctx:
177 ctx['id'] = 1
178 ctx['id'] = (ctx['id'] + 1) % 256
179
180 if ctx['num'] == 1:
181 logger.info("Test: Missing payload")
182 return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'], 4 + 1,
183 EAP_TYPE_SAKE)
184
185 if ctx['num'] == 2:
186 logger.info("Test: Identity subtype without any attributes")
187 return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
188 4 + 1 + 3,
189 EAP_TYPE_SAKE,
190 EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY)
191
192 if ctx['num'] == 3:
193 logger.info("Test: Identity subtype")
194 return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
195 4 + 1 + 3 + 4,
196 EAP_TYPE_SAKE,
197 EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
198 EAP_SAKE_AT_ANY_ID_REQ, 4, 0)
199 if ctx['num'] == 4:
200 logger.info("Test: Identity subtype (different session id)")
201 return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
202 4 + 1 + 3 + 4,
203 EAP_TYPE_SAKE,
204 EAP_SAKE_VERSION, 1, EAP_SAKE_SUBTYPE_IDENTITY,
205 EAP_SAKE_AT_PERM_ID_REQ, 4, 0)
206
207 if ctx['num'] == 5:
208 logger.info("Test: Identity subtype with too short attribute")
209 return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
210 4 + 1 + 3 + 2,
211 EAP_TYPE_SAKE,
212 EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
213 EAP_SAKE_AT_ANY_ID_REQ, 2)
214
215 if ctx['num'] == 6:
216 logger.info("Test: Identity subtype with truncated attribute")
217 return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
218 4 + 1 + 3 + 2,
219 EAP_TYPE_SAKE,
220 EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
221 EAP_SAKE_AT_ANY_ID_REQ, 4)
222
223 if ctx['num'] == 7:
224 logger.info("Test: Unknown subtype")
225 return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
226 4 + 1 + 3,
227 EAP_TYPE_SAKE,
228 EAP_SAKE_VERSION, 0, 123)
229
230 if ctx['num'] == 8:
231 logger.info("Test: Challenge subtype without any attributes")
232 return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
233 4 + 1 + 3,
234 EAP_TYPE_SAKE,
235 EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE)
236
237 if ctx['num'] == 9:
238 logger.info("Test: Challenge subtype with too short AT_RAND_S")
239 return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
240 4 + 1 + 3 + 2,
241 EAP_TYPE_SAKE,
242 EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE,
243 EAP_SAKE_AT_RAND_S, 2)
244
245 if ctx['num'] == 10:
246 return sake_challenge(ctx)
247 if ctx['num'] == 11:
248 logger.info("Test: Unexpected Identity subtype")
249 return struct.pack(">BBHBBBBBBH", EAP_CODE_REQUEST, ctx['id'],
250 4 + 1 + 3 + 4,
251 EAP_TYPE_SAKE,
252 EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_IDENTITY,
253 EAP_SAKE_AT_ANY_ID_REQ, 4, 0)
254
255 if ctx['num'] == 12:
256 return sake_challenge(ctx)
257 if ctx['num'] == 13:
258 logger.info("Test: Unexpected Challenge subtype")
259 return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
260 4 + 1 + 3 + 18,
261 EAP_TYPE_SAKE,
262 EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CHALLENGE,
263 EAP_SAKE_AT_RAND_S, 18, 0, 0, 0, 0)
264
265 if ctx['num'] == 14:
266 return sake_challenge(ctx)
267 if ctx['num'] == 15:
268 logger.info("Test: Confirm subtype without any attributes")
269 return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
270 4 + 1 + 3,
271 EAP_TYPE_SAKE,
272 EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM)
273
274 if ctx['num'] == 16:
275 return sake_challenge(ctx)
276 if ctx['num'] == 17:
277 logger.info("Test: Confirm subtype with too short AT_MIC_S")
278 return struct.pack(">BBHBBBBBB", EAP_CODE_REQUEST, ctx['id'],
279 4 + 1 + 3 + 2,
280 EAP_TYPE_SAKE,
281 EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM,
282 EAP_SAKE_AT_MIC_S, 2)
283
284 if ctx['num'] == 18:
285 logger.info("Test: Unexpected Confirm subtype")
286 return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
287 4 + 1 + 3 + 18,
288 EAP_TYPE_SAKE,
289 EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM,
290 EAP_SAKE_AT_MIC_S, 18, 0, 0, 0, 0)
291
292 if ctx['num'] == 19:
293 return sake_challenge(ctx)
294 if ctx['num'] == 20:
295 logger.info("Test: Confirm subtype with incorrect AT_MIC_S")
296 return struct.pack(">BBHBBBBBBLLLL", EAP_CODE_REQUEST, ctx['id'],
297 4 + 1 + 3 + 18,
298 EAP_TYPE_SAKE,
299 EAP_SAKE_VERSION, 0, EAP_SAKE_SUBTYPE_CONFIRM,
300 EAP_SAKE_AT_MIC_S, 18, 0, 0, 0, 0)
301
302 return sake_challenge(ctx)
303
304 srv = start_radius_server(sake_handler)
305 if srv is None:
306 return "skip"
307
308 try:
309 hapd = start_ap(apdev[0]['ifname'])
310
311 for i in range(0, 14):
312 dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
313 eap="SAKE", identity="sake user",
314 password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
315 wait_connect=False)
316 ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
317 if ev is None:
318 raise Exception("Timeout on EAP start")
319 time.sleep(0.1)
320 dev[0].request("REMOVE_NETWORK all")
321
322 logger.info("Too short password")
323 dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
324 eap="SAKE", identity="sake user",
325 password_hex="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd",
326 wait_connect=False)
327 ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
328 if ev is None:
329 raise Exception("Timeout on EAP start")
330 time.sleep(0.1)
331 finally:
332 stop_radius_server(srv)
333
334 def test_eap_proto_leap(dev, apdev):
335 """EAP-LEAP protocol tests"""
336 def leap_handler(ctx, req):
337 logger.info("leap_handler - RX " + req.encode("hex"))
338 if 'num' not in ctx:
339 ctx['num'] = 0
340 ctx['num'] = ctx['num'] + 1
341 if 'id' not in ctx:
342 ctx['id'] = 1
343 ctx['id'] = (ctx['id'] + 1) % 256
344
345 if ctx['num'] == 1:
346 logger.info("Test: Missing payload")
347 return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
348 4 + 1,
349 EAP_TYPE_LEAP)
350
351 if ctx['num'] == 2:
352 logger.info("Test: Unexpected version")
353 return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
354 4 + 1 + 3,
355 EAP_TYPE_LEAP,
356 0, 0, 0)
357
358 if ctx['num'] == 3:
359 logger.info("Test: Invalid challenge length")
360 return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
361 4 + 1 + 3,
362 EAP_TYPE_LEAP,
363 1, 0, 0)
364
365 if ctx['num'] == 4:
366 logger.info("Test: Truncated challenge")
367 return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
368 4 + 1 + 3,
369 EAP_TYPE_LEAP,
370 1, 0, 8)
371
372 if ctx['num'] == 5:
373 logger.info("Test: Valid challenge")
374 return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
375 4 + 1 + 3 + 8,
376 EAP_TYPE_LEAP,
377 1, 0, 8, 0, 0)
378 if ctx['num'] == 6:
379 logger.info("Test: Missing payload in Response")
380 return struct.pack(">BBHB", EAP_CODE_RESPONSE, ctx['id'],
381 4 + 1,
382 EAP_TYPE_LEAP)
383
384 if ctx['num'] == 7:
385 logger.info("Test: Valid challenge")
386 return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
387 4 + 1 + 3 + 8,
388 EAP_TYPE_LEAP,
389 1, 0, 8, 0, 0)
390 if ctx['num'] == 8:
391 logger.info("Test: Unexpected version in Response")
392 return struct.pack(">BBHBBBB", EAP_CODE_RESPONSE, ctx['id'],
393 4 + 1 + 3,
394 EAP_TYPE_LEAP,
395 0, 0, 8)
396
397 if ctx['num'] == 9:
398 logger.info("Test: Valid challenge")
399 return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
400 4 + 1 + 3 + 8,
401 EAP_TYPE_LEAP,
402 1, 0, 8, 0, 0)
403 if ctx['num'] == 10:
404 logger.info("Test: Invalid challenge length in Response")
405 return struct.pack(">BBHBBBB", EAP_CODE_RESPONSE, ctx['id'],
406 4 + 1 + 3,
407 EAP_TYPE_LEAP,
408 1, 0, 0)
409
410 if ctx['num'] == 11:
411 logger.info("Test: Valid challenge")
412 return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
413 4 + 1 + 3 + 8,
414 EAP_TYPE_LEAP,
415 1, 0, 8, 0, 0)
416 if ctx['num'] == 12:
417 logger.info("Test: Truncated challenge in Response")
418 return struct.pack(">BBHBBBB", EAP_CODE_RESPONSE, ctx['id'],
419 4 + 1 + 3,
420 EAP_TYPE_LEAP,
421 1, 0, 24)
422
423 if ctx['num'] == 13:
424 logger.info("Test: Valid challenge")
425 return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
426 4 + 1 + 3 + 8,
427 EAP_TYPE_LEAP,
428 1, 0, 8, 0, 0)
429 if ctx['num'] == 14:
430 logger.info("Test: Invalid challange value in Response")
431 return struct.pack(">BBHBBBB6L", EAP_CODE_RESPONSE, ctx['id'],
432 4 + 1 + 3 + 24,
433 EAP_TYPE_LEAP,
434 1, 0, 24,
435 0, 0, 0, 0, 0, 0)
436
437 if ctx['num'] == 15:
438 logger.info("Test: Valid challenge")
439 return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
440 4 + 1 + 3 + 8,
441 EAP_TYPE_LEAP,
442 1, 0, 8, 0, 0)
443 if ctx['num'] == 16:
444 logger.info("Test: Valid challange value in Response")
445 return struct.pack(">BBHBBBB24B", EAP_CODE_RESPONSE, ctx['id'],
446 4 + 1 + 3 + 24,
447 EAP_TYPE_LEAP,
448 1, 0, 24,
449 0x48, 0x4e, 0x46, 0xe3, 0x88, 0x49, 0x46, 0xbd,
450 0x28, 0x48, 0xf8, 0x53, 0x82, 0x50, 0x00, 0x04,
451 0x93, 0x50, 0x30, 0xd7, 0x25, 0xea, 0x5f, 0x66)
452
453 if ctx['num'] == 17:
454 logger.info("Test: Valid challenge")
455 return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
456 4 + 1 + 3 + 8,
457 EAP_TYPE_LEAP,
458 1, 0, 8, 0, 0)
459 if ctx['num'] == 18:
460 logger.info("Test: Success")
461 return struct.pack(">BBHB", EAP_CODE_SUCCESS, ctx['id'],
462 4 + 1,
463 EAP_TYPE_LEAP)
464 # hostapd will drop the next frame in the sequence
465
466 if ctx['num'] == 19:
467 logger.info("Test: Valid challenge")
468 return struct.pack(">BBHBBBBLL", EAP_CODE_REQUEST, ctx['id'],
469 4 + 1 + 3 + 8,
470 EAP_TYPE_LEAP,
471 1, 0, 8, 0, 0)
472 if ctx['num'] == 20:
473 logger.info("Test: Failure")
474 return struct.pack(">BBHB", EAP_CODE_FAILURE, ctx['id'],
475 4 + 1,
476 EAP_TYPE_LEAP)
477
478 return None
479
480 srv = start_radius_server(leap_handler)
481 if srv is None:
482 return "skip"
483
484 try:
485 hapd = start_ap(apdev[0]['ifname'])
486
487 for i in range(0, 12):
488 dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
489 eap="LEAP", identity="user", password="password",
490 wait_connect=False)
491 ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
492 if ev is None:
493 raise Exception("Timeout on EAP start")
494 time.sleep(0.1)
495 if i == 10:
496 logger.info("Wait for additional roundtrip")
497 time.sleep(1)
498 dev[0].request("REMOVE_NETWORK all")
499 finally:
500 stop_radius_server(srv)
501
502 def test_eap_proto_md5(dev, apdev):
503 """EAP-MD5 protocol tests"""
504 def md5_handler(ctx, req):
505 logger.info("md5_handler - RX " + req.encode("hex"))
506 if 'num' not in ctx:
507 ctx['num'] = 0
508 ctx['num'] = ctx['num'] + 1
509 if 'id' not in ctx:
510 ctx['id'] = 1
511 ctx['id'] = (ctx['id'] + 1) % 256
512
513 if ctx['num'] == 1:
514 logger.info("Test: Missing payload")
515 return struct.pack(">BBHB", EAP_CODE_REQUEST, ctx['id'],
516 4 + 1,
517 EAP_TYPE_MD5)
518
519 if ctx['num'] == 2:
520 logger.info("Test: Zero-length challenge")
521 return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
522 4 + 1 + 1,
523 EAP_TYPE_MD5,
524 0)
525
526 if ctx['num'] == 3:
527 logger.info("Test: Truncated challenge")
528 return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
529 4 + 1 + 1,
530 EAP_TYPE_MD5,
531 1)
532
533 if ctx['num'] == 4:
534 logger.info("Test: Shortest possible challenge and name")
535 return struct.pack(">BBHBBBB", EAP_CODE_REQUEST, ctx['id'],
536 4 + 1 + 3,
537 EAP_TYPE_MD5,
538 1, 0xaa, ord('n'))
539
540 return None
541
542 srv = start_radius_server(md5_handler)
543 if srv is None:
544 return "skip"
545
546 try:
547 hapd = start_ap(apdev[0]['ifname'])
548
549 for i in range(0, 4):
550 dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
551 eap="MD5", identity="user", password="password",
552 wait_connect=False)
553 ev = dev[0].wait_event(["CTRL-EVENT-EAP-PROPOSED-METHOD"], timeout=15)
554 if ev is None:
555 raise Exception("Timeout on EAP start")
556 time.sleep(0.1)
557 dev[0].request("REMOVE_NETWORK all")
558 finally:
559 stop_radius_server(srv)