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