1 /*
2 * PASN common processing
3 *
4 * Copyright (C) 2024, Qualcomm Innovation Center, Inc.
5 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10 #include "utils/includes.h"
11
12 #include "utils/common.h"
13 #include "common/wpa_common.h"
14 #include "common/sae.h"
15 #include "crypto/sha384.h"
16 #include "crypto/crypto.h"
17 #include "common/ieee802_11_defs.h"
18 #include "common/ieee802_11_common.h"
19 #include "crypto/aes_wrap.h"
20 #include "pasn_common.h"
21
22
pasn_data_init(void)23 struct pasn_data * pasn_data_init(void)
24 {
25 struct pasn_data *pasn = os_zalloc(sizeof(struct pasn_data));
26
27 return pasn;
28 }
29
30
pasn_data_deinit(struct pasn_data * pasn)31 void pasn_data_deinit(struct pasn_data *pasn)
32 {
33 if (!pasn)
34 return;
35 os_free(pasn->rsnxe_ie);
36 wpabuf_free(pasn->frame);
37 bin_clear_free(pasn, sizeof(struct pasn_data));
38 }
39
40
pasn_register_callbacks(struct pasn_data * pasn,void * cb_ctx,int (* send_mgmt)(void * ctx,const u8 * data,size_t data_len,int noack,unsigned int freq,unsigned int wait),int (* validate_custom_pmkid)(void * ctx,const u8 * addr,const u8 * pmkid))41 void pasn_register_callbacks(struct pasn_data *pasn, void *cb_ctx,
42 int (*send_mgmt)(void *ctx, const u8 *data,
43 size_t data_len, int noack,
44 unsigned int freq,
45 unsigned int wait),
46 int (*validate_custom_pmkid)(void *ctx,
47 const u8 *addr,
48 const u8 *pmkid))
49 {
50 if (!pasn)
51 return;
52
53 pasn->cb_ctx = cb_ctx;
54 pasn->send_mgmt = send_mgmt;
55 pasn->validate_custom_pmkid = validate_custom_pmkid;
56 }
57
58
pasn_enable_kdk_derivation(struct pasn_data * pasn)59 void pasn_enable_kdk_derivation(struct pasn_data *pasn)
60 {
61 if (!pasn)
62 return;
63 pasn->derive_kdk = true;
64 pasn->kdk_len = WPA_KDK_MAX_LEN;
65 }
66
67
pasn_disable_kdk_derivation(struct pasn_data * pasn)68 void pasn_disable_kdk_derivation(struct pasn_data *pasn)
69 {
70 if (!pasn)
71 return;
72 pasn->derive_kdk = false;
73 pasn->kdk_len = 0;
74 }
75
76
pasn_set_akmp(struct pasn_data * pasn,int akmp)77 void pasn_set_akmp(struct pasn_data *pasn, int akmp)
78 {
79 if (!pasn)
80 return;
81 pasn->akmp = akmp;
82 }
83
84
pasn_set_cipher(struct pasn_data * pasn,int cipher)85 void pasn_set_cipher(struct pasn_data *pasn, int cipher)
86 {
87 if (!pasn)
88 return;
89 pasn->cipher = cipher;
90 }
91
92
pasn_set_own_addr(struct pasn_data * pasn,const u8 * addr)93 void pasn_set_own_addr(struct pasn_data *pasn, const u8 *addr)
94 {
95 if (!pasn || !addr)
96 return;
97 os_memcpy(pasn->own_addr, addr, ETH_ALEN);
98 }
99
100
pasn_set_peer_addr(struct pasn_data * pasn,const u8 * addr)101 void pasn_set_peer_addr(struct pasn_data *pasn, const u8 *addr)
102 {
103 if (!pasn || !addr)
104 return;
105 os_memcpy(pasn->peer_addr, addr, ETH_ALEN);
106 }
107
108
pasn_set_bssid(struct pasn_data * pasn,const u8 * addr)109 void pasn_set_bssid(struct pasn_data *pasn, const u8 *addr)
110 {
111 if (!pasn || !addr)
112 return;
113 os_memcpy(pasn->bssid, addr, ETH_ALEN);
114 }
115
116
pasn_set_pt(struct pasn_data * pasn,struct sae_pt * pt)117 int pasn_set_pt(struct pasn_data *pasn, struct sae_pt *pt)
118 {
119 if (!pasn)
120 return -1;
121 #ifdef CONFIG_SAE
122 pasn->pt = pt;
123 return 0;
124 #else /* CONFIG_SAE */
125 return -1;
126 #endif /* CONFIG_SAE */
127 }
128
129
pasn_set_password(struct pasn_data * pasn,const char * password)130 void pasn_set_password(struct pasn_data *pasn, const char *password)
131 {
132 if (!pasn)
133 return;
134 pasn->password = password;
135 }
136
137
pasn_set_wpa_key_mgmt(struct pasn_data * pasn,int key_mgmt)138 void pasn_set_wpa_key_mgmt(struct pasn_data *pasn, int key_mgmt)
139 {
140 if (!pasn)
141 return;
142 pasn->wpa_key_mgmt = key_mgmt;
143 }
144
145
pasn_set_rsn_pairwise(struct pasn_data * pasn,int rsn_pairwise)146 void pasn_set_rsn_pairwise(struct pasn_data *pasn, int rsn_pairwise)
147 {
148 if (!pasn)
149 return;
150 pasn->rsn_pairwise = rsn_pairwise;
151 }
152
153
pasn_set_rsnxe_caps(struct pasn_data * pasn,u16 rsnxe_capab)154 void pasn_set_rsnxe_caps(struct pasn_data *pasn, u16 rsnxe_capab)
155 {
156 if (!pasn)
157 return;
158 pasn->rsnxe_capab = rsnxe_capab;
159 }
160
161
pasn_set_rsnxe_ie(struct pasn_data * pasn,const u8 * rsnxe_ie)162 void pasn_set_rsnxe_ie(struct pasn_data *pasn, const u8 *rsnxe_ie)
163 {
164 if (!pasn || !rsnxe_ie)
165 return;
166 pasn->rsnxe_ie = os_memdup(rsnxe_ie, 2 + rsnxe_ie[1]);
167 }
168
169
pasn_set_custom_pmkid(struct pasn_data * pasn,const u8 * pmkid)170 void pasn_set_custom_pmkid(struct pasn_data *pasn, const u8 *pmkid)
171 {
172 if (!pasn || !pmkid)
173 return;
174 os_memcpy(pasn->custom_pmkid, pmkid, PMKID_LEN);
175 pasn->custom_pmkid_valid = true;
176 }
177
178
pasn_set_extra_ies(struct pasn_data * pasn,const u8 * extra_ies,size_t extra_ies_len)179 int pasn_set_extra_ies(struct pasn_data *pasn, const u8 *extra_ies,
180 size_t extra_ies_len)
181 {
182 if (!pasn || !extra_ies_len || !extra_ies)
183 return -1;
184
185 if (pasn->extra_ies) {
186 os_free((u8 *) pasn->extra_ies);
187 pasn->extra_ies_len = extra_ies_len;
188 }
189
190 pasn->extra_ies = os_memdup(extra_ies, extra_ies_len);
191 if (!pasn->extra_ies) {
192 wpa_printf(MSG_ERROR,
193 "PASN: Extra IEs memory allocation failed");
194 return -1;
195 }
196 pasn->extra_ies_len = extra_ies_len;
197 return 0;
198 }
199
200
pasn_set_noauth(struct pasn_data * pasn,bool noauth)201 void pasn_set_noauth(struct pasn_data *pasn, bool noauth)
202 {
203 if (!pasn)
204 return;
205 pasn->noauth = noauth;
206 }
207
208
pasn_get_akmp(struct pasn_data * pasn)209 int pasn_get_akmp(struct pasn_data *pasn)
210 {
211 if (!pasn)
212 return 0;
213 return pasn->akmp;
214 }
215
216
pasn_get_cipher(struct pasn_data * pasn)217 int pasn_get_cipher(struct pasn_data *pasn)
218 {
219 if (!pasn)
220 return 0;
221 return pasn->cipher;
222 }
223
224
pasn_get_pmk_len(struct pasn_data * pasn)225 size_t pasn_get_pmk_len(struct pasn_data *pasn)
226 {
227 if (!pasn)
228 return 0;
229 return pasn->pmk_len;
230 }
231
232
pasn_get_pmk(struct pasn_data * pasn)233 u8 * pasn_get_pmk(struct pasn_data *pasn)
234 {
235 if (!pasn)
236 return NULL;
237 return pasn->pmk;
238 }
239
240
pasn_get_ptk(struct pasn_data * pasn)241 struct wpa_ptk * pasn_get_ptk(struct pasn_data *pasn)
242 {
243 if (!pasn)
244 return NULL;
245 return &pasn->ptk;
246 }
247
248
pasn_add_encrypted_data(struct pasn_data * pasn,struct wpabuf * buf,const u8 * data,size_t data_len)249 int pasn_add_encrypted_data(struct pasn_data *pasn, struct wpabuf *buf,
250 const u8 *data, size_t data_len)
251 {
252 int ret;
253 u8 *encrypted_data, *padded_data = NULL;
254 u8 *len;
255 size_t pad_len = 0;
256
257 if (!pasn->ptk.kek_len) {
258 wpa_printf(MSG_DEBUG, "PASN: KEK not available");
259 return -2;
260 }
261
262 pad_len = data_len % 8;
263 if (pad_len) {
264 pad_len = 8 - pad_len;
265 padded_data = os_zalloc(data_len + pad_len);
266 if (!padded_data)
267 return -1;
268 os_memcpy(padded_data, data, data_len);
269 data = padded_data;
270 padded_data[data_len] = 0xdd;
271 }
272 data_len += pad_len + 8;
273
274 encrypted_data = os_malloc(data_len);
275 if (!encrypted_data) {
276 os_free(padded_data);
277 return -1;
278 }
279
280 ret = aes_wrap(pasn->ptk.kek, pasn->ptk.kek_len,
281 (data_len - 8) / 8, data, encrypted_data);
282 if (ret) {
283 wpa_printf(MSG_DEBUG, "PASN: AES wrap failed, ret=%d", ret);
284 goto out;
285 }
286
287 if (wpabuf_tailroom(buf) < 1 + 1 + 1 + data_len) {
288 wpa_printf(MSG_DEBUG,
289 "PASN: Not enough room in the buffer for PASN Encrypred Data element");
290 ret = -1;
291 goto out;
292 }
293
294 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
295 len = wpabuf_put(buf, 1);
296
297 wpabuf_put_u8(buf, WLAN_EID_EXT_PASN_ENCRYPTED_DATA);
298
299 wpabuf_put_data(buf, encrypted_data, data_len);
300 *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
301
302 out:
303 os_free(padded_data);
304 os_free(encrypted_data);
305 return ret;
306 }
307
308
pasn_parse_encrypted_data(struct pasn_data * pasn,const u8 * data,size_t len)309 int pasn_parse_encrypted_data(struct pasn_data *pasn, const u8 *data,
310 size_t len)
311 {
312 int ret = -1;
313 u8 *buf;
314 u16 buf_len;
315 struct ieee802_11_elems elems;
316 const struct ieee80211_mgmt *mgmt =
317 (const struct ieee80211_mgmt *) data;
318
319 if (len < 24 + 6 ||
320 ieee802_11_parse_elems(mgmt->u.auth.variable,
321 len - offsetof(struct ieee80211_mgmt,
322 u.auth.variable),
323 &elems, 0) == ParseFailed) {
324 wpa_printf(MSG_DEBUG,
325 "PASN: Failed parsing Authentication frame");
326 return -1;
327 }
328
329 if (!elems.pasn_encrypted_data || elems.pasn_encrypted_data_len < 8 ||
330 elems.pasn_encrypted_data_len % 8) {
331 wpa_printf(MSG_DEBUG, "PASN: No encrypted elements");
332 return 0;
333 }
334
335 buf_len = elems.pasn_encrypted_data_len - 8;
336
337 buf = os_malloc(buf_len);
338 if (!buf)
339 return -1;
340
341 ret = aes_unwrap(pasn->ptk.kek, pasn->ptk.kek_len, buf_len / 8,
342 elems.pasn_encrypted_data, buf);
343 if (ret)
344 wpa_printf(MSG_DEBUG, "PASN: AES unwrap failed, ret=%d", ret);
345 else if (pasn->parse_data_element && pasn->cb_ctx)
346 ret = pasn->parse_data_element(pasn->cb_ctx, buf, buf_len);
347
348 os_free(buf);
349 return ret;
350 }
351