/src/hostap/src/pasn/pasn_common.c
Line | Count | Source |
1 | | /* |
2 | | * PASN common processing |
3 | | * |
4 | | * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. |
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 | | |
23 | | struct pasn_data * pasn_data_init(void) |
24 | 2.41k | { |
25 | 2.41k | struct pasn_data *pasn = os_zalloc(sizeof(struct pasn_data)); |
26 | | |
27 | 2.41k | return pasn; |
28 | 2.41k | } |
29 | | |
30 | | |
31 | | void pasn_data_deinit(struct pasn_data *pasn) |
32 | 2.41k | { |
33 | 2.41k | if (!pasn) |
34 | 0 | return; |
35 | 2.41k | os_free(pasn->rsnxe_ie); |
36 | 2.41k | os_free(pasn->rsn_ie); |
37 | 2.41k | wpabuf_free(pasn->frame); |
38 | 2.41k | os_free(pasn->pasn_groups); |
39 | 2.41k | wpabuf_free(pasn->auth1); |
40 | 2.41k | os_free(pasn->dec_pw_id); |
41 | 2.41k | wpabuf_free(pasn->security_profile); |
42 | 2.41k | bin_clear_free(pasn, sizeof(struct pasn_data)); |
43 | 2.41k | } |
44 | | |
45 | | |
46 | | void pasn_register_callbacks(struct pasn_data *pasn, void *cb_ctx, |
47 | | int (*send_mgmt)(void *ctx, const u8 *data, |
48 | | size_t data_len, int noack, |
49 | | unsigned int freq, |
50 | | unsigned int wait), |
51 | | int (*validate_custom_pmkid)(void *ctx, |
52 | | const u8 *addr, |
53 | | const u8 *pmkid), |
54 | | int (*eppke_set_key)(void *ctx, enum wpa_alg alg, |
55 | | const u8 *addr, int vlan_id, |
56 | | const u8 *key, |
57 | | size_t key_len), |
58 | | struct rsn_pmksa_cache_entry * |
59 | | (*pmksa_cache_search)(void *ctx, const u8 *spa, |
60 | | const u8 *pmkid, bool is_ml)) |
61 | 0 | { |
62 | 0 | if (!pasn) |
63 | 0 | return; |
64 | | |
65 | 0 | pasn->cb_ctx = cb_ctx; |
66 | 0 | pasn->send_mgmt = send_mgmt; |
67 | 0 | pasn->validate_custom_pmkid = validate_custom_pmkid; |
68 | | #ifdef CONFIG_ENC_ASSOC |
69 | | pasn->eppke_set_key = eppke_set_key; |
70 | | #endif /* CONFIG_ENC_ASSOC */ |
71 | 0 | pasn->pmksa_cache_search = pmksa_cache_search; |
72 | 0 | } |
73 | | |
74 | | |
75 | | void pasn_enable_kdk_derivation(struct pasn_data *pasn) |
76 | 0 | { |
77 | 0 | if (!pasn) |
78 | 0 | return; |
79 | 0 | pasn->derive_kdk = true; |
80 | 0 | pasn->kdk_len = WPA_KDK_MAX_LEN; |
81 | 0 | } |
82 | | |
83 | | |
84 | | void pasn_disable_kdk_derivation(struct pasn_data *pasn) |
85 | 0 | { |
86 | 0 | if (!pasn) |
87 | 0 | return; |
88 | 0 | pasn->derive_kdk = false; |
89 | 0 | pasn->kdk_len = 0; |
90 | 0 | } |
91 | | |
92 | | |
93 | | void pasn_set_akmp(struct pasn_data *pasn, int akmp) |
94 | 0 | { |
95 | 0 | if (!pasn) |
96 | 0 | return; |
97 | 0 | pasn->akmp = akmp; |
98 | 0 | } |
99 | | |
100 | | |
101 | | void pasn_set_cipher(struct pasn_data *pasn, int cipher) |
102 | 0 | { |
103 | 0 | if (!pasn) |
104 | 0 | return; |
105 | 0 | pasn->cipher = cipher; |
106 | 0 | } |
107 | | |
108 | | |
109 | | void pasn_set_own_addr(struct pasn_data *pasn, const u8 *addr) |
110 | 0 | { |
111 | 0 | if (!pasn || !addr) |
112 | 0 | return; |
113 | 0 | os_memcpy(pasn->own_addr, addr, ETH_ALEN); |
114 | 0 | } |
115 | | |
116 | | |
117 | | #ifdef CONFIG_ENC_ASSOC |
118 | | void pasn_set_own_mld_addr(struct pasn_data *pasn, const u8 *addr) |
119 | | { |
120 | | if (!pasn || !addr) |
121 | | return; |
122 | | os_memcpy(pasn->mld_addr, addr, ETH_ALEN); |
123 | | } |
124 | | #endif /* CONFIG_ENC_ASSOC */ |
125 | | |
126 | | |
127 | | void pasn_set_peer_addr(struct pasn_data *pasn, const u8 *addr) |
128 | 0 | { |
129 | 0 | if (!pasn || !addr) |
130 | 0 | return; |
131 | 0 | os_memcpy(pasn->peer_addr, addr, ETH_ALEN); |
132 | 0 | } |
133 | | |
134 | | |
135 | | void pasn_set_bssid(struct pasn_data *pasn, const u8 *addr) |
136 | 0 | { |
137 | 0 | if (!pasn || !addr) |
138 | 0 | return; |
139 | 0 | os_memcpy(pasn->bssid, addr, ETH_ALEN); |
140 | 0 | } |
141 | | |
142 | | |
143 | | int pasn_set_pt(struct pasn_data *pasn, struct sae_pt *pt) |
144 | 0 | { |
145 | 0 | if (!pasn) |
146 | 0 | return -1; |
147 | 0 | #ifdef CONFIG_SAE |
148 | 0 | pasn->pt = pt; |
149 | 0 | return 0; |
150 | | #else /* CONFIG_SAE */ |
151 | | return -1; |
152 | | #endif /* CONFIG_SAE */ |
153 | 0 | } |
154 | | |
155 | | |
156 | | void pasn_set_wpa_key_mgmt(struct pasn_data *pasn, int key_mgmt) |
157 | 0 | { |
158 | 0 | if (!pasn) |
159 | 0 | return; |
160 | 0 | pasn->wpa_key_mgmt = key_mgmt; |
161 | 0 | } |
162 | | |
163 | | |
164 | | void pasn_set_mfp(struct pasn_data *pasn, enum mfp_options mfp) |
165 | 0 | { |
166 | 0 | if (pasn) |
167 | 0 | pasn->ieee80211w = mfp; |
168 | 0 | } |
169 | | |
170 | | |
171 | | void pasn_set_rsn_pairwise(struct pasn_data *pasn, int rsn_pairwise) |
172 | 0 | { |
173 | 0 | if (!pasn) |
174 | 0 | return; |
175 | 0 | pasn->rsn_pairwise = rsn_pairwise; |
176 | 0 | } |
177 | | |
178 | | |
179 | | void pasn_set_rsnxe_caps(struct pasn_data *pasn, u64 rsnxe_capab) |
180 | 0 | { |
181 | 0 | if (!pasn) |
182 | 0 | return; |
183 | 0 | pasn->rsnxe_capab = rsnxe_capab; |
184 | 0 | } |
185 | | |
186 | | |
187 | | void pasn_set_rsnxe_ie(struct pasn_data *pasn, const u8 *rsnxe_ie) |
188 | 0 | { |
189 | 0 | if (!pasn || !rsnxe_ie) |
190 | 0 | return; |
191 | 0 | os_free(pasn->rsnxe_ie); |
192 | 0 | pasn->rsnxe_ie = os_memdup(rsnxe_ie, 2 + rsnxe_ie[1]); |
193 | 0 | } |
194 | | |
195 | | |
196 | | void pasn_set_rsne(struct pasn_data *pasn, const u8 *rsne) |
197 | 0 | { |
198 | 0 | if (!pasn || !rsne) |
199 | 0 | return; |
200 | 0 | os_free(pasn->rsn_ie); |
201 | 0 | pasn->rsn_ie = os_memdup(rsne, 2 + rsne[1]); |
202 | 0 | pasn->rsn_ie_len = pasn->rsn_ie ? 2 + rsne[1] : 0; |
203 | 0 | } |
204 | | |
205 | | |
206 | | void pasn_set_custom_pmkid(struct pasn_data *pasn, const u8 *pmkid) |
207 | 0 | { |
208 | 0 | if (!pasn || !pmkid) |
209 | 0 | return; |
210 | 0 | os_memcpy(pasn->custom_pmkid, pmkid, PMKID_LEN); |
211 | 0 | pasn->custom_pmkid_valid = true; |
212 | 0 | } |
213 | | |
214 | | |
215 | | int pasn_set_extra_ies(struct pasn_data *pasn, const u8 *extra_ies, |
216 | | size_t extra_ies_len) |
217 | 0 | { |
218 | 0 | if (!pasn || !extra_ies_len || !extra_ies) |
219 | 0 | return -1; |
220 | | |
221 | 0 | if (pasn->extra_ies) { |
222 | 0 | os_free((u8 *) pasn->extra_ies); |
223 | 0 | pasn->extra_ies_len = 0; |
224 | 0 | } |
225 | |
|
226 | 0 | pasn->extra_ies = os_memdup(extra_ies, extra_ies_len); |
227 | 0 | if (!pasn->extra_ies) { |
228 | 0 | wpa_printf(MSG_ERROR, |
229 | 0 | "PASN: Extra IEs memory allocation failed"); |
230 | 0 | return -1; |
231 | 0 | } |
232 | 0 | pasn->extra_ies_len = extra_ies_len; |
233 | 0 | return 0; |
234 | 0 | } |
235 | | |
236 | | |
237 | | int pasn_set_security_profile(struct pasn_data *pasn, const u8 *sp, |
238 | | size_t sp_len) |
239 | 0 | { |
240 | 0 | if (!pasn || !sp || !sp_len) |
241 | 0 | return -1; |
242 | | |
243 | 0 | wpabuf_free(pasn->security_profile); |
244 | 0 | pasn->security_profile = wpabuf_alloc_copy(sp, sp_len); |
245 | 0 | if (!pasn->security_profile) { |
246 | 0 | wpa_printf(MSG_ERROR, |
247 | 0 | "PASN: Security Profile element memory allocation failed"); |
248 | 0 | return -1; |
249 | 0 | } |
250 | | |
251 | 0 | wpa_printf(MSG_DEBUG, |
252 | 0 | "PASN: Security Profile element set (len=%zu)", sp_len); |
253 | 0 | return 0; |
254 | 0 | } |
255 | | |
256 | | |
257 | | void pasn_set_noauth(struct pasn_data *pasn, bool noauth) |
258 | 0 | { |
259 | 0 | if (!pasn) |
260 | 0 | return; |
261 | 0 | pasn->noauth = noauth; |
262 | 0 | } |
263 | | |
264 | | |
265 | | int pasn_get_akmp(struct pasn_data *pasn) |
266 | 0 | { |
267 | 0 | if (!pasn) |
268 | 0 | return 0; |
269 | 0 | return pasn->akmp; |
270 | 0 | } |
271 | | |
272 | | |
273 | | int pasn_get_cipher(struct pasn_data *pasn) |
274 | 0 | { |
275 | 0 | if (!pasn) |
276 | 0 | return 0; |
277 | 0 | return pasn->cipher; |
278 | 0 | } |
279 | | |
280 | | |
281 | | size_t pasn_get_pmk_len(struct pasn_data *pasn) |
282 | 0 | { |
283 | 0 | if (!pasn) |
284 | 0 | return 0; |
285 | 0 | return pasn->pmk_len; |
286 | 0 | } |
287 | | |
288 | | |
289 | | u8 * pasn_get_pmk(struct pasn_data *pasn) |
290 | 0 | { |
291 | 0 | if (!pasn) |
292 | 0 | return NULL; |
293 | 0 | return pasn->pmk; |
294 | 0 | } |
295 | | |
296 | | |
297 | | struct wpa_ptk * pasn_get_ptk(struct pasn_data *pasn) |
298 | 0 | { |
299 | 0 | if (!pasn) |
300 | 0 | return NULL; |
301 | 0 | return &pasn->ptk; |
302 | 0 | } |
303 | | |
304 | | |
305 | | int pasn_add_encrypted_data(struct pasn_data *pasn, struct wpabuf *buf, |
306 | | const u8 *data, size_t data_len) |
307 | 0 | { |
308 | 0 | int ret; |
309 | 0 | u8 *encrypted_data, *padded_data = NULL; |
310 | 0 | u8 *len; |
311 | 0 | size_t pad_len = 0; |
312 | |
|
313 | 0 | if (!pasn->ptk.kek_len) { |
314 | 0 | wpa_printf(MSG_DEBUG, "PASN: KEK not available"); |
315 | 0 | return -2; |
316 | 0 | } |
317 | | |
318 | 0 | pad_len = data_len % 8; |
319 | 0 | if (pad_len) { |
320 | 0 | pad_len = 8 - pad_len; |
321 | 0 | padded_data = os_zalloc(data_len + pad_len); |
322 | 0 | if (!padded_data) |
323 | 0 | return -1; |
324 | 0 | os_memcpy(padded_data, data, data_len); |
325 | 0 | data = padded_data; |
326 | 0 | padded_data[data_len] = 0xdd; |
327 | 0 | } |
328 | 0 | data_len += pad_len + 8; |
329 | |
|
330 | 0 | encrypted_data = os_malloc(data_len); |
331 | 0 | if (!encrypted_data) { |
332 | 0 | os_free(padded_data); |
333 | 0 | return -1; |
334 | 0 | } |
335 | | |
336 | 0 | ret = aes_wrap(pasn->ptk.kek, pasn->ptk.kek_len, |
337 | 0 | (data_len - 8) / 8, data, encrypted_data); |
338 | 0 | if (ret) { |
339 | 0 | wpa_printf(MSG_DEBUG, "PASN: AES wrap failed, ret=%d", ret); |
340 | 0 | goto out; |
341 | 0 | } |
342 | | |
343 | 0 | if (wpabuf_tailroom(buf) < 1 + 1 + 1 + data_len) { |
344 | 0 | wpa_printf(MSG_DEBUG, |
345 | 0 | "PASN: Not enough room in the buffer for PASN Encrypred Data element"); |
346 | 0 | ret = -1; |
347 | 0 | goto out; |
348 | 0 | } |
349 | | |
350 | 0 | wpabuf_put_u8(buf, WLAN_EID_EXTENSION); |
351 | 0 | len = wpabuf_put(buf, 1); |
352 | |
|
353 | 0 | wpabuf_put_u8(buf, WLAN_EID_EXT_PASN_ENCRYPTED_DATA); |
354 | |
|
355 | 0 | wpabuf_put_data(buf, encrypted_data, data_len); |
356 | 0 | *len = (u8 *) wpabuf_put(buf, 0) - len - 1; |
357 | |
|
358 | 0 | out: |
359 | 0 | os_free(padded_data); |
360 | 0 | os_free(encrypted_data); |
361 | 0 | return ret; |
362 | 0 | } |
363 | | |
364 | | |
365 | | int pasn_parse_encrypted_data(struct pasn_data *pasn, const u8 *data, |
366 | | size_t len) |
367 | 0 | { |
368 | 0 | int ret = -1; |
369 | 0 | u8 *buf; |
370 | 0 | u16 buf_len; |
371 | 0 | struct ieee802_11_elems elems; |
372 | 0 | if (ieee802_11_parse_elems(data, len, &elems, 0) == ParseFailed) { |
373 | 0 | wpa_printf(MSG_DEBUG, |
374 | 0 | "PASN: Failed parsing Authentication frame"); |
375 | 0 | return -1; |
376 | 0 | } |
377 | | |
378 | 0 | if (!elems.pasn_encrypted_data || elems.pasn_encrypted_data_len < 8 || |
379 | 0 | elems.pasn_encrypted_data_len % 8) { |
380 | 0 | wpa_printf(MSG_DEBUG, "PASN: No encrypted elements"); |
381 | 0 | return 0; |
382 | 0 | } |
383 | | |
384 | 0 | buf_len = elems.pasn_encrypted_data_len - 8; |
385 | |
|
386 | 0 | buf = os_malloc(buf_len); |
387 | 0 | if (!buf) |
388 | 0 | return -1; |
389 | | |
390 | 0 | ret = aes_unwrap(pasn->ptk.kek, pasn->ptk.kek_len, buf_len / 8, |
391 | 0 | elems.pasn_encrypted_data, buf); |
392 | 0 | if (ret) |
393 | 0 | wpa_printf(MSG_DEBUG, "PASN: AES unwrap failed, ret=%d", ret); |
394 | 0 | else if (pasn->parse_data_element && pasn->cb_ctx) |
395 | 0 | ret = pasn->parse_data_element(pasn->cb_ctx, buf, buf_len); |
396 | |
|
397 | 0 | os_free(buf); |
398 | 0 | return ret; |
399 | 0 | } |