xref: /freebsd/contrib/wpa/src/common/dpp_pkex.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1c1d255d3SCy Schubert /*
2c1d255d3SCy Schubert  * DPP PKEX functionality
3c1d255d3SCy Schubert  * Copyright (c) 2017, Qualcomm Atheros, Inc.
4c1d255d3SCy Schubert  * Copyright (c) 2018-2020, The Linux Foundation
5c1d255d3SCy Schubert  *
6c1d255d3SCy Schubert  * This software may be distributed under the terms of the BSD license.
7c1d255d3SCy Schubert  * See README for more details.
8c1d255d3SCy Schubert  */
9c1d255d3SCy Schubert 
10c1d255d3SCy Schubert #include "utils/includes.h"
11c1d255d3SCy Schubert 
12c1d255d3SCy Schubert #include "utils/common.h"
13c1d255d3SCy Schubert #include "common/wpa_ctrl.h"
14c1d255d3SCy Schubert #include "crypto/aes.h"
15c1d255d3SCy Schubert #include "crypto/aes_siv.h"
16c1d255d3SCy Schubert #include "crypto/crypto.h"
17c1d255d3SCy Schubert #include "dpp.h"
18c1d255d3SCy Schubert #include "dpp_i.h"
19c1d255d3SCy Schubert 
20c1d255d3SCy Schubert 
21c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
22c1d255d3SCy Schubert u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
23c1d255d3SCy Schubert u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
24c1d255d3SCy Schubert u8 dpp_pkex_ephemeral_key_override[600];
25c1d255d3SCy Schubert size_t dpp_pkex_ephemeral_key_override_len = 0;
26c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
27c1d255d3SCy Schubert 
28c1d255d3SCy Schubert 
dpp_pkex_build_exchange_req(struct dpp_pkex * pkex,bool v2)2932a95656SCy Schubert static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex,
3032a95656SCy Schubert 						   bool v2)
31c1d255d3SCy Schubert {
324b72b91aSCy Schubert 	struct crypto_ec *ec = NULL;
33*a90b9d01SCy Schubert 	struct crypto_ec_point *Qi = NULL, *M = NULL, *X = NULL;
344b72b91aSCy Schubert 	u8 *Mx, *My;
35c1d255d3SCy Schubert 	struct wpabuf *msg = NULL;
36c1d255d3SCy Schubert 	size_t attr_len;
37c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
38c1d255d3SCy Schubert 
3932a95656SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Build PKEX %sExchange Request",
4032a95656SCy Schubert 		   v2 ? "" : "Version 1 ");
41c1d255d3SCy Schubert 
4232a95656SCy Schubert 	/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
4332a95656SCy Schubert 	Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : pkex->own_mac, pkex->code,
44*a90b9d01SCy Schubert 				pkex->code_len, pkex->identifier, &ec);
45c1d255d3SCy Schubert 	if (!Qi)
46c1d255d3SCy Schubert 		goto fail;
47c1d255d3SCy Schubert 
48c1d255d3SCy Schubert 	/* Generate a random ephemeral keypair x/X */
49c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
50c1d255d3SCy Schubert 	if (dpp_pkex_ephemeral_key_override_len) {
51c1d255d3SCy Schubert 		const struct dpp_curve_params *tmp_curve;
52c1d255d3SCy Schubert 
53c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
54c1d255d3SCy Schubert 			   "DPP: TESTING - override ephemeral key x/X");
55c1d255d3SCy Schubert 		pkex->x = dpp_set_keypair(&tmp_curve,
56c1d255d3SCy Schubert 					  dpp_pkex_ephemeral_key_override,
57c1d255d3SCy Schubert 					  dpp_pkex_ephemeral_key_override_len);
58c1d255d3SCy Schubert 	} else {
59c1d255d3SCy Schubert 		pkex->x = dpp_gen_keypair(curve);
60c1d255d3SCy Schubert 	}
61c1d255d3SCy Schubert #else /* CONFIG_TESTING_OPTIONS */
62c1d255d3SCy Schubert 	pkex->x = dpp_gen_keypair(curve);
63c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
64c1d255d3SCy Schubert 	if (!pkex->x)
65c1d255d3SCy Schubert 		goto fail;
66c1d255d3SCy Schubert 
67c1d255d3SCy Schubert 	/* M = X + Qi */
684b72b91aSCy Schubert 	X = crypto_ec_key_get_public_key(pkex->x);
694b72b91aSCy Schubert 	M = crypto_ec_point_init(ec);
704b72b91aSCy Schubert 	if (!X || !M)
71c1d255d3SCy Schubert 		goto fail;
724b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, X, "DPP: X");
734b72b91aSCy Schubert 
744b72b91aSCy Schubert 	if (crypto_ec_point_add(ec, X, Qi, M))
75c1d255d3SCy Schubert 		goto fail;
764b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, M, "DPP: M");
77c1d255d3SCy Schubert 
78c1d255d3SCy Schubert 	/* Initiator -> Responder: group, [identifier,] M */
79c1d255d3SCy Schubert 	attr_len = 4 + 2;
8032a95656SCy Schubert #ifdef CONFIG_DPP2
8132a95656SCy Schubert 	if (v2)
8232a95656SCy Schubert 		attr_len += 4 + 1;
8332a95656SCy Schubert #endif /* CONFIG_DPP2 */
84c1d255d3SCy Schubert 	if (pkex->identifier)
85c1d255d3SCy Schubert 		attr_len += 4 + os_strlen(pkex->identifier);
86c1d255d3SCy Schubert 	attr_len += 4 + 2 * curve->prime_len;
8732a95656SCy Schubert 	msg = dpp_alloc_msg(v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
8832a95656SCy Schubert 			    DPP_PA_PKEX_V1_EXCHANGE_REQ, attr_len);
89c1d255d3SCy Schubert 	if (!msg)
90c1d255d3SCy Schubert 		goto fail;
91c1d255d3SCy Schubert 
9232a95656SCy Schubert #ifdef CONFIG_DPP2
9332a95656SCy Schubert 	if (v2) {
9432a95656SCy Schubert 		/* Protocol Version */
9532a95656SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
9632a95656SCy Schubert 		wpabuf_put_le16(msg, 1);
9732a95656SCy Schubert 		wpabuf_put_u8(msg, DPP_VERSION);
9832a95656SCy Schubert 	}
9932a95656SCy Schubert #endif /* CONFIG_DPP2 */
10032a95656SCy Schubert 
101c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
102c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
103c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
104c1d255d3SCy Schubert 		goto skip_finite_cyclic_group;
105c1d255d3SCy Schubert 	}
106c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
107c1d255d3SCy Schubert 
108c1d255d3SCy Schubert 	/* Finite Cyclic Group attribute */
109c1d255d3SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
110c1d255d3SCy Schubert 	wpabuf_put_le16(msg, 2);
111c1d255d3SCy Schubert 	wpabuf_put_le16(msg, curve->ike_group);
112c1d255d3SCy Schubert 
113c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
114c1d255d3SCy Schubert skip_finite_cyclic_group:
115c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
116c1d255d3SCy Schubert 
117c1d255d3SCy Schubert 	/* Code Identifier attribute */
118c1d255d3SCy Schubert 	if (pkex->identifier) {
119c1d255d3SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
120c1d255d3SCy Schubert 		wpabuf_put_le16(msg, os_strlen(pkex->identifier));
121c1d255d3SCy Schubert 		wpabuf_put_str(msg, pkex->identifier);
122c1d255d3SCy Schubert 	}
123c1d255d3SCy Schubert 
124c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
125c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
126c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
127c1d255d3SCy Schubert 		goto out;
128c1d255d3SCy Schubert 	}
129c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
130c1d255d3SCy Schubert 
131c1d255d3SCy Schubert 	/* M in Encrypted Key attribute */
132c1d255d3SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
133c1d255d3SCy Schubert 	wpabuf_put_le16(msg, 2 * curve->prime_len);
134c1d255d3SCy Schubert 
135c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
136c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
137c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
138c1d255d3SCy Schubert 		if (dpp_test_gen_invalid_key(msg, curve) < 0)
139c1d255d3SCy Schubert 			goto fail;
140c1d255d3SCy Schubert 		goto out;
141c1d255d3SCy Schubert 	}
142c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
143c1d255d3SCy Schubert 
1444b72b91aSCy Schubert 	Mx = wpabuf_put(msg, curve->prime_len);
1454b72b91aSCy Schubert 	My = wpabuf_put(msg, curve->prime_len);
1464b72b91aSCy Schubert 	if (crypto_ec_point_to_bin(ec, M, Mx, My))
147c1d255d3SCy Schubert 		goto fail;
148*a90b9d01SCy Schubert 	wpabuf_free(pkex->enc_key);
149*a90b9d01SCy Schubert 	pkex->enc_key = wpabuf_alloc_copy(Mx, 2 * curve->prime_len);
150c1d255d3SCy Schubert 
1514b72b91aSCy Schubert 	os_memcpy(pkex->Mx, Mx, curve->prime_len);
1524b72b91aSCy Schubert 
153c1d255d3SCy Schubert out:
154*a90b9d01SCy Schubert 	crypto_ec_point_deinit(X, 1);
1554b72b91aSCy Schubert 	crypto_ec_point_deinit(M, 1);
1564b72b91aSCy Schubert 	crypto_ec_point_deinit(Qi, 1);
1574b72b91aSCy Schubert 	crypto_ec_deinit(ec);
158c1d255d3SCy Schubert 	return msg;
159c1d255d3SCy Schubert fail:
160c1d255d3SCy Schubert 	wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
161c1d255d3SCy Schubert 	wpabuf_free(msg);
162c1d255d3SCy Schubert 	msg = NULL;
163c1d255d3SCy Schubert 	goto out;
164c1d255d3SCy Schubert }
165c1d255d3SCy Schubert 
166c1d255d3SCy Schubert 
dpp_pkex_fail(struct dpp_pkex * pkex,const char * txt)167c1d255d3SCy Schubert static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
168c1d255d3SCy Schubert {
169c1d255d3SCy Schubert 	wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
170c1d255d3SCy Schubert }
171c1d255d3SCy Schubert 
172c1d255d3SCy Schubert 
dpp_pkex_init(void * msg_ctx,struct dpp_bootstrap_info * bi,const u8 * own_mac,const char * identifier,const char * code,size_t code_len,bool v2)173c1d255d3SCy Schubert struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
174c1d255d3SCy Schubert 				const u8 *own_mac,
17532a95656SCy Schubert 				const char *identifier, const char *code,
176*a90b9d01SCy Schubert 				size_t code_len, bool v2)
177c1d255d3SCy Schubert {
178c1d255d3SCy Schubert 	struct dpp_pkex *pkex;
179c1d255d3SCy Schubert 
180c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
181c1d255d3SCy Schubert 	if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
182c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
183c1d255d3SCy Schubert 			   MAC2STR(dpp_pkex_own_mac_override));
184c1d255d3SCy Schubert 		own_mac = dpp_pkex_own_mac_override;
185c1d255d3SCy Schubert 	}
186c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
187c1d255d3SCy Schubert 
188c1d255d3SCy Schubert 	pkex = os_zalloc(sizeof(*pkex));
189c1d255d3SCy Schubert 	if (!pkex)
190c1d255d3SCy Schubert 		return NULL;
191c1d255d3SCy Schubert 	pkex->msg_ctx = msg_ctx;
192c1d255d3SCy Schubert 	pkex->initiator = 1;
19332a95656SCy Schubert 	pkex->v2 = v2;
194c1d255d3SCy Schubert 	pkex->own_bi = bi;
195c1d255d3SCy Schubert 	os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
196c1d255d3SCy Schubert 	if (identifier) {
197c1d255d3SCy Schubert 		pkex->identifier = os_strdup(identifier);
198c1d255d3SCy Schubert 		if (!pkex->identifier)
199c1d255d3SCy Schubert 			goto fail;
200c1d255d3SCy Schubert 	}
201*a90b9d01SCy Schubert 	pkex->code = os_memdup(code, code_len);
202c1d255d3SCy Schubert 	if (!pkex->code)
203c1d255d3SCy Schubert 		goto fail;
204*a90b9d01SCy Schubert 	pkex->code_len = code_len;
20532a95656SCy Schubert 	pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2);
206c1d255d3SCy Schubert 	if (!pkex->exchange_req)
207c1d255d3SCy Schubert 		goto fail;
208c1d255d3SCy Schubert 	return pkex;
209c1d255d3SCy Schubert fail:
210c1d255d3SCy Schubert 	dpp_pkex_free(pkex);
211c1d255d3SCy Schubert 	return NULL;
212c1d255d3SCy Schubert }
213c1d255d3SCy Schubert 
214c1d255d3SCy Schubert 
215c1d255d3SCy Schubert static struct wpabuf *
dpp_pkex_build_exchange_resp(struct dpp_pkex * pkex,enum dpp_status_error status,const u8 * Nx,const u8 * Ny)216c1d255d3SCy Schubert dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
217c1d255d3SCy Schubert 			     enum dpp_status_error status,
2184b72b91aSCy Schubert 			     const u8 *Nx, const u8 *Ny)
219c1d255d3SCy Schubert {
220c1d255d3SCy Schubert 	struct wpabuf *msg = NULL;
221c1d255d3SCy Schubert 	size_t attr_len;
222c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
223c1d255d3SCy Schubert 
22432a95656SCy Schubert 	/* Initiator -> Responder: DPP Status, [Protocol Version,] [identifier,]
22532a95656SCy Schubert 	 * N */
226c1d255d3SCy Schubert 	attr_len = 4 + 1;
22732a95656SCy Schubert #ifdef CONFIG_DPP2
22832a95656SCy Schubert 	if (pkex->v2)
22932a95656SCy Schubert 		attr_len += 4 + 1;
23032a95656SCy Schubert #endif /* CONFIG_DPP2 */
231c1d255d3SCy Schubert 	if (pkex->identifier)
232c1d255d3SCy Schubert 		attr_len += 4 + os_strlen(pkex->identifier);
233c1d255d3SCy Schubert 	attr_len += 4 + 2 * curve->prime_len;
234c1d255d3SCy Schubert 	msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
235c1d255d3SCy Schubert 	if (!msg)
236c1d255d3SCy Schubert 		goto fail;
237c1d255d3SCy Schubert 
238c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
239c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
240c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
241c1d255d3SCy Schubert 		goto skip_status;
242c1d255d3SCy Schubert 	}
243c1d255d3SCy Schubert 
244c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
245c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
246c1d255d3SCy Schubert 		status = 255;
247c1d255d3SCy Schubert 	}
248c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
249c1d255d3SCy Schubert 
250c1d255d3SCy Schubert 	/* DPP Status */
251c1d255d3SCy Schubert 	dpp_build_attr_status(msg, status);
252c1d255d3SCy Schubert 
253c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
254c1d255d3SCy Schubert skip_status:
255c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
256c1d255d3SCy Schubert 
25732a95656SCy Schubert #ifdef CONFIG_DPP2
25832a95656SCy Schubert 	if (pkex->v2) {
25932a95656SCy Schubert 		/* Protocol Version */
26032a95656SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
26132a95656SCy Schubert 		wpabuf_put_le16(msg, 1);
26232a95656SCy Schubert 		wpabuf_put_u8(msg, DPP_VERSION);
26332a95656SCy Schubert 	}
26432a95656SCy Schubert #endif /* CONFIG_DPP2 */
26532a95656SCy Schubert 
266c1d255d3SCy Schubert 	/* Code Identifier attribute */
267c1d255d3SCy Schubert 	if (pkex->identifier) {
268c1d255d3SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
269c1d255d3SCy Schubert 		wpabuf_put_le16(msg, os_strlen(pkex->identifier));
270c1d255d3SCy Schubert 		wpabuf_put_str(msg, pkex->identifier);
271c1d255d3SCy Schubert 	}
272c1d255d3SCy Schubert 
273c1d255d3SCy Schubert 	if (status != DPP_STATUS_OK)
274c1d255d3SCy Schubert 		goto skip_encrypted_key;
275c1d255d3SCy Schubert 
276c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
277c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
278c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
279c1d255d3SCy Schubert 		goto skip_encrypted_key;
280c1d255d3SCy Schubert 	}
281c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
282c1d255d3SCy Schubert 
283c1d255d3SCy Schubert 	/* N in Encrypted Key attribute */
284c1d255d3SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
285c1d255d3SCy Schubert 	wpabuf_put_le16(msg, 2 * curve->prime_len);
286c1d255d3SCy Schubert 
287c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
288c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
289c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
290c1d255d3SCy Schubert 		if (dpp_test_gen_invalid_key(msg, curve) < 0)
291c1d255d3SCy Schubert 			goto fail;
292c1d255d3SCy Schubert 		goto skip_encrypted_key;
293c1d255d3SCy Schubert 	}
294c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
295c1d255d3SCy Schubert 
2964b72b91aSCy Schubert 	wpabuf_put_data(msg, Nx, curve->prime_len);
2974b72b91aSCy Schubert 	wpabuf_put_data(msg, Ny, curve->prime_len);
2984b72b91aSCy Schubert 	os_memcpy(pkex->Nx, Nx, curve->prime_len);
299c1d255d3SCy Schubert 
300c1d255d3SCy Schubert skip_encrypted_key:
301c1d255d3SCy Schubert 	if (status == DPP_STATUS_BAD_GROUP) {
302c1d255d3SCy Schubert 		/* Finite Cyclic Group attribute */
303c1d255d3SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
304c1d255d3SCy Schubert 		wpabuf_put_le16(msg, 2);
305c1d255d3SCy Schubert 		wpabuf_put_le16(msg, curve->ike_group);
306c1d255d3SCy Schubert 	}
307c1d255d3SCy Schubert 
308c1d255d3SCy Schubert 	return msg;
309c1d255d3SCy Schubert fail:
310c1d255d3SCy Schubert 	wpabuf_free(msg);
311c1d255d3SCy Schubert 	return NULL;
312c1d255d3SCy Schubert }
313c1d255d3SCy Schubert 
314c1d255d3SCy Schubert 
dpp_pkex_identifier_match(const u8 * attr_id,u16 attr_id_len,const char * identifier)315c1d255d3SCy Schubert static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
316c1d255d3SCy Schubert 				     const char *identifier)
317c1d255d3SCy Schubert {
318c1d255d3SCy Schubert 	if (!attr_id && identifier) {
319c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
320c1d255d3SCy Schubert 			   "DPP: No PKEX code identifier received, but expected one");
321c1d255d3SCy Schubert 		return 0;
322c1d255d3SCy Schubert 	}
323c1d255d3SCy Schubert 
324c1d255d3SCy Schubert 	if (attr_id && !identifier) {
325c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
326c1d255d3SCy Schubert 			   "DPP: PKEX code identifier received, but not expecting one");
327c1d255d3SCy Schubert 		return 0;
328c1d255d3SCy Schubert 	}
329c1d255d3SCy Schubert 
330c1d255d3SCy Schubert 	if (attr_id && identifier &&
331c1d255d3SCy Schubert 	    (os_strlen(identifier) != attr_id_len ||
332c1d255d3SCy Schubert 	     os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
333c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
334c1d255d3SCy Schubert 		return 0;
335c1d255d3SCy Schubert 	}
336c1d255d3SCy Schubert 
337c1d255d3SCy Schubert 	return 1;
338c1d255d3SCy Schubert }
339c1d255d3SCy Schubert 
340c1d255d3SCy Schubert 
dpp_pkex_rx_exchange_req(void * msg_ctx,struct dpp_bootstrap_info * bi,const u8 * own_mac,const u8 * peer_mac,const char * identifier,const char * code,size_t code_len,const u8 * buf,size_t len,bool v2)341c1d255d3SCy Schubert struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
342c1d255d3SCy Schubert 					   struct dpp_bootstrap_info *bi,
343c1d255d3SCy Schubert 					   const u8 *own_mac,
344c1d255d3SCy Schubert 					   const u8 *peer_mac,
345c1d255d3SCy Schubert 					   const char *identifier,
346*a90b9d01SCy Schubert 					   const char *code, size_t code_len,
34732a95656SCy Schubert 					   const u8 *buf, size_t len, bool v2)
348c1d255d3SCy Schubert {
349c1d255d3SCy Schubert 	const u8 *attr_group, *attr_id, *attr_key;
350c1d255d3SCy Schubert 	u16 attr_group_len, attr_id_len, attr_key_len;
351c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = bi->curve;
352c1d255d3SCy Schubert 	u16 ike_group;
353c1d255d3SCy Schubert 	struct dpp_pkex *pkex = NULL;
3544b72b91aSCy Schubert 	struct crypto_ec_point *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL,
355*a90b9d01SCy Schubert 		*N = NULL, *Y = NULL;
3564b72b91aSCy Schubert 	struct crypto_ec *ec = NULL;
3574b72b91aSCy Schubert 	u8 *x_coord = NULL, *y_coord = NULL;
358c1d255d3SCy Schubert 	u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
359c1d255d3SCy Schubert 	size_t Kx_len;
360c1d255d3SCy Schubert 	int res;
36132a95656SCy Schubert 	u8 peer_version = 0;
362c1d255d3SCy Schubert 
363c1d255d3SCy Schubert 	if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
364c1d255d3SCy Schubert 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
365c1d255d3SCy Schubert 			"PKEX counter t limit reached - ignore message");
366c1d255d3SCy Schubert 		return NULL;
367c1d255d3SCy Schubert 	}
368c1d255d3SCy Schubert 
36932a95656SCy Schubert #ifdef CONFIG_DPP2
37032a95656SCy Schubert 	if (v2) {
37132a95656SCy Schubert 		const u8 *version;
37232a95656SCy Schubert 		u16 version_len;
37332a95656SCy Schubert 
37432a95656SCy Schubert 		version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
37532a95656SCy Schubert 				       &version_len);
37632a95656SCy Schubert 		if (!version || version_len < 1 || version[0] == 0) {
37732a95656SCy Schubert 			wpa_msg(msg_ctx, MSG_INFO,
37832a95656SCy Schubert 				"Missing or invalid Protocol Version attribute");
37932a95656SCy Schubert 			return NULL;
38032a95656SCy Schubert 		}
38132a95656SCy Schubert 		peer_version = version[0];
38232a95656SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
38332a95656SCy Schubert 			   peer_version);
38432a95656SCy Schubert 	}
38532a95656SCy Schubert #endif /* CONFIG_DPP2 */
38632a95656SCy Schubert 
387c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
388c1d255d3SCy Schubert 	if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
389c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
390c1d255d3SCy Schubert 			   MAC2STR(dpp_pkex_peer_mac_override));
391c1d255d3SCy Schubert 		peer_mac = dpp_pkex_peer_mac_override;
392c1d255d3SCy Schubert 	}
393c1d255d3SCy Schubert 	if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
394c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
395c1d255d3SCy Schubert 			   MAC2STR(dpp_pkex_own_mac_override));
396c1d255d3SCy Schubert 		own_mac = dpp_pkex_own_mac_override;
397c1d255d3SCy Schubert 	}
398c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
399c1d255d3SCy Schubert 
400c1d255d3SCy Schubert 	attr_id_len = 0;
401c1d255d3SCy Schubert 	attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
402c1d255d3SCy Schubert 			       &attr_id_len);
403c1d255d3SCy Schubert 	if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
404c1d255d3SCy Schubert 		return NULL;
405c1d255d3SCy Schubert 
406c1d255d3SCy Schubert 	attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
407c1d255d3SCy Schubert 				  &attr_group_len);
408c1d255d3SCy Schubert 	if (!attr_group || attr_group_len != 2) {
409c1d255d3SCy Schubert 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
410c1d255d3SCy Schubert 			"Missing or invalid Finite Cyclic Group attribute");
411c1d255d3SCy Schubert 		return NULL;
412c1d255d3SCy Schubert 	}
413c1d255d3SCy Schubert 	ike_group = WPA_GET_LE16(attr_group);
414c1d255d3SCy Schubert 	if (ike_group != curve->ike_group) {
415c1d255d3SCy Schubert 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
416c1d255d3SCy Schubert 			"Mismatching PKEX curve: peer=%u own=%u",
417c1d255d3SCy Schubert 			ike_group, curve->ike_group);
418c1d255d3SCy Schubert 		pkex = os_zalloc(sizeof(*pkex));
419c1d255d3SCy Schubert 		if (!pkex)
420c1d255d3SCy Schubert 			goto fail;
42132a95656SCy Schubert 		pkex->v2 = v2;
42232a95656SCy Schubert 		pkex->peer_version = peer_version;
423c1d255d3SCy Schubert 		pkex->own_bi = bi;
424c1d255d3SCy Schubert 		pkex->failed = 1;
425c1d255d3SCy Schubert 		pkex->exchange_resp = dpp_pkex_build_exchange_resp(
426c1d255d3SCy Schubert 			pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
427c1d255d3SCy Schubert 		if (!pkex->exchange_resp)
428c1d255d3SCy Schubert 			goto fail;
429c1d255d3SCy Schubert 		return pkex;
430c1d255d3SCy Schubert 	}
431c1d255d3SCy Schubert 
432c1d255d3SCy Schubert 	/* M in Encrypted Key attribute */
433c1d255d3SCy Schubert 	attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
434c1d255d3SCy Schubert 				&attr_key_len);
435c1d255d3SCy Schubert 	if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
436c1d255d3SCy Schubert 	    attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
437c1d255d3SCy Schubert 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
438c1d255d3SCy Schubert 			"Missing Encrypted Key attribute");
439c1d255d3SCy Schubert 		return NULL;
440c1d255d3SCy Schubert 	}
441c1d255d3SCy Schubert 
44232a95656SCy Schubert 	/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
443*a90b9d01SCy Schubert 	Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, code_len,
444*a90b9d01SCy Schubert 				identifier, &ec);
445c1d255d3SCy Schubert 	if (!Qi)
446c1d255d3SCy Schubert 		goto fail;
447c1d255d3SCy Schubert 
448c1d255d3SCy Schubert 	/* X' = M - Qi */
4494b72b91aSCy Schubert 	X = crypto_ec_point_init(ec);
4504b72b91aSCy Schubert 	M = crypto_ec_point_from_bin(ec, attr_key);
4514b72b91aSCy Schubert 	if (!X || !M ||
4524b72b91aSCy Schubert 	    crypto_ec_point_is_at_infinity(ec, M) ||
4534b72b91aSCy Schubert 	    !crypto_ec_point_is_on_curve(ec, M) ||
4544b72b91aSCy Schubert 	    crypto_ec_point_invert(ec, Qi) ||
4554b72b91aSCy Schubert 	    crypto_ec_point_add(ec, M, Qi, X) ||
4564b72b91aSCy Schubert 	    crypto_ec_point_is_at_infinity(ec, X) ||
4574b72b91aSCy Schubert 	    !crypto_ec_point_is_on_curve(ec, X)) {
458c1d255d3SCy Schubert 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
459c1d255d3SCy Schubert 			"Invalid Encrypted Key value");
460c1d255d3SCy Schubert 		bi->pkex_t++;
461c1d255d3SCy Schubert 		goto fail;
462c1d255d3SCy Schubert 	}
4634b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, M, "DPP: M");
4644b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, X, "DPP: X'");
465c1d255d3SCy Schubert 
466c1d255d3SCy Schubert 	pkex = os_zalloc(sizeof(*pkex));
467c1d255d3SCy Schubert 	if (!pkex)
468c1d255d3SCy Schubert 		goto fail;
46932a95656SCy Schubert 	pkex->v2 = v2;
47032a95656SCy Schubert 	pkex->peer_version = peer_version;
471c1d255d3SCy Schubert 	pkex->t = bi->pkex_t;
472c1d255d3SCy Schubert 	pkex->msg_ctx = msg_ctx;
473c1d255d3SCy Schubert 	pkex->own_bi = bi;
474*a90b9d01SCy Schubert 	if (own_mac)
475c1d255d3SCy Schubert 		os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
476*a90b9d01SCy Schubert 	if (peer_mac)
477c1d255d3SCy Schubert 		os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
478c1d255d3SCy Schubert 	if (identifier) {
479c1d255d3SCy Schubert 		pkex->identifier = os_strdup(identifier);
480c1d255d3SCy Schubert 		if (!pkex->identifier)
481c1d255d3SCy Schubert 			goto fail;
482c1d255d3SCy Schubert 	}
483*a90b9d01SCy Schubert 	pkex->code = os_memdup(code, code_len);
484c1d255d3SCy Schubert 	if (!pkex->code)
485c1d255d3SCy Schubert 		goto fail;
486*a90b9d01SCy Schubert 	pkex->code_len = code_len;
487c1d255d3SCy Schubert 
488c1d255d3SCy Schubert 	os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
489c1d255d3SCy Schubert 
4904b72b91aSCy Schubert 	x_coord = os_malloc(curve->prime_len);
4914b72b91aSCy Schubert 	y_coord = os_malloc(curve->prime_len);
4924b72b91aSCy Schubert 	if (!x_coord || !y_coord ||
4934b72b91aSCy Schubert 	    crypto_ec_point_to_bin(ec, X, x_coord, y_coord))
494c1d255d3SCy Schubert 		goto fail;
4954b72b91aSCy Schubert 
4964b72b91aSCy Schubert 	pkex->x = crypto_ec_key_set_pub(curve->ike_group, x_coord,
4974b72b91aSCy Schubert 					y_coord, crypto_ec_prime_len(ec));
4984b72b91aSCy Schubert 	if (!pkex->x)
499c1d255d3SCy Schubert 		goto fail;
500c1d255d3SCy Schubert 
50132a95656SCy Schubert 	/* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
502*a90b9d01SCy Schubert 	Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, code_len,
503*a90b9d01SCy Schubert 				identifier, NULL);
504c1d255d3SCy Schubert 	if (!Qr)
505c1d255d3SCy Schubert 		goto fail;
506c1d255d3SCy Schubert 
507c1d255d3SCy Schubert 	/* Generate a random ephemeral keypair y/Y */
508c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
509c1d255d3SCy Schubert 	if (dpp_pkex_ephemeral_key_override_len) {
510c1d255d3SCy Schubert 		const struct dpp_curve_params *tmp_curve;
511c1d255d3SCy Schubert 
512c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
513c1d255d3SCy Schubert 			   "DPP: TESTING - override ephemeral key y/Y");
514c1d255d3SCy Schubert 		pkex->y = dpp_set_keypair(&tmp_curve,
515c1d255d3SCy Schubert 					  dpp_pkex_ephemeral_key_override,
516c1d255d3SCy Schubert 					  dpp_pkex_ephemeral_key_override_len);
517c1d255d3SCy Schubert 	} else {
518c1d255d3SCy Schubert 		pkex->y = dpp_gen_keypair(curve);
519c1d255d3SCy Schubert 	}
520c1d255d3SCy Schubert #else /* CONFIG_TESTING_OPTIONS */
521c1d255d3SCy Schubert 	pkex->y = dpp_gen_keypair(curve);
522c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
523c1d255d3SCy Schubert 	if (!pkex->y)
524c1d255d3SCy Schubert 		goto fail;
525c1d255d3SCy Schubert 
526c1d255d3SCy Schubert 	/* N = Y + Qr */
5274b72b91aSCy Schubert 	Y = crypto_ec_key_get_public_key(pkex->y);
5284b72b91aSCy Schubert 	if (!Y)
529c1d255d3SCy Schubert 		goto fail;
5304b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, Y, "DPP: Y");
5314b72b91aSCy Schubert 
5324b72b91aSCy Schubert 	N = crypto_ec_point_init(ec);
5334b72b91aSCy Schubert 	if (!N ||
5344b72b91aSCy Schubert 	    crypto_ec_point_add(ec, Y, Qr, N) ||
5354b72b91aSCy Schubert 	    crypto_ec_point_to_bin(ec, N, x_coord, y_coord))
536c1d255d3SCy Schubert 		goto fail;
5374b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, N, "DPP: N");
538c1d255d3SCy Schubert 
539c1d255d3SCy Schubert 	pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
5404b72b91aSCy Schubert 							   x_coord, y_coord);
541c1d255d3SCy Schubert 	if (!pkex->exchange_resp)
542c1d255d3SCy Schubert 		goto fail;
543c1d255d3SCy Schubert 
544c1d255d3SCy Schubert 	/* K = y * X' */
545c1d255d3SCy Schubert 	if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
546c1d255d3SCy Schubert 		goto fail;
547c1d255d3SCy Schubert 
548c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
549c1d255d3SCy Schubert 			Kx, Kx_len);
550c1d255d3SCy Schubert 
55132a95656SCy Schubert 	/* z = HKDF(<>, info | M.x | N.x | code, K.x) */
55232a95656SCy Schubert 	res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->peer_mac,
55332a95656SCy Schubert 				pkex->v2 ? NULL : pkex->own_mac,
55432a95656SCy Schubert 				pkex->peer_version, DPP_VERSION,
555c1d255d3SCy Schubert 				pkex->Mx, curve->prime_len,
556c1d255d3SCy Schubert 				pkex->Nx, curve->prime_len, pkex->code,
557*a90b9d01SCy Schubert 				pkex->code_len,	Kx, Kx_len, pkex->z,
558*a90b9d01SCy Schubert 				curve->hash_len);
559c1d255d3SCy Schubert 	os_memset(Kx, 0, Kx_len);
560c1d255d3SCy Schubert 	if (res < 0)
561c1d255d3SCy Schubert 		goto fail;
562c1d255d3SCy Schubert 
563c1d255d3SCy Schubert 	pkex->exchange_done = 1;
564c1d255d3SCy Schubert 
565c1d255d3SCy Schubert out:
5664b72b91aSCy Schubert 	os_free(x_coord);
5674b72b91aSCy Schubert 	os_free(y_coord);
5684b72b91aSCy Schubert 	crypto_ec_point_deinit(Qi, 1);
5694b72b91aSCy Schubert 	crypto_ec_point_deinit(Qr, 1);
5704b72b91aSCy Schubert 	crypto_ec_point_deinit(M, 1);
5714b72b91aSCy Schubert 	crypto_ec_point_deinit(N, 1);
5724b72b91aSCy Schubert 	crypto_ec_point_deinit(X, 1);
573*a90b9d01SCy Schubert 	crypto_ec_point_deinit(Y, 1);
5744b72b91aSCy Schubert 	crypto_ec_deinit(ec);
575c1d255d3SCy Schubert 	return pkex;
576c1d255d3SCy Schubert fail:
577c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
578c1d255d3SCy Schubert 	dpp_pkex_free(pkex);
579c1d255d3SCy Schubert 	pkex = NULL;
580c1d255d3SCy Schubert 	goto out;
581c1d255d3SCy Schubert }
582c1d255d3SCy Schubert 
583c1d255d3SCy Schubert 
584c1d255d3SCy Schubert static struct wpabuf *
dpp_pkex_build_commit_reveal_req(struct dpp_pkex * pkex,const struct wpabuf * A_pub,const u8 * u)585c1d255d3SCy Schubert dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
586c1d255d3SCy Schubert 				 const struct wpabuf *A_pub, const u8 *u)
587c1d255d3SCy Schubert {
588c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
589c1d255d3SCy Schubert 	struct wpabuf *msg = NULL;
590c1d255d3SCy Schubert 	size_t clear_len, attr_len;
591c1d255d3SCy Schubert 	struct wpabuf *clear = NULL;
592c1d255d3SCy Schubert 	u8 *wrapped;
593c1d255d3SCy Schubert 	u8 octet;
594c1d255d3SCy Schubert 	const u8 *addr[2];
595c1d255d3SCy Schubert 	size_t len[2];
596c1d255d3SCy Schubert 
597c1d255d3SCy Schubert 	/* {A, u, [bootstrapping info]}z */
598c1d255d3SCy Schubert 	clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
599c1d255d3SCy Schubert 	clear = wpabuf_alloc(clear_len);
600c1d255d3SCy Schubert 	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
601c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
602c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
603c1d255d3SCy Schubert 		attr_len += 5;
604c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
605c1d255d3SCy Schubert 	msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
606c1d255d3SCy Schubert 	if (!clear || !msg)
607c1d255d3SCy Schubert 		goto fail;
608c1d255d3SCy Schubert 
609c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
610c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
611c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
612c1d255d3SCy Schubert 		goto skip_bootstrap_key;
613c1d255d3SCy Schubert 	}
614c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
615c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
616c1d255d3SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
617c1d255d3SCy Schubert 		wpabuf_put_le16(clear, 2 * curve->prime_len);
618c1d255d3SCy Schubert 		if (dpp_test_gen_invalid_key(clear, curve) < 0)
619c1d255d3SCy Schubert 			goto fail;
620c1d255d3SCy Schubert 		goto skip_bootstrap_key;
621c1d255d3SCy Schubert 	}
622c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
623c1d255d3SCy Schubert 
624c1d255d3SCy Schubert 	/* A in Bootstrap Key attribute */
625c1d255d3SCy Schubert 	wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
626c1d255d3SCy Schubert 	wpabuf_put_le16(clear, wpabuf_len(A_pub));
627c1d255d3SCy Schubert 	wpabuf_put_buf(clear, A_pub);
628c1d255d3SCy Schubert 
629c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
630c1d255d3SCy Schubert skip_bootstrap_key:
631c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
632c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
633c1d255d3SCy Schubert 		goto skip_i_auth_tag;
634c1d255d3SCy Schubert 	}
635c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
636c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
637c1d255d3SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
638c1d255d3SCy Schubert 		wpabuf_put_le16(clear, curve->hash_len);
639c1d255d3SCy Schubert 		wpabuf_put_data(clear, u, curve->hash_len - 1);
640c1d255d3SCy Schubert 		wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
641c1d255d3SCy Schubert 		goto skip_i_auth_tag;
642c1d255d3SCy Schubert 	}
643c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
644c1d255d3SCy Schubert 
645c1d255d3SCy Schubert 	/* u in I-Auth tag attribute */
646c1d255d3SCy Schubert 	wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
647c1d255d3SCy Schubert 	wpabuf_put_le16(clear, curve->hash_len);
648c1d255d3SCy Schubert 	wpabuf_put_data(clear, u, curve->hash_len);
649c1d255d3SCy Schubert 
650c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
651c1d255d3SCy Schubert skip_i_auth_tag:
652c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
653c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
654c1d255d3SCy Schubert 		goto skip_wrapped_data;
655c1d255d3SCy Schubert 	}
656c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
657c1d255d3SCy Schubert 
658c1d255d3SCy Schubert 	addr[0] = wpabuf_head_u8(msg) + 2;
659c1d255d3SCy Schubert 	len[0] = DPP_HDR_LEN;
660c1d255d3SCy Schubert 	octet = 0;
661c1d255d3SCy Schubert 	addr[1] = &octet;
662c1d255d3SCy Schubert 	len[1] = sizeof(octet);
663c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
664c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
665c1d255d3SCy Schubert 
666c1d255d3SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
667c1d255d3SCy Schubert 	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
668c1d255d3SCy Schubert 	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
669c1d255d3SCy Schubert 
670c1d255d3SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
671c1d255d3SCy Schubert 	if (aes_siv_encrypt(pkex->z, curve->hash_len,
672c1d255d3SCy Schubert 			    wpabuf_head(clear), wpabuf_len(clear),
673c1d255d3SCy Schubert 			    2, addr, len, wrapped) < 0)
674c1d255d3SCy Schubert 		goto fail;
675c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
676c1d255d3SCy Schubert 		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
677c1d255d3SCy Schubert 
678c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
679c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
680c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
681c1d255d3SCy Schubert 		dpp_build_attr_status(msg, DPP_STATUS_OK);
682c1d255d3SCy Schubert 	}
683c1d255d3SCy Schubert skip_wrapped_data:
684c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
685c1d255d3SCy Schubert 
686c1d255d3SCy Schubert out:
687c1d255d3SCy Schubert 	wpabuf_free(clear);
688c1d255d3SCy Schubert 	return msg;
689c1d255d3SCy Schubert 
690c1d255d3SCy Schubert fail:
691c1d255d3SCy Schubert 	wpabuf_free(msg);
692c1d255d3SCy Schubert 	msg = NULL;
693c1d255d3SCy Schubert 	goto out;
694c1d255d3SCy Schubert }
695c1d255d3SCy Schubert 
696c1d255d3SCy Schubert 
dpp_pkex_rx_exchange_resp(struct dpp_pkex * pkex,const u8 * peer_mac,const u8 * buf,size_t buflen)697c1d255d3SCy Schubert struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
698c1d255d3SCy Schubert 					  const u8 *peer_mac,
699c1d255d3SCy Schubert 					  const u8 *buf, size_t buflen)
700c1d255d3SCy Schubert {
701c1d255d3SCy Schubert 	const u8 *attr_status, *attr_id, *attr_key, *attr_group;
702c1d255d3SCy Schubert 	u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
7034b72b91aSCy Schubert 	struct crypto_ec *ec = NULL;
704c1d255d3SCy Schubert 	struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
705c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
7064b72b91aSCy Schubert 	struct crypto_ec_point *Qr = NULL, *Y = NULL, *N = NULL;
7074b72b91aSCy Schubert 	u8 *x_coord = NULL, *y_coord = NULL;
708c1d255d3SCy Schubert 	size_t Jx_len, Kx_len;
709c1d255d3SCy Schubert 	u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
710c1d255d3SCy Schubert 	const u8 *addr[4];
711c1d255d3SCy Schubert 	size_t len[4];
71232a95656SCy Schubert 	size_t num_elem;
713c1d255d3SCy Schubert 	u8 u[DPP_MAX_HASH_LEN];
714c1d255d3SCy Schubert 	int res;
715c1d255d3SCy Schubert 
716c1d255d3SCy Schubert 	if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
717c1d255d3SCy Schubert 		return NULL;
718c1d255d3SCy Schubert 
719c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
720c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
721c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
722c1d255d3SCy Schubert 			   "DPP: TESTING - stop at PKEX Exchange Response");
723c1d255d3SCy Schubert 		pkex->failed = 1;
724c1d255d3SCy Schubert 		return NULL;
725c1d255d3SCy Schubert 	}
726c1d255d3SCy Schubert 
727c1d255d3SCy Schubert 	if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
728c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
729c1d255d3SCy Schubert 			   MAC2STR(dpp_pkex_peer_mac_override));
730c1d255d3SCy Schubert 		peer_mac = dpp_pkex_peer_mac_override;
731c1d255d3SCy Schubert 	}
732c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
733c1d255d3SCy Schubert 
73432a95656SCy Schubert #ifdef CONFIG_DPP2
73532a95656SCy Schubert 	if (pkex->v2) {
73632a95656SCy Schubert 		const u8 *version;
73732a95656SCy Schubert 		u16 version_len;
73832a95656SCy Schubert 
73932a95656SCy Schubert 		version = dpp_get_attr(buf, buflen, DPP_ATTR_PROTOCOL_VERSION,
74032a95656SCy Schubert 				       &version_len);
74132a95656SCy Schubert 		if (!version || version_len < 1 || version[0] == 0) {
74232a95656SCy Schubert 		dpp_pkex_fail(pkex,
74332a95656SCy Schubert 			      "Missing or invalid Protocol Version attribute");
74432a95656SCy Schubert 			return NULL;
74532a95656SCy Schubert 		}
74632a95656SCy Schubert 		pkex->peer_version = version[0];
74732a95656SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
74832a95656SCy Schubert 			   pkex->peer_version);
74932a95656SCy Schubert 	}
75032a95656SCy Schubert #endif /* CONFIG_DPP2 */
75132a95656SCy Schubert 
752*a90b9d01SCy Schubert 	if (peer_mac)
753c1d255d3SCy Schubert 		os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
754c1d255d3SCy Schubert 
755c1d255d3SCy Schubert 	attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
756c1d255d3SCy Schubert 				   &attr_status_len);
757c1d255d3SCy Schubert 	if (!attr_status || attr_status_len != 1) {
758c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "No DPP Status attribute");
759c1d255d3SCy Schubert 		return NULL;
760c1d255d3SCy Schubert 	}
761c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
762c1d255d3SCy Schubert 
763c1d255d3SCy Schubert 	if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
764c1d255d3SCy Schubert 		attr_group = dpp_get_attr(buf, buflen,
765c1d255d3SCy Schubert 					  DPP_ATTR_FINITE_CYCLIC_GROUP,
766c1d255d3SCy Schubert 					  &attr_group_len);
767c1d255d3SCy Schubert 		if (attr_group && attr_group_len == 2) {
768c1d255d3SCy Schubert 			wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
769c1d255d3SCy Schubert 				"Peer indicated mismatching PKEX group - proposed %u",
770c1d255d3SCy Schubert 				WPA_GET_LE16(attr_group));
771c1d255d3SCy Schubert 			return NULL;
772c1d255d3SCy Schubert 		}
773c1d255d3SCy Schubert 	}
774c1d255d3SCy Schubert 
775c1d255d3SCy Schubert 	if (attr_status[0] != DPP_STATUS_OK) {
776c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
777c1d255d3SCy Schubert 		return NULL;
778c1d255d3SCy Schubert 	}
779c1d255d3SCy Schubert 
780c1d255d3SCy Schubert 	attr_id_len = 0;
781c1d255d3SCy Schubert 	attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
782c1d255d3SCy Schubert 			       &attr_id_len);
783c1d255d3SCy Schubert 	if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
784c1d255d3SCy Schubert 				       pkex->identifier)) {
785c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
786c1d255d3SCy Schubert 		return NULL;
787c1d255d3SCy Schubert 	}
788c1d255d3SCy Schubert 
789c1d255d3SCy Schubert 	/* N in Encrypted Key attribute */
790c1d255d3SCy Schubert 	attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
791c1d255d3SCy Schubert 				&attr_key_len);
792c1d255d3SCy Schubert 	if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
793c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
794c1d255d3SCy Schubert 		return NULL;
795c1d255d3SCy Schubert 	}
796c1d255d3SCy Schubert 
79732a95656SCy Schubert 	/* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
79832a95656SCy Schubert 	Qr = dpp_pkex_derive_Qr(curve, pkex->v2 ? NULL : pkex->peer_mac,
799*a90b9d01SCy Schubert 				pkex->code, pkex->code_len, pkex->identifier,
800*a90b9d01SCy Schubert 				&ec);
801c1d255d3SCy Schubert 	if (!Qr)
802c1d255d3SCy Schubert 		goto fail;
803c1d255d3SCy Schubert 
804c1d255d3SCy Schubert 	/* Y' = N - Qr */
8054b72b91aSCy Schubert 	Y = crypto_ec_point_init(ec);
8064b72b91aSCy Schubert 	N = crypto_ec_point_from_bin(ec, attr_key);
8074b72b91aSCy Schubert 	if (!Y || !N ||
8084b72b91aSCy Schubert 	    crypto_ec_point_is_at_infinity(ec, N) ||
8094b72b91aSCy Schubert 	    !crypto_ec_point_is_on_curve(ec, N) ||
8104b72b91aSCy Schubert 	    crypto_ec_point_invert(ec, Qr) ||
8114b72b91aSCy Schubert 	    crypto_ec_point_add(ec, N, Qr, Y) ||
8124b72b91aSCy Schubert 	    crypto_ec_point_is_at_infinity(ec, Y) ||
8134b72b91aSCy Schubert 	    !crypto_ec_point_is_on_curve(ec, Y)) {
814c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
815c1d255d3SCy Schubert 		pkex->t++;
816c1d255d3SCy Schubert 		goto fail;
817c1d255d3SCy Schubert 	}
8184b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, N, "DPP: N");
8194b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, Y, "DPP: Y'");
820c1d255d3SCy Schubert 
821c1d255d3SCy Schubert 	pkex->exchange_done = 1;
822c1d255d3SCy Schubert 
823c1d255d3SCy Schubert 	/* ECDH: J = a * Y' */
8244b72b91aSCy Schubert 	x_coord = os_malloc(curve->prime_len);
8254b72b91aSCy Schubert 	y_coord = os_malloc(curve->prime_len);
8264b72b91aSCy Schubert 	if (!x_coord || !y_coord ||
8274b72b91aSCy Schubert 	    crypto_ec_point_to_bin(ec, Y, x_coord, y_coord))
828c1d255d3SCy Schubert 		goto fail;
8294b72b91aSCy Schubert 	pkex->y = crypto_ec_key_set_pub(curve->ike_group, x_coord, y_coord,
8304b72b91aSCy Schubert 					curve->prime_len);
8314b72b91aSCy Schubert 	if (!pkex->y)
832c1d255d3SCy Schubert 		goto fail;
833c1d255d3SCy Schubert 	if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
834c1d255d3SCy Schubert 		goto fail;
835c1d255d3SCy Schubert 
836c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
837c1d255d3SCy Schubert 			Jx, Jx_len);
838c1d255d3SCy Schubert 
83932a95656SCy Schubert 	/* u = HMAC(J.x, [MAC-Initiator |] A.x | Y'.x | X.x) */
8404b72b91aSCy Schubert 	A_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
8414b72b91aSCy Schubert 	Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
8424b72b91aSCy Schubert 	X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
843c1d255d3SCy Schubert 	if (!A_pub || !Y_pub || !X_pub)
844c1d255d3SCy Schubert 		goto fail;
84532a95656SCy Schubert 	num_elem = 0;
84632a95656SCy Schubert 	if (!pkex->v2) {
84732a95656SCy Schubert 		addr[num_elem] = pkex->own_mac;
84832a95656SCy Schubert 		len[num_elem] = ETH_ALEN;
84932a95656SCy Schubert 		num_elem++;
85032a95656SCy Schubert 	}
85132a95656SCy Schubert 	addr[num_elem] = wpabuf_head(A_pub);
85232a95656SCy Schubert 	len[num_elem] = wpabuf_len(A_pub) / 2;
85332a95656SCy Schubert 	num_elem++;
85432a95656SCy Schubert 	addr[num_elem] = wpabuf_head(Y_pub);
85532a95656SCy Schubert 	len[num_elem] = wpabuf_len(Y_pub) / 2;
85632a95656SCy Schubert 	num_elem++;
85732a95656SCy Schubert 	addr[num_elem] = wpabuf_head(X_pub);
85832a95656SCy Schubert 	len[num_elem] = wpabuf_len(X_pub) / 2;
85932a95656SCy Schubert 	num_elem++;
86032a95656SCy Schubert 	if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u)
86132a95656SCy Schubert 	    < 0)
862c1d255d3SCy Schubert 		goto fail;
863c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
864c1d255d3SCy Schubert 
865c1d255d3SCy Schubert 	/* K = x * Y' */
866c1d255d3SCy Schubert 	if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
867c1d255d3SCy Schubert 		goto fail;
868c1d255d3SCy Schubert 
869c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
870c1d255d3SCy Schubert 			Kx, Kx_len);
871c1d255d3SCy Schubert 
87232a95656SCy Schubert 	/* z = HKDF(<>, info | M.x | N.x | code, K.x) */
87332a95656SCy Schubert 	res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->own_mac,
87432a95656SCy Schubert 				pkex->v2 ? NULL : pkex->peer_mac,
87532a95656SCy Schubert 				DPP_VERSION, pkex->peer_version,
876c1d255d3SCy Schubert 				pkex->Mx, curve->prime_len,
877c1d255d3SCy Schubert 				attr_key /* N.x */, attr_key_len / 2,
878*a90b9d01SCy Schubert 				pkex->code, pkex->code_len, Kx, Kx_len,
879c1d255d3SCy Schubert 				pkex->z, curve->hash_len);
880c1d255d3SCy Schubert 	os_memset(Kx, 0, Kx_len);
881c1d255d3SCy Schubert 	if (res < 0)
882c1d255d3SCy Schubert 		goto fail;
883c1d255d3SCy Schubert 
884c1d255d3SCy Schubert 	msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
885c1d255d3SCy Schubert 	if (!msg)
886c1d255d3SCy Schubert 		goto fail;
887c1d255d3SCy Schubert 
888c1d255d3SCy Schubert out:
889c1d255d3SCy Schubert 	wpabuf_free(A_pub);
890c1d255d3SCy Schubert 	wpabuf_free(X_pub);
891c1d255d3SCy Schubert 	wpabuf_free(Y_pub);
8924b72b91aSCy Schubert 	os_free(x_coord);
8934b72b91aSCy Schubert 	os_free(y_coord);
8944b72b91aSCy Schubert 	crypto_ec_point_deinit(Qr, 1);
8954b72b91aSCy Schubert 	crypto_ec_point_deinit(Y, 1);
8964b72b91aSCy Schubert 	crypto_ec_point_deinit(N, 1);
8974b72b91aSCy Schubert 	crypto_ec_deinit(ec);
898c1d255d3SCy Schubert 	return msg;
899c1d255d3SCy Schubert fail:
900c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
901c1d255d3SCy Schubert 	goto out;
902c1d255d3SCy Schubert }
903c1d255d3SCy Schubert 
904c1d255d3SCy Schubert 
905c1d255d3SCy Schubert static struct wpabuf *
dpp_pkex_build_commit_reveal_resp(struct dpp_pkex * pkex,const struct wpabuf * B_pub,const u8 * v)906c1d255d3SCy Schubert dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
907c1d255d3SCy Schubert 				  const struct wpabuf *B_pub, const u8 *v)
908c1d255d3SCy Schubert {
909c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
910c1d255d3SCy Schubert 	struct wpabuf *msg = NULL;
911c1d255d3SCy Schubert 	const u8 *addr[2];
912c1d255d3SCy Schubert 	size_t len[2];
913c1d255d3SCy Schubert 	u8 octet;
914c1d255d3SCy Schubert 	u8 *wrapped;
915c1d255d3SCy Schubert 	struct wpabuf *clear = NULL;
916c1d255d3SCy Schubert 	size_t clear_len, attr_len;
917c1d255d3SCy Schubert 
918c1d255d3SCy Schubert 	/* {B, v [bootstrapping info]}z */
919c1d255d3SCy Schubert 	clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
920c1d255d3SCy Schubert 	clear = wpabuf_alloc(clear_len);
921c1d255d3SCy Schubert 	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
922c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
923c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
924c1d255d3SCy Schubert 		attr_len += 5;
925c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
926c1d255d3SCy Schubert 	msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
927c1d255d3SCy Schubert 	if (!clear || !msg)
928c1d255d3SCy Schubert 		goto fail;
929c1d255d3SCy Schubert 
930c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
931c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
932c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
933c1d255d3SCy Schubert 		goto skip_bootstrap_key;
934c1d255d3SCy Schubert 	}
935c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
936c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
937c1d255d3SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
938c1d255d3SCy Schubert 		wpabuf_put_le16(clear, 2 * curve->prime_len);
939c1d255d3SCy Schubert 		if (dpp_test_gen_invalid_key(clear, curve) < 0)
940c1d255d3SCy Schubert 			goto fail;
941c1d255d3SCy Schubert 		goto skip_bootstrap_key;
942c1d255d3SCy Schubert 	}
943c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
944c1d255d3SCy Schubert 
945c1d255d3SCy Schubert 	/* B in Bootstrap Key attribute */
946c1d255d3SCy Schubert 	wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
947c1d255d3SCy Schubert 	wpabuf_put_le16(clear, wpabuf_len(B_pub));
948c1d255d3SCy Schubert 	wpabuf_put_buf(clear, B_pub);
949c1d255d3SCy Schubert 
950c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
951c1d255d3SCy Schubert skip_bootstrap_key:
952c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
953c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
954c1d255d3SCy Schubert 		goto skip_r_auth_tag;
955c1d255d3SCy Schubert 	}
956c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
957c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
958c1d255d3SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
959c1d255d3SCy Schubert 		wpabuf_put_le16(clear, curve->hash_len);
960c1d255d3SCy Schubert 		wpabuf_put_data(clear, v, curve->hash_len - 1);
961c1d255d3SCy Schubert 		wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
962c1d255d3SCy Schubert 		goto skip_r_auth_tag;
963c1d255d3SCy Schubert 	}
964c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
965c1d255d3SCy Schubert 
966c1d255d3SCy Schubert 	/* v in R-Auth tag attribute */
967c1d255d3SCy Schubert 	wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
968c1d255d3SCy Schubert 	wpabuf_put_le16(clear, curve->hash_len);
969c1d255d3SCy Schubert 	wpabuf_put_data(clear, v, curve->hash_len);
970c1d255d3SCy Schubert 
971c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
972c1d255d3SCy Schubert skip_r_auth_tag:
973c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
974c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
975c1d255d3SCy Schubert 		goto skip_wrapped_data;
976c1d255d3SCy Schubert 	}
977c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
978c1d255d3SCy Schubert 
979c1d255d3SCy Schubert 	addr[0] = wpabuf_head_u8(msg) + 2;
980c1d255d3SCy Schubert 	len[0] = DPP_HDR_LEN;
981c1d255d3SCy Schubert 	octet = 1;
982c1d255d3SCy Schubert 	addr[1] = &octet;
983c1d255d3SCy Schubert 	len[1] = sizeof(octet);
984c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
985c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
986c1d255d3SCy Schubert 
987c1d255d3SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
988c1d255d3SCy Schubert 	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
989c1d255d3SCy Schubert 	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
990c1d255d3SCy Schubert 
991c1d255d3SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
992c1d255d3SCy Schubert 	if (aes_siv_encrypt(pkex->z, curve->hash_len,
993c1d255d3SCy Schubert 			    wpabuf_head(clear), wpabuf_len(clear),
994c1d255d3SCy Schubert 			    2, addr, len, wrapped) < 0)
995c1d255d3SCy Schubert 		goto fail;
996c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
997c1d255d3SCy Schubert 		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
998c1d255d3SCy Schubert 
999c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1000c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
1001c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1002c1d255d3SCy Schubert 		dpp_build_attr_status(msg, DPP_STATUS_OK);
1003c1d255d3SCy Schubert 	}
1004c1d255d3SCy Schubert skip_wrapped_data:
1005c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1006c1d255d3SCy Schubert 
1007c1d255d3SCy Schubert out:
1008c1d255d3SCy Schubert 	wpabuf_free(clear);
1009c1d255d3SCy Schubert 	return msg;
1010c1d255d3SCy Schubert 
1011c1d255d3SCy Schubert fail:
1012c1d255d3SCy Schubert 	wpabuf_free(msg);
1013c1d255d3SCy Schubert 	msg = NULL;
1014c1d255d3SCy Schubert 	goto out;
1015c1d255d3SCy Schubert }
1016c1d255d3SCy Schubert 
1017c1d255d3SCy Schubert 
dpp_pkex_rx_commit_reveal_req(struct dpp_pkex * pkex,const u8 * hdr,const u8 * buf,size_t buflen)1018c1d255d3SCy Schubert struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
1019c1d255d3SCy Schubert 					      const u8 *hdr,
1020c1d255d3SCy Schubert 					      const u8 *buf, size_t buflen)
1021c1d255d3SCy Schubert {
1022c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
1023c1d255d3SCy Schubert 	size_t Jx_len, Lx_len;
1024c1d255d3SCy Schubert 	u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
1025c1d255d3SCy Schubert 	u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
1026c1d255d3SCy Schubert 	const u8 *wrapped_data, *b_key, *peer_u;
1027c1d255d3SCy Schubert 	u16 wrapped_data_len, b_key_len, peer_u_len = 0;
1028c1d255d3SCy Schubert 	const u8 *addr[4];
1029c1d255d3SCy Schubert 	size_t len[4];
103032a95656SCy Schubert 	size_t num_elem;
1031c1d255d3SCy Schubert 	u8 octet;
1032c1d255d3SCy Schubert 	u8 *unwrapped = NULL;
1033c1d255d3SCy Schubert 	size_t unwrapped_len = 0;
1034c1d255d3SCy Schubert 	struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
1035c1d255d3SCy Schubert 	struct wpabuf *B_pub = NULL;
1036c1d255d3SCy Schubert 	u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
1037c1d255d3SCy Schubert 
1038c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1039c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
1040c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
1041c1d255d3SCy Schubert 			   "DPP: TESTING - stop at PKEX CR Request");
1042c1d255d3SCy Schubert 		pkex->failed = 1;
1043c1d255d3SCy Schubert 		return NULL;
1044c1d255d3SCy Schubert 	}
1045c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1046c1d255d3SCy Schubert 
1047c1d255d3SCy Schubert 	if (!pkex->exchange_done || pkex->failed ||
1048c1d255d3SCy Schubert 	    pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
1049c1d255d3SCy Schubert 		goto fail;
1050c1d255d3SCy Schubert 
1051c1d255d3SCy Schubert 	wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
1052c1d255d3SCy Schubert 				    &wrapped_data_len);
1053c1d255d3SCy Schubert 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
1054c1d255d3SCy Schubert 		dpp_pkex_fail(pkex,
1055c1d255d3SCy Schubert 			      "Missing or invalid required Wrapped Data attribute");
1056c1d255d3SCy Schubert 		goto fail;
1057c1d255d3SCy Schubert 	}
1058c1d255d3SCy Schubert 
1059c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1060c1d255d3SCy Schubert 		    wrapped_data, wrapped_data_len);
1061c1d255d3SCy Schubert 	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1062c1d255d3SCy Schubert 	unwrapped = os_malloc(unwrapped_len);
1063c1d255d3SCy Schubert 	if (!unwrapped)
1064c1d255d3SCy Schubert 		goto fail;
1065c1d255d3SCy Schubert 
1066c1d255d3SCy Schubert 	addr[0] = hdr;
1067c1d255d3SCy Schubert 	len[0] = DPP_HDR_LEN;
1068c1d255d3SCy Schubert 	octet = 0;
1069c1d255d3SCy Schubert 	addr[1] = &octet;
1070c1d255d3SCy Schubert 	len[1] = sizeof(octet);
1071c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1072c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1073c1d255d3SCy Schubert 
1074c1d255d3SCy Schubert 	if (aes_siv_decrypt(pkex->z, curve->hash_len,
1075c1d255d3SCy Schubert 			    wrapped_data, wrapped_data_len,
1076c1d255d3SCy Schubert 			    2, addr, len, unwrapped) < 0) {
1077c1d255d3SCy Schubert 		dpp_pkex_fail(pkex,
1078c1d255d3SCy Schubert 			      "AES-SIV decryption failed - possible PKEX code mismatch");
1079c1d255d3SCy Schubert 		pkex->failed = 1;
1080c1d255d3SCy Schubert 		pkex->t++;
1081c1d255d3SCy Schubert 		goto fail;
1082c1d255d3SCy Schubert 	}
1083c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1084c1d255d3SCy Schubert 		    unwrapped, unwrapped_len);
1085c1d255d3SCy Schubert 
1086c1d255d3SCy Schubert 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1087c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
1088c1d255d3SCy Schubert 		goto fail;
1089c1d255d3SCy Schubert 	}
1090c1d255d3SCy Schubert 
1091c1d255d3SCy Schubert 	b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
1092c1d255d3SCy Schubert 			     &b_key_len);
1093c1d255d3SCy Schubert 	if (!b_key || b_key_len != 2 * curve->prime_len) {
1094c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
1095c1d255d3SCy Schubert 		goto fail;
1096c1d255d3SCy Schubert 	}
1097c1d255d3SCy Schubert 	pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
1098c1d255d3SCy Schubert 							b_key_len);
1099c1d255d3SCy Schubert 	if (!pkex->peer_bootstrap_key) {
1100c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
1101c1d255d3SCy Schubert 		goto fail;
1102c1d255d3SCy Schubert 	}
1103c1d255d3SCy Schubert 	dpp_debug_print_key("DPP: Peer bootstrap public key",
1104c1d255d3SCy Schubert 			    pkex->peer_bootstrap_key);
1105c1d255d3SCy Schubert 
1106c1d255d3SCy Schubert 	/* ECDH: J' = y * A' */
1107c1d255d3SCy Schubert 	if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
1108c1d255d3SCy Schubert 		goto fail;
1109c1d255d3SCy Schubert 
1110c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
1111c1d255d3SCy Schubert 			Jx, Jx_len);
1112c1d255d3SCy Schubert 
111332a95656SCy Schubert 	/* u' = HMAC(J'.x, [MAC-Initiator |] A'.x | Y.x | X'.x) */
11144b72b91aSCy Schubert 	A_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
11154b72b91aSCy Schubert 	Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
11164b72b91aSCy Schubert 	X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
1117c1d255d3SCy Schubert 	if (!A_pub || !Y_pub || !X_pub)
1118c1d255d3SCy Schubert 		goto fail;
111932a95656SCy Schubert 	num_elem = 0;
112032a95656SCy Schubert 	if (!pkex->v2) {
112132a95656SCy Schubert 		addr[num_elem] = pkex->peer_mac;
112232a95656SCy Schubert 		len[num_elem] = ETH_ALEN;
112332a95656SCy Schubert 		num_elem++;
112432a95656SCy Schubert 	}
112532a95656SCy Schubert 	addr[num_elem] = wpabuf_head(A_pub);
112632a95656SCy Schubert 	len[num_elem] = wpabuf_len(A_pub) / 2;
112732a95656SCy Schubert 	num_elem++;
112832a95656SCy Schubert 	addr[num_elem] = wpabuf_head(Y_pub);
112932a95656SCy Schubert 	len[num_elem] = wpabuf_len(Y_pub) / 2;
113032a95656SCy Schubert 	num_elem++;
113132a95656SCy Schubert 	addr[num_elem] = wpabuf_head(X_pub);
113232a95656SCy Schubert 	len[num_elem] = wpabuf_len(X_pub) / 2;
113332a95656SCy Schubert 	num_elem++;
113432a95656SCy Schubert 	if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u)
113532a95656SCy Schubert 	    < 0)
1136c1d255d3SCy Schubert 		goto fail;
1137c1d255d3SCy Schubert 
1138c1d255d3SCy Schubert 	peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
1139c1d255d3SCy Schubert 			      &peer_u_len);
1140c1d255d3SCy Schubert 	if (!peer_u || peer_u_len != curve->hash_len ||
1141c1d255d3SCy Schubert 	    os_memcmp(peer_u, u, curve->hash_len) != 0) {
1142c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
1143c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
1144c1d255d3SCy Schubert 			    u, curve->hash_len);
1145c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
1146c1d255d3SCy Schubert 		pkex->t++;
1147c1d255d3SCy Schubert 		goto fail;
1148c1d255d3SCy Schubert 	}
1149c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
1150c1d255d3SCy Schubert 
1151c1d255d3SCy Schubert 	/* ECDH: L = b * X' */
1152c1d255d3SCy Schubert 	if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
1153c1d255d3SCy Schubert 		goto fail;
1154c1d255d3SCy Schubert 
1155c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
1156c1d255d3SCy Schubert 			Lx, Lx_len);
1157c1d255d3SCy Schubert 
115832a95656SCy Schubert 	/* v = HMAC(L.x, [MAC-Responder |] B.x | X'.x | Y.x) */
11594b72b91aSCy Schubert 	B_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
1160c1d255d3SCy Schubert 	if (!B_pub)
1161c1d255d3SCy Schubert 		goto fail;
116232a95656SCy Schubert 	num_elem = 0;
116332a95656SCy Schubert 	if (!pkex->v2) {
116432a95656SCy Schubert 		addr[num_elem] = pkex->own_mac;
116532a95656SCy Schubert 		len[num_elem] = ETH_ALEN;
116632a95656SCy Schubert 		num_elem++;
116732a95656SCy Schubert 	}
116832a95656SCy Schubert 	addr[num_elem] = wpabuf_head(B_pub);
116932a95656SCy Schubert 	len[num_elem] = wpabuf_len(B_pub) / 2;
117032a95656SCy Schubert 	num_elem++;
117132a95656SCy Schubert 	addr[num_elem] = wpabuf_head(X_pub);
117232a95656SCy Schubert 	len[num_elem] = wpabuf_len(X_pub) / 2;
117332a95656SCy Schubert 	num_elem++;
117432a95656SCy Schubert 	addr[num_elem] = wpabuf_head(Y_pub);
117532a95656SCy Schubert 	len[num_elem] = wpabuf_len(Y_pub) / 2;
117632a95656SCy Schubert 	num_elem++;
117732a95656SCy Schubert 	if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v)
117832a95656SCy Schubert 	    < 0)
1179c1d255d3SCy Schubert 		goto fail;
1180c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
1181c1d255d3SCy Schubert 
1182c1d255d3SCy Schubert 	msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
1183c1d255d3SCy Schubert 	if (!msg)
1184c1d255d3SCy Schubert 		goto fail;
1185c1d255d3SCy Schubert 
1186c1d255d3SCy Schubert out:
1187c1d255d3SCy Schubert 	os_free(unwrapped);
1188c1d255d3SCy Schubert 	wpabuf_free(A_pub);
1189c1d255d3SCy Schubert 	wpabuf_free(B_pub);
1190c1d255d3SCy Schubert 	wpabuf_free(X_pub);
1191c1d255d3SCy Schubert 	wpabuf_free(Y_pub);
1192c1d255d3SCy Schubert 	return msg;
1193c1d255d3SCy Schubert fail:
1194c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG,
1195c1d255d3SCy Schubert 		   "DPP: PKEX Commit-Reveal Request processing failed");
1196c1d255d3SCy Schubert 	goto out;
1197c1d255d3SCy Schubert }
1198c1d255d3SCy Schubert 
1199c1d255d3SCy Schubert 
dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex * pkex,const u8 * hdr,const u8 * buf,size_t buflen)1200c1d255d3SCy Schubert int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
1201c1d255d3SCy Schubert 				   const u8 *buf, size_t buflen)
1202c1d255d3SCy Schubert {
1203c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
1204c1d255d3SCy Schubert 	const u8 *wrapped_data, *b_key, *peer_v;
1205c1d255d3SCy Schubert 	u16 wrapped_data_len, b_key_len, peer_v_len = 0;
1206c1d255d3SCy Schubert 	const u8 *addr[4];
1207c1d255d3SCy Schubert 	size_t len[4];
120832a95656SCy Schubert 	size_t num_elem;
1209c1d255d3SCy Schubert 	u8 octet;
1210c1d255d3SCy Schubert 	u8 *unwrapped = NULL;
1211c1d255d3SCy Schubert 	size_t unwrapped_len = 0;
1212c1d255d3SCy Schubert 	int ret = -1;
1213c1d255d3SCy Schubert 	u8 v[DPP_MAX_HASH_LEN];
1214c1d255d3SCy Schubert 	size_t Lx_len;
1215c1d255d3SCy Schubert 	u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
1216c1d255d3SCy Schubert 	struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
1217c1d255d3SCy Schubert 
1218c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1219c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
1220c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
1221c1d255d3SCy Schubert 			   "DPP: TESTING - stop at PKEX CR Response");
1222c1d255d3SCy Schubert 		pkex->failed = 1;
1223c1d255d3SCy Schubert 		goto fail;
1224c1d255d3SCy Schubert 	}
1225c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1226c1d255d3SCy Schubert 
1227c1d255d3SCy Schubert 	if (!pkex->exchange_done || pkex->failed ||
1228c1d255d3SCy Schubert 	    pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
1229c1d255d3SCy Schubert 		goto fail;
1230c1d255d3SCy Schubert 
1231c1d255d3SCy Schubert 	wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
1232c1d255d3SCy Schubert 				    &wrapped_data_len);
1233c1d255d3SCy Schubert 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
1234c1d255d3SCy Schubert 		dpp_pkex_fail(pkex,
1235c1d255d3SCy Schubert 			      "Missing or invalid required Wrapped Data attribute");
1236c1d255d3SCy Schubert 		goto fail;
1237c1d255d3SCy Schubert 	}
1238c1d255d3SCy Schubert 
1239c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1240c1d255d3SCy Schubert 		    wrapped_data, wrapped_data_len);
1241c1d255d3SCy Schubert 	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1242c1d255d3SCy Schubert 	unwrapped = os_malloc(unwrapped_len);
1243c1d255d3SCy Schubert 	if (!unwrapped)
1244c1d255d3SCy Schubert 		goto fail;
1245c1d255d3SCy Schubert 
1246c1d255d3SCy Schubert 	addr[0] = hdr;
1247c1d255d3SCy Schubert 	len[0] = DPP_HDR_LEN;
1248c1d255d3SCy Schubert 	octet = 1;
1249c1d255d3SCy Schubert 	addr[1] = &octet;
1250c1d255d3SCy Schubert 	len[1] = sizeof(octet);
1251c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1252c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1253c1d255d3SCy Schubert 
1254c1d255d3SCy Schubert 	if (aes_siv_decrypt(pkex->z, curve->hash_len,
1255c1d255d3SCy Schubert 			    wrapped_data, wrapped_data_len,
1256c1d255d3SCy Schubert 			    2, addr, len, unwrapped) < 0) {
1257c1d255d3SCy Schubert 		dpp_pkex_fail(pkex,
1258c1d255d3SCy Schubert 			      "AES-SIV decryption failed - possible PKEX code mismatch");
1259c1d255d3SCy Schubert 		pkex->t++;
1260c1d255d3SCy Schubert 		goto fail;
1261c1d255d3SCy Schubert 	}
1262c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1263c1d255d3SCy Schubert 		    unwrapped, unwrapped_len);
1264c1d255d3SCy Schubert 
1265c1d255d3SCy Schubert 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1266c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
1267c1d255d3SCy Schubert 		goto fail;
1268c1d255d3SCy Schubert 	}
1269c1d255d3SCy Schubert 
1270c1d255d3SCy Schubert 	b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
1271c1d255d3SCy Schubert 			     &b_key_len);
1272c1d255d3SCy Schubert 	if (!b_key || b_key_len != 2 * curve->prime_len) {
1273c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
1274c1d255d3SCy Schubert 		goto fail;
1275c1d255d3SCy Schubert 	}
1276c1d255d3SCy Schubert 	pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
1277c1d255d3SCy Schubert 							b_key_len);
1278c1d255d3SCy Schubert 	if (!pkex->peer_bootstrap_key) {
1279c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
1280c1d255d3SCy Schubert 		goto fail;
1281c1d255d3SCy Schubert 	}
1282c1d255d3SCy Schubert 	dpp_debug_print_key("DPP: Peer bootstrap public key",
1283c1d255d3SCy Schubert 			    pkex->peer_bootstrap_key);
1284c1d255d3SCy Schubert 
1285c1d255d3SCy Schubert 	/* ECDH: L' = x * B' */
1286c1d255d3SCy Schubert 	if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
1287c1d255d3SCy Schubert 		goto fail;
1288c1d255d3SCy Schubert 
1289c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
1290c1d255d3SCy Schubert 			Lx, Lx_len);
1291c1d255d3SCy Schubert 
129232a95656SCy Schubert 	/* v' = HMAC(L.x, [MAC-Responder |] B'.x | X.x | Y'.x) */
12934b72b91aSCy Schubert 	B_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
12944b72b91aSCy Schubert 	X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
12954b72b91aSCy Schubert 	Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
1296c1d255d3SCy Schubert 	if (!B_pub || !X_pub || !Y_pub)
1297c1d255d3SCy Schubert 		goto fail;
129832a95656SCy Schubert 	num_elem = 0;
129932a95656SCy Schubert 	if (!pkex->v2) {
130032a95656SCy Schubert 		addr[num_elem] = pkex->peer_mac;
130132a95656SCy Schubert 		len[num_elem] = ETH_ALEN;
130232a95656SCy Schubert 		num_elem++;
130332a95656SCy Schubert 	}
130432a95656SCy Schubert 	addr[num_elem] = wpabuf_head(B_pub);
130532a95656SCy Schubert 	len[num_elem] = wpabuf_len(B_pub) / 2;
130632a95656SCy Schubert 	num_elem++;
130732a95656SCy Schubert 	addr[num_elem] = wpabuf_head(X_pub);
130832a95656SCy Schubert 	len[num_elem] = wpabuf_len(X_pub) / 2;
130932a95656SCy Schubert 	num_elem++;
131032a95656SCy Schubert 	addr[num_elem] = wpabuf_head(Y_pub);
131132a95656SCy Schubert 	len[num_elem] = wpabuf_len(Y_pub) / 2;
131232a95656SCy Schubert 	num_elem++;
131332a95656SCy Schubert 	if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v)
131432a95656SCy Schubert 	    < 0)
1315c1d255d3SCy Schubert 		goto fail;
1316c1d255d3SCy Schubert 
1317c1d255d3SCy Schubert 	peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
1318c1d255d3SCy Schubert 			      &peer_v_len);
1319c1d255d3SCy Schubert 	if (!peer_v || peer_v_len != curve->hash_len ||
1320c1d255d3SCy Schubert 	    os_memcmp(peer_v, v, curve->hash_len) != 0) {
1321c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
1322c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
1323c1d255d3SCy Schubert 			    v, curve->hash_len);
1324c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
1325c1d255d3SCy Schubert 		pkex->t++;
1326c1d255d3SCy Schubert 		goto fail;
1327c1d255d3SCy Schubert 	}
1328c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
1329c1d255d3SCy Schubert 
1330c1d255d3SCy Schubert 	ret = 0;
1331c1d255d3SCy Schubert out:
1332c1d255d3SCy Schubert 	wpabuf_free(B_pub);
1333c1d255d3SCy Schubert 	wpabuf_free(X_pub);
1334c1d255d3SCy Schubert 	wpabuf_free(Y_pub);
1335c1d255d3SCy Schubert 	os_free(unwrapped);
1336c1d255d3SCy Schubert 	return ret;
1337c1d255d3SCy Schubert fail:
1338c1d255d3SCy Schubert 	goto out;
1339c1d255d3SCy Schubert }
1340c1d255d3SCy Schubert 
1341c1d255d3SCy Schubert 
1342c1d255d3SCy Schubert struct dpp_bootstrap_info *
dpp_pkex_finish(struct dpp_global * dpp,struct dpp_pkex * pkex,const u8 * peer,unsigned int freq)1343c1d255d3SCy Schubert dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
1344c1d255d3SCy Schubert 		unsigned int freq)
1345c1d255d3SCy Schubert {
1346c1d255d3SCy Schubert 	struct dpp_bootstrap_info *bi;
1347c1d255d3SCy Schubert 
1348c1d255d3SCy Schubert 	bi = os_zalloc(sizeof(*bi));
1349c1d255d3SCy Schubert 	if (!bi)
1350c1d255d3SCy Schubert 		return NULL;
1351c1d255d3SCy Schubert 	bi->id = dpp_next_id(dpp);
1352c1d255d3SCy Schubert 	bi->type = DPP_BOOTSTRAP_PKEX;
1353*a90b9d01SCy Schubert 	if (peer)
1354c1d255d3SCy Schubert 		os_memcpy(bi->mac_addr, peer, ETH_ALEN);
1355*a90b9d01SCy Schubert 	if (freq) {
1356c1d255d3SCy Schubert 		bi->num_freq = 1;
1357c1d255d3SCy Schubert 		bi->freq[0] = freq;
1358*a90b9d01SCy Schubert 	}
1359c1d255d3SCy Schubert 	bi->curve = pkex->own_bi->curve;
1360c1d255d3SCy Schubert 	bi->pubkey = pkex->peer_bootstrap_key;
1361c1d255d3SCy Schubert 	pkex->peer_bootstrap_key = NULL;
1362c1d255d3SCy Schubert 	if (dpp_bootstrap_key_hash(bi) < 0) {
1363c1d255d3SCy Schubert 		dpp_bootstrap_info_free(bi);
1364c1d255d3SCy Schubert 		return NULL;
1365c1d255d3SCy Schubert 	}
1366*a90b9d01SCy Schubert 	os_memcpy(pkex->own_bi->peer_pubkey_hash, bi->pubkey_hash,
1367*a90b9d01SCy Schubert 		  SHA256_MAC_LEN);
1368c1d255d3SCy Schubert 	dpp_pkex_free(pkex);
1369c1d255d3SCy Schubert 	dl_list_add(&dpp->bootstrap, &bi->list);
1370c1d255d3SCy Schubert 	return bi;
1371c1d255d3SCy Schubert }
1372c1d255d3SCy Schubert 
1373c1d255d3SCy Schubert 
dpp_pkex_free(struct dpp_pkex * pkex)1374c1d255d3SCy Schubert void dpp_pkex_free(struct dpp_pkex *pkex)
1375c1d255d3SCy Schubert {
1376c1d255d3SCy Schubert 	if (!pkex)
1377c1d255d3SCy Schubert 		return;
1378c1d255d3SCy Schubert 
1379c1d255d3SCy Schubert 	os_free(pkex->identifier);
1380c1d255d3SCy Schubert 	os_free(pkex->code);
13814b72b91aSCy Schubert 	crypto_ec_key_deinit(pkex->x);
13824b72b91aSCy Schubert 	crypto_ec_key_deinit(pkex->y);
13834b72b91aSCy Schubert 	crypto_ec_key_deinit(pkex->peer_bootstrap_key);
1384c1d255d3SCy Schubert 	wpabuf_free(pkex->exchange_req);
1385c1d255d3SCy Schubert 	wpabuf_free(pkex->exchange_resp);
1386*a90b9d01SCy Schubert 	wpabuf_free(pkex->enc_key);
1387c1d255d3SCy Schubert 	os_free(pkex);
1388c1d255d3SCy Schubert }
1389