1# Test cases for PASN
2# Copyright (C) 2019 Intel Corporation
3#
4# This software may be distributed under the terms of the BSD license.
5# See README for more details.
6
7from remotehost import remote_compatible
8import binascii
9import os
10import time
11import logging
12logger = logging.getLogger()
13import socket
14import struct
15import subprocess
16import re
17
18import hwsim_utils
19import hostapd
20from wpasupplicant import WpaSupplicant
21from utils import *
22from hwsim import HWSimRadio
23from test_erp import start_erp_as
24from test_ap_ft import run_roams, ft_params1, ft_params2
25
26def check_pasn_capab(dev):
27    if "PASN" not in dev.get_capability("auth_alg"):
28        raise HwsimSkip("PASN not supported")
29
30def pasn_ap_params(akmp="PASN", cipher="CCMP", group="19"):
31    params = {"ssid": "test-wpa2-pasn",
32              "wpa_passphrase": "12345678",
33              "wpa": "2",
34              "ieee80211w": "2",
35              "wpa_key_mgmt": "WPA-PSK " + akmp,
36              "rsn_pairwise": cipher,
37              "pasn_groups" : group}
38
39    return params
40
41def start_pasn_ap(apdev, params):
42    try:
43        return hostapd.add_ap(apdev, params)
44    except Exception as e:
45        if "Failed to set hostapd parameter wpa_key_mgmt" in str(e) or \
46           "Failed to set hostapd parameter force_kdk_derivation" in str(e):
47            raise HwsimSkip("PASN not supported")
48        raise
49
50def check_pasn_ptk(dev, hapd, cipher, fail_ptk=False, clear_keys=True):
51    sta_ptksa = dev.get_ptksa(hapd.own_addr(), cipher)
52    ap_ptksa = hapd.get_ptksa(dev.own_addr(), cipher)
53
54    if not (sta_ptksa and ap_ptksa):
55        if fail_ptk:
56            return
57        raise Exception("Could not get PTKSA entry")
58
59    logger.info("sta: TK: %s KDK: %s" % (sta_ptksa['tk'], sta_ptksa['kdk']))
60    logger.info("ap : TK: %s KDK: %s" % (ap_ptksa['tk'], ap_ptksa['kdk']))
61
62    if sta_ptksa['tk'] != ap_ptksa['tk'] or sta_ptksa['kdk'] != ap_ptksa['kdk']:
63        raise Exception("TK/KDK mismatch")
64    elif fail_ptk:
65        raise Exception("TK/KDK match although key derivation should have failed")
66    elif clear_keys:
67        cmd = "PASN_DEAUTH bssid=%s" % hapd.own_addr()
68        dev.request(cmd)
69
70        # Wait a little to let the AP process the deauth
71        time.sleep(0.2)
72
73        sta_ptksa = dev.get_ptksa(hapd.own_addr(), cipher)
74        ap_ptksa = hapd.get_ptksa(dev.own_addr(), cipher)
75        if sta_ptksa or ap_ptksa:
76            raise Exception("TK/KDK not deleted as expected")
77
78def check_pasn_akmp_cipher(dev, hapd, akmp="PASN", cipher="CCMP",
79                           group="19", status=0, fail=0, nid="",
80                           fail_ptk=False):
81    dev.flush_scan_cache()
82    dev.scan(type="ONLY", freq=2412)
83
84    cmd = "PASN_START bssid=%s akmp=%s cipher=%s group=%s" % (hapd.own_addr(), akmp, cipher, group)
85
86    if nid != "":
87        cmd += " nid=%s" % nid
88
89    resp = dev.request(cmd)
90
91    if fail:
92        if "OK" in resp:
93            raise Exception("Unexpected success to start PASN authentication")
94        return
95
96    if "OK" not in resp:
97        raise Exception("Failed to start PASN authentication")
98
99    ev = dev.wait_event(["PASN-AUTH-STATUS"], 3)
100    if not ev:
101        raise Exception("PASN: PASN-AUTH-STATUS not seen")
102
103    if hapd.own_addr() + " akmp=" + akmp + ", status=" + str(status) not in ev:
104        raise Exception("PASN: unexpected status")
105
106    if status:
107        return
108
109    check_pasn_ptk(dev, hapd, cipher, fail_ptk)
110
111@remote_compatible
112def test_pasn_ccmp(dev, apdev):
113    """PASN authentication with WPA2/CCMP AP"""
114    check_pasn_capab(dev[0])
115
116    params = pasn_ap_params("PASN", "CCMP", "19")
117    hapd = start_pasn_ap(apdev[0], params)
118
119    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
120
121@remote_compatible
122def test_pasn_gcmp(dev, apdev):
123    """PASN authentication with WPA2/GCMP AP"""
124    check_pasn_capab(dev[0])
125
126    params = pasn_ap_params("PASN", "GCMP", "19")
127    hapd = start_pasn_ap(apdev[0], params)
128
129    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "GCMP")
130
131@remote_compatible
132def test_pasn_ccmp_256(dev, apdev):
133    """PASN authentication with WPA2/CCMP256 AP"""
134    check_pasn_capab(dev[0])
135
136    params = pasn_ap_params("PASN", "CCMP-256", "19")
137    hapd = start_pasn_ap(apdev[0], params)
138
139    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP-256")
140
141@remote_compatible
142def test_pasn_gcmp_256(dev, apdev):
143    """PASN authentication with WPA2/GCMP-256 AP"""
144    check_pasn_capab(dev[0])
145
146    params = pasn_ap_params("PASN", "GCMP-256", "19")
147    hapd = start_pasn_ap(apdev[0], params)
148
149    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "GCMP-256")
150
151@remote_compatible
152def test_pasn_group_mismatch(dev, apdev):
153    """PASN authentication with WPA2/CCMP AP with group mismatch"""
154    check_pasn_capab(dev[0])
155
156    params = pasn_ap_params("PASN", "CCMP", "20")
157    hapd = start_pasn_ap(apdev[0], params)
158
159    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP", status=77)
160
161@remote_compatible
162def test_pasn_channel_mismatch(dev, apdev):
163    """PASN authentication with WPA2/CCMP AP with channel mismatch"""
164    check_pasn_capab(dev[0])
165
166    params = pasn_ap_params("PASN", "CCMP")
167    params['channel'] = "6"
168    hapd = start_pasn_ap(apdev[0], params)
169
170    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP", fail=1)
171
172@remote_compatible
173def test_pasn_while_connected_same_channel(dev, apdev):
174    """PASN authentication with WPA2/CCMP AP while connected same channel"""
175    check_pasn_capab(dev[0])
176
177    ssid = "test-wpa2-psk"
178    psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
179    params = hostapd.wpa2_params(ssid=ssid)
180    params['wpa_psk'] = psk
181    hapd = start_pasn_ap(apdev[0], params)
182
183    dev[0].connect(ssid, raw_psk=psk, scan_freq="2412")
184
185    params = pasn_ap_params("PASN", "CCMP")
186    hapd = start_pasn_ap(apdev[1], params)
187
188    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
189
190@remote_compatible
191def test_pasn_while_connected_same_ap(dev, apdev):
192    """PASN authentication with WPA2/CCMP AP while connected to it"""
193    check_pasn_capab(dev[0])
194
195    params = hostapd.wpa2_params(ssid="test-wpa2-psk",
196                                 passphrase="12345678")
197    hapd = start_pasn_ap(apdev[0], params)
198
199    dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412")
200
201    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP", fail=1)
202
203@remote_compatible
204def test_pasn_while_connected_diff_channel(dev, apdev):
205    """PASN authentication with WPA2/CCMP AP while connected diff channel"""
206    check_pasn_capab(dev[0])
207
208    with HWSimRadio(n_channels=2) as (radio, iface):
209        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
210        wpas.interface_add(iface)
211
212        if wpas.get_mcc() < 2:
213            raise HwsimSkip("PASN: New radio does not support MCC")
214
215        params = hostapd.wpa2_params(ssid="test-wpa2-psk",
216                                     passphrase="12345678")
217        params['channel'] = "6"
218        hapd = start_pasn_ap(apdev[0], params)
219        wpas.connect("test-wpa2-psk", psk="12345678", scan_freq="2437")
220
221        params = pasn_ap_params("PASN", "CCMP")
222        hapd2 = start_pasn_ap(apdev[1], params)
223
224        check_pasn_akmp_cipher(wpas, hapd2, "PASN", "CCMP")
225
226@remote_compatible
227def test_pasn_sae_pmksa_cache(dev, apdev):
228    """PASN authentication with SAE AP with PMKSA caching"""
229    check_pasn_capab(dev[0])
230    check_sae_capab(dev[0])
231
232    params = hostapd.wpa2_params(ssid="test-sae",
233                                 passphrase="12345678")
234    params['wpa_key_mgmt'] = 'SAE PASN'
235    params['sae_pwe'] = "2"
236    hapd = start_pasn_ap(apdev[0], params)
237
238    try:
239        dev[0].set("sae_groups", "19")
240        dev[0].set("sae_pwe", "2")
241        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412")
242
243        hapd.wait_sta()
244        hwsim_utils.test_connectivity(dev[0], hapd)
245
246        dev[0].request("DISCONNECT")
247        dev[0].wait_disconnected()
248
249        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP")
250    finally:
251        dev[0].set("sae_pwe", "0")
252
253def check_pasn_fils_pmksa_cache(dev, apdev, params, key_mgmt):
254    check_fils_capa(dev[0])
255    check_erp_capa(dev[0])
256    check_pasn_capab(dev[0])
257
258    start_erp_as(msk_dump=os.path.join(params['logdir'], "msk.lst"))
259
260    bssid = apdev[0]['bssid']
261    params = hostapd.wpa2_eap_params(ssid="fils")
262    params['wpa_key_mgmt'] = key_mgmt + " PASN"
263    params['auth_server_port'] = "18128"
264    params['erp_domain'] = 'example.com'
265    params['fils_realm'] = 'example.com'
266    hapd = start_pasn_ap(apdev[0], params)
267
268    dev[0].scan_for_bss(bssid, freq=2412)
269    dev[0].request("ERP_FLUSH")
270
271    id = dev[0].connect("fils", key_mgmt=key_mgmt,
272                        eap="PSK", identity="psk.user@example.com",
273                        password_hex="0123456789abcdef0123456789abcdef",
274                        erp="1", scan_freq="2412")
275    pmksa = dev[0].get_pmksa(bssid)
276    if pmksa is None:
277        raise Exception("No PMKSA cache entry created")
278
279    hapd.wait_sta()
280    hwsim_utils.test_connectivity(dev[0], hapd)
281
282    dev[0].request("DISCONNECT")
283    dev[0].wait_disconnected()
284
285    check_pasn_akmp_cipher(dev[0], hapd, key_mgmt, "CCMP")
286
287@remote_compatible
288def test_pasn_fils_sha256_pmksa_cache(dev, apdev, params):
289    """PASN authentication with FILS-SHA256 with PMKSA caching"""
290    check_pasn_fils_pmksa_cache(dev, apdev, params, "FILS-SHA256")
291
292@remote_compatible
293def test_pasn_fils_sha384_pmksa_cache(dev, apdev, params):
294    """PASN authentication with FILS-SHA384 with PMKSA caching"""
295    check_pasn_fils_pmksa_cache(dev, apdev, params, "FILS-SHA384")
296
297@remote_compatible
298def test_pasn_sae_kdk(dev, apdev):
299    """Station authentication with SAE AP with KDK derivation during connection"""
300    check_pasn_capab(dev[0])
301    check_sae_capab(dev[0])
302
303    try:
304        params = hostapd.wpa2_params(ssid="test-sae",
305                                     passphrase="12345678")
306        params['wpa_key_mgmt'] = 'SAE PASN'
307        params['sae_pwe'] = "2"
308        params['force_kdk_derivation'] = "1"
309        hapd = start_pasn_ap(apdev[0], params)
310
311        dev[0].set("force_kdk_derivation", "1")
312        dev[0].set("sae_pwe", "2")
313        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
314                       scan_freq="2412")
315
316        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=False)
317    finally:
318        dev[0].set("force_kdk_derivation", "0")
319        dev[0].set("sae_pwe", "0")
320
321
322def check_pasn_fils_kdk(dev, apdev, params, key_mgmt):
323    check_fils_capa(dev[0])
324    check_erp_capa(dev[0])
325    check_pasn_capab(dev[0])
326
327    start_erp_as(msk_dump=os.path.join(params['logdir'], "msk.lst"))
328
329    try:
330        bssid = apdev[0]['bssid']
331        params = hostapd.wpa2_eap_params(ssid="fils")
332        params['wpa_key_mgmt'] = key_mgmt
333        params['auth_server_port'] = "18128"
334        params['erp_domain'] = 'example.com'
335        params['fils_realm'] = 'example.com'
336        params['disable_pmksa_caching'] = '1'
337        params['force_kdk_derivation'] = "1"
338        hapd = start_pasn_ap(apdev[0], params)
339
340        dev[0].scan_for_bss(bssid, freq=2412)
341        dev[0].request("ERP_FLUSH")
342        dev[0].set("force_kdk_derivation", "1")
343
344        id = dev[0].connect("fils", key_mgmt=key_mgmt,
345                            eap="PSK", identity="psk.user@example.com",
346                            password_hex="0123456789abcdef0123456789abcdef",
347                            erp="1", scan_freq="2412")
348
349        hapd.wait_sta()
350        hwsim_utils.test_connectivity(dev[0], hapd)
351
352        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=False)
353
354        dev[0].request("DISCONNECT")
355        dev[0].wait_disconnected()
356
357        dev[0].dump_monitor()
358        dev[0].select_network(id, freq=2412)
359        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
360                                "EVENT-ASSOC-REJECT",
361                                "CTRL-EVENT-CONNECTED"], timeout=10)
362        if ev is None:
363            raise Exception("Connection using FILS/ERP timed out")
364        if "CTRL-EVENT-EAP-STARTED" in ev:
365            raise Exception("Unexpected EAP exchange")
366        if "EVENT-ASSOC-REJECT" in ev:
367            raise Exception("Association failed")
368
369        hapd.wait_sta()
370        hwsim_utils.test_connectivity(dev[0], hapd)
371
372        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=False)
373    finally:
374        dev[0].set("force_kdk_derivation", "0")
375
376@remote_compatible
377def test_pasn_fils_sha256_kdk(dev, apdev, params):
378    """Station authentication with FILS-SHA256 with KDK derivation during connection"""
379    check_pasn_fils_kdk(dev, apdev, params, "FILS-SHA256")
380
381@remote_compatible
382def test_pasn_fils_sha384_kdk(dev, apdev, params):
383    """Station authentication with FILS-SHA384 with KDK derivation during connection"""
384    check_pasn_fils_kdk(dev, apdev, params, "FILS-SHA384")
385
386@remote_compatible
387def test_pasn_sae(dev, apdev):
388    """PASN authentication with SAE AP with PMK derivation + PMKSA caching"""
389    check_pasn_capab(dev[0])
390    check_sae_capab(dev[0])
391
392    params = hostapd.wpa2_params(ssid="test-pasn-sae",
393                                 passphrase="12345678")
394    params['wpa_key_mgmt'] = 'SAE PASN'
395    params['sae_pwe'] = "2"
396    hapd = start_pasn_ap(apdev[0], params)
397
398    try:
399        dev[0].set("sae_pwe", "2")
400        dev[0].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE",
401                       scan_freq="2412", only_add_network=True)
402
403        # first test with a valid PSK
404        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="0")
405
406        # And now with PMKSA caching
407        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP")
408
409        # And now with a wrong passphrase
410        if "FAIL" in dev[0].request("PMKSA_FLUSH"):
411            raise Exception("PMKSA_FLUSH failed")
412
413        dev[0].set_network_quoted(0, "psk", "12345678787")
414        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", status=1, nid="0")
415    finally:
416        dev[0].set("sae_pwe", "0")
417
418@remote_compatible
419def test_pasn_sae_while_connected_same_channel(dev, apdev):
420    """PASN SAE authentication while connected same channel"""
421    check_pasn_capab(dev[0])
422    check_sae_capab(dev[0])
423
424    params = hostapd.wpa2_params(ssid="test-pasn-wpa2-psk",
425                                 passphrase="12345678")
426    hapd = hostapd.add_ap(apdev[0], params)
427
428    try:
429        dev[0].set("sae_pwe", "2")
430        dev[0].connect("test-pasn-wpa2-psk", psk="12345678", scan_freq="2412")
431
432        params = hostapd.wpa2_params(ssid="test-pasn-sae",
433                                     passphrase="12345678")
434
435        params['wpa_key_mgmt'] = 'SAE PASN'
436        params['sae_pwe'] = "2"
437        hapd = start_pasn_ap(apdev[1], params)
438
439        dev[0].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE",
440                       scan_freq="2412", only_add_network=True)
441
442        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="1")
443    finally:
444        dev[0].set("sae_pwe", "0")
445
446@remote_compatible
447def test_pasn_sae_while_connected_diff_channel(dev, apdev):
448    """PASN SAE authentication while connected diff channel"""
449    check_pasn_capab(dev[0])
450    check_sae_capab(dev[0])
451
452    with HWSimRadio(n_channels=2) as (radio, iface):
453        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
454        wpas.interface_add(iface)
455
456        if wpas.get_mcc() < 2:
457            raise HwsimSkip("PASN: New radio does not support MCC")
458
459        params = hostapd.wpa2_params(ssid="test-pasn-wpa2-psk",
460                                     passphrase="12345678")
461        params['channel'] = "6"
462        hapd = hostapd.add_ap(apdev[0], params)
463
464        try:
465            wpas.set("sae_pwe", "2")
466            wpas.connect("test-pasn-wpa2-psk", psk="12345678", scan_freq="2437")
467
468            params = hostapd.wpa2_params(ssid="test-pasn-sae",
469                                         passphrase="12345678")
470
471            params['wpa_key_mgmt'] = 'SAE PASN'
472            params['sae_pwe'] = "2"
473            hapd = start_pasn_ap(apdev[1], params)
474
475            wpas.connect("test-pasn-sae", psk="12345678", key_mgmt="SAE",
476                           scan_freq="2412", only_add_network=True)
477
478            check_pasn_akmp_cipher(wpas, hapd, "SAE", "CCMP", nid="1")
479        finally:
480            wpas.set("sae_pwe", "0")
481
482def pasn_fils_setup(wpas, apdev, params, key_mgmt):
483    check_fils_capa(wpas)
484    check_erp_capa(wpas)
485
486    wpas.flush_scan_cache()
487
488    start_erp_as(msk_dump=os.path.join(params['logdir'], "msk.lst"))
489
490    bssid = apdev[0]['bssid']
491    params = hostapd.wpa2_eap_params(ssid="fils")
492    params['wpa_key_mgmt'] = key_mgmt + " PASN"
493    params['auth_server_port'] = "18128"
494    params['erp_domain'] = 'example.com'
495    params['fils_realm'] = 'example.com'
496    params['disable_pmksa_caching'] = '1'
497    hapd = hostapd.add_ap(apdev[0]['ifname'], params)
498
499    id = wpas.connect("fils", key_mgmt=key_mgmt,
500                      eap="PSK", identity="psk.user@example.com",
501                      password_hex="0123456789abcdef0123456789abcdef",
502                      erp="1", scan_freq="2412")
503
504    wpas.request("DISCONNECT")
505    wpas.wait_disconnected()
506    wpas.dump_monitor()
507
508    if "FAIL" in wpas.request("PMKSA_FLUSH"):
509        raise Exception("PMKSA_FLUSH failed")
510
511    return hapd
512
513def check_pasn_fils(dev, apdev, params, key_mgmt):
514    check_pasn_capab(dev[0])
515
516    hapd = pasn_fils_setup(dev[0], apdev, params, key_mgmt);
517    check_pasn_akmp_cipher(dev[0], hapd, key_mgmt, "CCMP", nid="0")
518
519@remote_compatible
520def test_pasn_fils_sha256(dev, apdev, params):
521    """PASN FILS authentication using SHA-256"""
522    check_pasn_fils(dev, apdev, params, "FILS-SHA256")
523
524@remote_compatible
525def test_pasn_fils_sha384(dev, apdev, params):
526    """PASN FILS authentication using SHA-384"""
527    check_pasn_fils(dev, apdev, params, "FILS-SHA384")
528
529def check_pasn_fils_connected_same_channel(dev, apdev, params, key_mgmt):
530    check_pasn_capab(dev[0])
531
532    hapd = pasn_fils_setup(dev[0], apdev, params, key_mgmt);
533
534    # Connect to another AP on the same channel
535    hapd1 = hostapd.add_ap(apdev[1], {"ssid": "open"})
536    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
537                   bg_scan_period="0")
538
539    hwsim_utils.test_connectivity(dev[0], hapd1)
540
541    # And perform the PASN authentication with FILS
542    check_pasn_akmp_cipher(dev[0], hapd, key_mgmt, "CCMP", nid="0")
543
544@remote_compatible
545def test_pasn_fils_sha256_connected_same_channel(dev, apdev, params):
546    """PASN FILS authentication using SHA-256 while connected same channel"""
547    check_pasn_fils_connected_same_channel(dev, apdev, params, "FILS-SHA256")
548
549@remote_compatible
550def test_pasn_fils_sha384_connected_same_channel(dev, apdev, params):
551    """PASN FILS authentication using SHA-384 while connected same channel"""
552    check_pasn_fils_connected_same_channel(dev, apdev, params, "FILS-SHA384")
553
554def check_pasn_fils_connected_diff_channel(dev, apdev, params, key_mgmt):
555    check_pasn_capab(dev[0])
556
557    with HWSimRadio(n_channels=2) as (radio, iface):
558        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
559        wpas.interface_add(iface)
560        if wpas.get_mcc() < 2:
561           raise Exception("New radio does not support MCC")
562
563        hapd = pasn_fils_setup(wpas, apdev, params, key_mgmt);
564
565        # Connect to another AP on a different channel
566        hapd1 = hostapd.add_ap(apdev[1], {"ssid": "open", "channel" : "6"})
567        wpas.connect("open", key_mgmt="NONE", scan_freq="2437",
568                bg_scan_period="0")
569
570        hwsim_utils.test_connectivity(wpas, hapd1)
571
572        # And perform the PASN authentication with FILS
573        check_pasn_akmp_cipher(wpas, hapd, key_mgmt, "CCMP", nid="0")
574
575@remote_compatible
576def test_pasn_fils_sha256_connected_diff_channel(dev, apdev, params):
577    """PASN FILS authentication using SHA-256 while connected diff channel"""
578    check_pasn_fils_connected_diff_channel(dev, apdev, params, "FILS-SHA256")
579
580@remote_compatible
581def test_pasn_fils_sha384_connected_diff_channel(dev, apdev, params):
582    """PASN FILS authentication using SHA-384 while connected diff channel"""
583    check_pasn_fils_connected_diff_channel(dev, apdev, params, "FILS-SHA384")
584
585def test_pasn_ft_psk(dev, apdev):
586    """PASN authentication with FT-PSK"""
587    check_pasn_capab(dev[0])
588
589    ssid = "test-pasn-ft-psk"
590    passphrase = "12345678"
591
592    params = ft_params1(ssid=ssid, passphrase=passphrase)
593    params['wpa_key_mgmt'] += " PASN"
594    hapd0 = hostapd.add_ap(apdev[0], params)
595    params = ft_params2(ssid=ssid, passphrase=passphrase)
596    params['wpa_key_mgmt'] += " PASN"
597    hapd1 = hostapd.add_ap(apdev[1], params)
598
599    run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase)
600
601    if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
602        pasn_hapd = hapd1
603    else:
604        pasn_hapd = hapd0
605
606    check_pasn_akmp_cipher(dev[0], pasn_hapd, "FT-PSK", "CCMP")
607
608    run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, only_one_way=1)
609
610    if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
611        pasn_hapd = hapd1
612    else:
613        pasn_hapd = hapd0
614
615    check_pasn_akmp_cipher(dev[0], pasn_hapd, "FT-PSK", "CCMP")
616
617def test_pasn_ft_eap(dev, apdev):
618    """PASN authentication with FT-EAP"""
619    check_pasn_capab(dev[0])
620
621    ssid = "test-pasn-ft-psk"
622    passphrase = "12345678"
623    identity = "gpsk user"
624
625    radius = hostapd.radius_params()
626    params = ft_params1(ssid=ssid, passphrase=passphrase)
627    params['wpa_key_mgmt'] = "FT-EAP PASN"
628    params["ieee8021x"] = "1"
629    params = dict(list(radius.items()) + list(params.items()))
630    hapd0 = hostapd.add_ap(apdev[0], params)
631
632    params = ft_params2(ssid=ssid, passphrase=passphrase)
633    params['wpa_key_mgmt'] = "FT-EAP PASN"
634    params["ieee8021x"] = "1"
635    params = dict(list(radius.items()) + list(params.items()))
636    hapd1 = hostapd.add_ap(apdev[1], params)
637
638    run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, eap=True,
639              eap_identity=identity)
640
641    if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
642        pasn_hapd = hapd1
643    else:
644        pasn_hapd = hapd0
645
646    check_pasn_akmp_cipher(dev[0], pasn_hapd, "FT-EAP", "CCMP")
647
648def test_pasn_ft_eap_sha384(dev, apdev):
649    """PASN authentication with FT-EAP-SHA-384"""
650    check_pasn_capab(dev[0])
651
652    ssid = "test-pasn-ft-psk"
653    passphrase = "12345678"
654    identity = "gpsk user"
655
656    radius = hostapd.radius_params()
657    params = ft_params1(ssid=ssid, passphrase=passphrase)
658    params["ieee80211w"] = "2"
659    params['wpa_key_mgmt'] = "FT-EAP-SHA384 PASN"
660    params["ieee8021x"] = "1"
661    params = dict(list(radius.items()) + list(params.items()))
662    hapd0 = hostapd.add_ap(apdev[0], params)
663
664    params = ft_params2(ssid=ssid, passphrase=passphrase)
665    params["ieee80211w"] = "2"
666    params['wpa_key_mgmt'] = "FT-EAP-SHA384 PASN"
667    params["ieee8021x"] = "1"
668    params = dict(list(radius.items()) + list(params.items()))
669    hapd1 = hostapd.add_ap(apdev[1], params)
670
671    run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, eap=True,
672              sha384=True)
673
674    if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
675        pasn_hapd = hapd1
676    else:
677        pasn_hapd = hapd0
678
679    check_pasn_akmp_cipher(dev[0], pasn_hapd, "FT-EAP-SHA384", "CCMP")
680
681def test_pasn_sta_mic_error(dev, apdev):
682    """PASN authentication with WPA2/CCMP AP with corrupted MIC on station"""
683    check_pasn_capab(dev[0])
684
685    params = pasn_ap_params("PASN", "CCMP", "19")
686    hapd = hostapd.add_ap(apdev[0], params)
687
688    try:
689        # When forcing MIC corruption, the exchange would be still successful
690        # on the station side, but the AP would fail the exchange and would not
691        # store the keys.
692        dev[0].set("pasn_corrupt_mic", "1")
693        check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP", fail_ptk=True)
694    finally:
695        dev[0].set("pasn_corrupt_mic", "0")
696
697    # Now verify the successful case
698    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
699
700def test_pasn_ap_mic_error(dev, apdev):
701    """PASN authentication with WPA2/CCMP AP with corrupted MIC on AP"""
702    check_pasn_capab(dev[0])
703
704    params = pasn_ap_params("PASN", "CCMP", "19")
705    hapd0 = hostapd.add_ap(apdev[0], params)
706
707    params['pasn_corrupt_mic'] = "1"
708    hapd1 = hostapd.add_ap(apdev[1], params)
709
710    check_pasn_akmp_cipher(dev[0], hapd1, "PASN", "CCMP", status=1)
711    check_pasn_akmp_cipher(dev[0], hapd0, "PASN", "CCMP")
712
713@remote_compatible
714def test_pasn_comeback(dev, apdev, params):
715    """PASN authentication with comeback flow"""
716    check_pasn_capab(dev[0])
717
718    params = pasn_ap_params("PASN", "CCMP", "19")
719    params['sae_anti_clogging_threshold'] = '0'
720    hapd = hostapd.add_ap(apdev[0], params)
721    bssid = hapd.own_addr()
722
723    dev[0].scan(type="ONLY", freq=2412)
724    cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19" % bssid
725
726    resp = dev[0].request(cmd)
727    if "OK" not in resp:
728        raise Exception("Failed to start PASN authentication")
729
730    ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3)
731    if not ev:
732        raise Exception("PASN: PASN-AUTH-STATUS not seen")
733
734    if bssid + " akmp=PASN, status=30 comeback_after=" not in ev:
735        raise Exception("PASN: unexpected status")
736
737    comeback = re.split("comeback=", ev)[1]
738
739    cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19 comeback=%s" % \
740            (bssid, comeback)
741
742    resp = dev[0].request(cmd)
743    if "OK" not in resp:
744        raise Exception("Failed to start PASN authentication")
745
746    ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3)
747    if not ev:
748        raise Exception("PASN: PASN-AUTH-STATUS not seen")
749
750    if bssid + " akmp=PASN, status=0" not in ev:
751        raise Exception("PASN: unexpected status with comeback token")
752
753    check_pasn_ptk(dev[0], hapd, "CCMP")
754
755@remote_compatible
756def test_pasn_comeback_after_0(dev, apdev, params):
757    """PASN authentication with comeback flow with comeback after set to 0"""
758    check_pasn_capab(dev[0])
759
760    params = pasn_ap_params("PASN", "CCMP", "19")
761    params['anti_clogging_threshold'] = '0'
762    params['pasn_comeback_after'] = '0'
763    hapd = start_pasn_ap(apdev[0], params)
764
765    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
766
767@remote_compatible
768def test_pasn_comeback_after_0_sae(dev, apdev):
769    """PASN authentication with SAE, with comeback flow where comeback after is set to 0"""
770    check_pasn_capab(dev[0])
771    check_sae_capab(dev[0])
772
773    params = hostapd.wpa2_params(ssid="test-pasn-sae",
774                                 passphrase="12345678")
775    params['wpa_key_mgmt'] = 'SAE PASN'
776    params['anti_clogging_threshold'] = '0'
777    params['pasn_comeback_after'] = '0'
778    params['sae_pwe'] = "2"
779    hapd = start_pasn_ap(apdev[0], params)
780
781    try:
782        dev[0].set("sae_pwe", "2")
783        dev[0].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE",
784                       scan_freq="2412", only_add_network=True)
785
786        # first test with a valid PSK
787        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="0")
788
789        # And now with PMKSA caching
790        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP")
791
792        # And now with a wrong passphrase
793        if "FAIL" in dev[0].request("PMKSA_FLUSH"):
794            raise Exception("PMKSA_FLUSH failed")
795
796        dev[0].set_network_quoted(0, "psk", "12345678787")
797        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", status=1, nid="0")
798    finally:
799        dev[0].set("sae_pwe", "0")
800
801@remote_compatible
802def test_pasn_comeback_multi(dev, apdev):
803    """PASN authentication with SAE, with multiple stations with comeback"""
804    check_pasn_capab(dev[0])
805    check_sae_capab(dev[0])
806
807    params = hostapd.wpa2_params(ssid="test-pasn-sae",
808                                 passphrase="12345678")
809    params['wpa_key_mgmt'] = 'SAE PASN'
810    params['anti_clogging_threshold'] = '1'
811    params['pasn_comeback_after'] = '0'
812    hapd = start_pasn_ap(apdev[0], params)
813    bssid = hapd.own_addr()
814
815    id = {}
816    for i in range(0, 2):
817        dev[i].flush_scan_cache()
818        dev[i].scan(type="ONLY", freq=2412)
819        id[i] = dev[i].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE",
820                               scan_freq="2412", only_add_network=True)
821
822    for i in range(0, 2):
823        cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19, nid=%s" % (bssid, id[i])
824        resp = dev[i].request(cmd)
825
826        if "OK" not in resp:
827            raise Exception("Failed to start pasn authentication")
828
829    for i in range(0, 2):
830        ev = dev[i].wait_event(["PASN-AUTH-STATUS"], 3)
831        if not ev:
832            raise Exception("PASN: PASN-AUTH-STATUS not seen")
833
834        if bssid + " akmp=PASN, status=0" not in ev:
835            raise Exception("PASN: unexpected status")
836
837        check_pasn_ptk(dev[i], hapd, "CCMP")
838
839def test_pasn_kdk_derivation(dev, apdev):
840    """PASN authentication with forced KDK derivation"""
841    check_pasn_capab(dev[0])
842
843    params = pasn_ap_params("PASN", "CCMP", "19")
844    hapd0 = start_pasn_ap(apdev[0], params)
845
846    params['force_kdk_derivation'] = "1"
847    hapd1 = start_pasn_ap(apdev[1], params)
848
849    try:
850        check_pasn_akmp_cipher(dev[0], hapd0, "PASN", "CCMP")
851        dev[0].set("force_kdk_derivation", "1")
852        check_pasn_akmp_cipher(dev[0], hapd1, "PASN", "CCMP")
853    finally:
854        dev[0].set("force_kdk_derivation", "0")
855