1*a90b9d01SCy Schubert /*
2*a90b9d01SCy Schubert * PASN responder processing
3*a90b9d01SCy Schubert *
4*a90b9d01SCy Schubert * Copyright (C) 2019, Intel Corporation
5*a90b9d01SCy Schubert * Copyright (C) 2022, Qualcomm Innovation Center, Inc.
6*a90b9d01SCy Schubert *
7*a90b9d01SCy Schubert * This software may be distributed under the terms of the BSD license.
8*a90b9d01SCy Schubert * See README for more details.
9*a90b9d01SCy Schubert */
10*a90b9d01SCy Schubert
11*a90b9d01SCy Schubert #include "utils/includes.h"
12*a90b9d01SCy Schubert
13*a90b9d01SCy Schubert #include "utils/common.h"
14*a90b9d01SCy Schubert #include "common/wpa_common.h"
15*a90b9d01SCy Schubert #include "common/sae.h"
16*a90b9d01SCy Schubert #include "common/ieee802_11_common.h"
17*a90b9d01SCy Schubert #include "common/ieee802_11_defs.h"
18*a90b9d01SCy Schubert #include "crypto/sha384.h"
19*a90b9d01SCy Schubert #include "crypto/sha256.h"
20*a90b9d01SCy Schubert #include "crypto/random.h"
21*a90b9d01SCy Schubert #include "crypto/crypto.h"
22*a90b9d01SCy Schubert #include "ap/hostapd.h"
23*a90b9d01SCy Schubert #include "ap/comeback_token.h"
24*a90b9d01SCy Schubert #include "ap/ieee802_1x.h"
25*a90b9d01SCy Schubert #include "ap/pmksa_cache_auth.h"
26*a90b9d01SCy Schubert #include "pasn_common.h"
27*a90b9d01SCy Schubert
28*a90b9d01SCy Schubert
pasn_set_responder_pmksa(struct pasn_data * pasn,struct rsn_pmksa_cache * pmksa)29*a90b9d01SCy Schubert void pasn_set_responder_pmksa(struct pasn_data *pasn,
30*a90b9d01SCy Schubert struct rsn_pmksa_cache *pmksa)
31*a90b9d01SCy Schubert {
32*a90b9d01SCy Schubert if (pasn)
33*a90b9d01SCy Schubert pasn->pmksa = pmksa;
34*a90b9d01SCy Schubert }
35*a90b9d01SCy Schubert
36*a90b9d01SCy Schubert
37*a90b9d01SCy Schubert #ifdef CONFIG_PASN
38*a90b9d01SCy Schubert #ifdef CONFIG_SAE
39*a90b9d01SCy Schubert
pasn_wd_handle_sae_commit(struct pasn_data * pasn,const u8 * own_addr,const u8 * peer_addr,struct wpabuf * wd)40*a90b9d01SCy Schubert static int pasn_wd_handle_sae_commit(struct pasn_data *pasn,
41*a90b9d01SCy Schubert const u8 *own_addr, const u8 *peer_addr,
42*a90b9d01SCy Schubert struct wpabuf *wd)
43*a90b9d01SCy Schubert {
44*a90b9d01SCy Schubert const u8 *data;
45*a90b9d01SCy Schubert size_t buf_len;
46*a90b9d01SCy Schubert u16 res, alg, seq, status;
47*a90b9d01SCy Schubert int groups[] = { pasn->group, 0 };
48*a90b9d01SCy Schubert int ret;
49*a90b9d01SCy Schubert
50*a90b9d01SCy Schubert if (!wd)
51*a90b9d01SCy Schubert return -1;
52*a90b9d01SCy Schubert
53*a90b9d01SCy Schubert data = wpabuf_head_u8(wd);
54*a90b9d01SCy Schubert buf_len = wpabuf_len(wd);
55*a90b9d01SCy Schubert
56*a90b9d01SCy Schubert if (buf_len < 6) {
57*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu",
58*a90b9d01SCy Schubert buf_len);
59*a90b9d01SCy Schubert return -1;
60*a90b9d01SCy Schubert }
61*a90b9d01SCy Schubert
62*a90b9d01SCy Schubert alg = WPA_GET_LE16(data);
63*a90b9d01SCy Schubert seq = WPA_GET_LE16(data + 2);
64*a90b9d01SCy Schubert status = WPA_GET_LE16(data + 4);
65*a90b9d01SCy Schubert
66*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: SAE commit: alg=%u, seq=%u, status=%u",
67*a90b9d01SCy Schubert alg, seq, status);
68*a90b9d01SCy Schubert
69*a90b9d01SCy Schubert if (alg != WLAN_AUTH_SAE || seq != 1 ||
70*a90b9d01SCy Schubert status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
71*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit");
72*a90b9d01SCy Schubert return -1;
73*a90b9d01SCy Schubert }
74*a90b9d01SCy Schubert
75*a90b9d01SCy Schubert sae_clear_data(&pasn->sae);
76*a90b9d01SCy Schubert pasn->sae.state = SAE_NOTHING;
77*a90b9d01SCy Schubert
78*a90b9d01SCy Schubert ret = sae_set_group(&pasn->sae, pasn->group);
79*a90b9d01SCy Schubert if (ret) {
80*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group");
81*a90b9d01SCy Schubert return -1;
82*a90b9d01SCy Schubert }
83*a90b9d01SCy Schubert
84*a90b9d01SCy Schubert if (!pasn->password || !pasn->pt) {
85*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: No SAE PT found");
86*a90b9d01SCy Schubert return -1;
87*a90b9d01SCy Schubert }
88*a90b9d01SCy Schubert
89*a90b9d01SCy Schubert ret = sae_prepare_commit_pt(&pasn->sae, pasn->pt, own_addr, peer_addr,
90*a90b9d01SCy Schubert NULL, NULL);
91*a90b9d01SCy Schubert if (ret) {
92*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit");
93*a90b9d01SCy Schubert return -1;
94*a90b9d01SCy Schubert }
95*a90b9d01SCy Schubert
96*a90b9d01SCy Schubert res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0,
97*a90b9d01SCy Schubert groups, 0, NULL);
98*a90b9d01SCy Schubert if (res != WLAN_STATUS_SUCCESS) {
99*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit");
100*a90b9d01SCy Schubert return -1;
101*a90b9d01SCy Schubert }
102*a90b9d01SCy Schubert
103*a90b9d01SCy Schubert /* Process the commit message and derive the PMK */
104*a90b9d01SCy Schubert ret = sae_process_commit(&pasn->sae);
105*a90b9d01SCy Schubert if (ret) {
106*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
107*a90b9d01SCy Schubert return -1;
108*a90b9d01SCy Schubert }
109*a90b9d01SCy Schubert
110*a90b9d01SCy Schubert pasn->sae.state = SAE_COMMITTED;
111*a90b9d01SCy Schubert
112*a90b9d01SCy Schubert return 0;
113*a90b9d01SCy Schubert }
114*a90b9d01SCy Schubert
115*a90b9d01SCy Schubert
pasn_wd_handle_sae_confirm(struct pasn_data * pasn,const u8 * peer_addr,struct wpabuf * wd)116*a90b9d01SCy Schubert static int pasn_wd_handle_sae_confirm(struct pasn_data *pasn,
117*a90b9d01SCy Schubert const u8 *peer_addr, struct wpabuf *wd)
118*a90b9d01SCy Schubert {
119*a90b9d01SCy Schubert const u8 *data;
120*a90b9d01SCy Schubert size_t buf_len;
121*a90b9d01SCy Schubert u16 res, alg, seq, status;
122*a90b9d01SCy Schubert
123*a90b9d01SCy Schubert if (!wd)
124*a90b9d01SCy Schubert return -1;
125*a90b9d01SCy Schubert
126*a90b9d01SCy Schubert data = wpabuf_head_u8(wd);
127*a90b9d01SCy Schubert buf_len = wpabuf_len(wd);
128*a90b9d01SCy Schubert
129*a90b9d01SCy Schubert if (buf_len < 6) {
130*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu",
131*a90b9d01SCy Schubert buf_len);
132*a90b9d01SCy Schubert return -1;
133*a90b9d01SCy Schubert }
134*a90b9d01SCy Schubert
135*a90b9d01SCy Schubert alg = WPA_GET_LE16(data);
136*a90b9d01SCy Schubert seq = WPA_GET_LE16(data + 2);
137*a90b9d01SCy Schubert status = WPA_GET_LE16(data + 4);
138*a90b9d01SCy Schubert
139*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u",
140*a90b9d01SCy Schubert alg, seq, status);
141*a90b9d01SCy Schubert
142*a90b9d01SCy Schubert if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) {
143*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm");
144*a90b9d01SCy Schubert return -1;
145*a90b9d01SCy Schubert }
146*a90b9d01SCy Schubert
147*a90b9d01SCy Schubert res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6, NULL);
148*a90b9d01SCy Schubert if (res != WLAN_STATUS_SUCCESS) {
149*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm");
150*a90b9d01SCy Schubert return -1;
151*a90b9d01SCy Schubert }
152*a90b9d01SCy Schubert
153*a90b9d01SCy Schubert pasn->sae.state = SAE_ACCEPTED;
154*a90b9d01SCy Schubert
155*a90b9d01SCy Schubert /*
156*a90b9d01SCy Schubert * TODO: Based on on IEEE P802.11az/D2.6, the PMKSA derived with
157*a90b9d01SCy Schubert * PASN/SAE should only be allowed with future PASN only. For now do not
158*a90b9d01SCy Schubert * restrict this only for PASN.
159*a90b9d01SCy Schubert */
160*a90b9d01SCy Schubert if (pasn->disable_pmksa_caching)
161*a90b9d01SCy Schubert return 0;
162*a90b9d01SCy Schubert
163*a90b9d01SCy Schubert wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE",
164*a90b9d01SCy Schubert pasn->sae.pmk, pasn->sae.pmk_len);
165*a90b9d01SCy Schubert if (!pasn->sae.akmp)
166*a90b9d01SCy Schubert pasn->sae.akmp = WPA_KEY_MGMT_SAE;
167*a90b9d01SCy Schubert
168*a90b9d01SCy Schubert pmksa_cache_auth_add(pasn->pmksa, pasn->sae.pmk, pasn->sae.pmk_len,
169*a90b9d01SCy Schubert pasn->sae.pmkid, NULL, 0, pasn->own_addr,
170*a90b9d01SCy Schubert peer_addr, 0, NULL, pasn->sae.akmp);
171*a90b9d01SCy Schubert return 0;
172*a90b9d01SCy Schubert }
173*a90b9d01SCy Schubert
174*a90b9d01SCy Schubert
pasn_get_sae_wd(struct pasn_data * pasn)175*a90b9d01SCy Schubert static struct wpabuf * pasn_get_sae_wd(struct pasn_data *pasn)
176*a90b9d01SCy Schubert {
177*a90b9d01SCy Schubert struct wpabuf *buf = NULL;
178*a90b9d01SCy Schubert u8 *len_ptr;
179*a90b9d01SCy Schubert size_t len;
180*a90b9d01SCy Schubert
181*a90b9d01SCy Schubert /* Need to add the entire Authentication frame body */
182*a90b9d01SCy Schubert buf = wpabuf_alloc(8 + SAE_COMMIT_MAX_LEN + 8 + SAE_CONFIRM_MAX_LEN);
183*a90b9d01SCy Schubert if (!buf) {
184*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
185*a90b9d01SCy Schubert return NULL;
186*a90b9d01SCy Schubert }
187*a90b9d01SCy Schubert
188*a90b9d01SCy Schubert /* Need to add the entire authentication frame body for the commit */
189*a90b9d01SCy Schubert len_ptr = wpabuf_put(buf, 2);
190*a90b9d01SCy Schubert wpabuf_put_le16(buf, WLAN_AUTH_SAE);
191*a90b9d01SCy Schubert wpabuf_put_le16(buf, 1);
192*a90b9d01SCy Schubert wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
193*a90b9d01SCy Schubert
194*a90b9d01SCy Schubert /* Write the actual commit and update the length accordingly */
195*a90b9d01SCy Schubert sae_write_commit(&pasn->sae, buf, NULL, 0);
196*a90b9d01SCy Schubert len = wpabuf_len(buf);
197*a90b9d01SCy Schubert WPA_PUT_LE16(len_ptr, len - 2);
198*a90b9d01SCy Schubert
199*a90b9d01SCy Schubert /* Need to add the entire Authentication frame body for the confirm */
200*a90b9d01SCy Schubert len_ptr = wpabuf_put(buf, 2);
201*a90b9d01SCy Schubert wpabuf_put_le16(buf, WLAN_AUTH_SAE);
202*a90b9d01SCy Schubert wpabuf_put_le16(buf, 2);
203*a90b9d01SCy Schubert wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
204*a90b9d01SCy Schubert
205*a90b9d01SCy Schubert sae_write_confirm(&pasn->sae, buf);
206*a90b9d01SCy Schubert WPA_PUT_LE16(len_ptr, wpabuf_len(buf) - len - 2);
207*a90b9d01SCy Schubert
208*a90b9d01SCy Schubert pasn->sae.state = SAE_CONFIRMED;
209*a90b9d01SCy Schubert
210*a90b9d01SCy Schubert return buf;
211*a90b9d01SCy Schubert }
212*a90b9d01SCy Schubert
213*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
214*a90b9d01SCy Schubert
215*a90b9d01SCy Schubert
216*a90b9d01SCy Schubert #ifdef CONFIG_FILS
217*a90b9d01SCy Schubert
pasn_get_fils_wd(struct pasn_data * pasn)218*a90b9d01SCy Schubert static struct wpabuf * pasn_get_fils_wd(struct pasn_data *pasn)
219*a90b9d01SCy Schubert {
220*a90b9d01SCy Schubert struct pasn_fils *fils = &pasn->fils;
221*a90b9d01SCy Schubert struct wpabuf *buf = NULL;
222*a90b9d01SCy Schubert
223*a90b9d01SCy Schubert if (!fils->erp_resp) {
224*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: FILS: Missing erp_resp");
225*a90b9d01SCy Schubert return NULL;
226*a90b9d01SCy Schubert }
227*a90b9d01SCy Schubert
228*a90b9d01SCy Schubert buf = wpabuf_alloc(1500);
229*a90b9d01SCy Schubert if (!buf)
230*a90b9d01SCy Schubert return NULL;
231*a90b9d01SCy Schubert
232*a90b9d01SCy Schubert /* Add the authentication algorithm */
233*a90b9d01SCy Schubert wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK);
234*a90b9d01SCy Schubert
235*a90b9d01SCy Schubert /* Authentication Transaction seq# */
236*a90b9d01SCy Schubert wpabuf_put_le16(buf, 2);
237*a90b9d01SCy Schubert
238*a90b9d01SCy Schubert /* Status Code */
239*a90b9d01SCy Schubert wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
240*a90b9d01SCy Schubert
241*a90b9d01SCy Schubert /* Own RSNE */
242*a90b9d01SCy Schubert wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
243*a90b9d01SCy Schubert
244*a90b9d01SCy Schubert /* FILS Nonce */
245*a90b9d01SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
246*a90b9d01SCy Schubert wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN);
247*a90b9d01SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
248*a90b9d01SCy Schubert wpabuf_put_data(buf, fils->anonce, FILS_NONCE_LEN);
249*a90b9d01SCy Schubert
250*a90b9d01SCy Schubert /* FILS Session */
251*a90b9d01SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
252*a90b9d01SCy Schubert wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN);
253*a90b9d01SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
254*a90b9d01SCy Schubert wpabuf_put_data(buf, fils->session, FILS_SESSION_LEN);
255*a90b9d01SCy Schubert
256*a90b9d01SCy Schubert /* Wrapped Data */
257*a90b9d01SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
258*a90b9d01SCy Schubert wpabuf_put_u8(buf, 1 + wpabuf_len(fils->erp_resp));
259*a90b9d01SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
260*a90b9d01SCy Schubert wpabuf_put_buf(buf, fils->erp_resp);
261*a90b9d01SCy Schubert
262*a90b9d01SCy Schubert return buf;
263*a90b9d01SCy Schubert }
264*a90b9d01SCy Schubert
265*a90b9d01SCy Schubert #endif /* CONFIG_FILS */
266*a90b9d01SCy Schubert
pasn_get_wrapped_data(struct pasn_data * pasn)267*a90b9d01SCy Schubert static struct wpabuf * pasn_get_wrapped_data(struct pasn_data *pasn)
268*a90b9d01SCy Schubert {
269*a90b9d01SCy Schubert switch (pasn->akmp) {
270*a90b9d01SCy Schubert case WPA_KEY_MGMT_PASN:
271*a90b9d01SCy Schubert /* no wrapped data */
272*a90b9d01SCy Schubert return NULL;
273*a90b9d01SCy Schubert case WPA_KEY_MGMT_SAE:
274*a90b9d01SCy Schubert #ifdef CONFIG_SAE
275*a90b9d01SCy Schubert return pasn_get_sae_wd(pasn);
276*a90b9d01SCy Schubert #else /* CONFIG_SAE */
277*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
278*a90b9d01SCy Schubert "PASN: SAE: Cannot derive wrapped data");
279*a90b9d01SCy Schubert return NULL;
280*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
281*a90b9d01SCy Schubert case WPA_KEY_MGMT_FILS_SHA256:
282*a90b9d01SCy Schubert case WPA_KEY_MGMT_FILS_SHA384:
283*a90b9d01SCy Schubert #ifdef CONFIG_FILS
284*a90b9d01SCy Schubert return pasn_get_fils_wd(pasn);
285*a90b9d01SCy Schubert #endif /* CONFIG_FILS */
286*a90b9d01SCy Schubert /* fall through */
287*a90b9d01SCy Schubert case WPA_KEY_MGMT_FT_PSK:
288*a90b9d01SCy Schubert case WPA_KEY_MGMT_FT_IEEE8021X:
289*a90b9d01SCy Schubert case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
290*a90b9d01SCy Schubert default:
291*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
292*a90b9d01SCy Schubert "PASN: TODO: Wrapped data for akmp=0x%x",
293*a90b9d01SCy Schubert pasn->akmp);
294*a90b9d01SCy Schubert return NULL;
295*a90b9d01SCy Schubert }
296*a90b9d01SCy Schubert }
297*a90b9d01SCy Schubert
298*a90b9d01SCy Schubert
299*a90b9d01SCy Schubert static int
pasn_derive_keys(struct pasn_data * pasn,const u8 * own_addr,const u8 * peer_addr,const u8 * cached_pmk,size_t cached_pmk_len,struct wpa_pasn_params_data * pasn_data,struct wpabuf * wrapped_data,struct wpabuf * secret)300*a90b9d01SCy Schubert pasn_derive_keys(struct pasn_data *pasn,
301*a90b9d01SCy Schubert const u8 *own_addr, const u8 *peer_addr,
302*a90b9d01SCy Schubert const u8 *cached_pmk, size_t cached_pmk_len,
303*a90b9d01SCy Schubert struct wpa_pasn_params_data *pasn_data,
304*a90b9d01SCy Schubert struct wpabuf *wrapped_data,
305*a90b9d01SCy Schubert struct wpabuf *secret)
306*a90b9d01SCy Schubert {
307*a90b9d01SCy Schubert static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'};
308*a90b9d01SCy Schubert u8 pmk[PMK_LEN_MAX];
309*a90b9d01SCy Schubert u8 pmk_len;
310*a90b9d01SCy Schubert int ret;
311*a90b9d01SCy Schubert
312*a90b9d01SCy Schubert os_memset(pmk, 0, sizeof(pmk));
313*a90b9d01SCy Schubert pmk_len = 0;
314*a90b9d01SCy Schubert
315*a90b9d01SCy Schubert if (!cached_pmk || !cached_pmk_len)
316*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: No valid PMKSA entry");
317*a90b9d01SCy Schubert
318*a90b9d01SCy Schubert if (pasn->akmp == WPA_KEY_MGMT_PASN) {
319*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Using default PMK");
320*a90b9d01SCy Schubert
321*a90b9d01SCy Schubert pmk_len = WPA_PASN_PMK_LEN;
322*a90b9d01SCy Schubert os_memcpy(pmk, pasn_default_pmk, sizeof(pasn_default_pmk));
323*a90b9d01SCy Schubert } else if (cached_pmk && cached_pmk_len) {
324*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Using PMKSA entry");
325*a90b9d01SCy Schubert
326*a90b9d01SCy Schubert pmk_len = cached_pmk_len;
327*a90b9d01SCy Schubert os_memcpy(pmk, cached_pmk, cached_pmk_len);
328*a90b9d01SCy Schubert } else {
329*a90b9d01SCy Schubert switch (pasn->akmp) {
330*a90b9d01SCy Schubert #ifdef CONFIG_SAE
331*a90b9d01SCy Schubert case WPA_KEY_MGMT_SAE:
332*a90b9d01SCy Schubert if (pasn->sae.state == SAE_COMMITTED) {
333*a90b9d01SCy Schubert pmk_len = PMK_LEN;
334*a90b9d01SCy Schubert os_memcpy(pmk, pasn->sae.pmk, PMK_LEN);
335*a90b9d01SCy Schubert break;
336*a90b9d01SCy Schubert }
337*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
338*a90b9d01SCy Schubert /* fall through */
339*a90b9d01SCy Schubert default:
340*a90b9d01SCy Schubert /* TODO: Derive PMK based on wrapped data */
341*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
342*a90b9d01SCy Schubert "PASN: Missing PMK derivation");
343*a90b9d01SCy Schubert return -1;
344*a90b9d01SCy Schubert }
345*a90b9d01SCy Schubert }
346*a90b9d01SCy Schubert
347*a90b9d01SCy Schubert pasn->pmk_len = pmk_len;
348*a90b9d01SCy Schubert os_memcpy(pasn->pmk, pmk, pmk_len);
349*a90b9d01SCy Schubert ret = pasn_pmk_to_ptk(pmk, pmk_len, peer_addr, own_addr,
350*a90b9d01SCy Schubert wpabuf_head(secret), wpabuf_len(secret),
351*a90b9d01SCy Schubert &pasn->ptk, pasn->akmp,
352*a90b9d01SCy Schubert pasn->cipher, pasn->kdk_len);
353*a90b9d01SCy Schubert if (ret) {
354*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
355*a90b9d01SCy Schubert return -1;
356*a90b9d01SCy Schubert }
357*a90b9d01SCy Schubert
358*a90b9d01SCy Schubert if (pasn->secure_ltf) {
359*a90b9d01SCy Schubert ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp,
360*a90b9d01SCy Schubert pasn->cipher);
361*a90b9d01SCy Schubert if (ret) {
362*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
363*a90b9d01SCy Schubert "PASN: Failed to derive LTF keyseed");
364*a90b9d01SCy Schubert return -1;
365*a90b9d01SCy Schubert }
366*a90b9d01SCy Schubert }
367*a90b9d01SCy Schubert
368*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
369*a90b9d01SCy Schubert return 0;
370*a90b9d01SCy Schubert }
371*a90b9d01SCy Schubert
372*a90b9d01SCy Schubert
handle_auth_pasn_comeback(struct pasn_data * pasn,const u8 * own_addr,const u8 * peer_addr,u16 group)373*a90b9d01SCy Schubert static void handle_auth_pasn_comeback(struct pasn_data *pasn,
374*a90b9d01SCy Schubert const u8 *own_addr, const u8 *peer_addr,
375*a90b9d01SCy Schubert u16 group)
376*a90b9d01SCy Schubert {
377*a90b9d01SCy Schubert struct wpabuf *buf, *comeback;
378*a90b9d01SCy Schubert int ret;
379*a90b9d01SCy Schubert
380*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
381*a90b9d01SCy Schubert "PASN: Building comeback frame 2. Comeback after=%u",
382*a90b9d01SCy Schubert pasn->comeback_after);
383*a90b9d01SCy Schubert
384*a90b9d01SCy Schubert buf = wpabuf_alloc(1500);
385*a90b9d01SCy Schubert if (!buf)
386*a90b9d01SCy Schubert return;
387*a90b9d01SCy Schubert
388*a90b9d01SCy Schubert wpa_pasn_build_auth_header(buf, pasn->bssid, own_addr, peer_addr, 2,
389*a90b9d01SCy Schubert WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY);
390*a90b9d01SCy Schubert
391*a90b9d01SCy Schubert /*
392*a90b9d01SCy Schubert * Do not include the group as a part of the token since it is not going
393*a90b9d01SCy Schubert * to be used.
394*a90b9d01SCy Schubert */
395*a90b9d01SCy Schubert comeback = auth_build_token_req(&pasn->last_comeback_key_update,
396*a90b9d01SCy Schubert pasn->comeback_key, pasn->comeback_idx,
397*a90b9d01SCy Schubert pasn->comeback_pending_idx,
398*a90b9d01SCy Schubert sizeof(u16) * COMEBACK_PENDING_IDX_SIZE,
399*a90b9d01SCy Schubert 0, peer_addr, 0);
400*a90b9d01SCy Schubert if (!comeback) {
401*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
402*a90b9d01SCy Schubert "PASN: Failed sending auth with comeback");
403*a90b9d01SCy Schubert wpabuf_free(buf);
404*a90b9d01SCy Schubert return;
405*a90b9d01SCy Schubert }
406*a90b9d01SCy Schubert
407*a90b9d01SCy Schubert wpa_pasn_add_parameter_ie(buf, group,
408*a90b9d01SCy Schubert WPA_PASN_WRAPPED_DATA_NO,
409*a90b9d01SCy Schubert NULL, 0, comeback,
410*a90b9d01SCy Schubert pasn->comeback_after);
411*a90b9d01SCy Schubert wpabuf_free(comeback);
412*a90b9d01SCy Schubert
413*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
414*a90b9d01SCy Schubert "PASN: comeback: STA=" MACSTR, MAC2STR(peer_addr));
415*a90b9d01SCy Schubert
416*a90b9d01SCy Schubert ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf),
417*a90b9d01SCy Schubert wpabuf_len(buf), 0, 0, 0);
418*a90b9d01SCy Schubert if (ret)
419*a90b9d01SCy Schubert wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2");
420*a90b9d01SCy Schubert
421*a90b9d01SCy Schubert wpabuf_free(buf);
422*a90b9d01SCy Schubert }
423*a90b9d01SCy Schubert
424*a90b9d01SCy Schubert
handle_auth_pasn_resp(struct pasn_data * pasn,const u8 * own_addr,const u8 * peer_addr,struct rsn_pmksa_cache_entry * pmksa,u16 status)425*a90b9d01SCy Schubert int handle_auth_pasn_resp(struct pasn_data *pasn, const u8 *own_addr,
426*a90b9d01SCy Schubert const u8 *peer_addr,
427*a90b9d01SCy Schubert struct rsn_pmksa_cache_entry *pmksa, u16 status)
428*a90b9d01SCy Schubert {
429*a90b9d01SCy Schubert struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
430*a90b9d01SCy Schubert struct wpabuf *rsn_buf = NULL;
431*a90b9d01SCy Schubert u8 mic[WPA_PASN_MAX_MIC_LEN];
432*a90b9d01SCy Schubert u8 mic_len;
433*a90b9d01SCy Schubert u8 *ptr;
434*a90b9d01SCy Schubert const u8 *frame, *data, *rsn_ie, *rsnxe_ie;
435*a90b9d01SCy Schubert u8 *data_buf = NULL;
436*a90b9d01SCy Schubert size_t frame_len, data_len;
437*a90b9d01SCy Schubert int ret;
438*a90b9d01SCy Schubert const u8 *pmkid = NULL;
439*a90b9d01SCy Schubert
440*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Building frame 2: status=%u", status);
441*a90b9d01SCy Schubert
442*a90b9d01SCy Schubert buf = wpabuf_alloc(1500);
443*a90b9d01SCy Schubert if (!buf)
444*a90b9d01SCy Schubert goto fail;
445*a90b9d01SCy Schubert
446*a90b9d01SCy Schubert wpa_pasn_build_auth_header(buf, pasn->bssid, own_addr, peer_addr, 2,
447*a90b9d01SCy Schubert status);
448*a90b9d01SCy Schubert
449*a90b9d01SCy Schubert if (status != WLAN_STATUS_SUCCESS)
450*a90b9d01SCy Schubert goto done;
451*a90b9d01SCy Schubert
452*a90b9d01SCy Schubert if (pmksa && pasn->custom_pmkid_valid)
453*a90b9d01SCy Schubert pmkid = pasn->custom_pmkid;
454*a90b9d01SCy Schubert else if (pmksa) {
455*a90b9d01SCy Schubert pmkid = pmksa->pmkid;
456*a90b9d01SCy Schubert #ifdef CONFIG_SAE
457*a90b9d01SCy Schubert } else if (pasn->akmp == WPA_KEY_MGMT_SAE) {
458*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Use SAE PMKID");
459*a90b9d01SCy Schubert pmkid = pasn->sae.pmkid;
460*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
461*a90b9d01SCy Schubert #ifdef CONFIG_FILS
462*a90b9d01SCy Schubert } else if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
463*a90b9d01SCy Schubert pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
464*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Use FILS ERP PMKID");
465*a90b9d01SCy Schubert pmkid = pasn->fils.erp_pmkid;
466*a90b9d01SCy Schubert #endif /* CONFIG_FILS */
467*a90b9d01SCy Schubert }
468*a90b9d01SCy Schubert
469*a90b9d01SCy Schubert if (wpa_pasn_add_rsne(buf, pmkid,
470*a90b9d01SCy Schubert pasn->akmp, pasn->cipher) < 0)
471*a90b9d01SCy Schubert goto fail;
472*a90b9d01SCy Schubert
473*a90b9d01SCy Schubert /* No need to derive PMK if PMKSA is given */
474*a90b9d01SCy Schubert if (!pmksa)
475*a90b9d01SCy Schubert wrapped_data_buf = pasn_get_wrapped_data(pasn);
476*a90b9d01SCy Schubert else
477*a90b9d01SCy Schubert pasn->wrapped_data_format = WPA_PASN_WRAPPED_DATA_NO;
478*a90b9d01SCy Schubert
479*a90b9d01SCy Schubert /* Get public key */
480*a90b9d01SCy Schubert pubkey = crypto_ecdh_get_pubkey(pasn->ecdh, 0);
481*a90b9d01SCy Schubert pubkey = wpabuf_zeropad(pubkey,
482*a90b9d01SCy Schubert crypto_ecdh_prime_len(pasn->ecdh));
483*a90b9d01SCy Schubert if (!pubkey) {
484*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey");
485*a90b9d01SCy Schubert goto fail;
486*a90b9d01SCy Schubert }
487*a90b9d01SCy Schubert
488*a90b9d01SCy Schubert wpa_pasn_add_parameter_ie(buf, pasn->group,
489*a90b9d01SCy Schubert pasn->wrapped_data_format,
490*a90b9d01SCy Schubert pubkey, true, NULL, 0);
491*a90b9d01SCy Schubert
492*a90b9d01SCy Schubert if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
493*a90b9d01SCy Schubert goto fail;
494*a90b9d01SCy Schubert
495*a90b9d01SCy Schubert wpabuf_free(wrapped_data_buf);
496*a90b9d01SCy Schubert wrapped_data_buf = NULL;
497*a90b9d01SCy Schubert wpabuf_free(pubkey);
498*a90b9d01SCy Schubert pubkey = NULL;
499*a90b9d01SCy Schubert
500*a90b9d01SCy Schubert /* Add RSNXE if needed */
501*a90b9d01SCy Schubert rsnxe_ie = pasn->rsnxe_ie;
502*a90b9d01SCy Schubert if (rsnxe_ie)
503*a90b9d01SCy Schubert wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]);
504*a90b9d01SCy Schubert
505*a90b9d01SCy Schubert wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len);
506*a90b9d01SCy Schubert
507*a90b9d01SCy Schubert /* Add the mic */
508*a90b9d01SCy Schubert mic_len = pasn_mic_len(pasn->akmp, pasn->cipher);
509*a90b9d01SCy Schubert wpabuf_put_u8(buf, WLAN_EID_MIC);
510*a90b9d01SCy Schubert wpabuf_put_u8(buf, mic_len);
511*a90b9d01SCy Schubert ptr = wpabuf_put(buf, mic_len);
512*a90b9d01SCy Schubert
513*a90b9d01SCy Schubert os_memset(ptr, 0, mic_len);
514*a90b9d01SCy Schubert
515*a90b9d01SCy Schubert frame = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
516*a90b9d01SCy Schubert frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
517*a90b9d01SCy Schubert
518*a90b9d01SCy Schubert if (pasn->rsn_ie && pasn->rsn_ie_len) {
519*a90b9d01SCy Schubert rsn_ie = pasn->rsn_ie;
520*a90b9d01SCy Schubert } else {
521*a90b9d01SCy Schubert /*
522*a90b9d01SCy Schubert * Note: when pasn->rsn_ie is NULL, it is likely that Beacon
523*a90b9d01SCy Schubert * frame RSNE is not initialized. This is possible in case of
524*a90b9d01SCy Schubert * PASN authentication used for Wi-Fi Aware for which Beacon
525*a90b9d01SCy Schubert * frame RSNE and RSNXE are same as RSNE and RSNXE in the
526*a90b9d01SCy Schubert * Authentication frame.
527*a90b9d01SCy Schubert */
528*a90b9d01SCy Schubert rsn_buf = wpabuf_alloc(500);
529*a90b9d01SCy Schubert if (!rsn_buf)
530*a90b9d01SCy Schubert goto fail;
531*a90b9d01SCy Schubert
532*a90b9d01SCy Schubert if (wpa_pasn_add_rsne(rsn_buf, pmkid,
533*a90b9d01SCy Schubert pasn->akmp, pasn->cipher) < 0)
534*a90b9d01SCy Schubert goto fail;
535*a90b9d01SCy Schubert
536*a90b9d01SCy Schubert rsn_ie = wpabuf_head_u8(rsn_buf);
537*a90b9d01SCy Schubert }
538*a90b9d01SCy Schubert
539*a90b9d01SCy Schubert /*
540*a90b9d01SCy Schubert * Note: wpa_auth_get_wpa_ie() might return not only the RSNE but also
541*a90b9d01SCy Schubert * MDE, etc. Thus, do not use the returned length but instead use the
542*a90b9d01SCy Schubert * length specified in the IE header.
543*a90b9d01SCy Schubert */
544*a90b9d01SCy Schubert data_len = rsn_ie[1] + 2;
545*a90b9d01SCy Schubert if (rsnxe_ie) {
546*a90b9d01SCy Schubert data_buf = os_zalloc(rsn_ie[1] + 2 + rsnxe_ie[1] + 2);
547*a90b9d01SCy Schubert if (!data_buf)
548*a90b9d01SCy Schubert goto fail;
549*a90b9d01SCy Schubert
550*a90b9d01SCy Schubert os_memcpy(data_buf, rsn_ie, rsn_ie[1] + 2);
551*a90b9d01SCy Schubert os_memcpy(data_buf + rsn_ie[1] + 2, rsnxe_ie, rsnxe_ie[1] + 2);
552*a90b9d01SCy Schubert data_len += rsnxe_ie[1] + 2;
553*a90b9d01SCy Schubert data = data_buf;
554*a90b9d01SCy Schubert } else {
555*a90b9d01SCy Schubert data = rsn_ie;
556*a90b9d01SCy Schubert }
557*a90b9d01SCy Schubert
558*a90b9d01SCy Schubert ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
559*a90b9d01SCy Schubert own_addr, peer_addr, data, data_len,
560*a90b9d01SCy Schubert frame, frame_len, mic);
561*a90b9d01SCy Schubert os_free(data_buf);
562*a90b9d01SCy Schubert if (ret) {
563*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Frame 3: Failed MIC calculation");
564*a90b9d01SCy Schubert goto fail;
565*a90b9d01SCy Schubert }
566*a90b9d01SCy Schubert
567*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
568*a90b9d01SCy Schubert if (pasn->corrupt_mic) {
569*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: frame 2: Corrupt MIC");
570*a90b9d01SCy Schubert mic[0] = ~mic[0];
571*a90b9d01SCy Schubert }
572*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
573*a90b9d01SCy Schubert
574*a90b9d01SCy Schubert os_memcpy(ptr, mic, mic_len);
575*a90b9d01SCy Schubert
576*a90b9d01SCy Schubert done:
577*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
578*a90b9d01SCy Schubert "PASN: Building frame 2: success; resp STA=" MACSTR,
579*a90b9d01SCy Schubert MAC2STR(peer_addr));
580*a90b9d01SCy Schubert
581*a90b9d01SCy Schubert ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf),
582*a90b9d01SCy Schubert wpabuf_len(buf), 0, 0, 0);
583*a90b9d01SCy Schubert if (ret)
584*a90b9d01SCy Schubert wpa_printf(MSG_INFO, "send_auth_reply: Send failed");
585*a90b9d01SCy Schubert
586*a90b9d01SCy Schubert wpabuf_free(rsn_buf);
587*a90b9d01SCy Schubert wpabuf_free(buf);
588*a90b9d01SCy Schubert return ret;
589*a90b9d01SCy Schubert fail:
590*a90b9d01SCy Schubert wpabuf_free(wrapped_data_buf);
591*a90b9d01SCy Schubert wpabuf_free(pubkey);
592*a90b9d01SCy Schubert wpabuf_free(rsn_buf);
593*a90b9d01SCy Schubert wpabuf_free(buf);
594*a90b9d01SCy Schubert return -1;
595*a90b9d01SCy Schubert }
596*a90b9d01SCy Schubert
597*a90b9d01SCy Schubert
handle_auth_pasn_1(struct pasn_data * pasn,const u8 * own_addr,const u8 * peer_addr,const struct ieee80211_mgmt * mgmt,size_t len)598*a90b9d01SCy Schubert int handle_auth_pasn_1(struct pasn_data *pasn,
599*a90b9d01SCy Schubert const u8 *own_addr, const u8 *peer_addr,
600*a90b9d01SCy Schubert const struct ieee80211_mgmt *mgmt, size_t len)
601*a90b9d01SCy Schubert {
602*a90b9d01SCy Schubert struct ieee802_11_elems elems;
603*a90b9d01SCy Schubert struct wpa_ie_data rsn_data;
604*a90b9d01SCy Schubert struct wpa_pasn_params_data pasn_params;
605*a90b9d01SCy Schubert struct rsn_pmksa_cache_entry *pmksa = NULL;
606*a90b9d01SCy Schubert const u8 *cached_pmk = NULL;
607*a90b9d01SCy Schubert size_t cached_pmk_len = 0;
608*a90b9d01SCy Schubert struct wpabuf *wrapped_data = NULL, *secret = NULL;
609*a90b9d01SCy Schubert const int *groups = pasn->pasn_groups;
610*a90b9d01SCy Schubert static const int default_groups[] = { 19, 0 };
611*a90b9d01SCy Schubert u16 status = WLAN_STATUS_SUCCESS;
612*a90b9d01SCy Schubert int ret, inc_y;
613*a90b9d01SCy Schubert bool derive_keys;
614*a90b9d01SCy Schubert u32 i;
615*a90b9d01SCy Schubert
616*a90b9d01SCy Schubert if (!groups)
617*a90b9d01SCy Schubert groups = default_groups;
618*a90b9d01SCy Schubert
619*a90b9d01SCy Schubert if (ieee802_11_parse_elems(mgmt->u.auth.variable,
620*a90b9d01SCy Schubert len - offsetof(struct ieee80211_mgmt,
621*a90b9d01SCy Schubert u.auth.variable),
622*a90b9d01SCy Schubert &elems, 0) == ParseFailed) {
623*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
624*a90b9d01SCy Schubert "PASN: Failed parsing Authentication frame");
625*a90b9d01SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE;
626*a90b9d01SCy Schubert goto send_resp;
627*a90b9d01SCy Schubert }
628*a90b9d01SCy Schubert
629*a90b9d01SCy Schubert if (!elems.rsn_ie) {
630*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: No RSNE");
631*a90b9d01SCy Schubert status = WLAN_STATUS_INVALID_RSNIE;
632*a90b9d01SCy Schubert goto send_resp;
633*a90b9d01SCy Schubert }
634*a90b9d01SCy Schubert
635*a90b9d01SCy Schubert ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
636*a90b9d01SCy Schubert &rsn_data);
637*a90b9d01SCy Schubert if (ret) {
638*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE");
639*a90b9d01SCy Schubert status = WLAN_STATUS_INVALID_RSNIE;
640*a90b9d01SCy Schubert goto send_resp;
641*a90b9d01SCy Schubert }
642*a90b9d01SCy Schubert
643*a90b9d01SCy Schubert ret = wpa_pasn_validate_rsne(&rsn_data);
644*a90b9d01SCy Schubert if (ret) {
645*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
646*a90b9d01SCy Schubert status = WLAN_STATUS_INVALID_RSNIE;
647*a90b9d01SCy Schubert goto send_resp;
648*a90b9d01SCy Schubert }
649*a90b9d01SCy Schubert
650*a90b9d01SCy Schubert if (!(rsn_data.key_mgmt & pasn->wpa_key_mgmt) ||
651*a90b9d01SCy Schubert !(rsn_data.pairwise_cipher & pasn->rsn_pairwise)) {
652*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
653*a90b9d01SCy Schubert status = WLAN_STATUS_INVALID_RSNIE;
654*a90b9d01SCy Schubert goto send_resp;
655*a90b9d01SCy Schubert }
656*a90b9d01SCy Schubert
657*a90b9d01SCy Schubert pasn->akmp = rsn_data.key_mgmt;
658*a90b9d01SCy Schubert pasn->cipher = rsn_data.pairwise_cipher;
659*a90b9d01SCy Schubert
660*a90b9d01SCy Schubert if (pasn->derive_kdk &&
661*a90b9d01SCy Schubert ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
662*a90b9d01SCy Schubert WLAN_RSNX_CAPAB_SECURE_LTF))
663*a90b9d01SCy Schubert pasn->secure_ltf = true;
664*a90b9d01SCy Schubert
665*a90b9d01SCy Schubert if (pasn->derive_kdk)
666*a90b9d01SCy Schubert pasn->kdk_len = WPA_KDK_MAX_LEN;
667*a90b9d01SCy Schubert else
668*a90b9d01SCy Schubert pasn->kdk_len = 0;
669*a90b9d01SCy Schubert
670*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len);
671*a90b9d01SCy Schubert
672*a90b9d01SCy Schubert if (!elems.pasn_params || !elems.pasn_params_len) {
673*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
674*a90b9d01SCy Schubert "PASN: No PASN Parameters element found");
675*a90b9d01SCy Schubert status = WLAN_STATUS_INVALID_PARAMETERS;
676*a90b9d01SCy Schubert goto send_resp;
677*a90b9d01SCy Schubert }
678*a90b9d01SCy Schubert
679*a90b9d01SCy Schubert ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
680*a90b9d01SCy Schubert elems.pasn_params_len + 3,
681*a90b9d01SCy Schubert false, &pasn_params);
682*a90b9d01SCy Schubert if (ret) {
683*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
684*a90b9d01SCy Schubert "PASN: Failed validation of PASN Parameters IE");
685*a90b9d01SCy Schubert status = WLAN_STATUS_INVALID_PARAMETERS;
686*a90b9d01SCy Schubert goto send_resp;
687*a90b9d01SCy Schubert }
688*a90b9d01SCy Schubert
689*a90b9d01SCy Schubert for (i = 0; groups[i] > 0 && groups[i] != pasn_params.group; i++)
690*a90b9d01SCy Schubert ;
691*a90b9d01SCy Schubert
692*a90b9d01SCy Schubert if (!pasn_params.group || groups[i] != pasn_params.group) {
693*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Requested group=%hu not allowed",
694*a90b9d01SCy Schubert pasn_params.group);
695*a90b9d01SCy Schubert status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
696*a90b9d01SCy Schubert goto send_resp;
697*a90b9d01SCy Schubert }
698*a90b9d01SCy Schubert
699*a90b9d01SCy Schubert if (!pasn_params.pubkey || !pasn_params.pubkey_len) {
700*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Invalid public key");
701*a90b9d01SCy Schubert status = WLAN_STATUS_INVALID_PARAMETERS;
702*a90b9d01SCy Schubert goto send_resp;
703*a90b9d01SCy Schubert }
704*a90b9d01SCy Schubert
705*a90b9d01SCy Schubert if (pasn_params.comeback) {
706*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token");
707*a90b9d01SCy Schubert
708*a90b9d01SCy Schubert ret = check_comeback_token(pasn->comeback_key,
709*a90b9d01SCy Schubert pasn->comeback_pending_idx,
710*a90b9d01SCy Schubert peer_addr,
711*a90b9d01SCy Schubert pasn_params.comeback,
712*a90b9d01SCy Schubert pasn_params.comeback_len);
713*a90b9d01SCy Schubert
714*a90b9d01SCy Schubert if (ret) {
715*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token");
716*a90b9d01SCy Schubert status = WLAN_STATUS_INVALID_PARAMETERS;
717*a90b9d01SCy Schubert goto send_resp;
718*a90b9d01SCy Schubert }
719*a90b9d01SCy Schubert } else if (pasn->use_anti_clogging) {
720*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Respond with comeback");
721*a90b9d01SCy Schubert handle_auth_pasn_comeback(pasn, own_addr, peer_addr,
722*a90b9d01SCy Schubert pasn_params.group);
723*a90b9d01SCy Schubert return -1;
724*a90b9d01SCy Schubert }
725*a90b9d01SCy Schubert
726*a90b9d01SCy Schubert pasn->ecdh = crypto_ecdh_init(pasn_params.group);
727*a90b9d01SCy Schubert if (!pasn->ecdh) {
728*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
729*a90b9d01SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE;
730*a90b9d01SCy Schubert goto send_resp;
731*a90b9d01SCy Schubert }
732*a90b9d01SCy Schubert
733*a90b9d01SCy Schubert pasn->group = pasn_params.group;
734*a90b9d01SCy Schubert
735*a90b9d01SCy Schubert if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) {
736*a90b9d01SCy Schubert inc_y = 1;
737*a90b9d01SCy Schubert } else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 ||
738*a90b9d01SCy Schubert pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) {
739*a90b9d01SCy Schubert inc_y = 0;
740*a90b9d01SCy Schubert } else {
741*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
742*a90b9d01SCy Schubert "PASN: Invalid first octet in pubkey=0x%x",
743*a90b9d01SCy Schubert pasn_params.pubkey[0]);
744*a90b9d01SCy Schubert status = WLAN_STATUS_INVALID_PUBLIC_KEY;
745*a90b9d01SCy Schubert goto send_resp;
746*a90b9d01SCy Schubert }
747*a90b9d01SCy Schubert
748*a90b9d01SCy Schubert secret = crypto_ecdh_set_peerkey(pasn->ecdh, inc_y,
749*a90b9d01SCy Schubert pasn_params.pubkey + 1,
750*a90b9d01SCy Schubert pasn_params.pubkey_len - 1);
751*a90b9d01SCy Schubert if (!secret) {
752*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
753*a90b9d01SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE;
754*a90b9d01SCy Schubert goto send_resp;
755*a90b9d01SCy Schubert }
756*a90b9d01SCy Schubert
757*a90b9d01SCy Schubert if (!pasn->noauth && pasn->akmp == WPA_KEY_MGMT_PASN) {
758*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Refuse PASN-UNAUTH");
759*a90b9d01SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE;
760*a90b9d01SCy Schubert goto send_resp;
761*a90b9d01SCy Schubert }
762*a90b9d01SCy Schubert
763*a90b9d01SCy Schubert derive_keys = true;
764*a90b9d01SCy Schubert if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
765*a90b9d01SCy Schubert wrapped_data = ieee802_11_defrag(elems.wrapped_data,
766*a90b9d01SCy Schubert elems.wrapped_data_len, true);
767*a90b9d01SCy Schubert if (!wrapped_data) {
768*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
769*a90b9d01SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE;
770*a90b9d01SCy Schubert goto send_resp;
771*a90b9d01SCy Schubert }
772*a90b9d01SCy Schubert
773*a90b9d01SCy Schubert #ifdef CONFIG_SAE
774*a90b9d01SCy Schubert if (pasn->akmp == WPA_KEY_MGMT_SAE) {
775*a90b9d01SCy Schubert ret = pasn_wd_handle_sae_commit(pasn, own_addr,
776*a90b9d01SCy Schubert peer_addr,
777*a90b9d01SCy Schubert wrapped_data);
778*a90b9d01SCy Schubert if (ret) {
779*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
780*a90b9d01SCy Schubert "PASN: Failed processing SAE commit");
781*a90b9d01SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE;
782*a90b9d01SCy Schubert goto send_resp;
783*a90b9d01SCy Schubert }
784*a90b9d01SCy Schubert }
785*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
786*a90b9d01SCy Schubert #ifdef CONFIG_FILS
787*a90b9d01SCy Schubert if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
788*a90b9d01SCy Schubert pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
789*a90b9d01SCy Schubert if (!pasn->fils_wd_valid) {
790*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
791*a90b9d01SCy Schubert "PASN: Invalid FILS wrapped data");
792*a90b9d01SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE;
793*a90b9d01SCy Schubert goto send_resp;
794*a90b9d01SCy Schubert }
795*a90b9d01SCy Schubert
796*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
797*a90b9d01SCy Schubert "PASN: FILS: Pending AS response");
798*a90b9d01SCy Schubert
799*a90b9d01SCy Schubert /*
800*a90b9d01SCy Schubert * With PASN/FILS, keys can be derived only after a
801*a90b9d01SCy Schubert * response from the AS is processed.
802*a90b9d01SCy Schubert */
803*a90b9d01SCy Schubert derive_keys = false;
804*a90b9d01SCy Schubert }
805*a90b9d01SCy Schubert #endif /* CONFIG_FILS */
806*a90b9d01SCy Schubert }
807*a90b9d01SCy Schubert
808*a90b9d01SCy Schubert pasn->wrapped_data_format = pasn_params.wrapped_data_format;
809*a90b9d01SCy Schubert
810*a90b9d01SCy Schubert ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher,
811*a90b9d01SCy Schubert ((const u8 *) mgmt) + IEEE80211_HDRLEN,
812*a90b9d01SCy Schubert len - IEEE80211_HDRLEN, pasn->hash);
813*a90b9d01SCy Schubert if (ret) {
814*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
815*a90b9d01SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE;
816*a90b9d01SCy Schubert goto send_resp;
817*a90b9d01SCy Schubert }
818*a90b9d01SCy Schubert
819*a90b9d01SCy Schubert if (!derive_keys) {
820*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Storing secret");
821*a90b9d01SCy Schubert pasn->secret = secret;
822*a90b9d01SCy Schubert wpabuf_free(wrapped_data);
823*a90b9d01SCy Schubert return 0;
824*a90b9d01SCy Schubert }
825*a90b9d01SCy Schubert
826*a90b9d01SCy Schubert if (rsn_data.num_pmkid) {
827*a90b9d01SCy Schubert if (wpa_key_mgmt_ft(pasn->akmp)) {
828*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211R_AP
829*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: FT: Fetch PMK-R1");
830*a90b9d01SCy Schubert
831*a90b9d01SCy Schubert if (!pasn->pmk_r1_len) {
832*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
833*a90b9d01SCy Schubert "PASN: FT: Failed getting PMK-R1");
834*a90b9d01SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE;
835*a90b9d01SCy Schubert goto send_resp;
836*a90b9d01SCy Schubert }
837*a90b9d01SCy Schubert cached_pmk = pasn->pmk_r1;
838*a90b9d01SCy Schubert cached_pmk_len = pasn->pmk_r1_len;
839*a90b9d01SCy Schubert #else /* CONFIG_IEEE80211R_AP */
840*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: FT: Not supported");
841*a90b9d01SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE;
842*a90b9d01SCy Schubert goto send_resp;
843*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
844*a90b9d01SCy Schubert } else {
845*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Try to find PMKSA entry");
846*a90b9d01SCy Schubert
847*a90b9d01SCy Schubert if (pasn->pmksa) {
848*a90b9d01SCy Schubert const u8 *pmkid = NULL;
849*a90b9d01SCy Schubert
850*a90b9d01SCy Schubert if (pasn->custom_pmkid_valid) {
851*a90b9d01SCy Schubert ret = pasn->validate_custom_pmkid(
852*a90b9d01SCy Schubert pasn->cb_ctx, peer_addr,
853*a90b9d01SCy Schubert rsn_data.pmkid);
854*a90b9d01SCy Schubert if (ret) {
855*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
856*a90b9d01SCy Schubert "PASN: Failed custom PMKID validation");
857*a90b9d01SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE;
858*a90b9d01SCy Schubert goto send_resp;
859*a90b9d01SCy Schubert }
860*a90b9d01SCy Schubert } else {
861*a90b9d01SCy Schubert pmkid = rsn_data.pmkid;
862*a90b9d01SCy Schubert }
863*a90b9d01SCy Schubert
864*a90b9d01SCy Schubert pmksa = pmksa_cache_auth_get(pasn->pmksa,
865*a90b9d01SCy Schubert peer_addr,
866*a90b9d01SCy Schubert pmkid);
867*a90b9d01SCy Schubert if (pmksa) {
868*a90b9d01SCy Schubert cached_pmk = pmksa->pmk;
869*a90b9d01SCy Schubert cached_pmk_len = pmksa->pmk_len;
870*a90b9d01SCy Schubert }
871*a90b9d01SCy Schubert }
872*a90b9d01SCy Schubert }
873*a90b9d01SCy Schubert } else {
874*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: No PMKID specified");
875*a90b9d01SCy Schubert }
876*a90b9d01SCy Schubert
877*a90b9d01SCy Schubert ret = pasn_derive_keys(pasn, own_addr, peer_addr,
878*a90b9d01SCy Schubert cached_pmk, cached_pmk_len,
879*a90b9d01SCy Schubert &pasn_params, wrapped_data, secret);
880*a90b9d01SCy Schubert if (ret) {
881*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed to derive keys");
882*a90b9d01SCy Schubert status = WLAN_STATUS_PASN_BASE_AKMP_FAILED;
883*a90b9d01SCy Schubert goto send_resp;
884*a90b9d01SCy Schubert }
885*a90b9d01SCy Schubert
886*a90b9d01SCy Schubert ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher,
887*a90b9d01SCy Schubert ((const u8 *) mgmt) + IEEE80211_HDRLEN,
888*a90b9d01SCy Schubert len - IEEE80211_HDRLEN, pasn->hash);
889*a90b9d01SCy Schubert if (ret) {
890*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
891*a90b9d01SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE;
892*a90b9d01SCy Schubert }
893*a90b9d01SCy Schubert
894*a90b9d01SCy Schubert send_resp:
895*a90b9d01SCy Schubert ret = handle_auth_pasn_resp(pasn, own_addr, peer_addr, pmksa, status);
896*a90b9d01SCy Schubert if (ret) {
897*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed to send response");
898*a90b9d01SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE;
899*a90b9d01SCy Schubert } else {
900*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
901*a90b9d01SCy Schubert "PASN: Success handling transaction == 1");
902*a90b9d01SCy Schubert }
903*a90b9d01SCy Schubert
904*a90b9d01SCy Schubert wpabuf_free(secret);
905*a90b9d01SCy Schubert wpabuf_free(wrapped_data);
906*a90b9d01SCy Schubert
907*a90b9d01SCy Schubert if (status != WLAN_STATUS_SUCCESS)
908*a90b9d01SCy Schubert return -1;
909*a90b9d01SCy Schubert
910*a90b9d01SCy Schubert return 0;
911*a90b9d01SCy Schubert }
912*a90b9d01SCy Schubert
913*a90b9d01SCy Schubert
handle_auth_pasn_3(struct pasn_data * pasn,const u8 * own_addr,const u8 * peer_addr,const struct ieee80211_mgmt * mgmt,size_t len)914*a90b9d01SCy Schubert int handle_auth_pasn_3(struct pasn_data *pasn, const u8 *own_addr,
915*a90b9d01SCy Schubert const u8 *peer_addr,
916*a90b9d01SCy Schubert const struct ieee80211_mgmt *mgmt, size_t len)
917*a90b9d01SCy Schubert {
918*a90b9d01SCy Schubert struct ieee802_11_elems elems;
919*a90b9d01SCy Schubert struct wpa_pasn_params_data pasn_params;
920*a90b9d01SCy Schubert struct wpabuf *wrapped_data = NULL;
921*a90b9d01SCy Schubert u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
922*a90b9d01SCy Schubert u8 mic_len;
923*a90b9d01SCy Schubert int ret;
924*a90b9d01SCy Schubert u8 *copy = NULL;
925*a90b9d01SCy Schubert size_t copy_len, mic_offset;
926*a90b9d01SCy Schubert
927*a90b9d01SCy Schubert if (ieee802_11_parse_elems(mgmt->u.auth.variable,
928*a90b9d01SCy Schubert len - offsetof(struct ieee80211_mgmt,
929*a90b9d01SCy Schubert u.auth.variable),
930*a90b9d01SCy Schubert &elems, 0) == ParseFailed) {
931*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
932*a90b9d01SCy Schubert "PASN: Failed parsing Authentication frame");
933*a90b9d01SCy Schubert goto fail;
934*a90b9d01SCy Schubert }
935*a90b9d01SCy Schubert
936*a90b9d01SCy Schubert /* Check that the MIC IE exists. Save it and zero out the memory. */
937*a90b9d01SCy Schubert mic_len = pasn_mic_len(pasn->akmp, pasn->cipher);
938*a90b9d01SCy Schubert if (!elems.mic || elems.mic_len != mic_len) {
939*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
940*a90b9d01SCy Schubert "PASN: Invalid MIC. Expecting len=%u", mic_len);
941*a90b9d01SCy Schubert goto fail;
942*a90b9d01SCy Schubert }
943*a90b9d01SCy Schubert os_memcpy(mic, elems.mic, mic_len);
944*a90b9d01SCy Schubert
945*a90b9d01SCy Schubert if (!elems.pasn_params || !elems.pasn_params_len) {
946*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
947*a90b9d01SCy Schubert "PASN: No PASN Parameters element found");
948*a90b9d01SCy Schubert goto fail;
949*a90b9d01SCy Schubert }
950*a90b9d01SCy Schubert
951*a90b9d01SCy Schubert ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
952*a90b9d01SCy Schubert elems.pasn_params_len + 3,
953*a90b9d01SCy Schubert false, &pasn_params);
954*a90b9d01SCy Schubert if (ret) {
955*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
956*a90b9d01SCy Schubert "PASN: Failed validation of PASN Parameters IE");
957*a90b9d01SCy Schubert goto fail;
958*a90b9d01SCy Schubert }
959*a90b9d01SCy Schubert
960*a90b9d01SCy Schubert if (pasn_params.pubkey || pasn_params.pubkey_len) {
961*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
962*a90b9d01SCy Schubert "PASN: Public key should not be included");
963*a90b9d01SCy Schubert goto fail;
964*a90b9d01SCy Schubert }
965*a90b9d01SCy Schubert
966*a90b9d01SCy Schubert /* Verify the MIC */
967*a90b9d01SCy Schubert copy_len = len - offsetof(struct ieee80211_mgmt, u.auth);
968*a90b9d01SCy Schubert mic_offset = elems.mic - (const u8 *) &mgmt->u.auth;
969*a90b9d01SCy Schubert copy_len = len - offsetof(struct ieee80211_mgmt, u.auth);
970*a90b9d01SCy Schubert if (mic_offset + mic_len > copy_len)
971*a90b9d01SCy Schubert goto fail;
972*a90b9d01SCy Schubert copy = os_memdup(&mgmt->u.auth, copy_len);
973*a90b9d01SCy Schubert if (!copy)
974*a90b9d01SCy Schubert goto fail;
975*a90b9d01SCy Schubert os_memset(copy + mic_offset, 0, mic_len);
976*a90b9d01SCy Schubert ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
977*a90b9d01SCy Schubert peer_addr, own_addr,
978*a90b9d01SCy Schubert pasn->hash, mic_len * 2,
979*a90b9d01SCy Schubert copy, copy_len, out_mic);
980*a90b9d01SCy Schubert os_free(copy);
981*a90b9d01SCy Schubert copy = NULL;
982*a90b9d01SCy Schubert
983*a90b9d01SCy Schubert wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len);
984*a90b9d01SCy Schubert if (ret || os_memcmp(mic, out_mic, mic_len) != 0) {
985*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification");
986*a90b9d01SCy Schubert goto fail;
987*a90b9d01SCy Schubert }
988*a90b9d01SCy Schubert
989*a90b9d01SCy Schubert if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
990*a90b9d01SCy Schubert wrapped_data = ieee802_11_defrag(elems.wrapped_data,
991*a90b9d01SCy Schubert elems.wrapped_data_len,
992*a90b9d01SCy Schubert true);
993*a90b9d01SCy Schubert
994*a90b9d01SCy Schubert if (!wrapped_data) {
995*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
996*a90b9d01SCy Schubert goto fail;
997*a90b9d01SCy Schubert }
998*a90b9d01SCy Schubert
999*a90b9d01SCy Schubert #ifdef CONFIG_SAE
1000*a90b9d01SCy Schubert if (pasn->akmp == WPA_KEY_MGMT_SAE) {
1001*a90b9d01SCy Schubert ret = pasn_wd_handle_sae_confirm(pasn, peer_addr,
1002*a90b9d01SCy Schubert wrapped_data);
1003*a90b9d01SCy Schubert if (ret) {
1004*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1005*a90b9d01SCy Schubert "PASN: Failed processing SAE confirm");
1006*a90b9d01SCy Schubert wpabuf_free(wrapped_data);
1007*a90b9d01SCy Schubert goto fail;
1008*a90b9d01SCy Schubert }
1009*a90b9d01SCy Schubert }
1010*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
1011*a90b9d01SCy Schubert #ifdef CONFIG_FILS
1012*a90b9d01SCy Schubert if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
1013*a90b9d01SCy Schubert pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
1014*a90b9d01SCy Schubert if (wrapped_data) {
1015*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
1016*a90b9d01SCy Schubert "PASN: FILS: Ignore wrapped data");
1017*a90b9d01SCy Schubert }
1018*a90b9d01SCy Schubert }
1019*a90b9d01SCy Schubert #endif /* CONFIG_FILS */
1020*a90b9d01SCy Schubert wpabuf_free(wrapped_data);
1021*a90b9d01SCy Schubert }
1022*a90b9d01SCy Schubert
1023*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
1024*a90b9d01SCy Schubert "PASN: Success handling transaction == 3. Store PTK");
1025*a90b9d01SCy Schubert return 0;
1026*a90b9d01SCy Schubert
1027*a90b9d01SCy Schubert fail:
1028*a90b9d01SCy Schubert os_free(copy);
1029*a90b9d01SCy Schubert return -1;
1030*a90b9d01SCy Schubert }
1031*a90b9d01SCy Schubert
1032*a90b9d01SCy Schubert #endif /* CONFIG_PASN */
1033