1# WPA2-Enterprise PMKSA caching tests
2# Copyright (c) 2013-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
7import binascii
8import logging
9logger = logging.getLogger()
10import socket
11import struct
12import subprocess
13import time
14
15import hostapd
16import hwsim_utils
17from wpasupplicant import WpaSupplicant
18from utils import alloc_fail, HwsimSkip, wait_fail_trigger
19from test_ap_eap import eap_connect
20
21def test_pmksa_cache_on_roam_back(dev, apdev):
22    """PMKSA cache to skip EAP on reassociation back to same AP"""
23    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
24    hostapd.add_ap(apdev[0], params)
25    bssid = apdev[0]['bssid']
26    dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
27                   eap="GPSK", identity="gpsk user",
28                   password="abcdefghijklmnop0123456789abcdef",
29                   scan_freq="2412")
30    pmksa = dev[0].get_pmksa(bssid)
31    if pmksa is None:
32        raise Exception("No PMKSA cache entry created")
33    if pmksa['opportunistic'] != '0':
34        raise Exception("Unexpected opportunistic PMKSA cache entry")
35
36    hostapd.add_ap(apdev[1], params)
37    bssid2 = apdev[1]['bssid']
38
39    dev[0].dump_monitor()
40    logger.info("Roam to AP2")
41    # It can take some time for the second AP to become ready to reply to Probe
42    # Request frames especially under heavy CPU load, so allow couple of rounds
43    # of scanning to avoid reporting errors incorrectly just because of scans
44    # not having seen the target AP.
45    for i in range(0, 10):
46        dev[0].scan(freq="2412")
47        if dev[0].get_bss(bssid2) is not None:
48            break
49        logger.info("Scan again to find target AP")
50    dev[0].request("ROAM " + bssid2)
51    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
52    if ev is None:
53        raise Exception("EAP success timed out")
54    dev[0].wait_connected(timeout=10, error="Roaming timed out")
55    pmksa2 = dev[0].get_pmksa(bssid2)
56    if pmksa2 is None:
57        raise Exception("No PMKSA cache entry found")
58    if pmksa2['opportunistic'] != '0':
59        raise Exception("Unexpected opportunistic PMKSA cache entry")
60
61    dev[0].dump_monitor()
62    logger.info("Roam back to AP1")
63    dev[0].scan(freq="2412")
64    dev[0].request("ROAM " + bssid)
65    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
66                            "CTRL-EVENT-CONNECTED"], timeout=10)
67    if ev is None:
68        raise Exception("Roaming with the AP timed out")
69    if "CTRL-EVENT-EAP-STARTED" in ev:
70        raise Exception("Unexpected EAP exchange")
71    pmksa1b = dev[0].get_pmksa(bssid)
72    if pmksa1b is None:
73        raise Exception("No PMKSA cache entry found")
74    if pmksa['pmkid'] != pmksa1b['pmkid']:
75        raise Exception("Unexpected PMKID change for AP1")
76
77    dev[0].dump_monitor()
78    if "FAIL" in dev[0].request("PMKSA_FLUSH"):
79        raise Exception("PMKSA_FLUSH failed")
80    if dev[0].get_pmksa(bssid) is not None or dev[0].get_pmksa(bssid2) is not None:
81        raise Exception("PMKSA_FLUSH did not remove PMKSA entries")
82    dev[0].wait_disconnected(timeout=5)
83    dev[0].wait_connected(timeout=15, error="Reconnection timed out")
84
85def test_pmksa_cache_and_reauth(dev, apdev):
86    """PMKSA caching and EAPOL reauthentication"""
87    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
88    hapd = hostapd.add_ap(apdev[0], params)
89    bssid = apdev[0]['bssid']
90    dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
91                   eap="GPSK", identity="gpsk user",
92                   password="abcdefghijklmnop0123456789abcdef",
93                   scan_freq="2412")
94
95    hostapd.add_ap(apdev[1], params)
96    bssid2 = apdev[1]['bssid']
97
98    dev[0].dump_monitor()
99    logger.info("Roam to AP2")
100    # It can take some time for the second AP to become ready to reply to Probe
101    # Request frames especially under heavy CPU load, so allow couple of rounds
102    # of scanning to avoid reporting errors incorrectly just because of scans
103    # not having seen the target AP.
104    for i in range(0, 10):
105        dev[0].scan(freq="2412")
106        if dev[0].get_bss(bssid2) is not None:
107            break
108        logger.info("Scan again to find target AP")
109    dev[0].request("ROAM " + bssid2)
110    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
111    if ev is None:
112        raise Exception("EAP success timed out")
113    dev[0].wait_connected(timeout=10, error="Roaming timed out")
114
115    dev[0].dump_monitor()
116    logger.info("Roam back to AP1")
117    dev[0].scan(freq="2412")
118    dev[0].request("ROAM " + bssid)
119    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
120                            "CTRL-EVENT-CONNECTED"], timeout=10)
121    if ev is None:
122        raise Exception("Roaming with the AP timed out")
123    if "CTRL-EVENT-EAP-STARTED" in ev:
124        raise Exception("Unexpected EAP exchange")
125
126    # Verify EAPOL reauthentication after PMKSA caching
127    hapd.request("EAPOL_REAUTH " + dev[0].own_addr())
128    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=5)
129    if ev is None:
130        raise Exception("EAP authentication did not start")
131    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=5)
132    if ev is None:
133        raise Exception("EAP authentication did not succeed")
134
135def test_pmksa_cache_and_ptk_rekey_ap(dev, apdev):
136    """PMKSA caching and PTK rekey triggered by AP"""
137    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
138    params['wpa_ptk_rekey'] = '2'
139    hapd = hostapd.add_ap(apdev[0], params)
140    bssid = apdev[0]['bssid']
141    dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
142                   eap="GPSK", identity="gpsk user",
143                   password="abcdefghijklmnop0123456789abcdef",
144                   scan_freq="2412")
145
146    hostapd.add_ap(apdev[1], params)
147    bssid2 = apdev[1]['bssid']
148
149    dev[0].dump_monitor()
150    logger.info("Roam to AP2")
151    # It can take some time for the second AP to become ready to reply to Probe
152    # Request frames especially under heavy CPU load, so allow couple of rounds
153    # of scanning to avoid reporting errors incorrectly just because of scans
154    # not having seen the target AP.
155    for i in range(0, 10):
156        dev[0].scan(freq="2412")
157        if dev[0].get_bss(bssid2) is not None:
158            break
159        logger.info("Scan again to find target AP")
160    dev[0].request("ROAM " + bssid2)
161    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
162    if ev is None:
163        raise Exception("EAP success timed out")
164    dev[0].wait_connected(timeout=10, error="Roaming timed out")
165
166    dev[0].dump_monitor()
167    logger.info("Roam back to AP1")
168    dev[0].scan(freq="2412")
169    dev[0].request("ROAM " + bssid)
170    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
171                            "CTRL-EVENT-CONNECTED"], timeout=10)
172    if ev is None:
173        raise Exception("Roaming with the AP timed out")
174    if "CTRL-EVENT-EAP-STARTED" in ev:
175        raise Exception("Unexpected EAP exchange")
176
177    # Verify PTK rekeying after PMKSA caching
178    ev = dev[0].wait_event(["WPA: Key negotiation completed"], timeout=3)
179    if ev is None:
180        raise Exception("PTK rekey timed out")
181
182def test_pmksa_cache_opportunistic_only_on_sta(dev, apdev):
183    """Opportunistic PMKSA caching enabled only on station"""
184    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
185    hostapd.add_ap(apdev[0], params)
186    bssid = apdev[0]['bssid']
187    dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
188                   eap="GPSK", identity="gpsk user",
189                   password="abcdefghijklmnop0123456789abcdef", okc=True,
190                   scan_freq="2412")
191    pmksa = dev[0].get_pmksa(bssid)
192    if pmksa is None:
193        raise Exception("No PMKSA cache entry created")
194    if pmksa['opportunistic'] != '0':
195        raise Exception("Unexpected opportunistic PMKSA cache entry")
196
197    hostapd.add_ap(apdev[1], params)
198    bssid2 = apdev[1]['bssid']
199
200    dev[0].dump_monitor()
201    logger.info("Roam to AP2")
202    dev[0].scan(freq="2412")
203    dev[0].request("ROAM " + bssid2)
204    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
205    if ev is None:
206        raise Exception("EAP success timed out")
207    dev[0].wait_connected(timeout=10, error="Roaming timed out")
208    pmksa2 = dev[0].get_pmksa(bssid2)
209    if pmksa2 is None:
210        raise Exception("No PMKSA cache entry found")
211    if pmksa2['opportunistic'] != '0':
212        raise Exception("Unexpected opportunistic PMKSA cache entry")
213
214    dev[0].dump_monitor()
215    logger.info("Roam back to AP1")
216    dev[0].scan(freq="2412")
217    dev[0].request("ROAM " + bssid)
218    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
219                            "CTRL-EVENT-CONNECTED"], timeout=10)
220    if ev is None:
221        raise Exception("Roaming with the AP timed out")
222    if "CTRL-EVENT-EAP-STARTED" in ev:
223        raise Exception("Unexpected EAP exchange")
224    pmksa1b = dev[0].get_pmksa(bssid)
225    if pmksa1b is None:
226        raise Exception("No PMKSA cache entry found")
227    if pmksa['pmkid'] != pmksa1b['pmkid']:
228        raise Exception("Unexpected PMKID change for AP1")
229
230def test_pmksa_cache_opportunistic(dev, apdev):
231    """Opportunistic PMKSA caching"""
232    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
233    params['okc'] = "1"
234    hostapd.add_ap(apdev[0], params)
235    bssid = apdev[0]['bssid']
236    dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
237                   eap="GPSK", identity="gpsk user",
238                   password="abcdefghijklmnop0123456789abcdef", okc=True,
239                   scan_freq="2412")
240    pmksa = dev[0].get_pmksa(bssid)
241    if pmksa is None:
242        raise Exception("No PMKSA cache entry created")
243    if pmksa['opportunistic'] != '0':
244        raise Exception("Unexpected opportunistic PMKSA cache entry")
245
246    hostapd.add_ap(apdev[1], params)
247    bssid2 = apdev[1]['bssid']
248
249    dev[0].dump_monitor()
250    logger.info("Roam to AP2")
251    dev[0].scan(freq="2412")
252    dev[0].request("ROAM " + bssid2)
253    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
254                            "CTRL-EVENT-CONNECTED"], timeout=10)
255    if ev is None:
256        raise Exception("Roaming with the AP timed out")
257    if "CTRL-EVENT-EAP-STARTED" in ev:
258        raise Exception("Unexpected EAP exchange")
259    pmksa2 = dev[0].get_pmksa(bssid2)
260    if pmksa2 is None:
261        raise Exception("No PMKSA cache entry created")
262
263    dev[0].dump_monitor()
264    logger.info("Roam back to AP1")
265    dev[0].scan(freq="2412")
266    dev[0].request("ROAM " + bssid)
267    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
268                            "CTRL-EVENT-CONNECTED"], timeout=10)
269    if ev is None:
270        raise Exception("Roaming with the AP timed out")
271    if "CTRL-EVENT-EAP-STARTED" in ev:
272        raise Exception("Unexpected EAP exchange")
273
274    pmksa1b = dev[0].get_pmksa(bssid)
275    if pmksa1b is None:
276        raise Exception("No PMKSA cache entry found")
277    if pmksa['pmkid'] != pmksa1b['pmkid']:
278        raise Exception("Unexpected PMKID change for AP1")
279
280def test_pmksa_cache_opportunistic_connect(dev, apdev):
281    """Opportunistic PMKSA caching with connect API"""
282    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
283    params['okc'] = "1"
284    hostapd.add_ap(apdev[0], params)
285    bssid = apdev[0]['bssid']
286    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
287    wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
288    wpas.connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
289                 eap="GPSK", identity="gpsk user",
290                 password="abcdefghijklmnop0123456789abcdef", okc=True,
291                 scan_freq="2412")
292    pmksa = wpas.get_pmksa(bssid)
293    if pmksa is None:
294        raise Exception("No PMKSA cache entry created")
295    if pmksa['opportunistic'] != '0':
296        raise Exception("Unexpected opportunistic PMKSA cache entry")
297
298    hostapd.add_ap(apdev[1], params)
299    bssid2 = apdev[1]['bssid']
300
301    wpas.dump_monitor()
302    logger.info("Roam to AP2")
303    wpas.scan_for_bss(bssid2, freq="2412", force_scan=True)
304    wpas.request("ROAM " + bssid2)
305    ev = wpas.wait_event(["CTRL-EVENT-EAP-STARTED",
306                            "CTRL-EVENT-CONNECTED"], timeout=10)
307    if ev is None:
308        raise Exception("Roaming with the AP timed out")
309    if "CTRL-EVENT-EAP-STARTED" in ev:
310        raise Exception("Unexpected EAP exchange")
311    pmksa2 = wpas.get_pmksa(bssid2)
312    if pmksa2 is None:
313        raise Exception("No PMKSA cache entry created")
314
315    wpas.dump_monitor()
316    logger.info("Roam back to AP1")
317    wpas.scan(freq="2412")
318    wpas.request("ROAM " + bssid)
319    ev = wpas.wait_event(["CTRL-EVENT-EAP-STARTED",
320                            "CTRL-EVENT-CONNECTED"], timeout=10)
321    if ev is None:
322        raise Exception("Roaming with the AP timed out")
323    if "CTRL-EVENT-EAP-STARTED" in ev:
324        raise Exception("Unexpected EAP exchange")
325
326    pmksa1b = wpas.get_pmksa(bssid)
327    if pmksa1b is None:
328        raise Exception("No PMKSA cache entry found")
329    if pmksa['pmkid'] != pmksa1b['pmkid']:
330        raise Exception("Unexpected PMKID change for AP1")
331
332def test_pmksa_cache_expiration(dev, apdev):
333    """PMKSA cache entry expiration"""
334    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
335    hapd = hostapd.add_ap(apdev[0], params)
336    bssid = apdev[0]['bssid']
337    dev[0].request("SET dot11RSNAConfigPMKLifetime 10")
338    dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
339                   eap="GPSK", identity="gpsk user",
340                   password="abcdefghijklmnop0123456789abcdef",
341                   scan_freq="2412")
342    hapd.wait_sta()
343    pmksa = dev[0].get_pmksa(bssid)
344    if pmksa is None:
345        raise Exception("No PMKSA cache entry created")
346    logger.info("Wait for PMKSA cache entry to expire")
347    ev = dev[0].wait_event(["WPA: Key negotiation completed",
348                            "CTRL-EVENT-DISCONNECTED"], timeout=15)
349    if ev is None:
350        raise Exception("No EAP reauthentication seen")
351    if "CTRL-EVENT-DISCONNECTED" in ev:
352        raise Exception("Unexpected disconnection")
353    pmksa2 = dev[0].get_pmksa(bssid)
354    if pmksa['pmkid'] == pmksa2['pmkid']:
355        raise Exception("PMKID did not change")
356    hapd.wait_ptkinitdone(dev[0].own_addr())
357    hwsim_utils.test_connectivity(dev[0], hapd)
358
359def test_pmksa_cache_expiration_disconnect(dev, apdev):
360    """PMKSA cache entry expiration (disconnect)"""
361    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
362    hapd = hostapd.add_ap(apdev[0], params)
363    bssid = apdev[0]['bssid']
364    dev[0].request("SET dot11RSNAConfigPMKLifetime 2")
365    dev[0].request("SET dot11RSNAConfigPMKReauthThreshold 100")
366    dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
367                   eap="GPSK", identity="gpsk user",
368                   password="abcdefghijklmnop0123456789abcdef",
369                   scan_freq="2412")
370    pmksa = dev[0].get_pmksa(bssid)
371    if pmksa is None:
372        raise Exception("No PMKSA cache entry created")
373    hapd.request("SET auth_server_shared_secret incorrect")
374    logger.info("Wait for PMKSA cache entry to expire")
375    ev = dev[0].wait_event(["WPA: Key negotiation completed",
376                            "CTRL-EVENT-DISCONNECTED"], timeout=15)
377    if ev is None:
378        raise Exception("No EAP reauthentication seen")
379    if "CTRL-EVENT-DISCONNECTED" not in ev:
380        raise Exception("Missing disconnection")
381    hapd.request("SET auth_server_shared_secret radius")
382    ev = dev[0].wait_event(["WPA: Key negotiation completed"], timeout=15)
383    if ev is None:
384        raise Exception("No EAP reauthentication seen")
385    pmksa2 = dev[0].get_pmksa(bssid)
386    if pmksa['pmkid'] == pmksa2['pmkid']:
387        raise Exception("PMKID did not change")
388
389def test_pmksa_cache_and_cui(dev, apdev):
390    """PMKSA cache and Chargeable-User-Identity"""
391    params = hostapd.wpa2_eap_params(ssid="cui")
392    params['radius_request_cui'] = '1'
393    params['acct_server_addr'] = "127.0.0.1"
394    params['acct_server_port'] = "1813"
395    params['acct_server_shared_secret'] = "radius"
396    hapd = hostapd.add_ap(apdev[0], params)
397    bssid = apdev[0]['bssid']
398    dev[0].connect("cui", proto="RSN", key_mgmt="WPA-EAP",
399                   eap="GPSK", identity="gpsk-cui",
400                   password="abcdefghijklmnop0123456789abcdef",
401                   scan_freq="2412")
402    pmksa = dev[0].get_pmksa(bssid)
403    if pmksa is None:
404        raise Exception("No PMKSA cache entry created")
405    ev = hapd.wait_event(["AP-STA-CONNECTED"], timeout=5)
406    if ev is None:
407        raise Exception("No connection event received from hostapd")
408
409    dev[0].dump_monitor()
410    logger.info("Disconnect and reconnect to the same AP")
411    dev[0].request("DISCONNECT")
412    dev[0].wait_disconnected()
413    dev[0].request("RECONNECT")
414    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
415                            "CTRL-EVENT-CONNECTED"], timeout=10)
416    if ev is None:
417        raise Exception("Reconnect timed out")
418    if "CTRL-EVENT-EAP-STARTED" in ev:
419        raise Exception("Unexpected EAP exchange")
420    pmksa1b = dev[0].get_pmksa(bssid)
421    if pmksa1b is None:
422        raise Exception("No PMKSA cache entry found")
423    if pmksa['pmkid'] != pmksa1b['pmkid']:
424        raise Exception("Unexpected PMKID change for AP1")
425    hapd.wait_sta()
426
427    dev[0].request("REAUTHENTICATE")
428    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
429    if ev is None:
430        raise Exception("EAP success timed out")
431    for i in range(0, 20):
432        state = dev[0].get_status_field("wpa_state")
433        if state == "COMPLETED":
434            break
435        time.sleep(0.1)
436    if state != "COMPLETED":
437        raise Exception("Reauthentication did not complete")
438
439def test_pmksa_cache_preauth_auto(dev, apdev):
440    """RSN pre-authentication based on pre-connection scan results"""
441    try:
442        run_pmksa_cache_preauth_auto(dev, apdev)
443    finally:
444        hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev',
445                                       'ap-br0', 'down', '2>', '/dev/null'],
446                            shell=True)
447        hostapd.cmd_execute(apdev[0], ['brctl', 'delbr', 'ap-br0',
448                                       '2>', '/dev/null'], shell=True)
449
450def run_pmksa_cache_preauth_auto(dev, apdev):
451    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
452    params['bridge'] = 'ap-br0'
453    params['rsn_preauth'] = '1'
454    params['rsn_preauth_interfaces'] = 'ap-br0'
455
456    hapd = hostapd.add_ap(apdev[0], params)
457    hapd.cmd_execute(['brctl', 'setfd', 'ap-br0', '0'])
458    hapd.cmd_execute(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
459    hapd2 = hostapd.add_ap(apdev[1], params)
460
461    eap_connect(dev[0], None, "PAX", "pax.user@example.com",
462                password_hex="0123456789abcdef0123456789abcdef")
463
464    found = False
465    for i in range(20):
466        time.sleep(0.5)
467        res1 = dev[0].get_pmksa(apdev[0]['bssid'])
468        res2 = dev[0].get_pmksa(apdev[1]['bssid'])
469        if res1 and res2:
470            found = True
471            break
472    if not found:
473        raise Exception("The expected PMKSA cache entries not found")
474
475def generic_pmksa_cache_preauth(dev, apdev, extraparams, identity, databridge,
476                                force_disconnect=False):
477    if not extraparams:
478        extraparams = [{}, {}]
479    try:
480        params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
481        params['bridge'] = 'ap-br0'
482        for key, value in extraparams[0].items():
483            params[key] = value
484
485        hapd = hostapd.add_ap(apdev[0], params)
486        hapd.cmd_execute(['brctl', 'setfd', 'ap-br0', '0'])
487        hapd.cmd_execute(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
488        eap_connect(dev[0], hapd, "PAX", identity,
489                    password_hex="0123456789abcdef0123456789abcdef")
490
491        # Verify connectivity in the correct VLAN
492        hwsim_utils.test_connectivity_iface(dev[0], hapd, databridge)
493
494        params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
495        params['bridge'] = 'ap-br0'
496        params['rsn_preauth'] = '1'
497        params['rsn_preauth_interfaces'] = databridge
498        for key, value in extraparams[1].items():
499            params[key] = value
500        hapd1 = hostapd.add_ap(apdev[1], params)
501        bssid1 = apdev[1]['bssid']
502        if dev[0].get_pmksa(bssid1):
503            raise Exception("Unexpected PMKSA entry for AP before pre-auth")
504        dev[0].scan(freq="2412")
505        success = False
506        status_seen = False
507        for i in range(0, 500):
508            if not status_seen:
509                status = dev[0].request("STATUS")
510                if "Pre-authentication EAPOL state machines:" in status:
511                    status_seen = True
512            time.sleep(0.01)
513            pmksa = dev[0].get_pmksa(bssid1)
514            if pmksa:
515                success = True
516                break
517        if not success:
518            raise Exception("No PMKSA cache entry created from pre-authentication")
519        if not status_seen:
520            # This might not be seen due to a race condition.
521            logger.info("Pre-authentication EAPOL status was not available")
522
523        dev[0].scan(freq="2412")
524        if "[WPA2-EAP-CCMP-preauth]" not in dev[0].request("SCAN_RESULTS"):
525            raise Exception("Scan results missing RSN element info")
526        dev[0].request("ROAM " + bssid1)
527        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
528                                "CTRL-EVENT-CONNECTED"], timeout=10)
529        if ev is None:
530            raise Exception("Roaming with the AP timed out")
531        if "CTRL-EVENT-EAP-STARTED" in ev:
532            raise Exception("Unexpected EAP exchange")
533        pmksa2 = dev[0].get_pmksa(bssid1)
534        if pmksa2 is None:
535            raise Exception("No PMKSA cache entry")
536        if pmksa['pmkid'] != pmksa2['pmkid']:
537            raise Exception("Unexpected PMKID change")
538
539        hapd1.wait_sta()
540        # Verify connectivity in the correct VLAN
541        hwsim_utils.test_connectivity_iface(dev[0], hapd, databridge)
542
543        if not force_disconnect:
544            return
545
546        # Disconnect the STA from both APs to avoid forceful ifdown by the
547        # test script on a VLAN that this has an associated STA. That used to
548        # trigger a mac80211 warning.
549        dev[0].request("DISCONNECT")
550        hapd.request("DISABLE")
551
552    finally:
553        hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev',
554                                       'ap-br0', 'down', '2>', '/dev/null'],
555                            shell=True)
556        hostapd.cmd_execute(apdev[0], ['brctl', 'delbr', 'ap-br0',
557                                       '2>', '/dev/null'], shell=True)
558
559def test_pmksa_cache_preauth(dev, apdev):
560    """RSN pre-authentication to generate PMKSA cache entry"""
561    generic_pmksa_cache_preauth(dev, apdev, None,
562                                "pax.user@example.com", "ap-br0")
563
564def test_pmksa_cache_preauth_per_sta_vif(dev, apdev):
565    """RSN pre-authentication to generate PMKSA cache entry with per_sta_vif"""
566    extraparams = [{}, {}]
567    extraparams[0]['per_sta_vif'] = "1"
568    extraparams[1]['per_sta_vif'] = "1"
569    generic_pmksa_cache_preauth(dev, apdev, extraparams,
570                                "pax.user@example.com", "ap-br0")
571
572def test_pmksa_cache_preauth_vlan_enabled(dev, apdev):
573    """RSN pre-authentication to generate PMKSA cache entry (dynamic_vlan optional but station without VLAN set)"""
574    extraparams = [{}, {}]
575    extraparams[0]['dynamic_vlan'] = '1'
576    extraparams[1]['dynamic_vlan'] = '1'
577    generic_pmksa_cache_preauth(dev, apdev, extraparams,
578                                "pax.user@example.com", "ap-br0")
579
580def test_pmksa_cache_preauth_vlan_enabled_per_sta_vif(dev, apdev):
581    """RSN pre-authentication to generate PMKSA cache entry (dynamic_vlan optional but station without VLAN set, with per_sta_vif enabled)"""
582    extraparams = [{}, {}]
583    extraparams[0]['per_sta_vif'] = "1"
584    extraparams[1]['per_sta_vif'] = "1"
585    extraparams[0]['dynamic_vlan'] = '1'
586    extraparams[1]['dynamic_vlan'] = '1'
587    generic_pmksa_cache_preauth(dev, apdev, extraparams,
588                                "pax.user@example.com", "ap-br0")
589
590def test_pmksa_cache_preauth_vlan_used(dev, apdev):
591    """RSN pre-authentication to generate PMKSA cache entry (station with VLAN set)"""
592    run_pmksa_cache_preauth_vlan_used(dev, apdev, None, force_disconnect=True)
593
594def run_pmksa_cache_preauth_vlan_used(dev, apdev, extraparams=None,
595                                      force_disconnect=False):
596    try:
597        subprocess.call(['brctl', 'addbr', 'brvlan1'])
598        subprocess.call(['brctl', 'setfd', 'brvlan1', '0'])
599        if not extraparams:
600            extraparams = [{}, {}]
601        extraparams[0]['dynamic_vlan'] = '1'
602        extraparams[0]['vlan_file'] = 'hostapd.wlan3.vlan'
603        extraparams[1]['dynamic_vlan'] = '1'
604        extraparams[1]['vlan_file'] = 'hostapd.wlan4.vlan'
605        generic_pmksa_cache_preauth(dev, apdev, extraparams,
606                                    "vlan1", "brvlan1",
607                                    force_disconnect=force_disconnect)
608    finally:
609        subprocess.call(['ip', 'link', 'set', 'dev', 'brvlan1', 'down'])
610        subprocess.call(['ip', 'link', 'set', 'dev', 'wlan3.1', 'down'],
611                        stderr=open('/dev/null', 'w'))
612        subprocess.call(['ip', 'link', 'set', 'dev', 'wlan4.1', 'down'],
613                        stderr=open('/dev/null', 'w'))
614        subprocess.call(['brctl', 'delif', 'brvlan1', 'wlan3.1'],
615                        stderr=open('/dev/null', 'w'))
616        subprocess.call(['brctl', 'delif', 'brvlan1', 'wlan4.1'],
617                        stderr=open('/dev/null', 'w'))
618        subprocess.call(['brctl', 'delbr', 'brvlan1'])
619
620def test_pmksa_cache_preauth_vlan_used_per_sta_vif(dev, apdev):
621    """RSN pre-authentication to generate PMKSA cache entry (station with VLAN set, per_sta_vif=1)"""
622    extraparams = [{}, {}]
623    extraparams[0]['per_sta_vif'] = "1"
624    extraparams[1]['per_sta_vif'] = "1"
625    run_pmksa_cache_preauth_vlan_used(dev, apdev, extraparams)
626
627def test_pmksa_cache_disabled(dev, apdev):
628    """PMKSA cache disabling on AP"""
629    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
630    params['disable_pmksa_caching'] = '1'
631    hostapd.add_ap(apdev[0], params)
632    bssid = apdev[0]['bssid']
633    dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
634                   eap="GPSK", identity="gpsk user",
635                   password="abcdefghijklmnop0123456789abcdef",
636                   scan_freq="2412")
637
638    hostapd.add_ap(apdev[1], params)
639    bssid2 = apdev[1]['bssid']
640
641    dev[0].dump_monitor()
642    logger.info("Roam to AP2")
643    dev[0].scan_for_bss(bssid2, freq="2412")
644    dev[0].request("ROAM " + bssid2)
645    ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
646    if ev is None:
647        raise Exception("EAP success timed out")
648    dev[0].wait_connected(timeout=10, error="Roaming timed out")
649
650    dev[0].dump_monitor()
651    logger.info("Roam back to AP1")
652    dev[0].scan(freq="2412")
653    dev[0].request("ROAM " + bssid)
654    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
655                            "CTRL-EVENT-CONNECTED"], timeout=20)
656    if ev is None:
657        raise Exception("Roaming with the AP timed out")
658    if "CTRL-EVENT-CONNECTED" in ev:
659        raise Exception("EAP exchange missing")
660    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=20)
661    if ev is None:
662        raise Exception("Roaming with the AP timed out")
663
664def test_pmksa_cache_ap_expiration(dev, apdev):
665    """PMKSA cache entry expiring on AP"""
666    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
667    hapd = hostapd.add_ap(apdev[0], params)
668    bssid = apdev[0]['bssid']
669
670    dev[0].cmd_execute(['iw', 'dev', dev[0].ifname,
671                        'set', 'power_save', 'off'])
672    dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
673                   eap="GPSK", identity="gpsk-user-session-timeout",
674                   password="abcdefghijklmnop0123456789abcdef",
675                   scan_freq="2412")
676    ev = hapd.wait_event(["AP-STA-CONNECTED"], timeout=5)
677    if ev is None:
678        raise Exception("No connection event received from hostapd")
679    hapd.dump_monitor()
680
681    dev[0].request("DISCONNECT")
682    ev = hapd.wait_event(["AP-STA-DISCONNECTED"], timeout=5)
683    if ev is None:
684        raise Exception("No disconnection event received from hostapd")
685    dev[0].wait_disconnected()
686
687    # Wait for session timeout to remove PMKSA cache entry
688    time.sleep(5)
689    dev[0].dump_monitor()
690    hapd.dump_monitor()
691
692    dev[0].request("RECONNECT")
693    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
694                            "CTRL-EVENT-CONNECTED"], timeout=20)
695    if ev is None:
696        raise Exception("Reconnection with the AP timed out")
697    if "CTRL-EVENT-CONNECTED" in ev:
698        raise Exception("EAP exchange missing")
699    dev[0].wait_connected(timeout=20, error="Reconnect timed out")
700    dev[0].dump_monitor()
701    ev = hapd.wait_event(["AP-STA-CONNECTED"], timeout=5)
702    if ev is None:
703        raise Exception("No connection event received from hostapd [2]")
704    hapd.dump_monitor()
705
706    # Wait for session timeout
707    ev = hapd.wait_event(["AP-STA-DISCONNECTED"], timeout=10)
708    if ev is None:
709        raise Exception("No disconnection event received from hostapd [2]")
710    dev[0].wait_disconnected(timeout=20)
711    dev[0].wait_connected(timeout=20, error="Reassociation timed out")
712    ev = hapd.wait_event(["AP-STA-CONNECTED"], timeout=5)
713    if ev is None:
714        raise Exception("No connection event received from hostapd [3]")
715    hapd.dump_monitor()
716    dev[0].dump_monitor()
717
718def test_pmksa_cache_multiple_sta(dev, apdev):
719    """PMKSA cache with multiple stations"""
720    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
721    hostapd.add_ap(apdev[0], params)
722    bssid = apdev[0]['bssid']
723    for d in dev:
724        d.flush_scan_cache()
725    dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
726                   eap="GPSK", identity="gpsk-user-session-timeout",
727                   password="abcdefghijklmnop0123456789abcdef",
728                   scan_freq="2412")
729    dev[1].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
730                   eap="GPSK", identity="gpsk user",
731                   password="abcdefghijklmnop0123456789abcdef",
732                   scan_freq="2412")
733    dev[2].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
734                   eap="GPSK", identity="gpsk-user-session-timeout",
735                   password="abcdefghijklmnop0123456789abcdef",
736                   scan_freq="2412")
737
738    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
739    wpas.interface_add("wlan5")
740    wpas.flush_scan_cache()
741    wpas.connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
742                 eap="GPSK", identity="gpsk user",
743                 password="abcdefghijklmnop0123456789abcdef",
744                 scan_freq="2412")
745
746    hostapd.add_ap(apdev[1], params)
747    bssid2 = apdev[1]['bssid']
748
749    logger.info("Roam to AP2")
750    for sta in [dev[1], dev[0], dev[2], wpas]:
751        sta.dump_monitor()
752        sta.scan_for_bss(bssid2, freq="2412")
753        if "OK" not in sta.request("ROAM " + bssid2):
754            raise Exception("ROAM command failed (" + sta.ifname + ")")
755        ev = sta.wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
756        if ev is None:
757            raise Exception("EAP success timed out")
758        sta.wait_connected(timeout=10, error="Roaming timed out")
759        sta.dump_monitor()
760
761    logger.info("Roam back to AP1")
762    for sta in [dev[1], wpas, dev[0], dev[2]]:
763        sta.dump_monitor()
764        sta.scan(freq="2412")
765        sta.dump_monitor()
766        sta.request("ROAM " + bssid)
767        sta.wait_connected(timeout=10, error="Roaming timed out")
768        sta.dump_monitor()
769
770    time.sleep(4)
771
772    logger.info("Roam back to AP2")
773    for sta in [dev[1], wpas, dev[0], dev[2]]:
774        sta.dump_monitor()
775        sta.scan(freq="2412")
776        sta.dump_monitor()
777        sta.request("ROAM " + bssid2)
778        sta.wait_connected(timeout=10, error="Roaming timed out")
779        sta.dump_monitor()
780
781def test_pmksa_cache_opportunistic_multiple_sta(dev, apdev):
782    """Opportunistic PMKSA caching with multiple stations"""
783    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
784    params['okc'] = "1"
785    hostapd.add_ap(apdev[0], params)
786    bssid = apdev[0]['bssid']
787    for d in dev:
788        d.flush_scan_cache()
789    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
790    wpas.interface_add("wlan5")
791    wpas.flush_scan_cache()
792    for sta in [dev[0], dev[1], dev[2], wpas]:
793        sta.connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
794                    eap="GPSK", identity="gpsk user",
795                    password="abcdefghijklmnop0123456789abcdef", okc=True,
796                    scan_freq="2412")
797
798    hostapd.add_ap(apdev[1], params)
799    bssid2 = apdev[1]['bssid']
800
801    logger.info("Roam to AP2")
802    for sta in [dev[2], dev[0], wpas, dev[1]]:
803        sta.dump_monitor()
804        sta.scan_for_bss(bssid2, freq="2412")
805        if "OK" not in sta.request("ROAM " + bssid2):
806            raise Exception("ROAM command failed")
807        ev = sta.wait_event(["CTRL-EVENT-EAP-STARTED",
808                             "CTRL-EVENT-CONNECTED"], timeout=10)
809        if ev is None:
810            raise Exception("Roaming with the AP timed out")
811        if "CTRL-EVENT-EAP-STARTED" in ev:
812            raise Exception("Unexpected EAP exchange")
813        pmksa2 = sta.get_pmksa(bssid2)
814        if pmksa2 is None:
815            raise Exception("No PMKSA cache entry created")
816        sta.dump_monitor()
817
818    logger.info("Roam back to AP1")
819    for sta in [dev[0], dev[1], dev[2], wpas]:
820        sta.dump_monitor()
821        sta.scan_for_bss(bssid, freq="2412")
822        sta.request("ROAM " + bssid)
823        ev = sta.wait_event(["CTRL-EVENT-EAP-STARTED",
824                             "CTRL-EVENT-CONNECTED"], timeout=10)
825        if ev is None:
826            raise Exception("Roaming with the AP timed out")
827        if "CTRL-EVENT-EAP-STARTED" in ev:
828            raise Exception("Unexpected EAP exchange")
829
830def test_pmksa_cache_preauth_oom(dev, apdev):
831    """RSN pre-authentication to generate PMKSA cache entry and OOM"""
832    try:
833        _test_pmksa_cache_preauth_oom(dev, apdev)
834    finally:
835        hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev', 'ap-br0',
836                                       'down'])
837        hostapd.cmd_execute(apdev[0], ['brctl', 'delbr', 'ap-br0'])
838
839def _test_pmksa_cache_preauth_oom(dev, apdev):
840    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
841    params['bridge'] = 'ap-br0'
842    hapd = hostapd.add_ap(apdev[0], params)
843    hostapd.cmd_execute(apdev[0], ['brctl', 'setfd', 'ap-br0', '0'])
844    hostapd.cmd_execute(apdev[0], ['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
845    eap_connect(dev[0], hapd, "PAX", "pax.user@example.com",
846                password_hex="0123456789abcdef0123456789abcdef",
847                bssid=apdev[0]['bssid'])
848
849    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
850    params['bridge'] = 'ap-br0'
851    params['rsn_preauth'] = '1'
852    params['rsn_preauth_interfaces'] = 'ap-br0'
853    hapd = hostapd.add_ap(apdev[1], params)
854    bssid1 = apdev[1]['bssid']
855
856    tests = [(1, "rsn_preauth_receive"),
857             (2, "rsn_preauth_receive"),
858             (1, "rsn_preauth_send"),
859             (1, "wpa_auth_pmksa_add_preauth;rsn_preauth_finished")]
860    for test in tests:
861        hapd.request("DEAUTHENTICATE ff:ff:ff:ff:ff:ff")
862        with alloc_fail(hapd, test[0], test[1]):
863            dev[0].scan_for_bss(bssid1, freq="2412")
864            if "OK" not in dev[0].request("PREAUTH " + bssid1):
865                raise Exception("PREAUTH failed")
866
867            success = False
868            count = 0
869            for i in range(50):
870                time.sleep(0.1)
871                pmksa = dev[0].get_pmksa(bssid1)
872                if pmksa:
873                    success = True
874                    break
875                state = hapd.request('GET_ALLOC_FAIL')
876                if state.startswith('0:'):
877                    count += 1
878                    if count > 2:
879                        break
880            logger.info("PMKSA cache success: " + str(success))
881
882            dev[0].request("PMKSA_FLUSH")
883            dev[0].wait_disconnected()
884            dev[0].wait_connected()
885            dev[0].dump_monitor()
886
887def test_pmksa_cache_size_limit(dev, apdev):
888    """PMKSA cache size limit in wpa_supplicant"""
889    try:
890        _test_pmksa_cache_size_limit(dev, apdev)
891    finally:
892        try:
893            hapd = hostapd.HostapdGlobal(apdev[0])
894            hapd.flush()
895            hapd.remove(apdev[0]['ifname'])
896        except:
897            pass
898        params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
899        bssid = apdev[0]['bssid']
900        params['bssid'] = bssid
901        hostapd.add_ap(apdev[0], params)
902
903def _test_pmksa_cache_size_limit(dev, apdev):
904    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
905    id = dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
906                        eap="GPSK", identity="gpsk user",
907                        password="abcdefghijklmnop0123456789abcdef",
908                        scan_freq="2412", only_add_network=True)
909    for i in range(33):
910        bssid = apdev[0]['bssid'][0:15] + "%02x" % i
911        logger.info("Iteration with BSSID " + bssid)
912        params['bssid'] = bssid
913        hostapd.add_ap(apdev[0], params)
914        dev[0].request("BSS_FLUSH 0")
915        dev[0].scan_for_bss(bssid, freq=2412, only_new=True)
916        dev[0].select_network(id)
917        dev[0].wait_connected()
918        dev[0].request("DISCONNECT")
919        dev[0].wait_disconnected()
920        dev[0].dump_monitor()
921        entries = len(dev[0].request("PMKSA").splitlines()) - 1
922        if i == 32:
923            if entries != 32:
924                raise Exception("Unexpected number of PMKSA entries after expected removal of the oldest entry")
925        elif i + 1 != entries:
926            raise Exception("Unexpected number of PMKSA entries")
927
928        hapd = hostapd.HostapdGlobal(apdev[0])
929        hapd.flush()
930        hapd.remove(apdev[0]['ifname'])
931
932def test_pmksa_cache_preauth_timeout(dev, apdev):
933    """RSN pre-authentication timing out"""
934    try:
935        _test_pmksa_cache_preauth_timeout(dev, apdev)
936    finally:
937        dev[0].request("SET dot11RSNAConfigSATimeout 60")
938
939def _test_pmksa_cache_preauth_timeout(dev, apdev):
940    dev[0].request("SET dot11RSNAConfigSATimeout 1")
941    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
942    hapd = hostapd.add_ap(apdev[0], params)
943    eap_connect(dev[0], hapd, "PAX", "pax.user@example.com",
944                password_hex="0123456789abcdef0123456789abcdef",
945                bssid=apdev[0]['bssid'])
946    if "OK" not in dev[0].request("PREAUTH f2:11:22:33:44:55"):
947        raise Exception("PREAUTH failed")
948    ev = dev[0].wait_event(["RSN: pre-authentication with"], timeout=5)
949    if ev is None:
950        raise Exception("No timeout event seen")
951    if "timed out" not in ev:
952        raise Exception("Unexpected event: " + ev)
953
954def test_pmksa_cache_preauth_wpas_oom(dev, apdev):
955    """RSN pre-authentication OOM in wpa_supplicant"""
956    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
957    hapd = hostapd.add_ap(apdev[0], params)
958    eap_connect(dev[0], hapd, "PAX", "pax.user@example.com",
959                password_hex="0123456789abcdef0123456789abcdef",
960                bssid=apdev[0]['bssid'])
961    for i in range(1, 11):
962        with alloc_fail(dev[0], i, "rsn_preauth_init"):
963            res = dev[0].request("PREAUTH f2:11:22:33:44:55").strip()
964            logger.info("Iteration %d - PREAUTH command results: %s" % (i, res))
965            for j in range(10):
966                state = dev[0].request('GET_ALLOC_FAIL')
967                if state.startswith('0:'):
968                    break
969                time.sleep(0.05)
970
971def test_pmksa_cache_ctrl(dev, apdev):
972    """PMKSA cache control interface operations"""
973    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
974    hapd = hostapd.add_ap(apdev[0], params)
975    bssid = apdev[0]['bssid']
976    addr = dev[0].own_addr()
977
978    dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
979                   eap="GPSK", identity="gpsk user",
980                   password="abcdefghijklmnop0123456789abcdef",
981                   scan_freq="2412")
982
983    pmksa_sta = dev[0].get_pmksa(bssid)
984    if pmksa_sta is None:
985        raise Exception("No PMKSA cache entry created on STA")
986    hapd.wait_sta()
987    pmksa_ap = hapd.get_pmksa(addr)
988    if pmksa_ap is None:
989        raise Exception("No PMKSA cache entry created on AP")
990    if pmksa_sta['pmkid'] != pmksa_ap['pmkid']:
991        raise Exception("PMKID mismatch in PMKSA cache entries")
992
993    if "OK" not in hapd.request("PMKSA_FLUSH"):
994        raise Exception("PMKSA_FLUSH failed")
995    pmksa_ap = hapd.get_pmksa(addr)
996    if pmksa_ap is not None:
997        raise Exception("PMKSA cache entry was not removed on AP")
998
999    dev[0].request("DISCONNECT")
1000    dev[0].wait_disconnected()
1001    dev[0].request("RECONNECT")
1002    dev[0].wait_connected()
1003
1004    pmksa_sta2 = dev[0].get_pmksa(bssid)
1005    if pmksa_sta2 is None:
1006        raise Exception("No PMKSA cache entry created on STA after reconnect")
1007    hapd.wait_sta()
1008    pmksa_ap2 = hapd.get_pmksa(addr)
1009    if pmksa_ap2 is None:
1010        raise Exception("No PMKSA cache entry created on AP after reconnect")
1011    if pmksa_sta2['pmkid'] != pmksa_ap2['pmkid']:
1012        raise Exception("PMKID mismatch in PMKSA cache entries after reconnect")
1013    if pmksa_sta2['pmkid'] == pmksa_sta['pmkid']:
1014        raise Exception("PMKID did not change after reconnect")
1015
1016def test_pmksa_cache_ctrl_events(dev, apdev):
1017    """PMKSA cache control interface events"""
1018    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
1019    hapd = hostapd.add_ap(apdev[0], params)
1020    bssid = apdev[0]['bssid']
1021
1022    id = dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
1023                        eap="GPSK", identity="gpsk user",
1024                        password="abcdefghijklmnop0123456789abcdef",
1025                        scan_freq="2412", wait_connect=False)
1026
1027    ev = dev[0].wait_event(["PMKSA-CACHE-ADDED"], timeout=15)
1028    if ev is None:
1029        raise Exception("No PMKSA-CACHE-ADDED event")
1030    dev[0].wait_connected()
1031    items = ev.split(' ')
1032    if items[1] != bssid:
1033        raise Exception("BSSID mismatch: " + ev)
1034    if int(items[2]) != id:
1035        raise Exception("network_id mismatch: " + ev)
1036
1037    dev[0].request("PMKSA_FLUSH")
1038    ev = dev[0].wait_event(["PMKSA-CACHE-REMOVED"], timeout=15)
1039    if ev is None:
1040        raise Exception("No PMKSA-CACHE-REMOVED event")
1041    dev[0].wait_disconnected()
1042    dev[0].request("DISCONNECT")
1043    items = ev.split(' ')
1044    if items[1] != bssid:
1045        raise Exception("BSSID mismatch: " + ev)
1046    if int(items[2]) != id:
1047        raise Exception("network_id mismatch: " + ev)
1048
1049def test_pmksa_cache_ctrl_ext(dev, apdev):
1050    """PMKSA cache control interface for external management"""
1051    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
1052    hapd = hostapd.add_ap(apdev[0], params)
1053    bssid = apdev[0]['bssid']
1054
1055    id = dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
1056                        eap="GPSK", identity="gpsk user",
1057                        password="abcdefghijklmnop0123456789abcdef",
1058                        scan_freq="2412")
1059
1060    res1 = dev[0].request("PMKSA_GET %d" % id)
1061    logger.info("PMKSA_GET: " + res1)
1062    if "UNKNOWN COMMAND" in res1:
1063        raise HwsimSkip("PMKSA_GET not supported in the build")
1064    if bssid not in res1:
1065        raise Exception("PMKSA cache entry missing")
1066
1067    hostapd.add_ap(apdev[1], params)
1068    bssid2 = apdev[1]['bssid']
1069    dev[0].scan_for_bss(bssid2, freq=2412, force_scan=True)
1070    dev[0].request("ROAM " + bssid2)
1071    dev[0].wait_connected()
1072
1073    res2 = dev[0].request("PMKSA_GET %d" % id)
1074    logger.info("PMKSA_GET: " + res2)
1075    if bssid not in res2:
1076        raise Exception("PMKSA cache entry 1 missing")
1077    if bssid2 not in res2:
1078        raise Exception("PMKSA cache entry 2 missing")
1079
1080    dev[0].request("REMOVE_NETWORK all")
1081    dev[0].wait_disconnected()
1082    dev[0].request("PMKSA_FLUSH")
1083
1084    id = dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
1085                        eap="GPSK", identity="gpsk user",
1086                        password="abcdefghijklmnop0123456789abcdef",
1087                        scan_freq="2412", only_add_network=True)
1088    res3 = dev[0].request("PMKSA_GET %d" % id)
1089    if res3 != '':
1090        raise Exception("Unexpected PMKSA cache entry remains: " + res3)
1091    res4 = dev[0].request("PMKSA_GET %d" % (id + 1234))
1092    if not res4.startswith('FAIL'):
1093        raise Exception("Unexpected PMKSA cache entry for unknown network: " + res4)
1094
1095    for entry in res2.splitlines():
1096        if "OK" not in dev[0].request("PMKSA_ADD %d %s" % (id, entry)):
1097            raise Exception("Failed to add PMKSA entry")
1098
1099    dev[0].select_network(id)
1100    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
1101                            "CTRL-EVENT-CONNECTED"], timeout=15)
1102    if ev is None:
1103        raise Exception("Connection with the AP timed out")
1104    if "CTRL-EVENT-EAP-STARTED" in ev:
1105        raise Exception("Unexpected EAP exchange after external PMKSA cache restore")
1106
1107def test_pmksa_cache_ctrl_ext_ft(dev, apdev):
1108    """PMKSA cache control interface for external management (FT)"""
1109    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
1110    params['wpa_key_mgmt'] = "FT-EAP"
1111    params['nas_identifier'] = "nas.w1.fi"
1112    params['r1_key_holder'] = "000102030406"
1113    params["mobility_domain"] = "a1b2"
1114    hapd = hostapd.add_ap(apdev[0], params)
1115    bssid = apdev[0]['bssid']
1116
1117    id = dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="FT-EAP",
1118                        eap="GPSK", identity="gpsk user",
1119                        password="abcdefghijklmnop0123456789abcdef",
1120                        scan_freq="2412")
1121    hapd.wait_sta()
1122
1123    res1 = dev[0].request("PMKSA_GET %d" % id)
1124    logger.info("PMKSA_GET: " + res1)
1125    if "UNKNOWN COMMAND" in res1:
1126        raise HwsimSkip("PMKSA_GET not supported in the build")
1127    if bssid not in res1:
1128        raise Exception("PMKSA cache entry missing")
1129
1130    dev[0].request("REMOVE_NETWORK all")
1131    dev[0].wait_disconnected()
1132    dev[0].dump_monitor()
1133    dev[0].request("PMKSA_FLUSH")
1134    hapd.wait_sta_disconnect()
1135
1136    id = dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="FT-EAP",
1137                        eap="GPSK", identity="gpsk user",
1138                        password="abcdefghijklmnop0123456789abcdef",
1139                        ft_eap_pmksa_caching="1",
1140                        scan_freq="2412", only_add_network=True)
1141    res3 = dev[0].request("PMKSA_GET %d" % id)
1142    if res3 != '':
1143        raise Exception("Unexpected PMKSA cache entry remains: " + res3)
1144
1145    for entry in res1.splitlines():
1146        if "OK" not in dev[0].request("PMKSA_ADD %d %s" % (id, entry)):
1147            raise Exception("Failed to add PMKSA entry")
1148
1149    dev[0].select_network(id)
1150    ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
1151                            "CTRL-EVENT-CONNECTED"], timeout=15)
1152    if ev is None:
1153        raise Exception("Connection with the AP timed out")
1154    if "CTRL-EVENT-EAP-STARTED" in ev:
1155        raise Exception("Unexpected EAP exchange after external PMKSA cache restore")
1156
1157    dev[0].request("DISCONNECT")
1158    dev[0].wait_disconnected()
1159    dev[0].dump_monitor()
1160    dev[0].request("PMKSA_FLUSH")
1161    # Add a PMKSA cache entry for FT-EAP with PMKSA caching disabled to confirm
1162    # that the PMKID is not configured to the driver (this part requires manual
1163    # check of the debug log currently).
1164    dev[0].set_network(id, "ft_eap_pmksa_caching", "0")
1165    for entry in res1.splitlines():
1166        if "OK" not in dev[0].request("PMKSA_ADD %d %s" % (id, entry)):
1167            raise Exception("Failed to add PMKSA entry")
1168
1169def test_rsn_preauth_processing(dev, apdev):
1170    """RSN pre-authentication processing on AP"""
1171    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
1172    params['rsn_preauth'] = '1'
1173    params['rsn_preauth_interfaces'] = "lo"
1174    hapd = hostapd.add_ap(apdev[0], params)
1175    bssid = hapd.own_addr()
1176    _bssid = binascii.unhexlify(bssid.replace(':', ''))
1177    eap_connect(dev[0], hapd, "PAX", "pax.user@example.com",
1178                password_hex="0123456789abcdef0123456789abcdef")
1179    addr = dev[0].own_addr()
1180    _addr = binascii.unhexlify(addr.replace(':', ''))
1181
1182    sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW,
1183                         socket.htons(0x88c7))
1184    sock.bind(("lo", socket.htons(0x88c7)))
1185
1186    foreign = b"\x02\x03\x04\x05\x06\x07"
1187    proto = b"\x88\xc7"
1188    tests = []
1189    # RSN: too short pre-auth packet (len=14)
1190    tests += [_bssid + foreign + proto]
1191    # Not EAPOL-Start
1192    tests += [_bssid + foreign + proto + struct.pack('>BBH', 0, 0, 0)]
1193    # RSN: pre-auth for foreign address 02:03:04:05:06:07
1194    tests += [foreign + foreign + proto + struct.pack('>BBH', 0, 0, 0)]
1195    # RSN: pre-auth for already association STA 02:00:00:00:00:00
1196    tests += [_bssid + _addr + proto + struct.pack('>BBH', 0, 0, 0)]
1197    # New STA
1198    tests += [_bssid + foreign + proto + struct.pack('>BBH', 0, 1, 1)]
1199    # IEEE 802.1X: received EAPOL-Start from STA
1200    tests += [_bssid + foreign + proto + struct.pack('>BBH', 0, 1, 0)]
1201    # frame too short for this IEEE 802.1X packet
1202    tests += [_bssid + foreign + proto + struct.pack('>BBH', 0, 1, 1)]
1203    # EAPOL-Key - Dropped key data from unauthorized Supplicant
1204    tests += [_bssid + foreign + proto + struct.pack('>BBH', 2, 3, 0)]
1205    # EAPOL-Encapsulated-ASF-Alert
1206    tests += [_bssid + foreign + proto + struct.pack('>BBH', 2, 4, 0)]
1207    # unknown IEEE 802.1X packet type
1208    tests += [_bssid + foreign + proto + struct.pack('>BBH', 2, 255, 0)]
1209    for t in tests:
1210        sock.send(t)
1211
1212def test_rsn_preauth_local_errors(dev, apdev):
1213    """RSN pre-authentication and local errors on AP"""
1214    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
1215    params['rsn_preauth'] = '1'
1216    params['rsn_preauth_interfaces'] = "lo"
1217    hapd = hostapd.add_ap(apdev[0], params)
1218    bssid = hapd.own_addr()
1219    _bssid = binascii.unhexlify(bssid.replace(':', ''))
1220
1221    sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW,
1222                         socket.htons(0x88c7))
1223    sock.bind(("lo", socket.htons(0x88c7)))
1224
1225    foreign = b"\x02\x03\x04\x05\x06\x07"
1226    foreign2 = b"\x02\x03\x04\x05\x06\x08"
1227    proto = b"\x88\xc7"
1228
1229    with alloc_fail(hapd, 1, "ap_sta_add;rsn_preauth_receive"):
1230        sock.send(_bssid + foreign + proto + struct.pack('>BBH', 2, 1, 0))
1231        wait_fail_trigger(hapd, "GET_ALLOC_FAIL")
1232
1233    with alloc_fail(hapd, 1, "eapol_auth_alloc;rsn_preauth_receive"):
1234        sock.send(_bssid + foreign + proto + struct.pack('>BBH', 2, 1, 0))
1235        wait_fail_trigger(hapd, "GET_ALLOC_FAIL")
1236    sock.send(_bssid + foreign + proto + struct.pack('>BBH', 2, 1, 0))
1237
1238    with alloc_fail(hapd, 1, "eap_server_sm_init;ieee802_1x_new_station;rsn_preauth_receive"):
1239        sock.send(_bssid + foreign2 + proto + struct.pack('>BBH', 2, 1, 0))
1240        wait_fail_trigger(hapd, "GET_ALLOC_FAIL")
1241    sock.send(_bssid + foreign2 + proto + struct.pack('>BBH', 2, 1, 0))
1242
1243    hapd.request("DISABLE")
1244    tests = [(1, "=rsn_preauth_iface_add"),
1245             (2, "=rsn_preauth_iface_add"),
1246             (1, "l2_packet_init;rsn_preauth_iface_add"),
1247             (1, "rsn_preauth_iface_init"),
1248             (1, "rsn_preauth_iface_init")]
1249    for count, func in tests:
1250        with alloc_fail(hapd, count, func):
1251            if "FAIL" not in hapd.request("ENABLE"):
1252                raise Exception("ENABLE succeeded unexpectedly")
1253
1254    hapd.set("rsn_preauth_interfaces", "lo  lo lo does-not-exist lo ")
1255    if "FAIL" not in hapd.request("ENABLE"):
1256        raise Exception("ENABLE succeeded unexpectedly")
1257    hapd.set("rsn_preauth_interfaces", " lo  lo ")
1258    if "OK" not in hapd.request("ENABLE"):
1259        raise Exception("ENABLE failed")
1260    sock.send(_bssid + foreign + proto + struct.pack('>BBH', 2, 1, 0))
1261    sock.send(_bssid + foreign2 + proto + struct.pack('>BBH', 2, 1, 0))
1262
1263def test_pmksa_cache_add_failure(dev, apdev):
1264    """PMKSA cache add failure"""
1265    params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
1266    hostapd.add_ap(apdev[0], params)
1267    bssid = apdev[0]['bssid']
1268    with alloc_fail(dev[0], 1, "pmksa_cache_add"):
1269        dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
1270                       eap="GPSK", identity="gpsk user",
1271                       password="abcdefghijklmnop0123456789abcdef",
1272                       scan_freq="2412")
1273    pmksa = dev[0].get_pmksa(bssid)
1274    if pmksa is None:
1275        raise Exception("No PMKSA cache entry created")
1276