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