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                   require_kdk=False):
52    sta_ptksa = dev.get_ptksa(hapd.own_addr(), cipher)
53    ap_ptksa = hapd.get_ptksa(dev.own_addr(), cipher)
54
55    # There's no event indicating hostapd has finished
56    # processing - so just try once more if it isn't
57    # yet available, it might become available still.
58    for i in range(10):
59        if ap_ptksa:
60            break
61        time.sleep(0.1)
62        ap_ptksa = hapd.get_ptksa(dev.own_addr(), cipher)
63
64    if not (sta_ptksa and ap_ptksa):
65        if fail_ptk:
66            return
67        if not sta_ptksa and not ap_ptksa:
68            source = 'both'
69        elif sta_ptksa:
70            source = 'ap'
71        else:
72            source = 'sta'
73        raise Exception("Could not get PTKSA entry from %s" % source)
74
75    logger.info("sta: TK: %s KDK: %s" % (sta_ptksa['tk'], sta_ptksa['kdk']))
76    logger.info("ap : TK: %s KDK: %s" % (ap_ptksa['tk'], ap_ptksa['kdk']))
77
78    if sta_ptksa['tk'] != ap_ptksa['tk'] or sta_ptksa['kdk'] != ap_ptksa['kdk']:
79        raise Exception("TK/KDK mismatch")
80    if fail_ptk:
81        raise Exception("TK/KDK match although key derivation should have failed")
82    if require_kdk and sta_ptksa['kdk'] == '':
83        raise Exception("KDK was not derived")
84    if clear_keys:
85        cmd = "PASN_DEAUTH bssid=%s" % hapd.own_addr()
86        dev.request(cmd)
87
88        # Wait a little to let the AP process the deauth
89        time.sleep(0.2)
90
91        sta_ptksa = dev.get_ptksa(hapd.own_addr(), cipher)
92        ap_ptksa = hapd.get_ptksa(dev.own_addr(), cipher)
93        if sta_ptksa or ap_ptksa:
94            raise Exception("TK/KDK not deleted as expected")
95
96def check_pasn_akmp_cipher(dev, hapd, akmp="PASN", cipher="CCMP",
97                           group="19", status=0, fail=0, nid="",
98                           fail_ptk=False):
99    dev.flush_scan_cache()
100    dev.scan(type="ONLY", freq=2412)
101
102    cmd = "PASN_START bssid=%s akmp=%s cipher=%s group=%s" % (hapd.own_addr(), akmp, cipher, group)
103
104    if nid != "":
105        cmd += " nid=%s" % nid
106
107    resp = dev.request(cmd)
108
109    if fail:
110        if "OK" in resp:
111            raise Exception("Unexpected success to start PASN authentication")
112        return
113
114    if "OK" not in resp:
115        raise Exception("Failed to start PASN authentication")
116
117    ev = dev.wait_event(["PASN-AUTH-STATUS"], 3)
118    if not ev:
119        raise Exception("PASN: PASN-AUTH-STATUS not seen")
120
121    if hapd.own_addr() + " akmp=" + akmp + ", status=" + str(status) not in ev:
122        raise Exception("PASN: unexpected status")
123
124    if status:
125        return
126
127    # There is a small window for a race condition here since the hostapd side
128    # might not yet have processed the PASN message 3 and added the PTKSA entry,
129    # so wait a bit before checking the results.
130    time.sleep(0.1)
131
132    check_pasn_ptk(dev, hapd, cipher, fail_ptk)
133
134@remote_compatible
135def test_pasn_ccmp(dev, apdev):
136    """PASN authentication with WPA2/CCMP AP"""
137    check_pasn_capab(dev[0])
138
139    params = pasn_ap_params("PASN", "CCMP", "19")
140    hapd = start_pasn_ap(apdev[0], params)
141
142    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
143
144@remote_compatible
145def test_pasn_gcmp(dev, apdev):
146    """PASN authentication with WPA2/GCMP AP"""
147    check_pasn_capab(dev[0])
148
149    params = pasn_ap_params("PASN", "GCMP", "19")
150    hapd = start_pasn_ap(apdev[0], params)
151
152    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "GCMP")
153
154@remote_compatible
155def test_pasn_ccmp_256(dev, apdev):
156    """PASN authentication with WPA2/CCMP256 AP"""
157    check_pasn_capab(dev[0])
158
159    params = pasn_ap_params("PASN", "CCMP-256", "19")
160    hapd = start_pasn_ap(apdev[0], params)
161
162    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP-256")
163
164@remote_compatible
165def test_pasn_gcmp_256(dev, apdev):
166    """PASN authentication with WPA2/GCMP-256 AP"""
167    check_pasn_capab(dev[0])
168
169    params = pasn_ap_params("PASN", "GCMP-256", "19")
170    hapd = start_pasn_ap(apdev[0], params)
171
172    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "GCMP-256")
173
174@remote_compatible
175def test_pasn_group_mismatch(dev, apdev):
176    """PASN authentication with WPA2/CCMP AP with group mismatch"""
177    check_pasn_capab(dev[0])
178
179    params = pasn_ap_params("PASN", "CCMP", "20")
180    hapd = start_pasn_ap(apdev[0], params)
181
182    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP", status=77)
183
184@remote_compatible
185def test_pasn_channel_mismatch(dev, apdev):
186    """PASN authentication with WPA2/CCMP AP with channel mismatch"""
187    check_pasn_capab(dev[0])
188
189    params = pasn_ap_params("PASN", "CCMP")
190    params['channel'] = "6"
191    hapd = start_pasn_ap(apdev[0], params)
192
193    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP", fail=1)
194
195@remote_compatible
196def test_pasn_while_connected_same_channel(dev, apdev):
197    """PASN authentication with WPA2/CCMP AP while connected same channel"""
198    check_pasn_capab(dev[0])
199
200    ssid = "test-wpa2-psk"
201    psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
202    params = hostapd.wpa2_params(ssid=ssid)
203    params['wpa_psk'] = psk
204    hapd = start_pasn_ap(apdev[0], params)
205
206    dev[0].connect(ssid, raw_psk=psk, scan_freq="2412")
207
208    params = pasn_ap_params("PASN", "CCMP")
209    hapd = start_pasn_ap(apdev[1], params)
210
211    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
212
213@remote_compatible
214def test_pasn_while_connected_same_ap(dev, apdev):
215    """PASN authentication with WPA2/CCMP AP while connected to it"""
216    check_pasn_capab(dev[0])
217
218    params = hostapd.wpa2_params(ssid="test-wpa2-psk",
219                                 passphrase="12345678")
220    hapd = start_pasn_ap(apdev[0], params)
221
222    dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412")
223
224    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP", fail=1)
225
226@remote_compatible
227def test_pasn_while_connected_diff_channel(dev, apdev):
228    """PASN authentication with WPA2/CCMP AP while connected diff channel"""
229    check_pasn_capab(dev[0])
230
231    with HWSimRadio(n_channels=2) as (radio, iface):
232        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
233        wpas.interface_add(iface)
234
235        if wpas.get_mcc() < 2:
236            raise HwsimSkip("PASN: New radio does not support MCC")
237
238        params = hostapd.wpa2_params(ssid="test-wpa2-psk",
239                                     passphrase="12345678")
240        params['channel'] = "6"
241        hapd = start_pasn_ap(apdev[0], params)
242        wpas.connect("test-wpa2-psk", psk="12345678", scan_freq="2437")
243
244        params = pasn_ap_params("PASN", "CCMP")
245        hapd2 = start_pasn_ap(apdev[1], params)
246
247        check_pasn_akmp_cipher(wpas, hapd2, "PASN", "CCMP")
248
249@remote_compatible
250def test_pasn_sae_pmksa_cache(dev, apdev):
251    """PASN authentication with SAE AP with PMKSA caching"""
252    check_pasn_capab(dev[0])
253    check_sae_capab(dev[0])
254
255    params = hostapd.wpa2_params(ssid="test-sae",
256                                 passphrase="12345678")
257    params['wpa_key_mgmt'] = 'SAE PASN'
258    params['sae_pwe'] = "2"
259    hapd = start_pasn_ap(apdev[0], params)
260
261    try:
262        dev[0].set("sae_groups", "19")
263        dev[0].set("sae_pwe", "2")
264        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412")
265
266        hapd.wait_sta()
267        hwsim_utils.test_connectivity(dev[0], hapd)
268
269        dev[0].request("DISCONNECT")
270        dev[0].wait_disconnected()
271
272        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP")
273    finally:
274        dev[0].set("sae_pwe", "0")
275
276def check_pasn_fils_pmksa_cache(dev, apdev, params, key_mgmt):
277    check_fils_capa(dev[0])
278    check_erp_capa(dev[0])
279    check_pasn_capab(dev[0])
280
281    start_erp_as(msk_dump=os.path.join(params['logdir'], "msk.lst"))
282
283    bssid = apdev[0]['bssid']
284    params = hostapd.wpa2_eap_params(ssid="fils")
285    params['wpa_key_mgmt'] = key_mgmt + " PASN"
286    params['auth_server_port'] = "18128"
287    params['erp_domain'] = 'example.com'
288    params['fils_realm'] = 'example.com'
289    hapd = start_pasn_ap(apdev[0], params)
290
291    dev[0].scan_for_bss(bssid, freq=2412)
292    dev[0].request("ERP_FLUSH")
293
294    id = dev[0].connect("fils", key_mgmt=key_mgmt,
295                        eap="PSK", identity="psk.user@example.com",
296                        password_hex="0123456789abcdef0123456789abcdef",
297                        erp="1", scan_freq="2412")
298    pmksa = dev[0].get_pmksa(bssid)
299    if pmksa is None:
300        raise Exception("No PMKSA cache entry created")
301
302    hapd.wait_sta()
303    hwsim_utils.test_connectivity(dev[0], hapd)
304
305    dev[0].request("DISCONNECT")
306    dev[0].wait_disconnected()
307
308    check_pasn_akmp_cipher(dev[0], hapd, key_mgmt, "CCMP")
309
310@remote_compatible
311def test_pasn_fils_sha256_pmksa_cache(dev, apdev, params):
312    """PASN authentication with FILS-SHA256 with PMKSA caching"""
313    check_pasn_fils_pmksa_cache(dev, apdev, params, "FILS-SHA256")
314
315@remote_compatible
316def test_pasn_fils_sha384_pmksa_cache(dev, apdev, params):
317    """PASN authentication with FILS-SHA384 with PMKSA caching"""
318    check_pasn_fils_pmksa_cache(dev, apdev, params, "FILS-SHA384")
319
320@remote_compatible
321def test_pasn_sae_kdk(dev, apdev):
322    """Station authentication with SAE AP with KDK derivation during connection"""
323    check_pasn_capab(dev[0])
324    check_sae_capab(dev[0])
325
326    try:
327        params = hostapd.wpa2_params(ssid="test-sae",
328                                     passphrase="12345678")
329        params['wpa_key_mgmt'] = 'SAE PASN'
330        params['sae_pwe'] = "2"
331        params['force_kdk_derivation'] = "1"
332        hapd = start_pasn_ap(apdev[0], params)
333
334        dev[0].set("force_kdk_derivation", "1")
335        dev[0].set("sae_groups", "")
336        dev[0].set("sae_pwe", "2")
337        dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
338                       scan_freq="2412")
339
340        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=False)
341    finally:
342        dev[0].set("force_kdk_derivation", "0")
343        dev[0].set("sae_pwe", "0")
344
345def test_pasn_sae_kdk_ft(dev, apdev):
346    """Station authentication with SAE AP with KDK derivation during connection with FT protocol"""
347    check_pasn_capab(dev[0])
348    check_sae_capab(dev[0])
349
350    try:
351        params = hostapd.wpa2_params(ssid="test-sae",
352                                     passphrase="12345678")
353        params['wpa_key_mgmt'] = 'FT-SAE'
354        params['sae_pwe'] = "2"
355        params['force_kdk_derivation'] = "1"
356        params['nas_identifier'] = "nas1.w1.fi"
357        params['r1_key_holder'] = "000102030405"
358        params['r0kh'] = ["02:00:00:00:03:00 nas1.w1.fi 100102030405060708090a0b0c0d0e0f100102030405060708090a0b0c0d0e0f",
359                          "02:00:00:00:04:00 nas2.w1.fi 300102030405060708090a0b0c0d0e0f300102030405060708090a0b0c0d0e0f"]
360        params['r1kh'] = "02:00:00:00:04:00 00:01:02:03:04:06 200102030405060708090a0b0c0d0e0f200102030405060708090a0b0c0d0e0f"
361        hapd = start_pasn_ap(apdev[0], params)
362
363        dev[0].set("force_kdk_derivation", "1")
364        dev[0].set("sae_groups", "")
365        dev[0].set("sae_pwe", "2")
366        dev[0].connect("test-sae", psk="12345678", key_mgmt="FT-SAE",
367                       scan_freq="2412")
368
369        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=False)
370
371        params = hostapd.wpa2_params(ssid="test-sae",
372                                     passphrase="12345678")
373        params['wpa_key_mgmt'] = 'FT-SAE'
374        params['sae_pwe'] = "2"
375        params['force_kdk_derivation'] = "1"
376        params['nas_identifier'] = "nas2.w1.fi"
377        params['r1_key_holder'] = "000102030406"
378        params['r0kh'] = ["02:00:00:00:03:00 nas1.w1.fi 200102030405060708090a0b0c0d0e0f200102030405060708090a0b0c0d0e0f",
379                          "02:00:00:00:04:00 nas2.w1.fi 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"]
380        params['r1kh'] = "02:00:00:00:03:00 00:01:02:03:04:05 300102030405060708090a0b0c0d0e0f300102030405060708090a0b0c0d0e0f"
381        hapd2 = start_pasn_ap(apdev[1], params)
382
383        bssid = hapd2.own_addr()
384        dev[0].scan_for_bss(bssid, freq="2412")
385        dev[0].roam(bssid)
386
387        check_pasn_ptk(dev[0], hapd2, "CCMP", clear_keys=False)
388
389        bssid = hapd.own_addr()
390        dev[0].roam(bssid)
391
392        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=False)
393    finally:
394        dev[0].set("force_kdk_derivation", "0")
395        dev[0].set("sae_pwe", "0")
396
397def check_pasn_fils_kdk(dev, apdev, params, key_mgmt):
398    check_fils_capa(dev[0])
399    check_erp_capa(dev[0])
400    check_pasn_capab(dev[0])
401
402    start_erp_as(msk_dump=os.path.join(params['logdir'], "msk.lst"))
403
404    try:
405        bssid = apdev[0]['bssid']
406        params = hostapd.wpa2_eap_params(ssid="fils")
407        params['wpa_key_mgmt'] = key_mgmt
408        params['auth_server_port'] = "18128"
409        params['erp_domain'] = 'example.com'
410        params['fils_realm'] = 'example.com'
411        params['disable_pmksa_caching'] = '1'
412        params['force_kdk_derivation'] = "1"
413        hapd = start_pasn_ap(apdev[0], params)
414
415        dev[0].scan_for_bss(bssid, freq=2412)
416        dev[0].request("ERP_FLUSH")
417        dev[0].set("force_kdk_derivation", "1")
418
419        id = dev[0].connect("fils", key_mgmt=key_mgmt,
420                            eap="PSK", identity="psk.user@example.com",
421                            password_hex="0123456789abcdef0123456789abcdef",
422                            erp="1", scan_freq="2412")
423
424        hapd.wait_sta()
425        hwsim_utils.test_connectivity(dev[0], hapd)
426
427        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=False)
428
429        dev[0].request("DISCONNECT")
430        dev[0].wait_disconnected()
431
432        dev[0].dump_monitor()
433        dev[0].select_network(id, freq=2412)
434        ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
435                                "EVENT-ASSOC-REJECT",
436                                "CTRL-EVENT-CONNECTED"], timeout=10)
437        if ev is None:
438            raise Exception("Connection using FILS/ERP timed out")
439        if "CTRL-EVENT-EAP-STARTED" in ev:
440            raise Exception("Unexpected EAP exchange")
441        if "EVENT-ASSOC-REJECT" in ev:
442            raise Exception("Association failed")
443
444        hapd.wait_sta()
445        hwsim_utils.test_connectivity(dev[0], hapd)
446
447        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=False)
448    finally:
449        dev[0].set("force_kdk_derivation", "0")
450
451@remote_compatible
452def test_pasn_fils_sha256_kdk(dev, apdev, params):
453    """Station authentication with FILS-SHA256 with KDK derivation during connection"""
454    check_pasn_fils_kdk(dev, apdev, params, "FILS-SHA256")
455
456@remote_compatible
457def test_pasn_fils_sha384_kdk(dev, apdev, params):
458    """Station authentication with FILS-SHA384 with KDK derivation during connection"""
459    check_pasn_fils_kdk(dev, apdev, params, "FILS-SHA384")
460
461@remote_compatible
462def test_pasn_sae(dev, apdev):
463    """PASN authentication with SAE AP with PMK derivation + PMKSA caching"""
464    check_pasn_capab(dev[0])
465    check_sae_capab(dev[0])
466
467    params = hostapd.wpa2_params(ssid="test-pasn-sae",
468                                 passphrase="12345678")
469    params['wpa_key_mgmt'] = 'SAE PASN'
470    params['sae_pwe'] = "2"
471    hapd = start_pasn_ap(apdev[0], params)
472
473    try:
474        dev[0].set("sae_pwe", "2")
475        dev[0].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE",
476                       scan_freq="2412", only_add_network=True)
477
478        # first test with a valid PSK
479        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="0")
480
481        # And now with PMKSA caching
482        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP")
483
484        # And now with a wrong passphrase
485        if "FAIL" in dev[0].request("PMKSA_FLUSH"):
486            raise Exception("PMKSA_FLUSH failed")
487
488        dev[0].set_network_quoted(0, "psk", "12345678787")
489        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", status=1, nid="0")
490    finally:
491        dev[0].set("sae_pwe", "0")
492
493@remote_compatible
494def test_pasn_sae_while_connected_same_channel(dev, apdev):
495    """PASN SAE authentication while connected same channel"""
496    check_pasn_capab(dev[0])
497    check_sae_capab(dev[0])
498
499    params = hostapd.wpa2_params(ssid="test-pasn-wpa2-psk",
500                                 passphrase="12345678")
501    hapd = hostapd.add_ap(apdev[0], params)
502
503    try:
504        dev[0].set("sae_pwe", "2")
505        dev[0].connect("test-pasn-wpa2-psk", psk="12345678", scan_freq="2412")
506
507        params = hostapd.wpa2_params(ssid="test-pasn-sae",
508                                     passphrase="12345678")
509
510        params['wpa_key_mgmt'] = 'SAE PASN'
511        params['sae_pwe'] = "2"
512        hapd = start_pasn_ap(apdev[1], params)
513
514        dev[0].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE",
515                       scan_freq="2412", only_add_network=True)
516
517        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="1")
518    finally:
519        dev[0].set("sae_pwe", "0")
520
521@remote_compatible
522def test_pasn_sae_while_connected_diff_channel(dev, apdev):
523    """PASN SAE authentication while connected diff channel"""
524    check_pasn_capab(dev[0])
525    check_sae_capab(dev[0])
526
527    with HWSimRadio(n_channels=2) as (radio, iface):
528        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
529        wpas.interface_add(iface)
530
531        if wpas.get_mcc() < 2:
532            raise HwsimSkip("PASN: New radio does not support MCC")
533
534        params = hostapd.wpa2_params(ssid="test-pasn-wpa2-psk",
535                                     passphrase="12345678")
536        params['channel'] = "6"
537        hapd = hostapd.add_ap(apdev[0], params)
538
539        try:
540            wpas.set("sae_pwe", "2")
541            wpas.connect("test-pasn-wpa2-psk", psk="12345678", scan_freq="2437")
542
543            params = hostapd.wpa2_params(ssid="test-pasn-sae",
544                                         passphrase="12345678")
545
546            params['wpa_key_mgmt'] = 'SAE PASN'
547            params['sae_pwe'] = "2"
548            hapd = start_pasn_ap(apdev[1], params)
549
550            wpas.connect("test-pasn-sae", psk="12345678", key_mgmt="SAE",
551                           scan_freq="2412", only_add_network=True)
552
553            check_pasn_akmp_cipher(wpas, hapd, "SAE", "CCMP", nid="1")
554        finally:
555            wpas.set("sae_pwe", "0")
556
557def pasn_fils_setup(wpas, apdev, params, key_mgmt):
558    check_fils_capa(wpas)
559    check_erp_capa(wpas)
560
561    wpas.flush_scan_cache()
562
563    start_erp_as(msk_dump=os.path.join(params['logdir'], "msk.lst"))
564
565    bssid = apdev[0]['bssid']
566    params = hostapd.wpa2_eap_params(ssid="fils")
567    params['wpa_key_mgmt'] = key_mgmt + " PASN"
568    params['auth_server_port'] = "18128"
569    params['erp_domain'] = 'example.com'
570    params['fils_realm'] = 'example.com'
571    params['disable_pmksa_caching'] = '1'
572    hapd = hostapd.add_ap(apdev[0], params)
573
574    id = wpas.connect("fils", key_mgmt=key_mgmt,
575                      eap="PSK", identity="psk.user@example.com",
576                      password_hex="0123456789abcdef0123456789abcdef",
577                      erp="1", scan_freq="2412")
578
579    wpas.request("DISCONNECT")
580    wpas.wait_disconnected()
581    wpas.dump_monitor()
582
583    if "FAIL" in wpas.request("PMKSA_FLUSH"):
584        raise Exception("PMKSA_FLUSH failed")
585
586    return hapd
587
588def check_pasn_fils(dev, apdev, params, key_mgmt):
589    check_pasn_capab(dev[0])
590
591    hapd = pasn_fils_setup(dev[0], apdev, params, key_mgmt);
592    check_pasn_akmp_cipher(dev[0], hapd, key_mgmt, "CCMP", nid="0")
593
594@remote_compatible
595def test_pasn_fils_sha256(dev, apdev, params):
596    """PASN FILS authentication using SHA-256"""
597    check_pasn_fils(dev, apdev, params, "FILS-SHA256")
598
599@remote_compatible
600def test_pasn_fils_sha384(dev, apdev, params):
601    """PASN FILS authentication using SHA-384"""
602    check_pasn_fils(dev, apdev, params, "FILS-SHA384")
603
604def check_pasn_fils_connected_same_channel(dev, apdev, params, key_mgmt):
605    check_pasn_capab(dev[0])
606
607    hapd = pasn_fils_setup(dev[0], apdev, params, key_mgmt);
608
609    # Connect to another AP on the same channel
610    hapd1 = hostapd.add_ap(apdev[1], {"ssid": "open"})
611    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
612                   bg_scan_period="0")
613
614    hwsim_utils.test_connectivity(dev[0], hapd1)
615
616    # And perform the PASN authentication with FILS
617    check_pasn_akmp_cipher(dev[0], hapd, key_mgmt, "CCMP", nid="0")
618
619@remote_compatible
620def test_pasn_fils_sha256_connected_same_channel(dev, apdev, params):
621    """PASN FILS authentication using SHA-256 while connected same channel"""
622    check_pasn_fils_connected_same_channel(dev, apdev, params, "FILS-SHA256")
623
624@remote_compatible
625def test_pasn_fils_sha384_connected_same_channel(dev, apdev, params):
626    """PASN FILS authentication using SHA-384 while connected same channel"""
627    check_pasn_fils_connected_same_channel(dev, apdev, params, "FILS-SHA384")
628
629def check_pasn_fils_connected_diff_channel(dev, apdev, params, key_mgmt):
630    check_pasn_capab(dev[0])
631
632    with HWSimRadio(n_channels=2) as (radio, iface):
633        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
634        wpas.interface_add(iface)
635        if wpas.get_mcc() < 2:
636           raise Exception("New radio does not support MCC")
637
638        hapd = pasn_fils_setup(wpas, apdev, params, key_mgmt);
639
640        # Connect to another AP on a different channel
641        hapd1 = hostapd.add_ap(apdev[1], {"ssid": "open", "channel" : "6"})
642        wpas.connect("open", key_mgmt="NONE", scan_freq="2437",
643                bg_scan_period="0")
644
645        hwsim_utils.test_connectivity(wpas, hapd1)
646
647        # And perform the PASN authentication with FILS
648        check_pasn_akmp_cipher(wpas, hapd, key_mgmt, "CCMP", nid="0")
649
650@remote_compatible
651def test_pasn_fils_sha256_connected_diff_channel(dev, apdev, params):
652    """PASN FILS authentication using SHA-256 while connected diff channel"""
653    check_pasn_fils_connected_diff_channel(dev, apdev, params, "FILS-SHA256")
654
655@remote_compatible
656def test_pasn_fils_sha384_connected_diff_channel(dev, apdev, params):
657    """PASN FILS authentication using SHA-384 while connected diff channel"""
658    check_pasn_fils_connected_diff_channel(dev, apdev, params, "FILS-SHA384")
659
660def test_pasn_ft_psk(dev, apdev):
661    """PASN authentication with FT-PSK"""
662    check_pasn_capab(dev[0])
663
664    ssid = "test-pasn-ft-psk"
665    passphrase = "12345678"
666
667    params = ft_params1(ssid=ssid, passphrase=passphrase)
668    params['wpa_key_mgmt'] += " PASN"
669    hapd0 = hostapd.add_ap(apdev[0], params)
670    params = ft_params2(ssid=ssid, passphrase=passphrase)
671    params['wpa_key_mgmt'] += " PASN"
672    hapd1 = hostapd.add_ap(apdev[1], params)
673
674    run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase)
675
676    if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
677        pasn_hapd = hapd1
678    else:
679        pasn_hapd = hapd0
680
681    check_pasn_akmp_cipher(dev[0], pasn_hapd, "FT-PSK", "CCMP")
682
683    run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, only_one_way=1)
684
685    if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
686        pasn_hapd = hapd1
687    else:
688        pasn_hapd = hapd0
689
690    check_pasn_akmp_cipher(dev[0], pasn_hapd, "FT-PSK", "CCMP")
691
692def test_pasn_ft_eap(dev, apdev):
693    """PASN authentication with FT-EAP"""
694    check_pasn_capab(dev[0])
695
696    ssid = "test-pasn-ft-psk"
697    passphrase = "12345678"
698    identity = "gpsk user"
699
700    radius = hostapd.radius_params()
701    params = ft_params1(ssid=ssid, passphrase=passphrase)
702    params['wpa_key_mgmt'] = "FT-EAP PASN"
703    params["ieee8021x"] = "1"
704    params = dict(list(radius.items()) + list(params.items()))
705    hapd0 = hostapd.add_ap(apdev[0], params)
706
707    params = ft_params2(ssid=ssid, passphrase=passphrase)
708    params['wpa_key_mgmt'] = "FT-EAP PASN"
709    params["ieee8021x"] = "1"
710    params = dict(list(radius.items()) + list(params.items()))
711    hapd1 = hostapd.add_ap(apdev[1], params)
712
713    run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, eap=True,
714              eap_identity=identity)
715
716    if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
717        pasn_hapd = hapd1
718    else:
719        pasn_hapd = hapd0
720
721    check_pasn_akmp_cipher(dev[0], pasn_hapd, "FT-EAP", "CCMP")
722
723def test_pasn_ft_eap_sha384(dev, apdev):
724    """PASN authentication with FT-EAP-SHA-384"""
725    check_pasn_capab(dev[0])
726
727    ssid = "test-pasn-ft-psk"
728    passphrase = "12345678"
729    identity = "gpsk user"
730
731    radius = hostapd.radius_params()
732    params = ft_params1(ssid=ssid, passphrase=passphrase)
733    params["ieee80211w"] = "2"
734    params['wpa_key_mgmt'] = "FT-EAP-SHA384 PASN"
735    params["ieee8021x"] = "1"
736    params = dict(list(radius.items()) + list(params.items()))
737    hapd0 = hostapd.add_ap(apdev[0], params)
738
739    params = ft_params2(ssid=ssid, passphrase=passphrase)
740    params["ieee80211w"] = "2"
741    params['wpa_key_mgmt'] = "FT-EAP-SHA384 PASN"
742    params["ieee8021x"] = "1"
743    params = dict(list(radius.items()) + list(params.items()))
744    hapd1 = hostapd.add_ap(apdev[1], params)
745
746    run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, eap=True,
747              sha384=True)
748
749    if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
750        pasn_hapd = hapd1
751    else:
752        pasn_hapd = hapd0
753
754    check_pasn_akmp_cipher(dev[0], pasn_hapd, "FT-EAP-SHA384", "CCMP")
755
756def test_pasn_sta_mic_error(dev, apdev):
757    """PASN authentication with WPA2/CCMP AP with corrupted MIC on station"""
758    check_pasn_capab(dev[0])
759
760    params = pasn_ap_params("PASN", "CCMP", "19")
761    hapd = hostapd.add_ap(apdev[0], params)
762
763    try:
764        # When forcing MIC corruption, the exchange would be still successful
765        # on the station side, but the AP would fail the exchange and would not
766        # store the keys.
767        dev[0].set("pasn_corrupt_mic", "1")
768        check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP", fail_ptk=True)
769    finally:
770        dev[0].set("pasn_corrupt_mic", "0")
771
772    # Now verify the successful case
773    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
774
775def test_pasn_ap_mic_error(dev, apdev):
776    """PASN authentication with WPA2/CCMP AP with corrupted MIC on AP"""
777    check_pasn_capab(dev[0])
778
779    params = pasn_ap_params("PASN", "CCMP", "19")
780    hapd0 = hostapd.add_ap(apdev[0], params)
781
782    params['pasn_corrupt_mic'] = "1"
783    hapd1 = hostapd.add_ap(apdev[1], params)
784
785    check_pasn_akmp_cipher(dev[0], hapd1, "PASN", "CCMP", status=1)
786    check_pasn_akmp_cipher(dev[0], hapd0, "PASN", "CCMP")
787
788@remote_compatible
789def test_pasn_comeback(dev, apdev, params):
790    """PASN authentication with comeback flow"""
791    check_pasn_capab(dev[0])
792
793    params = pasn_ap_params("PASN", "CCMP", "19")
794    params['sae_anti_clogging_threshold'] = '0'
795    hapd = hostapd.add_ap(apdev[0], params)
796    bssid = hapd.own_addr()
797
798    dev[0].scan(type="ONLY", freq=2412)
799    cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19" % bssid
800
801    resp = dev[0].request(cmd)
802    if "OK" not in resp:
803        raise Exception("Failed to start PASN authentication")
804
805    ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3)
806    if not ev:
807        raise Exception("PASN: PASN-AUTH-STATUS not seen")
808
809    if bssid + " akmp=PASN, status=30 comeback_after=" not in ev:
810        raise Exception("PASN: unexpected status")
811
812    comeback = re.split("comeback=", ev)[1]
813
814    cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19 comeback=%s" % \
815            (bssid, comeback)
816
817    resp = dev[0].request(cmd)
818    if "OK" not in resp:
819        raise Exception("Failed to start PASN authentication")
820
821    ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3)
822    if not ev:
823        raise Exception("PASN: PASN-AUTH-STATUS not seen")
824
825    if bssid + " akmp=PASN, status=0" not in ev:
826        raise Exception("PASN: unexpected status with comeback token")
827
828    check_pasn_ptk(dev[0], hapd, "CCMP")
829
830@remote_compatible
831def test_pasn_comeback_after_0(dev, apdev, params):
832    """PASN authentication with comeback flow with comeback after set to 0"""
833    check_pasn_capab(dev[0])
834
835    params = pasn_ap_params("PASN", "CCMP", "19")
836    params['anti_clogging_threshold'] = '0'
837    params['pasn_comeback_after'] = '0'
838    hapd = start_pasn_ap(apdev[0], params)
839
840    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
841
842@remote_compatible
843def test_pasn_comeback_after_0_sae(dev, apdev):
844    """PASN authentication with SAE, with comeback flow where comeback after is set to 0"""
845    check_pasn_capab(dev[0])
846    check_sae_capab(dev[0])
847
848    params = hostapd.wpa2_params(ssid="test-pasn-sae",
849                                 passphrase="12345678")
850    params['wpa_key_mgmt'] = 'SAE PASN'
851    params['anti_clogging_threshold'] = '0'
852    params['pasn_comeback_after'] = '0'
853    params['sae_pwe'] = "2"
854    hapd = start_pasn_ap(apdev[0], params)
855
856    try:
857        dev[0].set("sae_pwe", "2")
858        dev[0].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE",
859                       scan_freq="2412", only_add_network=True)
860
861        # first test with a valid PSK
862        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="0")
863
864        # And now with PMKSA caching
865        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP")
866
867        # And now with a wrong passphrase
868        if "FAIL" in dev[0].request("PMKSA_FLUSH"):
869            raise Exception("PMKSA_FLUSH failed")
870
871        dev[0].set_network_quoted(0, "psk", "12345678787")
872        check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", status=1, nid="0")
873    finally:
874        dev[0].set("sae_pwe", "0")
875
876@remote_compatible
877def test_pasn_comeback_multi(dev, apdev):
878    """PASN authentication with SAE, with multiple stations with comeback"""
879    check_pasn_capab(dev[0])
880    check_sae_capab(dev[0])
881
882    params = hostapd.wpa2_params(ssid="test-pasn-sae",
883                                 passphrase="12345678")
884    params['wpa_key_mgmt'] = 'SAE PASN'
885    params['anti_clogging_threshold'] = '1'
886    params['pasn_comeback_after'] = '0'
887    hapd = start_pasn_ap(apdev[0], params)
888    bssid = hapd.own_addr()
889
890    id = {}
891    for i in range(0, 2):
892        dev[i].flush_scan_cache()
893        dev[i].scan(type="ONLY", freq=2412)
894        id[i] = dev[i].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE",
895                               scan_freq="2412", only_add_network=True)
896
897    for i in range(0, 2):
898        cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19, nid=%s" % (bssid, id[i])
899        resp = dev[i].request(cmd)
900
901        if "OK" not in resp:
902            raise Exception("Failed to start pasn authentication")
903
904    for i in range(0, 2):
905        ev = dev[i].wait_event(["PASN-AUTH-STATUS"], 3)
906        if not ev:
907            raise Exception("PASN: PASN-AUTH-STATUS not seen")
908
909        if bssid + " akmp=PASN, status=0" not in ev:
910            raise Exception("PASN: unexpected status")
911
912        check_pasn_ptk(dev[i], hapd, "CCMP")
913
914def test_pasn_kdk_derivation(dev, apdev):
915    """PASN authentication with forced KDK derivation"""
916    check_pasn_capab(dev[0])
917
918    params = pasn_ap_params("PASN", "CCMP", "19")
919    hapd0 = start_pasn_ap(apdev[0], params)
920
921    params['force_kdk_derivation'] = "1"
922    hapd1 = start_pasn_ap(apdev[1], params)
923
924    try:
925        check_pasn_akmp_cipher(dev[0], hapd0, "PASN", "CCMP")
926        dev[0].set("force_kdk_derivation", "1")
927        check_pasn_akmp_cipher(dev[0], hapd1, "PASN", "CCMP")
928    finally:
929        dev[0].set("force_kdk_derivation", "0")
930
931def test_pasn_sae_kdk_secure_ltf(dev, apdev):
932    """Station authentication with SAE AP with KDK derivation during connection based on Secure LTF support"""
933    params = hostapd.wpa2_params(ssid="test-sae",
934                                 passphrase="12345678")
935    params['wpa_key_mgmt'] = 'SAE'
936    params['sae_pwe'] = "2"
937    params['driver_params'] = "secure_ltf=1"
938    hapd = start_pasn_ap(apdev[0], params)
939
940    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
941    wpas.interface_add("wlan5", drv_params="secure_ltf=1")
942    check_pasn_capab(wpas)
943    check_sae_capab(wpas)
944
945    try:
946        wpas.set("sae_groups", "")
947        wpas.set("sae_pwe", "2")
948        wpas.connect("test-sae", psk="12345678", key_mgmt="SAE",
949                     scan_freq="2412")
950
951        check_pasn_ptk(wpas, hapd, "CCMP", clear_keys=False, require_kdk=True)
952    finally:
953        wpas.set("sae_pwe", "0")
954
955def test_pasn_owe_kdk_secure_ltf(dev, apdev):
956    """Station authentication with OWE AP with KDK derivation during connection based on Secure LTF support"""
957    params = {"ssid": "owe",
958              "wpa": "2",
959              "ieee80211w": "2",
960              "wpa_key_mgmt": "OWE",
961              "rsn_pairwise": "CCMP"}
962    params['driver_params'] = "secure_ltf=1"
963    hapd = start_pasn_ap(apdev[0], params)
964
965    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
966    wpas.interface_add("wlan5", drv_params="secure_ltf=1")
967    check_pasn_capab(wpas)
968    check_owe_capab(wpas)
969
970    wpas.connect("owe", key_mgmt="OWE", ieee80211w="2", scan_freq="2412")
971
972    check_pasn_ptk(wpas, hapd, "CCMP", clear_keys=False, require_kdk=True)
973
974def test_pasn_owe_tm_kdk_secure_ltf(dev, apdev):
975    """Station authentication with OWE transition mode AP with KDK derivation during connection based on Secure LTF support"""
976    params = {"ssid": "owe-random",
977              "wpa": "2",
978              "ieee80211w": "2",
979              "wpa_key_mgmt": "OWE",
980              "rsn_pairwise": "CCMP",
981              "owe_transition_bssid": apdev[1]['bssid'],
982              "owe_transition_ssid": '"owe-test"',
983              "ignore_broadcast_ssid": "1",
984              'driver_params': "secure_ltf=1"}
985    hapd = start_pasn_ap(apdev[0], params)
986    bssid = hapd.own_addr()
987
988    params = {"ssid": "owe-test",
989              "owe_transition_bssid": apdev[0]['bssid'],
990              "owe_transition_ssid": '"owe-random"',
991              'driver_params': "secure_ltf=1"}
992    hapd2 = hostapd.add_ap(apdev[1], params)
993    bssid2 = hapd2.own_addr()
994
995    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
996    wpas.interface_add("wlan5", drv_params="secure_ltf=1")
997    check_pasn_capab(wpas)
998    check_owe_capab(wpas)
999    wpas.flush_scan_cache()
1000
1001    wpas.scan_for_bss(bssid, freq="2412")
1002    wpas.scan_for_bss(bssid2, freq="2412")
1003
1004    wpas.connect("owe-test", key_mgmt="OWE", ieee80211w="2", scan_freq="2412")
1005
1006    check_pasn_ptk(wpas, hapd, "CCMP", clear_keys=False, require_kdk=True)
1007
1008    wpas.scan(type="ONLY", freq=2412)
1009
1010    wpas.request("DISCONNECT")
1011    wpas.wait_disconnected()
1012    wpas.request("RECONNECT")
1013    wpas.wait_connected()
1014    check_pasn_ptk(wpas, hapd, "CCMP", clear_keys=False, require_kdk=True)
1015
1016def test_pasn_noauth_0(dev, apdev):
1017    """PASN without mutual authentication disabled on the AP"""
1018    check_pasn_capab(dev[0])
1019
1020    params = pasn_ap_params("PASN", "CCMP", "19")
1021    params["pasn_noauth"] = "0"
1022    hapd = start_pasn_ap(apdev[0], params)
1023
1024    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP", status=1)
1025
1026def test_pasn_sae_driver(dev, apdev):
1027    """PASN authentication using driver event as trigger"""
1028    check_pasn_capab(dev[0])
1029    check_sae_capab(dev[0])
1030
1031    params = hostapd.wpa2_params(ssid="test-pasn-sae",
1032                                 passphrase="12345678")
1033    params['ieee80211w'] = "2"
1034    params['wpa_key_mgmt'] = 'SAE SAE-EXT-KEY PASN'
1035    params['sae_pwe'] = "2"
1036    hapd = start_pasn_ap(apdev[0], params)
1037    bssid = hapd.own_addr()
1038
1039    params = hostapd.wpa2_params(ssid="test-pasn-sae",
1040                                 passphrase="12345678")
1041    params['wpa_key_mgmt'] = 'SAE PASN'
1042    params['sae_pwe'] = "0"
1043    hapd2 = start_pasn_ap(apdev[1], params)
1044    bssid2 = hapd2.own_addr()
1045
1046    dev[0].scan_for_bss(bssid, freq=2412)
1047    dev[0].scan_for_bss(bssid2, freq=2412)
1048
1049    try:
1050        dev[0].set("sae_pwe", "2")
1051        cmd = f"PASN_DRIVER auth {bssid} 02:11:22:33:44:55 {bssid2}"
1052        if "OK" not in dev[0].request(cmd):
1053            raise Exception("PASN_DRIVER failed")
1054
1055        ev = dev[0].wait_event(["PASN-AUTH-STATUS"], timeout=10)
1056        if ev is None:
1057            raise Exception("No PASN-AUTH-STATUS event (1)")
1058        if f"{bssid} akmp=PASN, status=0" not in ev:
1059            raise Exception("Unexpected event 1 contents: " + ev)
1060
1061        ev = dev[0].wait_event(["PASN-AUTH-STATUS"], timeout=10)
1062        if ev is None:
1063            raise Exception("No PASN-AUTH-STATUS event (2)")
1064        if f"{bssid2} akmp=PASN, status=0" not in ev:
1065            raise Exception("Unexpected event 2 contents: " + ev)
1066
1067        hapd2.disable()
1068        time.sleep(1)
1069        dev[0].dump_monitor()
1070
1071        if "OK" not in dev[0].request(cmd):
1072            raise Exception("PASN_DRIVER failed")
1073
1074        ev = dev[0].wait_event(["PASN-AUTH-STATUS"], timeout=10)
1075        if ev is None:
1076            raise Exception("No PASN-AUTH-STATUS event (1b)")
1077        if f"{bssid} akmp=PASN, status=0" not in ev:
1078            raise Exception("Unexpected event 1b contents: " + ev)
1079
1080        ev = dev[0].wait_event(["PASN-AUTH-STATUS"], timeout=10)
1081        if ev is None:
1082            raise Exception("No PASN-AUTH-STATUS event (2b)")
1083        if f"{bssid2} akmp=PASN, status=1" not in ev:
1084            raise Exception("Unexpected event 2b contents: " + ev)
1085    finally:
1086        dev[0].set("sae_pwe", "0")
1087