1# Test cases for Opportunistic Wireless Encryption (OWE)
2# Copyright (c) 2017, 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 time
11import os
12import struct
13
14import hostapd
15from wpasupplicant import WpaSupplicant
16import hwsim_utils
17from tshark import run_tshark
18from utils import HwsimSkip, fail_test, alloc_fail, wait_fail_trigger
19from test_ap_acs import wait_acs
20
21def test_owe(dev, apdev):
22    """Opportunistic Wireless Encryption"""
23    if "OWE" not in dev[0].get_capability("key_mgmt"):
24        raise HwsimSkip("OWE not supported")
25    params = {"ssid": "owe",
26              "wpa": "2",
27              "ieee80211w": "2",
28              "wpa_key_mgmt": "OWE",
29              "rsn_pairwise": "CCMP"}
30    hapd = hostapd.add_ap(apdev[0], params)
31    bssid = hapd.own_addr()
32    conf = hapd.request("GET_CONFIG")
33    if "key_mgmt=OWE" not in conf.splitlines():
34        logger.info("GET_CONFIG:\n" + conf)
35        raise Exception("GET_CONFIG did not report correct key_mgmt")
36
37    dev[0].scan_for_bss(bssid, freq="2412")
38    bss = dev[0].get_bss(bssid)
39    if "[WPA2-OWE-CCMP]" not in bss['flags']:
40        raise Exception("OWE AKM not recognized: " + bss['flags'])
41
42    id = dev[0].connect("owe", key_mgmt="OWE", ieee80211w="2", scan_freq="2412")
43    hapd.wait_sta()
44    pmk_h = hapd.request("GET_PMK " + dev[0].own_addr())
45    pmk_w = dev[0].get_pmk(id)
46    if pmk_h != pmk_w:
47        raise Exception("Fetched PMK does not match: hostapd %s, wpa_supplicant %s" % (pmk_h, pmk_w))
48    hwsim_utils.test_connectivity(dev[0], hapd)
49    val = dev[0].get_status_field("key_mgmt")
50    if val != "OWE":
51        raise Exception("Unexpected key_mgmt: " + val)
52
53def test_owe_groups(dev, apdev):
54    """Opportunistic Wireless Encryption - DH groups"""
55    if "OWE" not in dev[0].get_capability("key_mgmt"):
56        raise HwsimSkip("OWE not supported")
57    params = {"ssid": "owe",
58              "wpa": "2",
59              "wpa_key_mgmt": "OWE",
60              "rsn_pairwise": "CCMP"}
61    hapd = hostapd.add_ap(apdev[0], params)
62    bssid = hapd.own_addr()
63
64    dev[0].scan_for_bss(bssid, freq="2412")
65    for group in [19, 20, 21]:
66        dev[0].connect("owe", key_mgmt="OWE", owe_group=str(group))
67        hapd.wait_sta()
68        hwsim_utils.test_connectivity(dev[0], hapd)
69        dev[0].request("REMOVE_NETWORK all")
70        dev[0].wait_disconnected()
71        dev[0].dump_monitor()
72        hapd.dump_monitor()
73
74def test_owe_pmksa_caching(dev, apdev):
75    """Opportunistic Wireless Encryption and PMKSA caching"""
76    try:
77        run_owe_pmksa_caching(dev, apdev)
78    finally:
79        dev[0].set("reassoc_same_bss_optim", "0")
80
81def test_owe_pmksa_caching_connect_cmd(dev, apdev):
82    """Opportunistic Wireless Encryption and PMKSA caching using cfg80211 connect command"""
83    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
84    wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
85    try:
86        run_owe_pmksa_caching([wpas], apdev)
87    finally:
88        wpas.set("reassoc_same_bss_optim", "0")
89
90def run_owe_pmksa_caching(dev, apdev):
91    if "OWE" not in dev[0].get_capability("key_mgmt"):
92        raise HwsimSkip("OWE not supported")
93    params = {"ssid": "owe",
94              "wpa": "2",
95              "wpa_key_mgmt": "OWE",
96              "rsn_pairwise": "CCMP"}
97    hapd = hostapd.add_ap(apdev[0], params)
98    bssid = hapd.own_addr()
99
100    dev[0].set("reassoc_same_bss_optim", "1")
101    dev[0].scan_for_bss(bssid, freq="2412")
102    id = dev[0].connect("owe", key_mgmt="OWE")
103    hapd.wait_sta()
104    hwsim_utils.test_connectivity(dev[0], hapd)
105    pmksa = dev[0].get_pmksa(bssid)
106    dev[0].request("DISCONNECT")
107    dev[0].wait_disconnected()
108    dev[0].dump_monitor()
109
110    dev[0].select_network(id, 2412)
111    dev[0].wait_connected()
112    hapd.wait_sta()
113    hwsim_utils.test_connectivity(dev[0], hapd)
114    pmksa2 = dev[0].get_pmksa(bssid)
115    dev[0].request("DISCONNECT")
116    dev[0].wait_disconnected()
117    dev[0].dump_monitor()
118
119    if "OK" not in hapd.request("PMKSA_FLUSH"):
120        raise Exception("PMKSA_FLUSH failed")
121
122    dev[0].select_network(id, 2412)
123    dev[0].wait_connected()
124    hapd.wait_sta()
125    hwsim_utils.test_connectivity(dev[0], hapd)
126    pmksa3 = dev[0].get_pmksa(bssid)
127
128    if pmksa is None or pmksa2 is None or pmksa3 is None:
129        raise Exception("PMKSA entry missing")
130    if pmksa['pmkid'] != pmksa2['pmkid']:
131        raise Exception("Unexpected PMKID change when using PMKSA caching")
132    if pmksa['pmkid'] == pmksa3['pmkid']:
133        raise Exception("PMKID did not change after PMKSA cache flush")
134
135    dev[0].request("REASSOCIATE")
136    dev[0].wait_connected()
137    pmksa4 = dev[0].get_pmksa(bssid)
138    if pmksa3['pmkid'] != pmksa4['pmkid']:
139        raise Exception("Unexpected PMKID change when using PMKSA caching [2]")
140
141def test_owe_and_psk(dev, apdev):
142    """Opportunistic Wireless Encryption and WPA2-PSK enabled"""
143    if "OWE" not in dev[0].get_capability("key_mgmt"):
144        raise HwsimSkip("OWE not supported")
145    params = {"ssid": "owe+psk",
146              "wpa": "2",
147              "wpa_key_mgmt": "OWE WPA-PSK",
148              "rsn_pairwise": "CCMP",
149              "wpa_passphrase": "12345678"}
150    hapd = hostapd.add_ap(apdev[0], params)
151    bssid = hapd.own_addr()
152
153    dev[0].scan_for_bss(bssid, freq="2412")
154    dev[0].connect("owe+psk", psk="12345678")
155    hapd.wait_sta()
156    hwsim_utils.test_connectivity(dev[0], hapd)
157
158    dev[1].scan_for_bss(bssid, freq="2412")
159    dev[1].connect("owe+psk", key_mgmt="OWE")
160    hapd.wait_sta()
161    hwsim_utils.test_connectivity(dev[1], hapd)
162
163def test_owe_transition_mode(dev, apdev):
164    """Opportunistic Wireless Encryption transition mode"""
165    run_owe_transition_mode(dev, apdev)
166
167def test_owe_transition_mode_connect_cmd(dev, apdev):
168    """Opportunistic Wireless Encryption transition mode using cfg80211 connect command"""
169    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
170    wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
171    run_owe_transition_mode([wpas], apdev)
172
173def test_owe_transition_mode_mismatch1(dev, apdev):
174    """Opportunistic Wireless Encryption transition mode (mismatch 1)"""
175    run_owe_transition_mode(dev, apdev, adv_bssid0="02:11:22:33:44:55")
176
177def test_owe_transition_mode_mismatch2(dev, apdev):
178    """Opportunistic Wireless Encryption transition mode (mismatch 2)"""
179    run_owe_transition_mode(dev, apdev, adv_bssid1="02:11:22:33:44:66")
180
181def test_owe_transition_mode_mismatch3(dev, apdev):
182    """Opportunistic Wireless Encryption transition mode (mismatch 3)"""
183    run_owe_transition_mode(dev, apdev, adv_bssid0="02:11:22:33:44:55",
184                            adv_bssid1="02:11:22:33:44:66")
185
186def run_owe_transition_mode(dev, apdev, adv_bssid0=None, adv_bssid1=None):
187    if "OWE" not in dev[0].get_capability("key_mgmt"):
188        raise HwsimSkip("OWE not supported")
189    dev[0].flush_scan_cache()
190    adv_bssid = adv_bssid0 if adv_bssid0 else apdev[1]['bssid']
191    params = {"ssid": "owe-random",
192              "wpa": "2",
193              "wpa_key_mgmt": "OWE",
194              "rsn_pairwise": "CCMP",
195              "ieee80211w": "2",
196              "owe_transition_bssid": adv_bssid,
197              "owe_transition_ssid": '"owe-test"',
198              "ignore_broadcast_ssid": "1"}
199    hapd = hostapd.add_ap(apdev[0], params)
200    bssid = hapd.own_addr()
201
202    adv_bssid = adv_bssid1 if adv_bssid1 else apdev[0]['bssid']
203    params = {"ssid": "owe-test",
204              "owe_transition_bssid": adv_bssid,
205              "owe_transition_ssid": '"owe-random"'}
206    hapd2 = hostapd.add_ap(apdev[1], params)
207    bssid2 = hapd2.own_addr()
208
209    dev[0].scan_for_bss(bssid, freq="2412")
210    dev[0].scan_for_bss(bssid2, freq="2412")
211
212    bss = dev[0].get_bss(bssid)
213    if "[WPA2-OWE-CCMP]" not in bss['flags']:
214        raise Exception("OWE AKM not recognized: " + bss['flags'])
215    if "[OWE-TRANS]" not in bss['flags']:
216        raise Exception("OWE transition not recognized: " + bss['flags'])
217
218    bss = dev[0].get_bss(bssid2)
219    if "[OWE-TRANS-OPEN]" not in bss['flags']:
220        raise Exception("OWE transition (open) not recognized: " + bss['flags'])
221
222    id = dev[0].connect("owe-test", key_mgmt="OWE", ieee80211w="2",
223                        scan_freq="2412")
224    hapd.wait_sta()
225    hwsim_utils.test_connectivity(dev[0], hapd)
226    val = dev[0].get_status_field("key_mgmt")
227    if val != "OWE":
228        raise Exception("Unexpected key_mgmt: " + val)
229
230    logger.info("Move to OWE only mode (disable transition mode)")
231
232    dev[0].request("DISCONNECT")
233    dev[0].wait_disconnected()
234    dev[0].dump_monitor()
235
236    hapd2.disable()
237    hapd.disable()
238    dev[0].flush_scan_cache()
239    hapd.set("owe_transition_bssid", "00:00:00:00:00:00")
240    hapd.set("ignore_broadcast_ssid", '0')
241    hapd.set("ssid", 'owe-test')
242    hapd.enable()
243
244    dev[0].scan_for_bss(bssid, freq="2412")
245    dev[0].select_network(id, 2412)
246    dev[0].wait_connected()
247    hapd.wait_sta()
248    hwsim_utils.test_connectivity(dev[0], hapd)
249
250def test_owe_transition_mode_ifname(dev, apdev):
251    """Opportunistic Wireless Encryption transition mode (ifname)"""
252    if "OWE" not in dev[0].get_capability("key_mgmt"):
253        raise HwsimSkip("OWE not supported")
254    dev[0].flush_scan_cache()
255    params = {"ssid": "owe-random",
256              "wpa": "2",
257              "wpa_key_mgmt": "OWE",
258              "rsn_pairwise": "CCMP",
259              "ieee80211w": "2",
260              "owe_transition_ifname": apdev[1]['ifname'],
261              "ignore_broadcast_ssid": "1"}
262    hapd = hostapd.add_ap(apdev[0], params)
263    bssid = hapd.own_addr()
264
265    params = {"ssid": "owe-test",
266              "owe_transition_ifname": apdev[0]['ifname']}
267    hapd2 = hostapd.add_ap(apdev[1], params)
268    bssid2 = hapd2.own_addr()
269
270    dev[0].scan_for_bss(bssid, freq="2412")
271    dev[0].scan_for_bss(bssid2, freq="2412")
272
273    id = dev[0].connect("owe-test", key_mgmt="OWE", ieee80211w="2",
274                        scan_freq="2412")
275    val = dev[0].get_status_field("key_mgmt")
276    if val != "OWE":
277        raise Exception("Unexpected key_mgmt: " + val)
278
279def test_owe_transition_mode_ifname_acs(dev, apdev):
280    """Opportunistic Wireless Encryption transition mode (ifname, ACS)"""
281    run_owe_transition_mode_ifname_acs(dev, apdev, wait_first=False)
282
283def test_owe_transition_mode_ifname_acs2(dev, apdev):
284    """Opportunistic Wireless Encryption transition mode (ifname, ACS)"""
285    run_owe_transition_mode_ifname_acs(dev, apdev, wait_first=True)
286
287def run_owe_transition_mode_ifname_acs(dev, apdev, wait_first):
288    if "OWE" not in dev[0].get_capability("key_mgmt"):
289        raise HwsimSkip("OWE not supported")
290    dev[0].flush_scan_cache()
291    params = {"ssid": "owe-random",
292              "channel": "0",
293              "wpa": "2",
294              "wpa_key_mgmt": "OWE",
295              "rsn_pairwise": "CCMP",
296              "ieee80211w": "2",
297              "owe_transition_ifname": apdev[1]['ifname'],
298              "ignore_broadcast_ssid": "1"}
299    hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
300    bssid = hapd.own_addr()
301
302    if wait_first:
303        wait_acs(hapd)
304
305    params = {"ssid": "owe-test",
306              "channel": "0",
307              "owe_transition_ifname": apdev[0]['ifname']}
308    hapd2 = hostapd.add_ap(apdev[1], params, wait_enabled=False)
309    bssid2 = hapd2.own_addr()
310
311    wait_acs(hapd2)
312    if not wait_first:
313        state = hapd.get_status_field("state")
314        if state == "ACS-STARTED":
315            time.sleep(5)
316            state = hapd.get_status_field("state")
317        if state != "ENABLED":
318            raise Exception("AP1 startup did not succeed")
319
320    freq = hapd.get_status_field("freq")
321    freq2 = hapd2.get_status_field("freq")
322
323    dev[0].scan_for_bss(bssid, freq=freq)
324    dev[0].scan_for_bss(bssid2, freq=freq2)
325
326    id = dev[0].connect("owe-test", key_mgmt="OWE", ieee80211w="2",
327                        scan_freq="%s %s" % (freq, freq2))
328    val = dev[0].get_status_field("key_mgmt")
329    if val != "OWE":
330        raise Exception("Unexpected key_mgmt: " + val)
331
332def test_owe_transition_mode_open_only_ap(dev, apdev):
333    """Opportunistic Wireless Encryption transition mode connect to open-only AP"""
334    if "OWE" not in dev[0].get_capability("key_mgmt"):
335        raise HwsimSkip("OWE not supported")
336    dev[0].flush_scan_cache()
337    params = {"ssid": "owe-test-open"}
338    hapd = hostapd.add_ap(apdev[0], params)
339    bssid = hapd.own_addr()
340
341    dev[0].scan_for_bss(bssid, freq="2412")
342
343    bss = dev[0].get_bss(bssid)
344
345    id = dev[0].connect("owe-test-open", key_mgmt="OWE", ieee80211w="2",
346                        scan_freq="2412")
347    hwsim_utils.test_connectivity(dev[0], hapd)
348    val = dev[0].get_status_field("key_mgmt")
349    if val != "NONE":
350        raise Exception("Unexpected key_mgmt: " + val)
351
352def test_owe_only_sta(dev, apdev):
353    """Opportunistic Wireless Encryption transition mode disabled on STA"""
354    if "OWE" not in dev[0].get_capability("key_mgmt"):
355        raise HwsimSkip("OWE not supported")
356    dev[0].flush_scan_cache()
357    params = {"ssid": "owe-test-open"}
358    hapd = hostapd.add_ap(apdev[0], params)
359    bssid = hapd.own_addr()
360
361    dev[0].scan_for_bss(bssid, freq="2412")
362    id = dev[0].connect("owe-test-open", key_mgmt="OWE", ieee80211w="2",
363                        scan_freq="2412", owe_only="1", wait_connect=False)
364    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
365                            "CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
366    if not ev:
367        raise Exception("Unknown result for the connection attempt")
368    if "CTRL-EVENT-CONNECTED" in ev:
369        raise Exception("Unexpected connection to open network")
370    dev[0].request("DISCONNECT")
371    dev[0].dump_monitor()
372
373    params = {"ssid": "owe-test-open",
374              "wpa": "2",
375              "ieee80211w": "2",
376              "wpa_key_mgmt": "OWE",
377              "rsn_pairwise": "CCMP"}
378    hapd2 = hostapd.add_ap(apdev[1], params)
379    dev[0].request("RECONNECT")
380    dev[0].wait_connected()
381
382def test_owe_transition_mode_open_multiple_scans(dev, apdev):
383    """Opportunistic Wireless Encryption transition mode and need for multiple scans"""
384    if "OWE" not in dev[0].get_capability("key_mgmt"):
385        raise HwsimSkip("OWE not supported")
386    dev[0].flush_scan_cache()
387    params = {"ssid": "owe-test",
388              "owe_transition_bssid": apdev[0]['bssid'],
389              "owe_transition_ssid": '"owe-random"'}
390    hapd2 = hostapd.add_ap(apdev[1], params)
391    bssid2 = hapd2.own_addr()
392
393    dev[0].scan_for_bss(bssid2, freq="2412")
394
395    dev[0].dump_monitor()
396    id = dev[0].connect("owe-test", key_mgmt="OWE", ieee80211w="2",
397                        scan_freq="2412", wait_connect=False)
398    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=1)
399
400    params = {"ssid": "owe-random",
401              "wpa": "2",
402              "wpa_key_mgmt": "OWE",
403              "rsn_pairwise": "CCMP",
404              "ieee80211w": "2",
405              "owe_transition_bssid": apdev[1]['bssid'],
406              "owe_transition_ssid": '"owe-test"',
407              "ignore_broadcast_ssid": "1"}
408    hapd = hostapd.add_ap(apdev[0], params)
409    bssid = hapd.own_addr()
410
411    dev[0].wait_connected()
412
413    val = dev[0].get_status_field("key_mgmt")
414    if val != "OWE":
415        raise Exception("Unexpected key_mgmt: " + val)
416
417def test_owe_transition_mode_multi_bss(dev, apdev):
418    """Opportunistic Wireless Encryption transition mode (multi BSS)"""
419    try:
420        run_owe_transition_mode_multi_bss(dev, apdev)
421    finally:
422        dev[0].request("SCAN_INTERVAL 5")
423
424def run_owe_transition_mode_multi_bss(dev, apdev):
425    if "OWE" not in dev[0].get_capability("key_mgmt"):
426        raise HwsimSkip("OWE not supported")
427    ifname1 = apdev[0]['ifname']
428    ifname2 = apdev[0]['ifname'] + '-2'
429    hapd1 = hostapd.add_bss(apdev[0], ifname1, 'owe-bss-1.conf')
430    hapd2 = hostapd.add_bss(apdev[0], ifname2, 'owe-bss-2.conf')
431    hapd2.bssidx = 1
432
433    bssid = hapd1.own_addr()
434    bssid2 = hapd2.own_addr()
435
436    # Beaconing with the OWE Transition Mode element can start only once both
437    # BSSs are enabled, so the very first Beacon frame may go out without this
438    # element. Wait a bit to avoid getting incomplete scan results.
439    time.sleep(0.1)
440
441    dev[0].request("SCAN_INTERVAL 1")
442    dev[0].scan_for_bss(bssid2, freq="2412")
443    dev[0].scan_for_bss(bssid, freq="2412")
444    dev[0].connect("transition-mode-open", key_mgmt="OWE")
445    val = dev[0].get_status_field("bssid")
446    if val != bssid2:
447        raise Exception("Unexpected bssid: " + val)
448    val = dev[0].get_status_field("key_mgmt")
449    if val != "OWE":
450        raise Exception("Unexpected key_mgmt: " + val)
451    hwsim_utils.test_connectivity(dev[0], hapd2)
452
453def test_owe_transition_mode_rsne_mismatch(dev, apdev):
454    """Opportunistic Wireless Encryption transition mode and RSNE mismatch"""
455    if "OWE" not in dev[0].get_capability("key_mgmt"):
456        raise HwsimSkip("OWE not supported")
457    dev[0].flush_scan_cache()
458    params = {"ssid": "owe-random",
459              "wpa": "2",
460              "wpa_key_mgmt": "OWE",
461              "rsn_pairwise": "CCMP",
462              "ieee80211w": "2",
463              "rsne_override_eapol": "30140100000fac040100000fac040100000fac020c00",
464              "owe_transition_bssid": apdev[1]['bssid'],
465              "owe_transition_ssid": '"owe-test"',
466              "ignore_broadcast_ssid": "1"}
467    hapd = hostapd.add_ap(apdev[0], params)
468    bssid = hapd.own_addr()
469
470    params = {"ssid": "owe-test",
471              "owe_transition_bssid": apdev[0]['bssid'],
472              "owe_transition_ssid": '"owe-random"'}
473    hapd2 = hostapd.add_ap(apdev[1], params)
474    bssid2 = hapd2.own_addr()
475
476    dev[0].scan_for_bss(bssid, freq="2412")
477    dev[0].scan_for_bss(bssid2, freq="2412")
478
479    id = dev[0].connect("owe-test", key_mgmt="OWE", ieee80211w="2",
480                        scan_freq="2412", wait_connect=False)
481    ev = dev[0].wait_event(["PMKSA-CACHE-ADDED"], timeout=5)
482    if ev is None:
483        raise Exception("OWE PMKSA not created")
484    ev = dev[0].wait_event(["WPA: IE in 3/4 msg does not match with IE in Beacon/ProbeResp"],
485                           timeout=5)
486    if ev is None:
487        raise Exception("RSNE mismatch not reported")
488    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
489                            "CTRL-EVENT-DISCONNECTED"], timeout=5)
490    dev[0].request("REMOVE_NETWORK all")
491    if ev is None:
492        raise Exception("No disconnection seen")
493    if "CTRL-EVENT-DISCONNECTED" not in ev:
494        raise Exception("Unexpected connection")
495    if "reason=17 locally_generated=1" not in ev:
496        raise Exception("Unexpected disconnection reason: " + ev)
497
498def test_owe_unsupported_group(dev, apdev):
499    """Opportunistic Wireless Encryption and unsupported group"""
500    try:
501        run_owe_unsupported_group(dev, apdev)
502    finally:
503        dev[0].request("VENDOR_ELEM_REMOVE 13 *")
504
505def test_owe_unsupported_group_connect_cmd(dev, apdev):
506    """Opportunistic Wireless Encryption and unsupported group using cfg80211 connect command"""
507    try:
508        wpas = None
509        wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
510        wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
511        run_owe_unsupported_group([wpas], apdev)
512    finally:
513        if wpas:
514            wpas.request("VENDOR_ELEM_REMOVE 13 *")
515
516def run_owe_unsupported_group(dev, apdev):
517    if "OWE" not in dev[0].get_capability("key_mgmt"):
518        raise HwsimSkip("OWE not supported")
519    # Override OWE Dh Parameters element with a payload that uses invalid group
520    # 0 (and actual group 19 data) to make the AP reject this with the specific
521    # status code 77.
522    dev[0].request("VENDOR_ELEM_ADD 13 ff23200000783590fb7440e03d5b3b33911f86affdcc6b4411b707846ac4ff08ddc8831ccd")
523
524    params = {"ssid": "owe",
525              "wpa": "2",
526              "wpa_key_mgmt": "OWE",
527              "rsn_pairwise": "CCMP"}
528    hapd = hostapd.add_ap(apdev[0], params)
529    bssid = hapd.own_addr()
530
531    dev[0].scan_for_bss(bssid, freq="2412")
532    dev[0].connect("owe", key_mgmt="OWE", wait_connect=False)
533    ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"], timeout=10)
534    dev[0].request("DISCONNECT")
535    if ev is None:
536        raise Exception("Association not rejected")
537    if "status_code=77" not in ev:
538        raise Exception("Unexpected rejection reason: " + ev)
539
540def test_owe_limited_group_set(dev, apdev):
541    """Opportunistic Wireless Encryption and limited group set"""
542    if "OWE" not in dev[0].get_capability("key_mgmt"):
543        raise HwsimSkip("OWE not supported")
544    params = {"ssid": "owe",
545              "wpa": "2",
546              "wpa_key_mgmt": "OWE",
547              "rsn_pairwise": "CCMP",
548              "owe_groups": "20 21"}
549    hapd = hostapd.add_ap(apdev[0], params)
550    bssid = hapd.own_addr()
551
552    dev[0].scan_for_bss(bssid, freq="2412")
553    dev[0].connect("owe", key_mgmt="OWE", owe_group="19", wait_connect=False)
554    ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"], timeout=10)
555    dev[0].request("DISCONNECT")
556    if ev is None:
557        raise Exception("Association not rejected")
558    if "status_code=77" not in ev:
559        raise Exception("Unexpected rejection reason: " + ev)
560    dev[0].dump_monitor()
561
562    for group in [20, 21]:
563        dev[0].connect("owe", key_mgmt="OWE", owe_group=str(group))
564        dev[0].request("REMOVE_NETWORK all")
565        dev[0].wait_disconnected()
566        dev[0].dump_monitor()
567
568def test_owe_limited_group_set_pmf(dev, apdev, params):
569    """Opportunistic Wireless Encryption and limited group set (PMF)"""
570    if "OWE" not in dev[0].get_capability("key_mgmt"):
571        raise HwsimSkip("OWE not supported")
572    pcapng = os.path.join(params['logdir'], "hwsim0.pcapng")
573
574    params = {"ssid": "owe",
575              "wpa": "2",
576              "ieee80211w": "2",
577              "wpa_key_mgmt": "OWE",
578              "rsn_pairwise": "CCMP",
579              "owe_groups": "21"}
580    hapd = hostapd.add_ap(apdev[0], params)
581    bssid = hapd.own_addr()
582
583    dev[0].scan_for_bss(bssid, freq="2412")
584    dev[0].connect("owe", key_mgmt="OWE", owe_group="19", ieee80211w="2",
585                   scan_freq="2412", wait_connect=False)
586    ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"], timeout=10)
587    dev[0].request("DISCONNECT")
588    if ev is None:
589        raise Exception("Association not rejected")
590    if "status_code=77" not in ev:
591        raise Exception("Unexpected rejection reason: " + ev)
592    dev[0].dump_monitor()
593
594    dev[0].connect("owe", key_mgmt="OWE", owe_group="20", ieee80211w="2",
595                   scan_freq="2412", wait_connect=False)
596    ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"], timeout=10)
597    dev[0].request("DISCONNECT")
598    if ev is None:
599        raise Exception("Association not rejected (2)")
600    if "status_code=77" not in ev:
601        raise Exception("Unexpected rejection reason (2): " + ev)
602    dev[0].dump_monitor()
603
604    dev[0].connect("owe", key_mgmt="OWE", owe_group="21", ieee80211w="2",
605                   scan_freq="2412")
606    dev[0].request("REMOVE_NETWORK all")
607    dev[0].wait_disconnected()
608    dev[0].dump_monitor()
609
610    out = run_tshark(pcapng,
611                     "wlan.fc.type_subtype == 1",
612                     display=['wlan_mgt.fixed.status_code'])
613    status = out.splitlines()
614    logger.info("Association Response frame status codes: " + str(status))
615    if len(status) != 3:
616        raise Exception("Unexpected number of Association Response frames")
617    if (int(status[0], base=0) != 77 or int(status[1], base=0) != 77 or
618        int(status[2], base=0) != 0):
619        raise Exception("Unexpected Association Response frame status code")
620
621def test_owe_group_negotiation(dev, apdev):
622    """Opportunistic Wireless Encryption and group negotiation"""
623    run_owe_group_negotiation(dev[0], apdev)
624
625def test_owe_group_negotiation_connect_cmd(dev, apdev):
626    """Opportunistic Wireless Encryption and group negotiation (connect command)"""
627    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
628    wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
629    run_owe_group_negotiation(wpas, apdev)
630
631def run_owe_group_negotiation(dev, apdev):
632    if "OWE" not in dev.get_capability("key_mgmt"):
633        raise HwsimSkip("OWE not supported")
634    params = {"ssid": "owe",
635              "wpa": "2",
636              "wpa_key_mgmt": "OWE",
637              "rsn_pairwise": "CCMP",
638              "owe_groups": "21"}
639    hapd = hostapd.add_ap(apdev[0], params)
640    bssid = hapd.own_addr()
641
642    dev.scan_for_bss(bssid, freq="2412")
643    dev.connect("owe", key_mgmt="OWE")
644
645def test_owe_assoc_reject(dev, apdev):
646    """Opportunistic Wireless Encryption association rejection handling"""
647    if "OWE" not in dev[0].get_capability("key_mgmt"):
648        raise HwsimSkip("OWE not supported")
649    params = {"ssid": "owe",
650              "require_ht": "1",
651              "wpa": "2",
652              "ieee80211w": "2",
653              "wpa_key_mgmt": "OWE",
654              "rsn_pairwise": "CCMP",
655              "owe_groups": "19"}
656    hapd = hostapd.add_ap(apdev[0], params)
657    bssid = hapd.own_addr()
658
659    # First, reject two associations with HT-required (i.e., not OWE related)
660    dev[0].scan_for_bss(bssid, freq="2412")
661    dev[0].connect("owe", key_mgmt="OWE", ieee80211w="2",
662                   disable_ht="1", scan_freq="2412", wait_connect=False)
663    for i in range(0, 2):
664        ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"], timeout=10)
665        if ev is None:
666            raise Exception("Association rejection not reported")
667
668    # Then, verify that STA tries OWE with the default group (19) on the next
669    # attempt instead of having moved to testing another group.
670    hapd.set("require_ht", "0")
671    for i in range(0, 2):
672        ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT",
673                                "CTRL-EVENT-CONNECTED"], timeout=10)
674        if ev is None:
675            raise Exception("Association result not reported")
676        if "CTRL-EVENT-CONNECTED" in ev:
677            break
678        if "status_code=77" in ev:
679            raise Exception("Unexpected unsupport group rejection")
680    if "CTRL-EVENT-CONNECTED" not in ev:
681        raise Exception("Did not connect successfully")
682
683def test_owe_local_errors(dev, apdev):
684    """Opportunistic Wireless Encryption - local errors on supplicant"""
685    if "OWE" not in dev[0].get_capability("key_mgmt"):
686        raise HwsimSkip("OWE not supported")
687    params = {"ssid": "owe",
688              "wpa": "2",
689              "ieee80211w": "2",
690              "wpa_key_mgmt": "OWE",
691              "rsn_pairwise": "CCMP"}
692    hapd = hostapd.add_ap(apdev[0], params)
693    bssid = hapd.own_addr()
694
695    dev[0].scan_for_bss(bssid, freq="2412")
696
697    tests = [(1, "crypto_ecdh_init;owe_build_assoc_req"),
698             (1, "crypto_ecdh_get_pubkey;owe_build_assoc_req"),
699             (1, "wpabuf_alloc;owe_build_assoc_req")]
700    for count, func in tests:
701        with alloc_fail(dev[0], count, func):
702            dev[0].connect("owe", key_mgmt="OWE", owe_group="20",
703                           ieee80211w="2",
704                           scan_freq="2412", wait_connect=False)
705            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
706            dev[0].request("REMOVE_NETWORK all")
707            dev[0].dump_monitor()
708
709    tests = [(1, "crypto_ecdh_set_peerkey;owe_process_assoc_resp"),
710             (1, "crypto_ecdh_get_pubkey;owe_process_assoc_resp"),
711             (1, "wpabuf_alloc;=owe_process_assoc_resp")]
712    for count, func in tests:
713        with alloc_fail(dev[0], count, func):
714            dev[0].connect("owe", key_mgmt="OWE", owe_group="20",
715                           ieee80211w="2",
716                           scan_freq="2412", wait_connect=False)
717            dev[0].wait_disconnected()
718            dev[0].request("REMOVE_NETWORK all")
719            dev[0].dump_monitor()
720
721    tests = [(1, "hmac_sha256;owe_process_assoc_resp", 19),
722             (1, "hmac_sha256_kdf;owe_process_assoc_resp", 19),
723             (1, "hmac_sha384;owe_process_assoc_resp", 20),
724             (1, "hmac_sha384_kdf;owe_process_assoc_resp", 20),
725             (1, "hmac_sha512;owe_process_assoc_resp", 21),
726             (1, "hmac_sha512_kdf;owe_process_assoc_resp", 21)]
727    for count, func, group in tests:
728        with fail_test(dev[0], count, func):
729            dev[0].connect("owe", key_mgmt="OWE", owe_group=str(group),
730                           ieee80211w="2",
731                           scan_freq="2412", wait_connect=False)
732            dev[0].wait_disconnected()
733            dev[0].request("REMOVE_NETWORK all")
734            dev[0].dump_monitor()
735
736    dev[0].connect("owe", key_mgmt="OWE", owe_group="18",
737                   ieee80211w="2",
738                   scan_freq="2412", wait_connect=False)
739    ev = dev[0].wait_event(["SME: Trying to authenticate"], timeout=5)
740    if ev is None:
741        raise Exception("No authentication attempt")
742    time.sleep(0.5)
743    dev[0].request("REMOVE_NETWORK all")
744    dev[0].dump_monitor()
745
746def hapd_auth(hapd):
747    for i in range(0, 10):
748        req = hapd.mgmt_rx()
749        if req is None:
750            raise Exception("MGMT RX wait timed out")
751        if req['subtype'] == 11:
752            break
753        req = None
754    if not req:
755        raise Exception("Authentication frame not received")
756
757    resp = {}
758    resp['fc'] = req['fc']
759    resp['da'] = req['sa']
760    resp['sa'] = req['da']
761    resp['bssid'] = req['bssid']
762    resp['payload'] = struct.pack('<HHH', 0, 2, 0)
763    hapd.mgmt_tx(resp)
764
765def hapd_assoc(hapd, extra):
766    for i in range(0, 10):
767        req = hapd.mgmt_rx()
768        if req is None:
769            raise Exception("MGMT RX wait timed out")
770        if req['subtype'] == 0:
771            break
772        req = None
773    if not req:
774        raise Exception("Association Request frame not received")
775
776    resp = {}
777    resp['fc'] = 0x0010
778    resp['da'] = req['sa']
779    resp['sa'] = req['da']
780    resp['bssid'] = req['bssid']
781    payload = struct.pack('<HHH', 0x0411, 0, 0xc001)
782    payload += binascii.unhexlify("010882848b960c121824")
783    resp['payload'] = payload + extra
784    hapd.mgmt_tx(resp)
785
786def test_owe_invalid_assoc_resp(dev, apdev):
787    """Opportunistic Wireless Encryption - invalid Association Response frame"""
788    if "OWE" not in dev[0].get_capability("key_mgmt"):
789        raise HwsimSkip("OWE not supported")
790    params = {"ssid": "owe",
791              "wpa": "2",
792              "ieee80211w": "2",
793              "wpa_key_mgmt": "OWE",
794              "rsn_pairwise": "CCMP"}
795    hapd = hostapd.add_ap(apdev[0], params)
796    bssid = hapd.own_addr()
797
798    dev[0].scan_for_bss(bssid, freq="2412")
799
800    hapd.set("ext_mgmt_frame_handling", "1")
801    # OWE: No Diffie-Hellman Parameter element found in Association Response frame
802    tests = [b'']
803    # No room for group --> no DH Params
804    tests += [binascii.unhexlify('ff0120')]
805    # OWE: Unexpected Diffie-Hellman group in response: 18
806    tests += [binascii.unhexlify('ff03201200')]
807    # OWE: Invalid peer DH public key
808    tests += [binascii.unhexlify('ff23201300' + 31*'00' + '01')]
809    # OWE: Invalid peer DH public key
810    tests += [binascii.unhexlify('ff24201300' + 33*'ee')]
811    for extra in tests:
812        dev[0].connect("owe", key_mgmt="OWE", owe_group="19", ieee80211w="2",
813                       scan_freq="2412", wait_connect=False)
814        hapd_auth(hapd)
815        hapd_assoc(hapd, extra)
816        dev[0].wait_disconnected()
817        dev[0].request("REMOVE_NETWORK all")
818        dev[0].dump_monitor()
819
820    # OWE: Empty public key (this ends up getting padded to a valid point)
821    dev[0].connect("owe", key_mgmt="OWE", owe_group="19", ieee80211w="2",
822                   scan_freq="2412", wait_connect=False)
823    hapd_auth(hapd)
824    hapd_assoc(hapd, binascii.unhexlify('ff03201300'))
825    ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED", "PMKSA-CACHE-ADDED"],
826                           timeout=5)
827    if ev is None:
828        raise Exception("No result reported for empty public key")
829    dev[0].request("REMOVE_NETWORK all")
830    dev[0].dump_monitor()
831
832def start_owe(dev, apdev, workaround=0):
833    if "OWE" not in dev[0].get_capability("key_mgmt"):
834        raise HwsimSkip("OWE not supported")
835    params = {"ssid": "owe",
836              "wpa": "2",
837              "ieee80211w": "2",
838              "wpa_key_mgmt": "OWE",
839              "owe_ptk_workaround": str(workaround),
840              "rsn_pairwise": "CCMP"}
841    hapd = hostapd.add_ap(apdev[0], params)
842    dev[0].scan_for_bss(hapd.own_addr(), freq="2412")
843    return hapd
844
845def owe_check_ok(dev, hapd, owe_group, owe_ptk_workaround):
846    dev.connect("owe", key_mgmt="OWE", ieee80211w="2",
847                owe_group=owe_group, owe_ptk_workaround=owe_ptk_workaround,
848                scan_freq="2412")
849    hapd.wait_sta()
850    dev.request("REMOVE_NETWORK all")
851    dev.wait_disconnected()
852    dev.dump_monitor()
853
854def test_owe_ptk_workaround_ap(dev, apdev):
855    """Opportunistic Wireless Encryption - AP using PTK workaround"""
856    hapd = start_owe(dev, apdev, workaround=1)
857    for group, workaround in [(19, 0), (20, 0), (21, 0),
858                              (19, 1), (20, 1), (21, 1)]:
859        owe_check_ok(dev[0], hapd, str(group), str(workaround))
860
861def test_owe_ptk_hash(dev, apdev):
862    """Opportunistic Wireless Encryption - PTK derivation hash alg"""
863    hapd = start_owe(dev, apdev)
864    for group, workaround in [(19, 0), (20, 0), (21, 0), (19, 1)]:
865        owe_check_ok(dev[0], hapd, str(group), str(workaround))
866
867    for group in [20, 21]:
868        dev[0].connect("owe", key_mgmt="OWE", ieee80211w="2",
869                       owe_group=str(group), owe_ptk_workaround="1",
870                       scan_freq="2412", wait_connect=False)
871        ev = dev[0].wait_event(["PMKSA-CACHE-ADDED"], timeout=10)
872        if ev is None:
873            raise Exception("Could not complete OWE association")
874        ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
875                                "CTRL-EVENT-DISCONNECTED"], timeout=5)
876        if ev is None:
877            raise Exception("Unknown connection result")
878        if "CTRL-EVENT-CONNECTED" in ev:
879            raise Exception("Unexpected connection")
880        dev[0].request("REMOVE_NETWORK all")
881        ev = dev[0].wait_event(["PMKSA-CACHE-REMOVED"], timeout=5)
882        if ev is None:
883            raise Exception("No PMKSA cache removal event seen")
884        dev[0].dump_monitor()
885
886def test_owe_transition_mode_disable(dev, apdev):
887    """Opportunistic Wireless Encryption transition mode disable"""
888    if "OWE" not in dev[0].get_capability("key_mgmt"):
889        raise HwsimSkip("OWE not supported")
890    dev[0].flush_scan_cache()
891    params = {"ssid": "owe-random",
892              "wpa": "2",
893              "wpa_key_mgmt": "OWE",
894              "rsn_pairwise": "CCMP",
895              "ieee80211w": "2",
896              "transition_disable": '0x08',
897              "owe_transition_bssid": apdev[1]['bssid'],
898              "owe_transition_ssid": '"owe-test"',
899              "ignore_broadcast_ssid": "1"}
900    hapd = hostapd.add_ap(apdev[0], params)
901    bssid = hapd.own_addr()
902
903    params = {"ssid": "owe-test",
904              "owe_transition_bssid": apdev[0]['bssid'],
905              "owe_transition_ssid": '"owe-random"'}
906    hapd2 = hostapd.add_ap(apdev[1], params)
907    bssid2 = hapd2.own_addr()
908
909    dev[0].scan_for_bss(bssid, freq="2412")
910    dev[0].scan_for_bss(bssid2, freq="2412")
911
912    id = dev[0].connect("owe-test", key_mgmt="OWE", ieee80211w="2",
913                        scan_freq="2412")
914
915    ev = dev[0].wait_event(["TRANSITION-DISABLE"], timeout=1)
916    if ev is None:
917        raise Exception("Transition disable not indicated")
918    if ev.split(' ')[1] != "08":
919        raise Exception("Unexpected transition disable bitmap: " + ev)
920
921    val = dev[0].get_network(id, "owe_only")
922    if val != "1":
923        raise Exception("Unexpected owe_only value: " + val)
924
925    dev[0].request("DISCONNECT")
926    dev[0].wait_disconnected()
927    dev[0].request("RECONNECT")
928    dev[0].wait_connected()
929
930def test_owe_sa_query(dev, apdev):
931    """Opportunistic Wireless Encryption - SA Query"""
932    if "OWE" not in dev[0].get_capability("key_mgmt"):
933        raise HwsimSkip("OWE not supported")
934    params = {"ssid": "owe",
935              "wpa": "2",
936              "ieee80211w": "2",
937              "wpa_key_mgmt": "OWE",
938              "rsn_pairwise": "CCMP"}
939    hapd = hostapd.add_ap(apdev[0], params)
940    bssid = hapd.own_addr()
941
942    dev[0].scan_for_bss(bssid, freq="2412")
943    dev[0].connect("owe", key_mgmt="OWE", owe_group="19", ieee80211w="2",
944                   scan_freq="2412")
945    hapd.wait_sta()
946
947    hapd.set("ext_mgmt_frame_handling", "1")
948    dev[0].request("DISCONNECT")
949    dev[0].wait_disconnected(timeout=10)
950    hapd.set("ext_mgmt_frame_handling", "0")
951    dev[0].request("PMKSA_FLUSH")
952    dev[0].request("REASSOCIATE")
953    dev[0].wait_connected(timeout=10, error="Timeout on re-connection")
954