1c1d255d3SCy Schubert /*
2c1d255d3SCy Schubert * wpa_supplicant - PASN processing
3c1d255d3SCy Schubert *
4c1d255d3SCy Schubert * Copyright (C) 2019 Intel Corporation
5c1d255d3SCy Schubert *
6c1d255d3SCy Schubert * This software may be distributed under the terms of the BSD license.
7c1d255d3SCy Schubert * See README for more details.
8c1d255d3SCy Schubert */
9c1d255d3SCy Schubert
10c1d255d3SCy Schubert #include "includes.h"
11c1d255d3SCy Schubert
12c1d255d3SCy Schubert #include "common/ieee802_11_defs.h"
13c1d255d3SCy Schubert #include "common/ieee802_11_common.h"
14c1d255d3SCy Schubert #include "common/dragonfly.h"
15c1d255d3SCy Schubert #include "common/ptksa_cache.h"
16c1d255d3SCy Schubert #include "utils/eloop.h"
17c1d255d3SCy Schubert #include "drivers/driver.h"
18c1d255d3SCy Schubert #include "crypto/crypto.h"
19c1d255d3SCy Schubert #include "crypto/random.h"
20c1d255d3SCy Schubert #include "eap_common/eap_defs.h"
21c1d255d3SCy Schubert #include "rsn_supp/wpa.h"
22c1d255d3SCy Schubert #include "rsn_supp/pmksa_cache.h"
23c1d255d3SCy Schubert #include "wpa_supplicant_i.h"
24c1d255d3SCy Schubert #include "driver_i.h"
25c1d255d3SCy Schubert #include "bss.h"
26*a90b9d01SCy Schubert #include "scan.h"
27c1d255d3SCy Schubert #include "config.h"
28c1d255d3SCy Schubert
29c1d255d3SCy Schubert static const int dot11RSNAConfigPMKLifetime = 43200;
30c1d255d3SCy Schubert
31c1d255d3SCy Schubert struct wpa_pasn_auth_work {
32*a90b9d01SCy Schubert u8 own_addr[ETH_ALEN];
33*a90b9d01SCy Schubert u8 peer_addr[ETH_ALEN];
34c1d255d3SCy Schubert int akmp;
35c1d255d3SCy Schubert int cipher;
36c1d255d3SCy Schubert u16 group;
37c1d255d3SCy Schubert int network_id;
38c1d255d3SCy Schubert struct wpabuf *comeback;
39c1d255d3SCy Schubert };
40c1d255d3SCy Schubert
41c1d255d3SCy Schubert
wpas_pasn_send_mlme(void * ctx,const u8 * data,size_t data_len,int noack,unsigned int freq,unsigned int wait)42*a90b9d01SCy Schubert static int wpas_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len,
43*a90b9d01SCy Schubert int noack, unsigned int freq, unsigned int wait)
44*a90b9d01SCy Schubert {
45*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = ctx;
46*a90b9d01SCy Schubert
47*a90b9d01SCy Schubert return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, wait);
48*a90b9d01SCy Schubert }
49*a90b9d01SCy Schubert
50*a90b9d01SCy Schubert
wpas_pasn_free_auth_work(struct wpa_pasn_auth_work * awork)51c1d255d3SCy Schubert static void wpas_pasn_free_auth_work(struct wpa_pasn_auth_work *awork)
52c1d255d3SCy Schubert {
53c1d255d3SCy Schubert wpabuf_free(awork->comeback);
54c1d255d3SCy Schubert awork->comeback = NULL;
55c1d255d3SCy Schubert os_free(awork);
56c1d255d3SCy Schubert }
57c1d255d3SCy Schubert
58c1d255d3SCy Schubert
wpas_pasn_auth_work_timeout(void * eloop_ctx,void * timeout_ctx)59c1d255d3SCy Schubert static void wpas_pasn_auth_work_timeout(void *eloop_ctx, void *timeout_ctx)
60c1d255d3SCy Schubert {
61c1d255d3SCy Schubert struct wpa_supplicant *wpa_s = eloop_ctx;
62c1d255d3SCy Schubert
63c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Auth work timeout - stopping auth");
64c1d255d3SCy Schubert
65c1d255d3SCy Schubert wpas_pasn_auth_stop(wpa_s);
66*a90b9d01SCy Schubert
67*a90b9d01SCy Schubert wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_FAILURE);
68c1d255d3SCy Schubert }
69c1d255d3SCy Schubert
70c1d255d3SCy Schubert
wpas_pasn_cancel_auth_work(struct wpa_supplicant * wpa_s)71c1d255d3SCy Schubert static void wpas_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
72c1d255d3SCy Schubert {
73c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Cancel pasn-start-auth work");
74c1d255d3SCy Schubert
75c1d255d3SCy Schubert /* Remove pending/started work */
76c1d255d3SCy Schubert radio_remove_works(wpa_s, "pasn-start-auth", 0);
77c1d255d3SCy Schubert }
78c1d255d3SCy Schubert
79c1d255d3SCy Schubert
wpas_pasn_auth_status(struct wpa_supplicant * wpa_s,const u8 * peer_addr,int akmp,int cipher,u8 status,struct wpabuf * comeback,u16 comeback_after)80*a90b9d01SCy Schubert static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s,
81*a90b9d01SCy Schubert const u8 *peer_addr,
82c1d255d3SCy Schubert int akmp, int cipher, u8 status,
83c1d255d3SCy Schubert struct wpabuf *comeback,
84c1d255d3SCy Schubert u16 comeback_after)
85c1d255d3SCy Schubert {
86c1d255d3SCy Schubert if (comeback) {
87c1d255d3SCy Schubert size_t comeback_len = wpabuf_len(comeback);
88c1d255d3SCy Schubert size_t buflen = comeback_len * 2 + 1;
89c1d255d3SCy Schubert char *comeback_txt = os_malloc(buflen);
90c1d255d3SCy Schubert
91c1d255d3SCy Schubert if (comeback_txt) {
92c1d255d3SCy Schubert wpa_snprintf_hex(comeback_txt, buflen,
93c1d255d3SCy Schubert wpabuf_head(comeback), comeback_len);
94c1d255d3SCy Schubert
95c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR
96c1d255d3SCy Schubert " akmp=%s, status=%u comeback_after=%u comeback=%s",
97*a90b9d01SCy Schubert MAC2STR(peer_addr),
98c1d255d3SCy Schubert wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
99c1d255d3SCy Schubert status, comeback_after, comeback_txt);
100c1d255d3SCy Schubert
101c1d255d3SCy Schubert os_free(comeback_txt);
102c1d255d3SCy Schubert return;
103c1d255d3SCy Schubert }
104c1d255d3SCy Schubert }
105c1d255d3SCy Schubert
106c1d255d3SCy Schubert wpa_msg(wpa_s, MSG_INFO,
107c1d255d3SCy Schubert PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u",
108*a90b9d01SCy Schubert MAC2STR(peer_addr), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
109c1d255d3SCy Schubert status);
110c1d255d3SCy Schubert }
111c1d255d3SCy Schubert
112c1d255d3SCy Schubert
113c1d255d3SCy Schubert #ifdef CONFIG_SAE
114c1d255d3SCy Schubert
115*a90b9d01SCy Schubert static struct sae_pt *
wpas_pasn_sae_derive_pt(struct wpa_ssid * ssid,int group)116*a90b9d01SCy Schubert wpas_pasn_sae_derive_pt(struct wpa_ssid *ssid, int group)
117c1d255d3SCy Schubert {
118c1d255d3SCy Schubert const char *password = ssid->sae_password;
119c1d255d3SCy Schubert int groups[2] = { group, 0 };
120c1d255d3SCy Schubert
121c1d255d3SCy Schubert if (!password)
122c1d255d3SCy Schubert password = ssid->passphrase;
123c1d255d3SCy Schubert
124c1d255d3SCy Schubert if (!password) {
125c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: SAE without a password");
126*a90b9d01SCy Schubert return NULL;
127*a90b9d01SCy Schubert }
128*a90b9d01SCy Schubert
129*a90b9d01SCy Schubert return sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
130*a90b9d01SCy Schubert (const u8 *) password, os_strlen(password),
131*a90b9d01SCy Schubert ssid->sae_password_id);
132*a90b9d01SCy Schubert }
133*a90b9d01SCy Schubert
134*a90b9d01SCy Schubert
wpas_pasn_sae_setup_pt(struct wpa_ssid * ssid,int group)135*a90b9d01SCy Schubert static int wpas_pasn_sae_setup_pt(struct wpa_ssid *ssid, int group)
136*a90b9d01SCy Schubert {
137*a90b9d01SCy Schubert if (!ssid->sae_password && !ssid->passphrase) {
138*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: SAE without a password");
139c1d255d3SCy Schubert return -1;
140c1d255d3SCy Schubert }
141c1d255d3SCy Schubert
142c1d255d3SCy Schubert if (ssid->pt)
143c1d255d3SCy Schubert return 0; /* PT already derived */
144c1d255d3SCy Schubert
145*a90b9d01SCy Schubert ssid->pt = wpas_pasn_sae_derive_pt(ssid, group);
146c1d255d3SCy Schubert
147c1d255d3SCy Schubert return ssid->pt ? 0 : -1;
148c1d255d3SCy Schubert }
149c1d255d3SCy Schubert
150c1d255d3SCy Schubert #endif /* CONFIG_SAE */
151c1d255d3SCy Schubert
152c1d255d3SCy Schubert
wpas_pasn_get_params_from_bss(struct wpa_supplicant * wpa_s,struct pasn_peer * peer)153*a90b9d01SCy Schubert static int wpas_pasn_get_params_from_bss(struct wpa_supplicant *wpa_s,
154*a90b9d01SCy Schubert struct pasn_peer *peer)
155c1d255d3SCy Schubert {
156c1d255d3SCy Schubert int ret;
157*a90b9d01SCy Schubert const u8 *rsne, *rsnxe;
158c1d255d3SCy Schubert struct wpa_bss *bss;
159c1d255d3SCy Schubert struct wpa_ie_data rsne_data;
160*a90b9d01SCy Schubert int sel, key_mgmt, pairwise_cipher;
161*a90b9d01SCy Schubert int network_id = 0, group = 19;
162*a90b9d01SCy Schubert struct wpa_ssid *ssid = NULL;
163*a90b9d01SCy Schubert size_t ssid_str_len = 0;
164*a90b9d01SCy Schubert const u8 *ssid_str = NULL;
165*a90b9d01SCy Schubert const u8 *peer_addr = peer->peer_addr;
166c1d255d3SCy Schubert
167*a90b9d01SCy Schubert bss = wpa_bss_get_bssid(wpa_s, peer_addr);
168*a90b9d01SCy Schubert if (!bss) {
169*a90b9d01SCy Schubert wpa_supplicant_update_scan_results(wpa_s, peer_addr);
170*a90b9d01SCy Schubert bss = wpa_bss_get_bssid(wpa_s, peer_addr);
171*a90b9d01SCy Schubert if (!bss) {
172*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: BSS not found");
173c1d255d3SCy Schubert return -1;
174*a90b9d01SCy Schubert }
175*a90b9d01SCy Schubert }
176c1d255d3SCy Schubert
177*a90b9d01SCy Schubert rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
178*a90b9d01SCy Schubert if (!rsne) {
179*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: BSS without RSNE");
180c1d255d3SCy Schubert return -1;
181c1d255d3SCy Schubert }
182c1d255d3SCy Schubert
183*a90b9d01SCy Schubert ret = wpa_parse_wpa_ie(rsne, *(rsne + 1) + 2, &rsne_data);
184*a90b9d01SCy Schubert if (ret) {
185*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE data");
186*a90b9d01SCy Schubert return -1;
187*a90b9d01SCy Schubert }
188c1d255d3SCy Schubert
189*a90b9d01SCy Schubert rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
190c1d255d3SCy Schubert
191*a90b9d01SCy Schubert ssid_str_len = bss->ssid_len;
192*a90b9d01SCy Schubert ssid_str = bss->ssid;
193*a90b9d01SCy Schubert
194*a90b9d01SCy Schubert /* Get the network configuration based on the obtained SSID */
195*a90b9d01SCy Schubert for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
196*a90b9d01SCy Schubert if (!wpas_network_disabled(wpa_s, ssid) &&
197*a90b9d01SCy Schubert ssid_str_len == ssid->ssid_len &&
198*a90b9d01SCy Schubert os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0)
199*a90b9d01SCy Schubert break;
200*a90b9d01SCy Schubert }
201*a90b9d01SCy Schubert
202*a90b9d01SCy Schubert if (ssid)
203*a90b9d01SCy Schubert network_id = ssid->id;
204*a90b9d01SCy Schubert
205*a90b9d01SCy Schubert sel = rsne_data.pairwise_cipher;
206*a90b9d01SCy Schubert if (ssid && ssid->pairwise_cipher)
207*a90b9d01SCy Schubert sel &= ssid->pairwise_cipher;
208*a90b9d01SCy Schubert
209*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: peer pairwise 0x%x, select 0x%x",
210*a90b9d01SCy Schubert rsne_data.pairwise_cipher, sel);
211*a90b9d01SCy Schubert
212*a90b9d01SCy Schubert pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1);
213*a90b9d01SCy Schubert if (pairwise_cipher < 0) {
214*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_WARNING,
215*a90b9d01SCy Schubert "PASN: Failed to select pairwise cipher");
216*a90b9d01SCy Schubert return -1;
217*a90b9d01SCy Schubert }
218*a90b9d01SCy Schubert
219*a90b9d01SCy Schubert sel = rsne_data.key_mgmt;
220*a90b9d01SCy Schubert if (ssid && ssid->key_mgmt)
221*a90b9d01SCy Schubert sel &= ssid->key_mgmt;
222*a90b9d01SCy Schubert
223*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: peer AKMP 0x%x, select 0x%x",
224*a90b9d01SCy Schubert rsne_data.key_mgmt, sel);
225*a90b9d01SCy Schubert #ifdef CONFIG_SAE
226*a90b9d01SCy Schubert if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) || !ssid)
227*a90b9d01SCy Schubert sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY |
228*a90b9d01SCy Schubert WPA_KEY_MGMT_FT_SAE | WPA_KEY_MGMT_FT_SAE_EXT_KEY);
229*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
230*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211R
231*a90b9d01SCy Schubert if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME |
232*a90b9d01SCy Schubert WPA_DRIVER_FLAGS_UPDATE_FT_IES)))
233*a90b9d01SCy Schubert sel &= ~WPA_KEY_MGMT_FT;
234*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211R */
235*a90b9d01SCy Schubert if (0) {
236*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211R
237*a90b9d01SCy Schubert #ifdef CONFIG_SHA384
238*a90b9d01SCy Schubert } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
239*a90b9d01SCy Schubert os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
240*a90b9d01SCy Schubert key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
241*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FT/802.1X-SHA384");
242*a90b9d01SCy Schubert if (ssid && !ssid->ft_eap_pmksa_caching &&
243*a90b9d01SCy Schubert pmksa_cache_get_current(wpa_s->wpa)) {
244*a90b9d01SCy Schubert /* PMKSA caching with FT may have interoperability
245*a90b9d01SCy Schubert * issues, so disable that case by default for now.
246*a90b9d01SCy Schubert */
247c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
248*a90b9d01SCy Schubert "PASN: Disable PMKSA caching for FT/802.1X connection");
249*a90b9d01SCy Schubert pmksa_cache_clear_current(wpa_s->wpa);
250c1d255d3SCy Schubert }
251*a90b9d01SCy Schubert #endif /* CONFIG_SHA384 */
252*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211R */
253*a90b9d01SCy Schubert #ifdef CONFIG_SAE
254*a90b9d01SCy Schubert } else if ((sel & WPA_KEY_MGMT_SAE_EXT_KEY) &&
255*a90b9d01SCy Schubert (ieee802_11_rsnx_capab(rsnxe,
256*a90b9d01SCy Schubert WLAN_RSNX_CAPAB_SAE_H2E)) &&
257*a90b9d01SCy Schubert (wpas_pasn_sae_setup_pt(ssid, group) == 0)) {
258*a90b9d01SCy Schubert key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
259*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT SAE (ext key)");
260*a90b9d01SCy Schubert } else if ((sel & WPA_KEY_MGMT_SAE) &&
261*a90b9d01SCy Schubert (ieee802_11_rsnx_capab(rsnxe,
262*a90b9d01SCy Schubert WLAN_RSNX_CAPAB_SAE_H2E)) &&
263*a90b9d01SCy Schubert (wpas_pasn_sae_setup_pt(ssid, group) == 0)) {
264*a90b9d01SCy Schubert key_mgmt = WPA_KEY_MGMT_SAE;
265*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT SAE");
266*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
267*a90b9d01SCy Schubert #ifdef CONFIG_FILS
268*a90b9d01SCy Schubert } else if (sel & WPA_KEY_MGMT_FILS_SHA384) {
269*a90b9d01SCy Schubert key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
270*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FILS-SHA384");
271*a90b9d01SCy Schubert } else if (sel & WPA_KEY_MGMT_FILS_SHA256) {
272*a90b9d01SCy Schubert key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
273*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FILS-SHA256");
274*a90b9d01SCy Schubert #endif /* CONFIG_FILS */
275*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211R
276*a90b9d01SCy Schubert } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X) &&
277*a90b9d01SCy Schubert os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
278*a90b9d01SCy Schubert key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
279*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FT/802.1X");
280*a90b9d01SCy Schubert if (ssid && !ssid->ft_eap_pmksa_caching &&
281*a90b9d01SCy Schubert pmksa_cache_get_current(wpa_s->wpa)) {
282*a90b9d01SCy Schubert /* PMKSA caching with FT may have interoperability
283*a90b9d01SCy Schubert * issues, so disable that case by default for now.
284*a90b9d01SCy Schubert */
285c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
286*a90b9d01SCy Schubert "PASN: Disable PMKSA caching for FT/802.1X connection");
287*a90b9d01SCy Schubert pmksa_cache_clear_current(wpa_s->wpa);
288*a90b9d01SCy Schubert }
289*a90b9d01SCy Schubert } else if (sel & WPA_KEY_MGMT_FT_PSK) {
290*a90b9d01SCy Schubert key_mgmt = WPA_KEY_MGMT_FT_PSK;
291*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FT/PSK");
292*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211R */
293*a90b9d01SCy Schubert } else if (sel & WPA_KEY_MGMT_PASN) {
294*a90b9d01SCy Schubert key_mgmt = WPA_KEY_MGMT_PASN;
295*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT PASN");
296*a90b9d01SCy Schubert } else {
297*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: invalid AKMP");
298c1d255d3SCy Schubert return -1;
299c1d255d3SCy Schubert }
300c1d255d3SCy Schubert
301*a90b9d01SCy Schubert peer->akmp = key_mgmt;
302*a90b9d01SCy Schubert peer->cipher = pairwise_cipher;
303*a90b9d01SCy Schubert peer->network_id = network_id;
304*a90b9d01SCy Schubert peer->group = group;
305c1d255d3SCy Schubert return 0;
306c1d255d3SCy Schubert }
307c1d255d3SCy Schubert
308c1d255d3SCy Schubert
wpas_pasn_set_keys_from_cache(struct wpa_supplicant * wpa_s,const u8 * own_addr,const u8 * peer_addr,int cipher,int akmp)309*a90b9d01SCy Schubert static int wpas_pasn_set_keys_from_cache(struct wpa_supplicant *wpa_s,
310*a90b9d01SCy Schubert const u8 *own_addr,
311*a90b9d01SCy Schubert const u8 *peer_addr,
312*a90b9d01SCy Schubert int cipher, int akmp)
313c1d255d3SCy Schubert {
314*a90b9d01SCy Schubert struct ptksa_cache_entry *entry;
315c1d255d3SCy Schubert
316*a90b9d01SCy Schubert entry = ptksa_cache_get(wpa_s->ptksa, peer_addr, cipher);
317*a90b9d01SCy Schubert if (!entry) {
318*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: peer " MACSTR
319*a90b9d01SCy Schubert " not present in PTKSA cache", MAC2STR(peer_addr));
320*a90b9d01SCy Schubert return -1;
321c1d255d3SCy Schubert }
322c1d255d3SCy Schubert
323*a90b9d01SCy Schubert if (!ether_addr_equal(entry->own_addr, own_addr)) {
324c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
325*a90b9d01SCy Schubert "PASN: own addr " MACSTR " and PTKSA entry own addr "
326*a90b9d01SCy Schubert MACSTR " differ",
327*a90b9d01SCy Schubert MAC2STR(own_addr), MAC2STR(entry->own_addr));
328*a90b9d01SCy Schubert return -1;
329c1d255d3SCy Schubert }
330c1d255d3SCy Schubert
331*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: " MACSTR " present in PTKSA cache",
332*a90b9d01SCy Schubert MAC2STR(peer_addr));
333*a90b9d01SCy Schubert wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, peer_addr, cipher,
334*a90b9d01SCy Schubert entry->ptk.tk_len,
335*a90b9d01SCy Schubert entry->ptk.tk,
336*a90b9d01SCy Schubert entry->ptk.ltf_keyseed_len,
337*a90b9d01SCy Schubert entry->ptk.ltf_keyseed, 0);
338*a90b9d01SCy Schubert return 0;
339c1d255d3SCy Schubert }
340c1d255d3SCy Schubert
341c1d255d3SCy Schubert
wpas_pasn_configure_next_peer(struct wpa_supplicant * wpa_s,struct pasn_auth * pasn_params)342*a90b9d01SCy Schubert static void wpas_pasn_configure_next_peer(struct wpa_supplicant *wpa_s,
343*a90b9d01SCy Schubert struct pasn_auth *pasn_params)
344c1d255d3SCy Schubert {
345*a90b9d01SCy Schubert struct pasn_peer *peer;
346*a90b9d01SCy Schubert u8 comeback_len = 0;
347*a90b9d01SCy Schubert const u8 *comeback = NULL;
348c1d255d3SCy Schubert
349*a90b9d01SCy Schubert if (!pasn_params)
350*a90b9d01SCy Schubert return;
351c1d255d3SCy Schubert
352*a90b9d01SCy Schubert while (wpa_s->pasn_count < pasn_params->num_peers) {
353*a90b9d01SCy Schubert peer = &pasn_params->peer[wpa_s->pasn_count];
354c1d255d3SCy Schubert
355*a90b9d01SCy Schubert if (ether_addr_equal(wpa_s->bssid, peer->peer_addr)) {
356*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
357*a90b9d01SCy Schubert "PASN: Associated peer is not expected");
358*a90b9d01SCy Schubert peer->status = PASN_STATUS_FAILURE;
359*a90b9d01SCy Schubert wpa_s->pasn_count++;
360*a90b9d01SCy Schubert continue;
361c1d255d3SCy Schubert }
362c1d255d3SCy Schubert
363*a90b9d01SCy Schubert if (wpas_pasn_set_keys_from_cache(wpa_s, peer->own_addr,
364*a90b9d01SCy Schubert peer->peer_addr,
365*a90b9d01SCy Schubert peer->cipher,
366*a90b9d01SCy Schubert peer->akmp) == 0) {
367*a90b9d01SCy Schubert peer->status = PASN_STATUS_SUCCESS;
368*a90b9d01SCy Schubert wpa_s->pasn_count++;
369*a90b9d01SCy Schubert continue;
370c1d255d3SCy Schubert }
371c1d255d3SCy Schubert
372*a90b9d01SCy Schubert if (wpas_pasn_get_params_from_bss(wpa_s, peer)) {
373*a90b9d01SCy Schubert peer->status = PASN_STATUS_FAILURE;
374*a90b9d01SCy Schubert wpa_s->pasn_count++;
375*a90b9d01SCy Schubert continue;
376c1d255d3SCy Schubert }
377c1d255d3SCy Schubert
378*a90b9d01SCy Schubert if (wpas_pasn_auth_start(wpa_s, peer->own_addr,
379*a90b9d01SCy Schubert peer->peer_addr, peer->akmp,
380*a90b9d01SCy Schubert peer->cipher, peer->group,
381*a90b9d01SCy Schubert peer->network_id,
382*a90b9d01SCy Schubert comeback, comeback_len)) {
383*a90b9d01SCy Schubert peer->status = PASN_STATUS_FAILURE;
384*a90b9d01SCy Schubert wpa_s->pasn_count++;
385*a90b9d01SCy Schubert continue;
386*a90b9d01SCy Schubert }
387*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Sent PASN auth start for " MACSTR,
388*a90b9d01SCy Schubert MAC2STR(peer->peer_addr));
389*a90b9d01SCy Schubert return;
390*a90b9d01SCy Schubert }
391*a90b9d01SCy Schubert
392*a90b9d01SCy Schubert if (wpa_s->pasn_count == pasn_params->num_peers) {
393*a90b9d01SCy Schubert wpa_drv_send_pasn_resp(wpa_s, pasn_params);
394*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Response sent");
395*a90b9d01SCy Schubert os_free(wpa_s->pasn_params);
396*a90b9d01SCy Schubert wpa_s->pasn_params = NULL;
397*a90b9d01SCy Schubert }
398*a90b9d01SCy Schubert }
399*a90b9d01SCy Schubert
400*a90b9d01SCy Schubert
wpas_pasn_auth_work_done(struct wpa_supplicant * wpa_s,int status)401*a90b9d01SCy Schubert void wpas_pasn_auth_work_done(struct wpa_supplicant *wpa_s, int status)
402*a90b9d01SCy Schubert {
403*a90b9d01SCy Schubert if (!wpa_s->pasn_params)
404*a90b9d01SCy Schubert return;
405*a90b9d01SCy Schubert
406*a90b9d01SCy Schubert wpa_s->pasn_params->peer[wpa_s->pasn_count].status = status;
407*a90b9d01SCy Schubert wpa_s->pasn_count++;
408*a90b9d01SCy Schubert wpas_pasn_configure_next_peer(wpa_s, wpa_s->pasn_params);
409*a90b9d01SCy Schubert }
410*a90b9d01SCy Schubert
411*a90b9d01SCy Schubert
wpas_pasn_delete_peers(struct wpa_supplicant * wpa_s,struct pasn_auth * pasn_params)412*a90b9d01SCy Schubert static void wpas_pasn_delete_peers(struct wpa_supplicant *wpa_s,
413*a90b9d01SCy Schubert struct pasn_auth *pasn_params)
414*a90b9d01SCy Schubert {
415*a90b9d01SCy Schubert struct pasn_peer *peer;
416*a90b9d01SCy Schubert unsigned int i;
417*a90b9d01SCy Schubert
418*a90b9d01SCy Schubert if (!pasn_params)
419*a90b9d01SCy Schubert return;
420*a90b9d01SCy Schubert
421*a90b9d01SCy Schubert for (i = 0; i < pasn_params->num_peers; i++) {
422*a90b9d01SCy Schubert peer = &pasn_params->peer[i];
423*a90b9d01SCy Schubert ptksa_cache_flush(wpa_s->ptksa, peer->peer_addr,
424*a90b9d01SCy Schubert WPA_CIPHER_NONE);
425*a90b9d01SCy Schubert }
426*a90b9d01SCy Schubert }
427*a90b9d01SCy Schubert
428*a90b9d01SCy Schubert
429*a90b9d01SCy Schubert #ifdef CONFIG_FILS
wpas_pasn_initiate_eapol(struct pasn_data * pasn,struct wpa_ssid * ssid)430*a90b9d01SCy Schubert static void wpas_pasn_initiate_eapol(struct pasn_data *pasn,
431*a90b9d01SCy Schubert struct wpa_ssid *ssid)
432*a90b9d01SCy Schubert {
433*a90b9d01SCy Schubert struct eapol_config eapol_conf;
434*a90b9d01SCy Schubert
435*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: FILS: Initiating EAPOL");
436*a90b9d01SCy Schubert
437*a90b9d01SCy Schubert eapol_sm_notify_eap_success(pasn->eapol, false);
438*a90b9d01SCy Schubert eapol_sm_notify_eap_fail(pasn->eapol, false);
439*a90b9d01SCy Schubert eapol_sm_notify_portControl(pasn->eapol, Auto);
440*a90b9d01SCy Schubert
441*a90b9d01SCy Schubert os_memset(&eapol_conf, 0, sizeof(eapol_conf));
442*a90b9d01SCy Schubert eapol_conf.fast_reauth = pasn->fast_reauth;
443*a90b9d01SCy Schubert eapol_conf.workaround = ssid->eap_workaround;
444*a90b9d01SCy Schubert
445*a90b9d01SCy Schubert eapol_sm_notify_config(pasn->eapol, &ssid->eap, &eapol_conf);
446*a90b9d01SCy Schubert }
447*a90b9d01SCy Schubert #endif /* CONFIG_FILS */
448*a90b9d01SCy Schubert
449c1d255d3SCy Schubert
wpas_pasn_reset(struct wpa_supplicant * wpa_s)450c1d255d3SCy Schubert static void wpas_pasn_reset(struct wpa_supplicant *wpa_s)
451c1d255d3SCy Schubert {
452*a90b9d01SCy Schubert struct pasn_data *pasn = &wpa_s->pasn;
453c1d255d3SCy Schubert
454c1d255d3SCy Schubert wpas_pasn_cancel_auth_work(wpa_s);
455c1d255d3SCy Schubert wpa_s->pasn_auth_work = NULL;
456c1d255d3SCy Schubert eloop_cancel_timeout(wpas_pasn_auth_work_timeout, wpa_s, NULL);
457c1d255d3SCy Schubert
458*a90b9d01SCy Schubert wpa_pasn_reset(pasn);
459c1d255d3SCy Schubert }
460c1d255d3SCy Schubert
461c1d255d3SCy Schubert
wpas_pasn_allowed(struct wpa_supplicant * wpa_s,const u8 * peer_addr,int akmp,int cipher)462c1d255d3SCy Schubert static struct wpa_bss * wpas_pasn_allowed(struct wpa_supplicant *wpa_s,
463*a90b9d01SCy Schubert const u8 *peer_addr, int akmp,
464*a90b9d01SCy Schubert int cipher)
465c1d255d3SCy Schubert {
466c1d255d3SCy Schubert struct wpa_bss *bss;
467c1d255d3SCy Schubert const u8 *rsne;
468c1d255d3SCy Schubert struct wpa_ie_data rsne_data;
469c1d255d3SCy Schubert int ret;
470c1d255d3SCy Schubert
471*a90b9d01SCy Schubert if (ether_addr_equal(wpa_s->bssid, peer_addr)) {
472c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
473c1d255d3SCy Schubert "PASN: Not doing authentication with current BSS");
474c1d255d3SCy Schubert return NULL;
475c1d255d3SCy Schubert }
476c1d255d3SCy Schubert
477*a90b9d01SCy Schubert bss = wpa_bss_get_bssid_latest(wpa_s, peer_addr);
478c1d255d3SCy Schubert if (!bss) {
479c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: BSS not found");
480c1d255d3SCy Schubert return NULL;
481c1d255d3SCy Schubert }
482c1d255d3SCy Schubert
483c1d255d3SCy Schubert rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
484c1d255d3SCy Schubert if (!rsne) {
485c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: BSS without RSNE");
486c1d255d3SCy Schubert return NULL;
487c1d255d3SCy Schubert }
488c1d255d3SCy Schubert
489c1d255d3SCy Schubert ret = wpa_parse_wpa_ie(rsne, *(rsne + 1) + 2, &rsne_data);
490c1d255d3SCy Schubert if (ret) {
491c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE data");
492c1d255d3SCy Schubert return NULL;
493c1d255d3SCy Schubert }
494c1d255d3SCy Schubert
495c1d255d3SCy Schubert if (!(rsne_data.key_mgmt & akmp) ||
496c1d255d3SCy Schubert !(rsne_data.pairwise_cipher & cipher)) {
497c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
498c1d255d3SCy Schubert "PASN: AP does not support requested AKMP or cipher");
499c1d255d3SCy Schubert return NULL;
500c1d255d3SCy Schubert }
501c1d255d3SCy Schubert
502c1d255d3SCy Schubert return bss;
503c1d255d3SCy Schubert }
504c1d255d3SCy Schubert
505c1d255d3SCy Schubert
wpas_pasn_auth_start_cb(struct wpa_radio_work * work,int deinit)506c1d255d3SCy Schubert static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
507c1d255d3SCy Schubert {
508c1d255d3SCy Schubert struct wpa_supplicant *wpa_s = work->wpa_s;
509c1d255d3SCy Schubert struct wpa_pasn_auth_work *awork = work->ctx;
510*a90b9d01SCy Schubert struct pasn_data *pasn = &wpa_s->pasn;
511*a90b9d01SCy Schubert struct wpa_ssid *ssid;
512c1d255d3SCy Schubert struct wpa_bss *bss;
513c1d255d3SCy Schubert const u8 *rsne, *rsnxe;
514*a90b9d01SCy Schubert #ifdef CONFIG_FILS
515*a90b9d01SCy Schubert const u8 *indic;
516*a90b9d01SCy Schubert u16 fils_info;
517*a90b9d01SCy Schubert #endif /* CONFIG_FILS */
518*a90b9d01SCy Schubert u16 capab = 0;
519*a90b9d01SCy Schubert bool derive_kdk;
520c1d255d3SCy Schubert int ret;
521c1d255d3SCy Schubert
522c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: deinit=%d", deinit);
523c1d255d3SCy Schubert
524c1d255d3SCy Schubert if (deinit) {
525c1d255d3SCy Schubert if (work->started) {
526c1d255d3SCy Schubert eloop_cancel_timeout(wpas_pasn_auth_work_timeout,
527c1d255d3SCy Schubert wpa_s, NULL);
528c1d255d3SCy Schubert wpa_s->pasn_auth_work = NULL;
529c1d255d3SCy Schubert }
530c1d255d3SCy Schubert
531c1d255d3SCy Schubert wpas_pasn_free_auth_work(awork);
532c1d255d3SCy Schubert return;
533c1d255d3SCy Schubert }
534c1d255d3SCy Schubert
535c1d255d3SCy Schubert /*
536c1d255d3SCy Schubert * It is possible that by the time the callback is called, the PASN
537c1d255d3SCy Schubert * authentication is not allowed, e.g., a connection with the AP was
538c1d255d3SCy Schubert * established.
539c1d255d3SCy Schubert */
540*a90b9d01SCy Schubert bss = wpas_pasn_allowed(wpa_s, awork->peer_addr, awork->akmp,
541c1d255d3SCy Schubert awork->cipher);
542c1d255d3SCy Schubert if (!bss) {
543c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: Not allowed");
544c1d255d3SCy Schubert goto fail;
545c1d255d3SCy Schubert }
546c1d255d3SCy Schubert
547c1d255d3SCy Schubert rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
548c1d255d3SCy Schubert if (!rsne) {
549c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: BSS without RSNE");
550c1d255d3SCy Schubert goto fail;
551c1d255d3SCy Schubert }
552c1d255d3SCy Schubert
553c1d255d3SCy Schubert rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
554c1d255d3SCy Schubert
555*a90b9d01SCy Schubert derive_kdk = (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) &&
556*a90b9d01SCy Schubert ieee802_11_rsnx_capab(rsnxe,
557*a90b9d01SCy Schubert WLAN_RSNX_CAPAB_SECURE_LTF);
558*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
559*a90b9d01SCy Schubert if (!derive_kdk)
560*a90b9d01SCy Schubert derive_kdk = wpa_s->conf->force_kdk_derivation;
561*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
562*a90b9d01SCy Schubert if (derive_kdk)
563*a90b9d01SCy Schubert pasn_enable_kdk_derivation(pasn);
564*a90b9d01SCy Schubert else
565*a90b9d01SCy Schubert pasn_disable_kdk_derivation(pasn);
566*a90b9d01SCy Schubert
567*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len);
568*a90b9d01SCy Schubert
569*a90b9d01SCy Schubert if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) &&
570*a90b9d01SCy Schubert ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))
571*a90b9d01SCy Schubert pasn->secure_ltf = true;
572*a90b9d01SCy Schubert else
573*a90b9d01SCy Schubert pasn->secure_ltf = false;
574*a90b9d01SCy Schubert
575*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
576*a90b9d01SCy Schubert pasn->corrupt_mic = wpa_s->conf->pasn_corrupt_mic;
577*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
578*a90b9d01SCy Schubert
579*a90b9d01SCy Schubert capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
580*a90b9d01SCy Schubert if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA)
581*a90b9d01SCy Schubert capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
582*a90b9d01SCy Schubert if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_STA)
583*a90b9d01SCy Schubert capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
584*a90b9d01SCy Schubert if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA)
585*a90b9d01SCy Schubert capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
586*a90b9d01SCy Schubert pasn_set_rsnxe_caps(pasn, capab);
587*a90b9d01SCy Schubert pasn_register_callbacks(pasn, wpa_s, wpas_pasn_send_mlme, NULL);
588*a90b9d01SCy Schubert ssid = wpa_config_get_network(wpa_s->conf, awork->network_id);
589*a90b9d01SCy Schubert
590*a90b9d01SCy Schubert #ifdef CONFIG_SAE
591*a90b9d01SCy Schubert if (awork->akmp == WPA_KEY_MGMT_SAE) {
592*a90b9d01SCy Schubert if (!ssid) {
593*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
594*a90b9d01SCy Schubert "PASN: No network profile found for SAE");
595*a90b9d01SCy Schubert goto fail;
596*a90b9d01SCy Schubert }
597*a90b9d01SCy Schubert pasn_set_pt(pasn, wpas_pasn_sae_derive_pt(ssid, awork->group));
598*a90b9d01SCy Schubert if (!pasn->pt) {
599*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed to derive PT");
600*a90b9d01SCy Schubert goto fail;
601*a90b9d01SCy Schubert }
602*a90b9d01SCy Schubert pasn->network_id = ssid->id;
603*a90b9d01SCy Schubert }
604*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
605*a90b9d01SCy Schubert
606*a90b9d01SCy Schubert #ifdef CONFIG_FILS
607*a90b9d01SCy Schubert /* Prepare needed information for wpas_pasn_wd_fils_auth(). */
608*a90b9d01SCy Schubert if (awork->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
609*a90b9d01SCy Schubert awork->akmp == WPA_KEY_MGMT_FILS_SHA384) {
610*a90b9d01SCy Schubert indic = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
611*a90b9d01SCy Schubert if (!ssid) {
612*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: FILS: No network block");
613*a90b9d01SCy Schubert } else if (!indic || indic[1] < 2) {
614*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
615*a90b9d01SCy Schubert "PASN: Missing FILS Indication IE");
616*a90b9d01SCy Schubert } else {
617*a90b9d01SCy Schubert fils_info = WPA_GET_LE16(indic + 2);
618*a90b9d01SCy Schubert if ((fils_info & BIT(9)) && ssid) {
619*a90b9d01SCy Schubert pasn->eapol = wpa_s->eapol;
620*a90b9d01SCy Schubert pasn->network_id = ssid->id;
621*a90b9d01SCy Schubert wpas_pasn_initiate_eapol(pasn, ssid);
622*a90b9d01SCy Schubert pasn->fils_eapol = true;
623*a90b9d01SCy Schubert } else {
624*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
625*a90b9d01SCy Schubert "PASN: FILS auth without PFS not supported");
626*a90b9d01SCy Schubert }
627*a90b9d01SCy Schubert }
628*a90b9d01SCy Schubert pasn->fast_reauth = wpa_s->conf->fast_reauth;
629*a90b9d01SCy Schubert }
630*a90b9d01SCy Schubert #endif /* CONFIG_FILS */
631*a90b9d01SCy Schubert
632*a90b9d01SCy Schubert pasn_set_initiator_pmksa(pasn, wpa_sm_get_pmksa_cache(wpa_s->wpa));
633*a90b9d01SCy Schubert
634*a90b9d01SCy Schubert if (wpa_key_mgmt_ft(awork->akmp)) {
635*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211R
636*a90b9d01SCy Schubert ret = wpa_pasn_ft_derive_pmk_r1(wpa_s->wpa, awork->akmp,
637*a90b9d01SCy Schubert awork->peer_addr,
638*a90b9d01SCy Schubert pasn->pmk_r1,
639*a90b9d01SCy Schubert &pasn->pmk_r1_len,
640*a90b9d01SCy Schubert pasn->pmk_r1_name);
641*a90b9d01SCy Schubert if (ret) {
642*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
643*a90b9d01SCy Schubert "PASN: FT: Failed to derive keys");
644*a90b9d01SCy Schubert goto fail;
645*a90b9d01SCy Schubert }
646*a90b9d01SCy Schubert #else /* CONFIG_IEEE80211R */
647*a90b9d01SCy Schubert goto fail;
648*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211R */
649*a90b9d01SCy Schubert }
650*a90b9d01SCy Schubert
651*a90b9d01SCy Schubert
652*a90b9d01SCy Schubert ret = wpas_pasn_start(pasn, awork->own_addr, awork->peer_addr,
653*a90b9d01SCy Schubert awork->peer_addr, awork->akmp, awork->cipher,
654c1d255d3SCy Schubert awork->group, bss->freq, rsne, *(rsne + 1) + 2,
655c1d255d3SCy Schubert rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0,
656*a90b9d01SCy Schubert awork->comeback);
657c1d255d3SCy Schubert if (ret) {
658c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
659c1d255d3SCy Schubert "PASN: Failed to start PASN authentication");
660c1d255d3SCy Schubert goto fail;
661c1d255d3SCy Schubert }
662*a90b9d01SCy Schubert eloop_register_timeout(2, 0, wpas_pasn_auth_work_timeout, wpa_s, NULL);
663c1d255d3SCy Schubert
664c1d255d3SCy Schubert /* comeback token is no longer needed at this stage */
665c1d255d3SCy Schubert wpabuf_free(awork->comeback);
666c1d255d3SCy Schubert awork->comeback = NULL;
667c1d255d3SCy Schubert
668c1d255d3SCy Schubert wpa_s->pasn_auth_work = work;
669c1d255d3SCy Schubert return;
670c1d255d3SCy Schubert fail:
671c1d255d3SCy Schubert wpas_pasn_free_auth_work(awork);
672c1d255d3SCy Schubert work->ctx = NULL;
673c1d255d3SCy Schubert radio_work_done(work);
674c1d255d3SCy Schubert }
675c1d255d3SCy Schubert
676c1d255d3SCy Schubert
wpas_pasn_auth_start(struct wpa_supplicant * wpa_s,const u8 * own_addr,const u8 * peer_addr,int akmp,int cipher,u16 group,int network_id,const u8 * comeback,size_t comeback_len)677*a90b9d01SCy Schubert int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
678*a90b9d01SCy Schubert const u8 *own_addr, const u8 *peer_addr,
679c1d255d3SCy Schubert int akmp, int cipher, u16 group, int network_id,
680c1d255d3SCy Schubert const u8 *comeback, size_t comeback_len)
681c1d255d3SCy Schubert {
682c1d255d3SCy Schubert struct wpa_pasn_auth_work *awork;
683c1d255d3SCy Schubert struct wpa_bss *bss;
684c1d255d3SCy Schubert
685c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Start: " MACSTR " akmp=0x%x, cipher=0x%x",
686*a90b9d01SCy Schubert MAC2STR(peer_addr), akmp, cipher);
687c1d255d3SCy Schubert
688c1d255d3SCy Schubert /*
689c1d255d3SCy Schubert * TODO: Consider modifying the offchannel logic to handle additional
690c1d255d3SCy Schubert * Management frames other then Action frames. For now allow PASN only
691c1d255d3SCy Schubert * with drivers that support off-channel TX.
692c1d255d3SCy Schubert */
693c1d255d3SCy Schubert if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX)) {
694c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
695c1d255d3SCy Schubert "PASN: Driver does not support offchannel TX");
696c1d255d3SCy Schubert return -1;
697c1d255d3SCy Schubert }
698c1d255d3SCy Schubert
699c1d255d3SCy Schubert if (radio_work_pending(wpa_s, "pasn-start-auth")) {
700c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
701c1d255d3SCy Schubert "PASN: send_auth: Work is already pending");
702c1d255d3SCy Schubert return -1;
703c1d255d3SCy Schubert }
704c1d255d3SCy Schubert
705c1d255d3SCy Schubert if (wpa_s->pasn_auth_work) {
706c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: send_auth: Already in progress");
707c1d255d3SCy Schubert return -1;
708c1d255d3SCy Schubert }
709c1d255d3SCy Schubert
710*a90b9d01SCy Schubert bss = wpas_pasn_allowed(wpa_s, peer_addr, akmp, cipher);
711c1d255d3SCy Schubert if (!bss)
712c1d255d3SCy Schubert return -1;
713c1d255d3SCy Schubert
714c1d255d3SCy Schubert wpas_pasn_reset(wpa_s);
715c1d255d3SCy Schubert
716c1d255d3SCy Schubert awork = os_zalloc(sizeof(*awork));
717c1d255d3SCy Schubert if (!awork)
718c1d255d3SCy Schubert return -1;
719c1d255d3SCy Schubert
720*a90b9d01SCy Schubert os_memcpy(awork->own_addr, own_addr, ETH_ALEN);
721*a90b9d01SCy Schubert os_memcpy(awork->peer_addr, peer_addr, ETH_ALEN);
722c1d255d3SCy Schubert awork->akmp = akmp;
723c1d255d3SCy Schubert awork->cipher = cipher;
724c1d255d3SCy Schubert awork->group = group;
725c1d255d3SCy Schubert awork->network_id = network_id;
726c1d255d3SCy Schubert
727c1d255d3SCy Schubert if (comeback && comeback_len) {
728c1d255d3SCy Schubert awork->comeback = wpabuf_alloc_copy(comeback, comeback_len);
729c1d255d3SCy Schubert if (!awork->comeback) {
730c1d255d3SCy Schubert wpas_pasn_free_auth_work(awork);
731c1d255d3SCy Schubert return -1;
732c1d255d3SCy Schubert }
733c1d255d3SCy Schubert }
734c1d255d3SCy Schubert
735c1d255d3SCy Schubert if (radio_add_work(wpa_s, bss->freq, "pasn-start-auth", 1,
736c1d255d3SCy Schubert wpas_pasn_auth_start_cb, awork) < 0) {
737c1d255d3SCy Schubert wpas_pasn_free_auth_work(awork);
738c1d255d3SCy Schubert return -1;
739c1d255d3SCy Schubert }
740c1d255d3SCy Schubert
741c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Auth work successfully added");
742c1d255d3SCy Schubert return 0;
743c1d255d3SCy Schubert }
744c1d255d3SCy Schubert
745c1d255d3SCy Schubert
wpas_pasn_auth_stop(struct wpa_supplicant * wpa_s)746c1d255d3SCy Schubert void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s)
747c1d255d3SCy Schubert {
748*a90b9d01SCy Schubert struct pasn_data *pasn = &wpa_s->pasn;
749c1d255d3SCy Schubert
750c1d255d3SCy Schubert if (!wpa_s->pasn.ecdh)
751c1d255d3SCy Schubert return;
752c1d255d3SCy Schubert
753c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Stopping authentication");
754c1d255d3SCy Schubert
755*a90b9d01SCy Schubert wpas_pasn_auth_status(wpa_s, pasn->peer_addr, pasn_get_akmp(pasn),
756*a90b9d01SCy Schubert pasn_get_cipher(pasn),
757c1d255d3SCy Schubert pasn->status, pasn->comeback,
758c1d255d3SCy Schubert pasn->comeback_after);
759c1d255d3SCy Schubert
760c1d255d3SCy Schubert wpas_pasn_reset(wpa_s);
761c1d255d3SCy Schubert }
762c1d255d3SCy Schubert
763c1d255d3SCy Schubert
wpas_pasn_immediate_retry(struct wpa_supplicant * wpa_s,struct pasn_data * pasn,struct wpa_pasn_params_data * params)764c1d255d3SCy Schubert static int wpas_pasn_immediate_retry(struct wpa_supplicant *wpa_s,
765*a90b9d01SCy Schubert struct pasn_data *pasn,
766c1d255d3SCy Schubert struct wpa_pasn_params_data *params)
767c1d255d3SCy Schubert {
768*a90b9d01SCy Schubert int akmp = pasn_get_akmp(pasn);
769*a90b9d01SCy Schubert int cipher = pasn_get_cipher(pasn);
770c1d255d3SCy Schubert u16 group = pasn->group;
771*a90b9d01SCy Schubert u8 own_addr[ETH_ALEN];
772*a90b9d01SCy Schubert u8 peer_addr[ETH_ALEN];
773c1d255d3SCy Schubert
774c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Immediate retry");
775*a90b9d01SCy Schubert os_memcpy(own_addr, pasn->own_addr, ETH_ALEN);
776*a90b9d01SCy Schubert os_memcpy(peer_addr, pasn->peer_addr, ETH_ALEN);
777c1d255d3SCy Schubert wpas_pasn_reset(wpa_s);
778c1d255d3SCy Schubert
779*a90b9d01SCy Schubert return wpas_pasn_auth_start(wpa_s, own_addr, peer_addr, akmp, cipher,
780*a90b9d01SCy Schubert group, pasn->network_id,
781c1d255d3SCy Schubert params->comeback, params->comeback_len);
782c1d255d3SCy Schubert }
783c1d255d3SCy Schubert
784c1d255d3SCy Schubert
wpas_pasn_deauth_cb(struct ptksa_cache_entry * entry)785*a90b9d01SCy Schubert static void wpas_pasn_deauth_cb(struct ptksa_cache_entry *entry)
786*a90b9d01SCy Schubert {
787*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = entry->ctx;
788*a90b9d01SCy Schubert u8 own_addr[ETH_ALEN];
789*a90b9d01SCy Schubert u8 peer_addr[ETH_ALEN];
790*a90b9d01SCy Schubert
791*a90b9d01SCy Schubert /* Use a copy of the addresses from the entry to avoid issues with the
792*a90b9d01SCy Schubert * entry getting freed during deauthentication processing. */
793*a90b9d01SCy Schubert os_memcpy(own_addr, entry->own_addr, ETH_ALEN);
794*a90b9d01SCy Schubert os_memcpy(peer_addr, entry->addr, ETH_ALEN);
795*a90b9d01SCy Schubert wpas_pasn_deauthenticate(wpa_s, own_addr, peer_addr);
796*a90b9d01SCy Schubert }
797*a90b9d01SCy Schubert
798*a90b9d01SCy Schubert
wpas_pasn_auth_rx(struct wpa_supplicant * wpa_s,const struct ieee80211_mgmt * mgmt,size_t len)799c1d255d3SCy Schubert int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
800c1d255d3SCy Schubert const struct ieee80211_mgmt *mgmt, size_t len)
801c1d255d3SCy Schubert {
802*a90b9d01SCy Schubert struct pasn_data *pasn = &wpa_s->pasn;
803*a90b9d01SCy Schubert struct wpa_pasn_params_data pasn_data;
804*a90b9d01SCy Schubert int ret;
805c1d255d3SCy Schubert
806*a90b9d01SCy Schubert if (!wpa_s->pasn_auth_work)
807c1d255d3SCy Schubert return -2;
808c1d255d3SCy Schubert
809*a90b9d01SCy Schubert pasn_register_callbacks(pasn, wpa_s, wpas_pasn_send_mlme, NULL);
810*a90b9d01SCy Schubert ret = wpa_pasn_auth_rx(pasn, (const u8 *) mgmt, len, &pasn_data);
811*a90b9d01SCy Schubert if (ret == 0) {
812*a90b9d01SCy Schubert ptksa_cache_add(wpa_s->ptksa, pasn->own_addr, pasn->peer_addr,
813*a90b9d01SCy Schubert pasn_get_cipher(pasn),
814*a90b9d01SCy Schubert dot11RSNAConfigPMKLifetime,
815*a90b9d01SCy Schubert pasn_get_ptk(pasn),
816*a90b9d01SCy Schubert wpa_s->pasn_params ? wpas_pasn_deauth_cb : NULL,
817*a90b9d01SCy Schubert wpa_s->pasn_params ? wpa_s : NULL,
818*a90b9d01SCy Schubert pasn_get_akmp(pasn));
819c1d255d3SCy Schubert
820*a90b9d01SCy Schubert if (pasn->pmksa_entry)
821*a90b9d01SCy Schubert wpa_sm_set_cur_pmksa(wpa_s->wpa, pasn->pmksa_entry);
822c1d255d3SCy Schubert }
823c1d255d3SCy Schubert
824*a90b9d01SCy Schubert forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk));
825c1d255d3SCy Schubert
826*a90b9d01SCy Schubert if (ret == -1) {
827c1d255d3SCy Schubert wpas_pasn_auth_stop(wpa_s);
828*a90b9d01SCy Schubert wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_FAILURE);
829c1d255d3SCy Schubert }
830c1d255d3SCy Schubert
831*a90b9d01SCy Schubert if (ret == 1)
832*a90b9d01SCy Schubert ret = wpas_pasn_immediate_retry(wpa_s, pasn, &pasn_data);
833*a90b9d01SCy Schubert
834*a90b9d01SCy Schubert return ret;
835*a90b9d01SCy Schubert }
836*a90b9d01SCy Schubert
837*a90b9d01SCy Schubert
wpas_pasn_auth_trigger(struct wpa_supplicant * wpa_s,struct pasn_auth * pasn_auth)838*a90b9d01SCy Schubert void wpas_pasn_auth_trigger(struct wpa_supplicant *wpa_s,
839*a90b9d01SCy Schubert struct pasn_auth *pasn_auth)
840*a90b9d01SCy Schubert {
841*a90b9d01SCy Schubert struct pasn_peer *src, *dst;
842*a90b9d01SCy Schubert unsigned int i, num_peers = pasn_auth->num_peers;
843*a90b9d01SCy Schubert
844*a90b9d01SCy Schubert if (wpa_s->pasn_params) {
845c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
846*a90b9d01SCy Schubert "PASN: auth_trigger: Already in progress");
847*a90b9d01SCy Schubert return;
848c1d255d3SCy Schubert }
849c1d255d3SCy Schubert
850*a90b9d01SCy Schubert if (!num_peers || num_peers > WPAS_MAX_PASN_PEERS) {
851c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
852*a90b9d01SCy Schubert "PASN: auth trigger: Invalid number of peers");
853*a90b9d01SCy Schubert return;
854c1d255d3SCy Schubert }
855c1d255d3SCy Schubert
856*a90b9d01SCy Schubert wpa_s->pasn_params = os_zalloc(sizeof(struct pasn_auth));
857*a90b9d01SCy Schubert if (!wpa_s->pasn_params) {
858c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
859*a90b9d01SCy Schubert "PASN: auth trigger: Failed to allocate a buffer");
860*a90b9d01SCy Schubert return;
861c1d255d3SCy Schubert }
862c1d255d3SCy Schubert
863*a90b9d01SCy Schubert wpa_s->pasn_count = 0;
864*a90b9d01SCy Schubert wpa_s->pasn_params->num_peers = num_peers;
865c1d255d3SCy Schubert
866*a90b9d01SCy Schubert for (i = 0; i < num_peers; i++) {
867*a90b9d01SCy Schubert dst = &wpa_s->pasn_params->peer[i];
868*a90b9d01SCy Schubert src = &pasn_auth->peer[i];
869*a90b9d01SCy Schubert os_memcpy(dst->own_addr, wpa_s->own_addr, ETH_ALEN);
870*a90b9d01SCy Schubert os_memcpy(dst->peer_addr, src->peer_addr, ETH_ALEN);
871*a90b9d01SCy Schubert dst->ltf_keyseed_required = src->ltf_keyseed_required;
872*a90b9d01SCy Schubert dst->status = PASN_STATUS_SUCCESS;
873c1d255d3SCy Schubert
874*a90b9d01SCy Schubert if (!is_zero_ether_addr(src->own_addr)) {
875*a90b9d01SCy Schubert os_memcpy(dst->own_addr, src->own_addr, ETH_ALEN);
876*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Own (source) MAC addr: "
877*a90b9d01SCy Schubert MACSTR, MAC2STR(dst->own_addr));
878c1d255d3SCy Schubert }
879c1d255d3SCy Schubert }
880c1d255d3SCy Schubert
881*a90b9d01SCy Schubert if (pasn_auth->action == PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT) {
882*a90b9d01SCy Schubert wpas_pasn_delete_peers(wpa_s, wpa_s->pasn_params);
883*a90b9d01SCy Schubert os_free(wpa_s->pasn_params);
884*a90b9d01SCy Schubert wpa_s->pasn_params = NULL;
885*a90b9d01SCy Schubert } else if (pasn_auth->action == PASN_ACTION_AUTH) {
886*a90b9d01SCy Schubert wpas_pasn_configure_next_peer(wpa_s, wpa_s->pasn_params);
887c1d255d3SCy Schubert }
888c1d255d3SCy Schubert }
889c1d255d3SCy Schubert
890c1d255d3SCy Schubert
wpas_pasn_auth_tx_status(struct wpa_supplicant * wpa_s,const u8 * data,size_t data_len,u8 acked)891c1d255d3SCy Schubert int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
892c1d255d3SCy Schubert const u8 *data, size_t data_len, u8 acked)
893c1d255d3SCy Schubert
894c1d255d3SCy Schubert {
895*a90b9d01SCy Schubert struct pasn_data *pasn = &wpa_s->pasn;
896*a90b9d01SCy Schubert int ret;
897c1d255d3SCy Schubert
898c1d255d3SCy Schubert if (!wpa_s->pasn_auth_work) {
899c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
900c1d255d3SCy Schubert "PASN: auth_tx_status: no work in progress");
901c1d255d3SCy Schubert return -1;
902c1d255d3SCy Schubert }
903c1d255d3SCy Schubert
904*a90b9d01SCy Schubert ret = wpa_pasn_auth_tx_status(pasn, data, data_len, acked);
905*a90b9d01SCy Schubert if (ret != 1)
906*a90b9d01SCy Schubert return ret;
907c1d255d3SCy Schubert
908*a90b9d01SCy Schubert if (!wpa_s->pasn_params) {
909c1d255d3SCy Schubert wpas_pasn_auth_stop(wpa_s);
910*a90b9d01SCy Schubert return 0;
911c1d255d3SCy Schubert }
912c1d255d3SCy Schubert
913*a90b9d01SCy Schubert wpas_pasn_set_keys_from_cache(wpa_s, pasn->own_addr, pasn->peer_addr,
914*a90b9d01SCy Schubert pasn_get_cipher(pasn),
915*a90b9d01SCy Schubert pasn_get_akmp(pasn));
916*a90b9d01SCy Schubert wpas_pasn_auth_stop(wpa_s);
917*a90b9d01SCy Schubert wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_SUCCESS);
918*a90b9d01SCy Schubert
919c1d255d3SCy Schubert return 0;
920c1d255d3SCy Schubert }
921c1d255d3SCy Schubert
922c1d255d3SCy Schubert
wpas_pasn_deauthenticate(struct wpa_supplicant * wpa_s,const u8 * own_addr,const u8 * peer_addr)923*a90b9d01SCy Schubert int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *own_addr,
924*a90b9d01SCy Schubert const u8 *peer_addr)
925c1d255d3SCy Schubert {
926c1d255d3SCy Schubert struct wpa_bss *bss;
927c1d255d3SCy Schubert struct wpabuf *buf;
928c1d255d3SCy Schubert struct ieee80211_mgmt *deauth;
929c1d255d3SCy Schubert int ret;
930c1d255d3SCy Schubert
931*a90b9d01SCy Schubert if (ether_addr_equal(wpa_s->bssid, peer_addr)) {
932c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
933c1d255d3SCy Schubert "PASN: Cannot deauthenticate from current BSS");
934c1d255d3SCy Schubert return -1;
935c1d255d3SCy Schubert }
936c1d255d3SCy Schubert
937*a90b9d01SCy Schubert wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, peer_addr, 0, 0, NULL,
938*a90b9d01SCy Schubert 0, NULL, 1);
939c1d255d3SCy Schubert
940*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: deauth: Flushing all PTKSA entries for "
941*a90b9d01SCy Schubert MACSTR, MAC2STR(peer_addr));
942*a90b9d01SCy Schubert ptksa_cache_flush(wpa_s->ptksa, peer_addr, WPA_CIPHER_NONE);
943*a90b9d01SCy Schubert
944*a90b9d01SCy Schubert bss = wpa_bss_get_bssid(wpa_s, peer_addr);
945c1d255d3SCy Schubert if (!bss) {
946c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: deauth: BSS not found");
947c1d255d3SCy Schubert return -1;
948c1d255d3SCy Schubert }
949c1d255d3SCy Schubert
950c1d255d3SCy Schubert buf = wpabuf_alloc(64);
951c1d255d3SCy Schubert if (!buf) {
952c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: deauth: Failed wpabuf allocate");
953c1d255d3SCy Schubert return -1;
954c1d255d3SCy Schubert }
955c1d255d3SCy Schubert
956c1d255d3SCy Schubert deauth = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
957c1d255d3SCy Schubert u.deauth.variable));
958c1d255d3SCy Schubert
959c1d255d3SCy Schubert deauth->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
960c1d255d3SCy Schubert (WLAN_FC_STYPE_DEAUTH << 4));
961c1d255d3SCy Schubert
962*a90b9d01SCy Schubert os_memcpy(deauth->da, peer_addr, ETH_ALEN);
963*a90b9d01SCy Schubert os_memcpy(deauth->sa, own_addr, ETH_ALEN);
964*a90b9d01SCy Schubert os_memcpy(deauth->bssid, peer_addr, ETH_ALEN);
965c1d255d3SCy Schubert deauth->u.deauth.reason_code =
966c1d255d3SCy Schubert host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
967c1d255d3SCy Schubert
968c1d255d3SCy Schubert /*
969c1d255d3SCy Schubert * Since we do not expect any response from the AP, implement the
970c1d255d3SCy Schubert * Deauthentication frame transmission using direct call to the driver
971c1d255d3SCy Schubert * without a radio work.
972c1d255d3SCy Schubert */
973c1d255d3SCy Schubert ret = wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
974c1d255d3SCy Schubert bss->freq, 0);
975c1d255d3SCy Schubert
976c1d255d3SCy Schubert wpabuf_free(buf);
977c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "PASN: deauth: send_mlme ret=%d", ret);
978c1d255d3SCy Schubert
979c1d255d3SCy Schubert return ret;
980c1d255d3SCy Schubert }
981