xref: /freebsd/contrib/wpa/src/common/dpp_pkex.c (revision 32a95656)
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;
334b72b91aSCy Schubert 	const struct crypto_ec_point *X;
344b72b91aSCy Schubert 	struct crypto_ec_point *Qi = NULL, *M = NULL;
354b72b91aSCy Schubert 	u8 *Mx, *My;
36c1d255d3SCy Schubert 	struct wpabuf *msg = NULL;
37c1d255d3SCy Schubert 	size_t attr_len;
38c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
39c1d255d3SCy Schubert 
4032a95656SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Build PKEX %sExchange Request",
4132a95656SCy Schubert 		   v2 ? "" : "Version 1 ");
42c1d255d3SCy Schubert 
4332a95656SCy Schubert 	/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
4432a95656SCy Schubert 	Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : pkex->own_mac, pkex->code,
454b72b91aSCy Schubert 				pkex->identifier, &ec);
46c1d255d3SCy Schubert 	if (!Qi)
47c1d255d3SCy Schubert 		goto fail;
48c1d255d3SCy Schubert 
49c1d255d3SCy Schubert 	/* Generate a random ephemeral keypair x/X */
50c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
51c1d255d3SCy Schubert 	if (dpp_pkex_ephemeral_key_override_len) {
52c1d255d3SCy Schubert 		const struct dpp_curve_params *tmp_curve;
53c1d255d3SCy Schubert 
54c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
55c1d255d3SCy Schubert 			   "DPP: TESTING - override ephemeral key x/X");
56c1d255d3SCy Schubert 		pkex->x = dpp_set_keypair(&tmp_curve,
57c1d255d3SCy Schubert 					  dpp_pkex_ephemeral_key_override,
58c1d255d3SCy Schubert 					  dpp_pkex_ephemeral_key_override_len);
59c1d255d3SCy Schubert 	} else {
60c1d255d3SCy Schubert 		pkex->x = dpp_gen_keypair(curve);
61c1d255d3SCy Schubert 	}
62c1d255d3SCy Schubert #else /* CONFIG_TESTING_OPTIONS */
63c1d255d3SCy Schubert 	pkex->x = dpp_gen_keypair(curve);
64c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
65c1d255d3SCy Schubert 	if (!pkex->x)
66c1d255d3SCy Schubert 		goto fail;
67c1d255d3SCy Schubert 
68c1d255d3SCy Schubert 	/* M = X + Qi */
694b72b91aSCy Schubert 	X = crypto_ec_key_get_public_key(pkex->x);
704b72b91aSCy Schubert 	M = crypto_ec_point_init(ec);
714b72b91aSCy Schubert 	if (!X || !M)
72c1d255d3SCy Schubert 		goto fail;
734b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, X, "DPP: X");
744b72b91aSCy Schubert 
754b72b91aSCy Schubert 	if (crypto_ec_point_add(ec, X, Qi, M))
76c1d255d3SCy Schubert 		goto fail;
774b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, M, "DPP: M");
78c1d255d3SCy Schubert 
79c1d255d3SCy Schubert 	/* Initiator -> Responder: group, [identifier,] M */
80c1d255d3SCy Schubert 	attr_len = 4 + 2;
8132a95656SCy Schubert #ifdef CONFIG_DPP2
8232a95656SCy Schubert 	if (v2)
8332a95656SCy Schubert 		attr_len += 4 + 1;
8432a95656SCy Schubert #endif /* CONFIG_DPP2 */
85c1d255d3SCy Schubert 	if (pkex->identifier)
86c1d255d3SCy Schubert 		attr_len += 4 + os_strlen(pkex->identifier);
87c1d255d3SCy Schubert 	attr_len += 4 + 2 * curve->prime_len;
8832a95656SCy Schubert 	msg = dpp_alloc_msg(v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
8932a95656SCy Schubert 			    DPP_PA_PKEX_V1_EXCHANGE_REQ, attr_len);
90c1d255d3SCy Schubert 	if (!msg)
91c1d255d3SCy Schubert 		goto fail;
92c1d255d3SCy Schubert 
9332a95656SCy Schubert #ifdef CONFIG_DPP2
9432a95656SCy Schubert 	if (v2) {
9532a95656SCy Schubert 		/* Protocol Version */
9632a95656SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
9732a95656SCy Schubert 		wpabuf_put_le16(msg, 1);
9832a95656SCy Schubert 		wpabuf_put_u8(msg, DPP_VERSION);
9932a95656SCy Schubert 	}
10032a95656SCy Schubert #endif /* CONFIG_DPP2 */
10132a95656SCy Schubert 
102c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
103c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
104c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
105c1d255d3SCy Schubert 		goto skip_finite_cyclic_group;
106c1d255d3SCy Schubert 	}
107c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
108c1d255d3SCy Schubert 
109c1d255d3SCy Schubert 	/* Finite Cyclic Group attribute */
110c1d255d3SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
111c1d255d3SCy Schubert 	wpabuf_put_le16(msg, 2);
112c1d255d3SCy Schubert 	wpabuf_put_le16(msg, curve->ike_group);
113c1d255d3SCy Schubert 
114c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
115c1d255d3SCy Schubert skip_finite_cyclic_group:
116c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
117c1d255d3SCy Schubert 
118c1d255d3SCy Schubert 	/* Code Identifier attribute */
119c1d255d3SCy Schubert 	if (pkex->identifier) {
120c1d255d3SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
121c1d255d3SCy Schubert 		wpabuf_put_le16(msg, os_strlen(pkex->identifier));
122c1d255d3SCy Schubert 		wpabuf_put_str(msg, pkex->identifier);
123c1d255d3SCy Schubert 	}
124c1d255d3SCy Schubert 
125c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
126c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
127c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
128c1d255d3SCy Schubert 		goto out;
129c1d255d3SCy Schubert 	}
130c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
131c1d255d3SCy Schubert 
132c1d255d3SCy Schubert 	/* M in Encrypted Key attribute */
133c1d255d3SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
134c1d255d3SCy Schubert 	wpabuf_put_le16(msg, 2 * curve->prime_len);
135c1d255d3SCy Schubert 
136c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
137c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
138c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
139c1d255d3SCy Schubert 		if (dpp_test_gen_invalid_key(msg, curve) < 0)
140c1d255d3SCy Schubert 			goto fail;
141c1d255d3SCy Schubert 		goto out;
142c1d255d3SCy Schubert 	}
143c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
144c1d255d3SCy Schubert 
1454b72b91aSCy Schubert 	Mx = wpabuf_put(msg, curve->prime_len);
1464b72b91aSCy Schubert 	My = wpabuf_put(msg, curve->prime_len);
1474b72b91aSCy Schubert 	if (crypto_ec_point_to_bin(ec, M, Mx, My))
148c1d255d3SCy Schubert 		goto fail;
149c1d255d3SCy Schubert 
1504b72b91aSCy Schubert 	os_memcpy(pkex->Mx, Mx, curve->prime_len);
1514b72b91aSCy Schubert 
152c1d255d3SCy Schubert out:
1534b72b91aSCy Schubert 	crypto_ec_point_deinit(M, 1);
1544b72b91aSCy Schubert 	crypto_ec_point_deinit(Qi, 1);
1554b72b91aSCy Schubert 	crypto_ec_deinit(ec);
156c1d255d3SCy Schubert 	return msg;
157c1d255d3SCy Schubert fail:
158c1d255d3SCy Schubert 	wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
159c1d255d3SCy Schubert 	wpabuf_free(msg);
160c1d255d3SCy Schubert 	msg = NULL;
161c1d255d3SCy Schubert 	goto out;
162c1d255d3SCy Schubert }
163c1d255d3SCy Schubert 
164c1d255d3SCy Schubert 
dpp_pkex_fail(struct dpp_pkex * pkex,const char * txt)165c1d255d3SCy Schubert static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
166c1d255d3SCy Schubert {
167c1d255d3SCy Schubert 	wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
168c1d255d3SCy Schubert }
169c1d255d3SCy Schubert 
170c1d255d3SCy Schubert 
dpp_pkex_init(void * msg_ctx,struct dpp_bootstrap_info * bi,const u8 * own_mac,const char * identifier,const char * code,bool v2)171c1d255d3SCy Schubert struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
172c1d255d3SCy Schubert 				const u8 *own_mac,
17332a95656SCy Schubert 				const char *identifier, const char *code,
17432a95656SCy Schubert 				bool v2)
175c1d255d3SCy Schubert {
176c1d255d3SCy Schubert 	struct dpp_pkex *pkex;
177c1d255d3SCy Schubert 
178c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
179c1d255d3SCy Schubert 	if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
180c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
181c1d255d3SCy Schubert 			   MAC2STR(dpp_pkex_own_mac_override));
182c1d255d3SCy Schubert 		own_mac = dpp_pkex_own_mac_override;
183c1d255d3SCy Schubert 	}
184c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
185c1d255d3SCy Schubert 
186c1d255d3SCy Schubert 	pkex = os_zalloc(sizeof(*pkex));
187c1d255d3SCy Schubert 	if (!pkex)
188c1d255d3SCy Schubert 		return NULL;
189c1d255d3SCy Schubert 	pkex->msg_ctx = msg_ctx;
190c1d255d3SCy Schubert 	pkex->initiator = 1;
19132a95656SCy Schubert 	pkex->v2 = v2;
192c1d255d3SCy Schubert 	pkex->own_bi = bi;
193c1d255d3SCy Schubert 	os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
194c1d255d3SCy Schubert 	if (identifier) {
195c1d255d3SCy Schubert 		pkex->identifier = os_strdup(identifier);
196c1d255d3SCy Schubert 		if (!pkex->identifier)
197c1d255d3SCy Schubert 			goto fail;
198c1d255d3SCy Schubert 	}
199c1d255d3SCy Schubert 	pkex->code = os_strdup(code);
200c1d255d3SCy Schubert 	if (!pkex->code)
201c1d255d3SCy Schubert 		goto fail;
20232a95656SCy Schubert 	pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2);
203c1d255d3SCy Schubert 	if (!pkex->exchange_req)
204c1d255d3SCy Schubert 		goto fail;
205c1d255d3SCy Schubert 	return pkex;
206c1d255d3SCy Schubert fail:
207c1d255d3SCy Schubert 	dpp_pkex_free(pkex);
208c1d255d3SCy Schubert 	return NULL;
209c1d255d3SCy Schubert }
210c1d255d3SCy Schubert 
211c1d255d3SCy Schubert 
212c1d255d3SCy Schubert static struct wpabuf *
dpp_pkex_build_exchange_resp(struct dpp_pkex * pkex,enum dpp_status_error status,const u8 * Nx,const u8 * Ny)213c1d255d3SCy Schubert dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
214c1d255d3SCy Schubert 			     enum dpp_status_error status,
2154b72b91aSCy Schubert 			     const u8 *Nx, const u8 *Ny)
216c1d255d3SCy Schubert {
217c1d255d3SCy Schubert 	struct wpabuf *msg = NULL;
218c1d255d3SCy Schubert 	size_t attr_len;
219c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
220c1d255d3SCy Schubert 
22132a95656SCy Schubert 	/* Initiator -> Responder: DPP Status, [Protocol Version,] [identifier,]
22232a95656SCy Schubert 	 * N */
223c1d255d3SCy Schubert 	attr_len = 4 + 1;
22432a95656SCy Schubert #ifdef CONFIG_DPP2
22532a95656SCy Schubert 	if (pkex->v2)
22632a95656SCy Schubert 		attr_len += 4 + 1;
22732a95656SCy Schubert #endif /* CONFIG_DPP2 */
228c1d255d3SCy Schubert 	if (pkex->identifier)
229c1d255d3SCy Schubert 		attr_len += 4 + os_strlen(pkex->identifier);
230c1d255d3SCy Schubert 	attr_len += 4 + 2 * curve->prime_len;
231c1d255d3SCy Schubert 	msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
232c1d255d3SCy Schubert 	if (!msg)
233c1d255d3SCy Schubert 		goto fail;
234c1d255d3SCy Schubert 
235c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
236c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
237c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
238c1d255d3SCy Schubert 		goto skip_status;
239c1d255d3SCy Schubert 	}
240c1d255d3SCy Schubert 
241c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
242c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
243c1d255d3SCy Schubert 		status = 255;
244c1d255d3SCy Schubert 	}
245c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
246c1d255d3SCy Schubert 
247c1d255d3SCy Schubert 	/* DPP Status */
248c1d255d3SCy Schubert 	dpp_build_attr_status(msg, status);
249c1d255d3SCy Schubert 
250c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
251c1d255d3SCy Schubert skip_status:
252c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
253c1d255d3SCy Schubert 
25432a95656SCy Schubert #ifdef CONFIG_DPP2
25532a95656SCy Schubert 	if (pkex->v2) {
25632a95656SCy Schubert 		/* Protocol Version */
25732a95656SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
25832a95656SCy Schubert 		wpabuf_put_le16(msg, 1);
25932a95656SCy Schubert 		wpabuf_put_u8(msg, DPP_VERSION);
26032a95656SCy Schubert 	}
26132a95656SCy Schubert #endif /* CONFIG_DPP2 */
26232a95656SCy Schubert 
263c1d255d3SCy Schubert 	/* Code Identifier attribute */
264c1d255d3SCy Schubert 	if (pkex->identifier) {
265c1d255d3SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
266c1d255d3SCy Schubert 		wpabuf_put_le16(msg, os_strlen(pkex->identifier));
267c1d255d3SCy Schubert 		wpabuf_put_str(msg, pkex->identifier);
268c1d255d3SCy Schubert 	}
269c1d255d3SCy Schubert 
270c1d255d3SCy Schubert 	if (status != DPP_STATUS_OK)
271c1d255d3SCy Schubert 		goto skip_encrypted_key;
272c1d255d3SCy Schubert 
273c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
274c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
275c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
276c1d255d3SCy Schubert 		goto skip_encrypted_key;
277c1d255d3SCy Schubert 	}
278c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
279c1d255d3SCy Schubert 
280c1d255d3SCy Schubert 	/* N in Encrypted Key attribute */
281c1d255d3SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
282c1d255d3SCy Schubert 	wpabuf_put_le16(msg, 2 * curve->prime_len);
283c1d255d3SCy Schubert 
284c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
285c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
286c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
287c1d255d3SCy Schubert 		if (dpp_test_gen_invalid_key(msg, curve) < 0)
288c1d255d3SCy Schubert 			goto fail;
289c1d255d3SCy Schubert 		goto skip_encrypted_key;
290c1d255d3SCy Schubert 	}
291c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
292c1d255d3SCy Schubert 
2934b72b91aSCy Schubert 	wpabuf_put_data(msg, Nx, curve->prime_len);
2944b72b91aSCy Schubert 	wpabuf_put_data(msg, Ny, curve->prime_len);
2954b72b91aSCy Schubert 	os_memcpy(pkex->Nx, Nx, curve->prime_len);
296c1d255d3SCy Schubert 
297c1d255d3SCy Schubert skip_encrypted_key:
298c1d255d3SCy Schubert 	if (status == DPP_STATUS_BAD_GROUP) {
299c1d255d3SCy Schubert 		/* Finite Cyclic Group attribute */
300c1d255d3SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
301c1d255d3SCy Schubert 		wpabuf_put_le16(msg, 2);
302c1d255d3SCy Schubert 		wpabuf_put_le16(msg, curve->ike_group);
303c1d255d3SCy Schubert 	}
304c1d255d3SCy Schubert 
305c1d255d3SCy Schubert 	return msg;
306c1d255d3SCy Schubert fail:
307c1d255d3SCy Schubert 	wpabuf_free(msg);
308c1d255d3SCy Schubert 	return NULL;
309c1d255d3SCy Schubert }
310c1d255d3SCy Schubert 
311c1d255d3SCy Schubert 
dpp_pkex_identifier_match(const u8 * attr_id,u16 attr_id_len,const char * identifier)312c1d255d3SCy Schubert static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
313c1d255d3SCy Schubert 				     const char *identifier)
314c1d255d3SCy Schubert {
315c1d255d3SCy Schubert 	if (!attr_id && identifier) {
316c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
317c1d255d3SCy Schubert 			   "DPP: No PKEX code identifier received, but expected one");
318c1d255d3SCy Schubert 		return 0;
319c1d255d3SCy Schubert 	}
320c1d255d3SCy Schubert 
321c1d255d3SCy Schubert 	if (attr_id && !identifier) {
322c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
323c1d255d3SCy Schubert 			   "DPP: PKEX code identifier received, but not expecting one");
324c1d255d3SCy Schubert 		return 0;
325c1d255d3SCy Schubert 	}
326c1d255d3SCy Schubert 
327c1d255d3SCy Schubert 	if (attr_id && identifier &&
328c1d255d3SCy Schubert 	    (os_strlen(identifier) != attr_id_len ||
329c1d255d3SCy Schubert 	     os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
330c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
331c1d255d3SCy Schubert 		return 0;
332c1d255d3SCy Schubert 	}
333c1d255d3SCy Schubert 
334c1d255d3SCy Schubert 	return 1;
335c1d255d3SCy Schubert }
336c1d255d3SCy Schubert 
337c1d255d3SCy 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,const u8 * buf,size_t len,bool v2)338c1d255d3SCy Schubert struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
339c1d255d3SCy Schubert 					   struct dpp_bootstrap_info *bi,
340c1d255d3SCy Schubert 					   const u8 *own_mac,
341c1d255d3SCy Schubert 					   const u8 *peer_mac,
342c1d255d3SCy Schubert 					   const char *identifier,
343c1d255d3SCy Schubert 					   const char *code,
34432a95656SCy Schubert 					   const u8 *buf, size_t len, bool v2)
345c1d255d3SCy Schubert {
346c1d255d3SCy Schubert 	const u8 *attr_group, *attr_id, *attr_key;
347c1d255d3SCy Schubert 	u16 attr_group_len, attr_id_len, attr_key_len;
348c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = bi->curve;
349c1d255d3SCy Schubert 	u16 ike_group;
350c1d255d3SCy Schubert 	struct dpp_pkex *pkex = NULL;
3514b72b91aSCy Schubert 	struct crypto_ec_point *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL,
3524b72b91aSCy Schubert 		*N = NULL;
3534b72b91aSCy Schubert 	struct crypto_ec *ec = NULL;
3544b72b91aSCy Schubert 	const struct crypto_ec_point *Y;
3554b72b91aSCy Schubert 	u8 *x_coord = NULL, *y_coord = NULL;
356c1d255d3SCy Schubert 	u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
357c1d255d3SCy Schubert 	size_t Kx_len;
358c1d255d3SCy Schubert 	int res;
35932a95656SCy Schubert 	u8 peer_version = 0;
360c1d255d3SCy Schubert 
361c1d255d3SCy Schubert 	if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
362c1d255d3SCy Schubert 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
363c1d255d3SCy Schubert 			"PKEX counter t limit reached - ignore message");
364c1d255d3SCy Schubert 		return NULL;
365c1d255d3SCy Schubert 	}
366c1d255d3SCy Schubert 
36732a95656SCy Schubert #ifdef CONFIG_DPP2
36832a95656SCy Schubert 	if (v2) {
36932a95656SCy Schubert 		const u8 *version;
37032a95656SCy Schubert 		u16 version_len;
37132a95656SCy Schubert 
37232a95656SCy Schubert 		version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
37332a95656SCy Schubert 				       &version_len);
37432a95656SCy Schubert 		if (!version || version_len < 1 || version[0] == 0) {
37532a95656SCy Schubert 			wpa_msg(msg_ctx, MSG_INFO,
37632a95656SCy Schubert 				"Missing or invalid Protocol Version attribute");
37732a95656SCy Schubert 			return NULL;
37832a95656SCy Schubert 		}
37932a95656SCy Schubert 		peer_version = version[0];
38032a95656SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
38132a95656SCy Schubert 			   peer_version);
38232a95656SCy Schubert 	}
38332a95656SCy Schubert #endif /* CONFIG_DPP2 */
38432a95656SCy Schubert 
385c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
386c1d255d3SCy Schubert 	if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
387c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
388c1d255d3SCy Schubert 			   MAC2STR(dpp_pkex_peer_mac_override));
389c1d255d3SCy Schubert 		peer_mac = dpp_pkex_peer_mac_override;
390c1d255d3SCy Schubert 	}
391c1d255d3SCy Schubert 	if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
392c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
393c1d255d3SCy Schubert 			   MAC2STR(dpp_pkex_own_mac_override));
394c1d255d3SCy Schubert 		own_mac = dpp_pkex_own_mac_override;
395c1d255d3SCy Schubert 	}
396c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
397c1d255d3SCy Schubert 
398c1d255d3SCy Schubert 	attr_id_len = 0;
399c1d255d3SCy Schubert 	attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
400c1d255d3SCy Schubert 			       &attr_id_len);
401c1d255d3SCy Schubert 	if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
402c1d255d3SCy Schubert 		return NULL;
403c1d255d3SCy Schubert 
404c1d255d3SCy Schubert 	attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
405c1d255d3SCy Schubert 				  &attr_group_len);
406c1d255d3SCy Schubert 	if (!attr_group || attr_group_len != 2) {
407c1d255d3SCy Schubert 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
408c1d255d3SCy Schubert 			"Missing or invalid Finite Cyclic Group attribute");
409c1d255d3SCy Schubert 		return NULL;
410c1d255d3SCy Schubert 	}
411c1d255d3SCy Schubert 	ike_group = WPA_GET_LE16(attr_group);
412c1d255d3SCy Schubert 	if (ike_group != curve->ike_group) {
413c1d255d3SCy Schubert 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
414c1d255d3SCy Schubert 			"Mismatching PKEX curve: peer=%u own=%u",
415c1d255d3SCy Schubert 			ike_group, curve->ike_group);
416c1d255d3SCy Schubert 		pkex = os_zalloc(sizeof(*pkex));
417c1d255d3SCy Schubert 		if (!pkex)
418c1d255d3SCy Schubert 			goto fail;
41932a95656SCy Schubert 		pkex->v2 = v2;
42032a95656SCy Schubert 		pkex->peer_version = peer_version;
421c1d255d3SCy Schubert 		pkex->own_bi = bi;
422c1d255d3SCy Schubert 		pkex->failed = 1;
423c1d255d3SCy Schubert 		pkex->exchange_resp = dpp_pkex_build_exchange_resp(
424c1d255d3SCy Schubert 			pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
425c1d255d3SCy Schubert 		if (!pkex->exchange_resp)
426c1d255d3SCy Schubert 			goto fail;
427c1d255d3SCy Schubert 		return pkex;
428c1d255d3SCy Schubert 	}
429c1d255d3SCy Schubert 
430c1d255d3SCy Schubert 	/* M in Encrypted Key attribute */
431c1d255d3SCy Schubert 	attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
432c1d255d3SCy Schubert 				&attr_key_len);
433c1d255d3SCy Schubert 	if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
434c1d255d3SCy Schubert 	    attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
435c1d255d3SCy Schubert 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
436c1d255d3SCy Schubert 			"Missing Encrypted Key attribute");
437c1d255d3SCy Schubert 		return NULL;
438c1d255d3SCy Schubert 	}
439c1d255d3SCy Schubert 
44032a95656SCy Schubert 	/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
44132a95656SCy Schubert 	Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, identifier,
44232a95656SCy Schubert 				&ec);
443c1d255d3SCy Schubert 	if (!Qi)
444c1d255d3SCy Schubert 		goto fail;
445c1d255d3SCy Schubert 
446c1d255d3SCy Schubert 	/* X' = M - Qi */
4474b72b91aSCy Schubert 	X = crypto_ec_point_init(ec);
4484b72b91aSCy Schubert 	M = crypto_ec_point_from_bin(ec, attr_key);
4494b72b91aSCy Schubert 	if (!X || !M ||
4504b72b91aSCy Schubert 	    crypto_ec_point_is_at_infinity(ec, M) ||
4514b72b91aSCy Schubert 	    !crypto_ec_point_is_on_curve(ec, M) ||
4524b72b91aSCy Schubert 	    crypto_ec_point_invert(ec, Qi) ||
4534b72b91aSCy Schubert 	    crypto_ec_point_add(ec, M, Qi, X) ||
4544b72b91aSCy Schubert 	    crypto_ec_point_is_at_infinity(ec, X) ||
4554b72b91aSCy Schubert 	    !crypto_ec_point_is_on_curve(ec, X)) {
456c1d255d3SCy Schubert 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
457c1d255d3SCy Schubert 			"Invalid Encrypted Key value");
458c1d255d3SCy Schubert 		bi->pkex_t++;
459c1d255d3SCy Schubert 		goto fail;
460c1d255d3SCy Schubert 	}
4614b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, M, "DPP: M");
4624b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, X, "DPP: X'");
463c1d255d3SCy Schubert 
464c1d255d3SCy Schubert 	pkex = os_zalloc(sizeof(*pkex));
465c1d255d3SCy Schubert 	if (!pkex)
466c1d255d3SCy Schubert 		goto fail;
46732a95656SCy Schubert 	pkex->v2 = v2;
46832a95656SCy Schubert 	pkex->peer_version = peer_version;
469c1d255d3SCy Schubert 	pkex->t = bi->pkex_t;
470c1d255d3SCy Schubert 	pkex->msg_ctx = msg_ctx;
471c1d255d3SCy Schubert 	pkex->own_bi = bi;
472c1d255d3SCy Schubert 	os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
473c1d255d3SCy Schubert 	os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
474c1d255d3SCy Schubert 	if (identifier) {
475c1d255d3SCy Schubert 		pkex->identifier = os_strdup(identifier);
476c1d255d3SCy Schubert 		if (!pkex->identifier)
477c1d255d3SCy Schubert 			goto fail;
478c1d255d3SCy Schubert 	}
479c1d255d3SCy Schubert 	pkex->code = os_strdup(code);
480c1d255d3SCy Schubert 	if (!pkex->code)
481c1d255d3SCy Schubert 		goto fail;
482c1d255d3SCy Schubert 
483c1d255d3SCy Schubert 	os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
484c1d255d3SCy Schubert 
4854b72b91aSCy Schubert 	x_coord = os_malloc(curve->prime_len);
4864b72b91aSCy Schubert 	y_coord = os_malloc(curve->prime_len);
4874b72b91aSCy Schubert 	if (!x_coord || !y_coord ||
4884b72b91aSCy Schubert 	    crypto_ec_point_to_bin(ec, X, x_coord, y_coord))
489c1d255d3SCy Schubert 		goto fail;
4904b72b91aSCy Schubert 
4914b72b91aSCy Schubert 	pkex->x = crypto_ec_key_set_pub(curve->ike_group, x_coord,
4924b72b91aSCy Schubert 					y_coord, crypto_ec_prime_len(ec));
4934b72b91aSCy Schubert 	if (!pkex->x)
494c1d255d3SCy Schubert 		goto fail;
495c1d255d3SCy Schubert 
49632a95656SCy Schubert 	/* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
49732a95656SCy Schubert 	Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, identifier,
49832a95656SCy Schubert 				NULL);
499c1d255d3SCy Schubert 	if (!Qr)
500c1d255d3SCy Schubert 		goto fail;
501c1d255d3SCy Schubert 
502c1d255d3SCy Schubert 	/* Generate a random ephemeral keypair y/Y */
503c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
504c1d255d3SCy Schubert 	if (dpp_pkex_ephemeral_key_override_len) {
505c1d255d3SCy Schubert 		const struct dpp_curve_params *tmp_curve;
506c1d255d3SCy Schubert 
507c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
508c1d255d3SCy Schubert 			   "DPP: TESTING - override ephemeral key y/Y");
509c1d255d3SCy Schubert 		pkex->y = dpp_set_keypair(&tmp_curve,
510c1d255d3SCy Schubert 					  dpp_pkex_ephemeral_key_override,
511c1d255d3SCy Schubert 					  dpp_pkex_ephemeral_key_override_len);
512c1d255d3SCy Schubert 	} else {
513c1d255d3SCy Schubert 		pkex->y = dpp_gen_keypair(curve);
514c1d255d3SCy Schubert 	}
515c1d255d3SCy Schubert #else /* CONFIG_TESTING_OPTIONS */
516c1d255d3SCy Schubert 	pkex->y = dpp_gen_keypair(curve);
517c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
518c1d255d3SCy Schubert 	if (!pkex->y)
519c1d255d3SCy Schubert 		goto fail;
520c1d255d3SCy Schubert 
521c1d255d3SCy Schubert 	/* N = Y + Qr */
5224b72b91aSCy Schubert 	Y = crypto_ec_key_get_public_key(pkex->y);
5234b72b91aSCy Schubert 	if (!Y)
524c1d255d3SCy Schubert 		goto fail;
5254b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, Y, "DPP: Y");
5264b72b91aSCy Schubert 
5274b72b91aSCy Schubert 	N = crypto_ec_point_init(ec);
5284b72b91aSCy Schubert 	if (!N ||
5294b72b91aSCy Schubert 	    crypto_ec_point_add(ec, Y, Qr, N) ||
5304b72b91aSCy Schubert 	    crypto_ec_point_to_bin(ec, N, x_coord, y_coord))
531c1d255d3SCy Schubert 		goto fail;
5324b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, N, "DPP: N");
533c1d255d3SCy Schubert 
534c1d255d3SCy Schubert 	pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
5354b72b91aSCy Schubert 							   x_coord, y_coord);
536c1d255d3SCy Schubert 	if (!pkex->exchange_resp)
537c1d255d3SCy Schubert 		goto fail;
538c1d255d3SCy Schubert 
539c1d255d3SCy Schubert 	/* K = y * X' */
540c1d255d3SCy Schubert 	if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
541c1d255d3SCy Schubert 		goto fail;
542c1d255d3SCy Schubert 
543c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
544c1d255d3SCy Schubert 			Kx, Kx_len);
545c1d255d3SCy Schubert 
54632a95656SCy Schubert 	/* z = HKDF(<>, info | M.x | N.x | code, K.x) */
54732a95656SCy Schubert 	res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->peer_mac,
54832a95656SCy Schubert 				pkex->v2 ? NULL : pkex->own_mac,
54932a95656SCy Schubert 				pkex->peer_version, DPP_VERSION,
550c1d255d3SCy Schubert 				pkex->Mx, curve->prime_len,
551c1d255d3SCy Schubert 				pkex->Nx, curve->prime_len, pkex->code,
552c1d255d3SCy Schubert 				Kx, Kx_len, pkex->z, curve->hash_len);
553c1d255d3SCy Schubert 	os_memset(Kx, 0, Kx_len);
554c1d255d3SCy Schubert 	if (res < 0)
555c1d255d3SCy Schubert 		goto fail;
556c1d255d3SCy Schubert 
557c1d255d3SCy Schubert 	pkex->exchange_done = 1;
558c1d255d3SCy Schubert 
559c1d255d3SCy Schubert out:
5604b72b91aSCy Schubert 	os_free(x_coord);
5614b72b91aSCy Schubert 	os_free(y_coord);
5624b72b91aSCy Schubert 	crypto_ec_point_deinit(Qi, 1);
5634b72b91aSCy Schubert 	crypto_ec_point_deinit(Qr, 1);
5644b72b91aSCy Schubert 	crypto_ec_point_deinit(M, 1);
5654b72b91aSCy Schubert 	crypto_ec_point_deinit(N, 1);
5664b72b91aSCy Schubert 	crypto_ec_point_deinit(X, 1);
5674b72b91aSCy Schubert 	crypto_ec_deinit(ec);
568c1d255d3SCy Schubert 	return pkex;
569c1d255d3SCy Schubert fail:
570c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
571c1d255d3SCy Schubert 	dpp_pkex_free(pkex);
572c1d255d3SCy Schubert 	pkex = NULL;
573c1d255d3SCy Schubert 	goto out;
574c1d255d3SCy Schubert }
575c1d255d3SCy Schubert 
576c1d255d3SCy Schubert 
577c1d255d3SCy Schubert static struct wpabuf *
dpp_pkex_build_commit_reveal_req(struct dpp_pkex * pkex,const struct wpabuf * A_pub,const u8 * u)578c1d255d3SCy Schubert dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
579c1d255d3SCy Schubert 				 const struct wpabuf *A_pub, const u8 *u)
580c1d255d3SCy Schubert {
581c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
582c1d255d3SCy Schubert 	struct wpabuf *msg = NULL;
583c1d255d3SCy Schubert 	size_t clear_len, attr_len;
584c1d255d3SCy Schubert 	struct wpabuf *clear = NULL;
585c1d255d3SCy Schubert 	u8 *wrapped;
586c1d255d3SCy Schubert 	u8 octet;
587c1d255d3SCy Schubert 	const u8 *addr[2];
588c1d255d3SCy Schubert 	size_t len[2];
589c1d255d3SCy Schubert 
590c1d255d3SCy Schubert 	/* {A, u, [bootstrapping info]}z */
591c1d255d3SCy Schubert 	clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
592c1d255d3SCy Schubert 	clear = wpabuf_alloc(clear_len);
593c1d255d3SCy Schubert 	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
594c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
595c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
596c1d255d3SCy Schubert 		attr_len += 5;
597c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
598c1d255d3SCy Schubert 	msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
599c1d255d3SCy Schubert 	if (!clear || !msg)
600c1d255d3SCy Schubert 		goto fail;
601c1d255d3SCy Schubert 
602c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
603c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
604c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
605c1d255d3SCy Schubert 		goto skip_bootstrap_key;
606c1d255d3SCy Schubert 	}
607c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
608c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
609c1d255d3SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
610c1d255d3SCy Schubert 		wpabuf_put_le16(clear, 2 * curve->prime_len);
611c1d255d3SCy Schubert 		if (dpp_test_gen_invalid_key(clear, curve) < 0)
612c1d255d3SCy Schubert 			goto fail;
613c1d255d3SCy Schubert 		goto skip_bootstrap_key;
614c1d255d3SCy Schubert 	}
615c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
616c1d255d3SCy Schubert 
617c1d255d3SCy Schubert 	/* A in Bootstrap Key attribute */
618c1d255d3SCy Schubert 	wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
619c1d255d3SCy Schubert 	wpabuf_put_le16(clear, wpabuf_len(A_pub));
620c1d255d3SCy Schubert 	wpabuf_put_buf(clear, A_pub);
621c1d255d3SCy Schubert 
622c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
623c1d255d3SCy Schubert skip_bootstrap_key:
624c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
625c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
626c1d255d3SCy Schubert 		goto skip_i_auth_tag;
627c1d255d3SCy Schubert 	}
628c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
629c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
630c1d255d3SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
631c1d255d3SCy Schubert 		wpabuf_put_le16(clear, curve->hash_len);
632c1d255d3SCy Schubert 		wpabuf_put_data(clear, u, curve->hash_len - 1);
633c1d255d3SCy Schubert 		wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
634c1d255d3SCy Schubert 		goto skip_i_auth_tag;
635c1d255d3SCy Schubert 	}
636c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
637c1d255d3SCy Schubert 
638c1d255d3SCy Schubert 	/* u in I-Auth tag attribute */
639c1d255d3SCy Schubert 	wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
640c1d255d3SCy Schubert 	wpabuf_put_le16(clear, curve->hash_len);
641c1d255d3SCy Schubert 	wpabuf_put_data(clear, u, curve->hash_len);
642c1d255d3SCy Schubert 
643c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
644c1d255d3SCy Schubert skip_i_auth_tag:
645c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
646c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
647c1d255d3SCy Schubert 		goto skip_wrapped_data;
648c1d255d3SCy Schubert 	}
649c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
650c1d255d3SCy Schubert 
651c1d255d3SCy Schubert 	addr[0] = wpabuf_head_u8(msg) + 2;
652c1d255d3SCy Schubert 	len[0] = DPP_HDR_LEN;
653c1d255d3SCy Schubert 	octet = 0;
654c1d255d3SCy Schubert 	addr[1] = &octet;
655c1d255d3SCy Schubert 	len[1] = sizeof(octet);
656c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
657c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
658c1d255d3SCy Schubert 
659c1d255d3SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
660c1d255d3SCy Schubert 	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
661c1d255d3SCy Schubert 	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
662c1d255d3SCy Schubert 
663c1d255d3SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
664c1d255d3SCy Schubert 	if (aes_siv_encrypt(pkex->z, curve->hash_len,
665c1d255d3SCy Schubert 			    wpabuf_head(clear), wpabuf_len(clear),
666c1d255d3SCy Schubert 			    2, addr, len, wrapped) < 0)
667c1d255d3SCy Schubert 		goto fail;
668c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
669c1d255d3SCy Schubert 		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
670c1d255d3SCy Schubert 
671c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
672c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
673c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
674c1d255d3SCy Schubert 		dpp_build_attr_status(msg, DPP_STATUS_OK);
675c1d255d3SCy Schubert 	}
676c1d255d3SCy Schubert skip_wrapped_data:
677c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
678c1d255d3SCy Schubert 
679c1d255d3SCy Schubert out:
680c1d255d3SCy Schubert 	wpabuf_free(clear);
681c1d255d3SCy Schubert 	return msg;
682c1d255d3SCy Schubert 
683c1d255d3SCy Schubert fail:
684c1d255d3SCy Schubert 	wpabuf_free(msg);
685c1d255d3SCy Schubert 	msg = NULL;
686c1d255d3SCy Schubert 	goto out;
687c1d255d3SCy Schubert }
688c1d255d3SCy Schubert 
689c1d255d3SCy Schubert 
dpp_pkex_rx_exchange_resp(struct dpp_pkex * pkex,const u8 * peer_mac,const u8 * buf,size_t buflen)690c1d255d3SCy Schubert struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
691c1d255d3SCy Schubert 					  const u8 *peer_mac,
692c1d255d3SCy Schubert 					  const u8 *buf, size_t buflen)
693c1d255d3SCy Schubert {
694c1d255d3SCy Schubert 	const u8 *attr_status, *attr_id, *attr_key, *attr_group;
695c1d255d3SCy Schubert 	u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
6964b72b91aSCy Schubert 	struct crypto_ec *ec = NULL;
697c1d255d3SCy Schubert 	struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
698c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
6994b72b91aSCy Schubert 	struct crypto_ec_point *Qr = NULL, *Y = NULL, *N = NULL;
7004b72b91aSCy Schubert 	u8 *x_coord = NULL, *y_coord = NULL;
701c1d255d3SCy Schubert 	size_t Jx_len, Kx_len;
702c1d255d3SCy Schubert 	u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
703c1d255d3SCy Schubert 	const u8 *addr[4];
704c1d255d3SCy Schubert 	size_t len[4];
70532a95656SCy Schubert 	size_t num_elem;
706c1d255d3SCy Schubert 	u8 u[DPP_MAX_HASH_LEN];
707c1d255d3SCy Schubert 	int res;
708c1d255d3SCy Schubert 
709c1d255d3SCy Schubert 	if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
710c1d255d3SCy Schubert 		return NULL;
711c1d255d3SCy Schubert 
712c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
713c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
714c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
715c1d255d3SCy Schubert 			   "DPP: TESTING - stop at PKEX Exchange Response");
716c1d255d3SCy Schubert 		pkex->failed = 1;
717c1d255d3SCy Schubert 		return NULL;
718c1d255d3SCy Schubert 	}
719c1d255d3SCy Schubert 
720c1d255d3SCy Schubert 	if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
721c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
722c1d255d3SCy Schubert 			   MAC2STR(dpp_pkex_peer_mac_override));
723c1d255d3SCy Schubert 		peer_mac = dpp_pkex_peer_mac_override;
724c1d255d3SCy Schubert 	}
725c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
726c1d255d3SCy Schubert 
72732a95656SCy Schubert #ifdef CONFIG_DPP2
72832a95656SCy Schubert 	if (pkex->v2) {
72932a95656SCy Schubert 		const u8 *version;
73032a95656SCy Schubert 		u16 version_len;
73132a95656SCy Schubert 
73232a95656SCy Schubert 		version = dpp_get_attr(buf, buflen, DPP_ATTR_PROTOCOL_VERSION,
73332a95656SCy Schubert 				       &version_len);
73432a95656SCy Schubert 		if (!version || version_len < 1 || version[0] == 0) {
73532a95656SCy Schubert 		dpp_pkex_fail(pkex,
73632a95656SCy Schubert 			      "Missing or invalid Protocol Version attribute");
73732a95656SCy Schubert 			return NULL;
73832a95656SCy Schubert 		}
73932a95656SCy Schubert 		pkex->peer_version = version[0];
74032a95656SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
74132a95656SCy Schubert 			   pkex->peer_version);
74232a95656SCy Schubert 	}
74332a95656SCy Schubert #endif /* CONFIG_DPP2 */
74432a95656SCy Schubert 
745c1d255d3SCy Schubert 	os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
746c1d255d3SCy Schubert 
747c1d255d3SCy Schubert 	attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
748c1d255d3SCy Schubert 				   &attr_status_len);
749c1d255d3SCy Schubert 	if (!attr_status || attr_status_len != 1) {
750c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "No DPP Status attribute");
751c1d255d3SCy Schubert 		return NULL;
752c1d255d3SCy Schubert 	}
753c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
754c1d255d3SCy Schubert 
755c1d255d3SCy Schubert 	if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
756c1d255d3SCy Schubert 		attr_group = dpp_get_attr(buf, buflen,
757c1d255d3SCy Schubert 					  DPP_ATTR_FINITE_CYCLIC_GROUP,
758c1d255d3SCy Schubert 					  &attr_group_len);
759c1d255d3SCy Schubert 		if (attr_group && attr_group_len == 2) {
760c1d255d3SCy Schubert 			wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
761c1d255d3SCy Schubert 				"Peer indicated mismatching PKEX group - proposed %u",
762c1d255d3SCy Schubert 				WPA_GET_LE16(attr_group));
763c1d255d3SCy Schubert 			return NULL;
764c1d255d3SCy Schubert 		}
765c1d255d3SCy Schubert 	}
766c1d255d3SCy Schubert 
767c1d255d3SCy Schubert 	if (attr_status[0] != DPP_STATUS_OK) {
768c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
769c1d255d3SCy Schubert 		return NULL;
770c1d255d3SCy Schubert 	}
771c1d255d3SCy Schubert 
772c1d255d3SCy Schubert 	attr_id_len = 0;
773c1d255d3SCy Schubert 	attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
774c1d255d3SCy Schubert 			       &attr_id_len);
775c1d255d3SCy Schubert 	if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
776c1d255d3SCy Schubert 				       pkex->identifier)) {
777c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
778c1d255d3SCy Schubert 		return NULL;
779c1d255d3SCy Schubert 	}
780c1d255d3SCy Schubert 
781c1d255d3SCy Schubert 	/* N in Encrypted Key attribute */
782c1d255d3SCy Schubert 	attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
783c1d255d3SCy Schubert 				&attr_key_len);
784c1d255d3SCy Schubert 	if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
785c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
786c1d255d3SCy Schubert 		return NULL;
787c1d255d3SCy Schubert 	}
788c1d255d3SCy Schubert 
78932a95656SCy Schubert 	/* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
79032a95656SCy Schubert 	Qr = dpp_pkex_derive_Qr(curve, pkex->v2 ? NULL : pkex->peer_mac,
79132a95656SCy Schubert 				pkex->code, pkex->identifier, &ec);
792c1d255d3SCy Schubert 	if (!Qr)
793c1d255d3SCy Schubert 		goto fail;
794c1d255d3SCy Schubert 
795c1d255d3SCy Schubert 	/* Y' = N - Qr */
7964b72b91aSCy Schubert 	Y = crypto_ec_point_init(ec);
7974b72b91aSCy Schubert 	N = crypto_ec_point_from_bin(ec, attr_key);
7984b72b91aSCy Schubert 	if (!Y || !N ||
7994b72b91aSCy Schubert 	    crypto_ec_point_is_at_infinity(ec, N) ||
8004b72b91aSCy Schubert 	    !crypto_ec_point_is_on_curve(ec, N) ||
8014b72b91aSCy Schubert 	    crypto_ec_point_invert(ec, Qr) ||
8024b72b91aSCy Schubert 	    crypto_ec_point_add(ec, N, Qr, Y) ||
8034b72b91aSCy Schubert 	    crypto_ec_point_is_at_infinity(ec, Y) ||
8044b72b91aSCy Schubert 	    !crypto_ec_point_is_on_curve(ec, Y)) {
805c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
806c1d255d3SCy Schubert 		pkex->t++;
807c1d255d3SCy Schubert 		goto fail;
808c1d255d3SCy Schubert 	}
8094b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, N, "DPP: N");
8104b72b91aSCy Schubert 	crypto_ec_point_debug_print(ec, Y, "DPP: Y'");
811c1d255d3SCy Schubert 
812c1d255d3SCy Schubert 	pkex->exchange_done = 1;
813c1d255d3SCy Schubert 
814c1d255d3SCy Schubert 	/* ECDH: J = a * Y' */
8154b72b91aSCy Schubert 	x_coord = os_malloc(curve->prime_len);
8164b72b91aSCy Schubert 	y_coord = os_malloc(curve->prime_len);
8174b72b91aSCy Schubert 	if (!x_coord || !y_coord ||
8184b72b91aSCy Schubert 	    crypto_ec_point_to_bin(ec, Y, x_coord, y_coord))
819c1d255d3SCy Schubert 		goto fail;
8204b72b91aSCy Schubert 	pkex->y = crypto_ec_key_set_pub(curve->ike_group, x_coord, y_coord,
8214b72b91aSCy Schubert 					curve->prime_len);
8224b72b91aSCy Schubert 	if (!pkex->y)
823c1d255d3SCy Schubert 		goto fail;
824c1d255d3SCy Schubert 	if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
825c1d255d3SCy Schubert 		goto fail;
826c1d255d3SCy Schubert 
827c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
828c1d255d3SCy Schubert 			Jx, Jx_len);
829c1d255d3SCy Schubert 
83032a95656SCy Schubert 	/* u = HMAC(J.x, [MAC-Initiator |] A.x | Y'.x | X.x) */
8314b72b91aSCy Schubert 	A_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
8324b72b91aSCy Schubert 	Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
8334b72b91aSCy Schubert 	X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
834c1d255d3SCy Schubert 	if (!A_pub || !Y_pub || !X_pub)
835c1d255d3SCy Schubert 		goto fail;
83632a95656SCy Schubert 	num_elem = 0;
83732a95656SCy Schubert 	if (!pkex->v2) {
83832a95656SCy Schubert 		addr[num_elem] = pkex->own_mac;
83932a95656SCy Schubert 		len[num_elem] = ETH_ALEN;
84032a95656SCy Schubert 		num_elem++;
84132a95656SCy Schubert 	}
84232a95656SCy Schubert 	addr[num_elem] = wpabuf_head(A_pub);
84332a95656SCy Schubert 	len[num_elem] = wpabuf_len(A_pub) / 2;
84432a95656SCy Schubert 	num_elem++;
84532a95656SCy Schubert 	addr[num_elem] = wpabuf_head(Y_pub);
84632a95656SCy Schubert 	len[num_elem] = wpabuf_len(Y_pub) / 2;
84732a95656SCy Schubert 	num_elem++;
84832a95656SCy Schubert 	addr[num_elem] = wpabuf_head(X_pub);
84932a95656SCy Schubert 	len[num_elem] = wpabuf_len(X_pub) / 2;
85032a95656SCy Schubert 	num_elem++;
85132a95656SCy Schubert 	if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u)
85232a95656SCy Schubert 	    < 0)
853c1d255d3SCy Schubert 		goto fail;
854c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
855c1d255d3SCy Schubert 
856c1d255d3SCy Schubert 	/* K = x * Y' */
857c1d255d3SCy Schubert 	if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
858c1d255d3SCy Schubert 		goto fail;
859c1d255d3SCy Schubert 
860c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
861c1d255d3SCy Schubert 			Kx, Kx_len);
862c1d255d3SCy Schubert 
86332a95656SCy Schubert 	/* z = HKDF(<>, info | M.x | N.x | code, K.x) */
86432a95656SCy Schubert 	res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->own_mac,
86532a95656SCy Schubert 				pkex->v2 ? NULL : pkex->peer_mac,
86632a95656SCy Schubert 				DPP_VERSION, pkex->peer_version,
867c1d255d3SCy Schubert 				pkex->Mx, curve->prime_len,
868c1d255d3SCy Schubert 				attr_key /* N.x */, attr_key_len / 2,
869c1d255d3SCy Schubert 				pkex->code, Kx, Kx_len,
870c1d255d3SCy Schubert 				pkex->z, curve->hash_len);
871c1d255d3SCy Schubert 	os_memset(Kx, 0, Kx_len);
872c1d255d3SCy Schubert 	if (res < 0)
873c1d255d3SCy Schubert 		goto fail;
874c1d255d3SCy Schubert 
875c1d255d3SCy Schubert 	msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
876c1d255d3SCy Schubert 	if (!msg)
877c1d255d3SCy Schubert 		goto fail;
878c1d255d3SCy Schubert 
879c1d255d3SCy Schubert out:
880c1d255d3SCy Schubert 	wpabuf_free(A_pub);
881c1d255d3SCy Schubert 	wpabuf_free(X_pub);
882c1d255d3SCy Schubert 	wpabuf_free(Y_pub);
8834b72b91aSCy Schubert 	os_free(x_coord);
8844b72b91aSCy Schubert 	os_free(y_coord);
8854b72b91aSCy Schubert 	crypto_ec_point_deinit(Qr, 1);
8864b72b91aSCy Schubert 	crypto_ec_point_deinit(Y, 1);
8874b72b91aSCy Schubert 	crypto_ec_point_deinit(N, 1);
8884b72b91aSCy Schubert 	crypto_ec_deinit(ec);
889c1d255d3SCy Schubert 	return msg;
890c1d255d3SCy Schubert fail:
891c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
892c1d255d3SCy Schubert 	goto out;
893c1d255d3SCy Schubert }
894c1d255d3SCy Schubert 
895c1d255d3SCy Schubert 
896c1d255d3SCy Schubert static struct wpabuf *
dpp_pkex_build_commit_reveal_resp(struct dpp_pkex * pkex,const struct wpabuf * B_pub,const u8 * v)897c1d255d3SCy Schubert dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
898c1d255d3SCy Schubert 				  const struct wpabuf *B_pub, const u8 *v)
899c1d255d3SCy Schubert {
900c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
901c1d255d3SCy Schubert 	struct wpabuf *msg = NULL;
902c1d255d3SCy Schubert 	const u8 *addr[2];
903c1d255d3SCy Schubert 	size_t len[2];
904c1d255d3SCy Schubert 	u8 octet;
905c1d255d3SCy Schubert 	u8 *wrapped;
906c1d255d3SCy Schubert 	struct wpabuf *clear = NULL;
907c1d255d3SCy Schubert 	size_t clear_len, attr_len;
908c1d255d3SCy Schubert 
909c1d255d3SCy Schubert 	/* {B, v [bootstrapping info]}z */
910c1d255d3SCy Schubert 	clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
911c1d255d3SCy Schubert 	clear = wpabuf_alloc(clear_len);
912c1d255d3SCy Schubert 	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
913c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
914c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
915c1d255d3SCy Schubert 		attr_len += 5;
916c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
917c1d255d3SCy Schubert 	msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
918c1d255d3SCy Schubert 	if (!clear || !msg)
919c1d255d3SCy Schubert 		goto fail;
920c1d255d3SCy Schubert 
921c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
922c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
923c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
924c1d255d3SCy Schubert 		goto skip_bootstrap_key;
925c1d255d3SCy Schubert 	}
926c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
927c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
928c1d255d3SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
929c1d255d3SCy Schubert 		wpabuf_put_le16(clear, 2 * curve->prime_len);
930c1d255d3SCy Schubert 		if (dpp_test_gen_invalid_key(clear, curve) < 0)
931c1d255d3SCy Schubert 			goto fail;
932c1d255d3SCy Schubert 		goto skip_bootstrap_key;
933c1d255d3SCy Schubert 	}
934c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
935c1d255d3SCy Schubert 
936c1d255d3SCy Schubert 	/* B in Bootstrap Key attribute */
937c1d255d3SCy Schubert 	wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
938c1d255d3SCy Schubert 	wpabuf_put_le16(clear, wpabuf_len(B_pub));
939c1d255d3SCy Schubert 	wpabuf_put_buf(clear, B_pub);
940c1d255d3SCy Schubert 
941c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
942c1d255d3SCy Schubert skip_bootstrap_key:
943c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
944c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
945c1d255d3SCy Schubert 		goto skip_r_auth_tag;
946c1d255d3SCy Schubert 	}
947c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
948c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
949c1d255d3SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
950c1d255d3SCy Schubert 		wpabuf_put_le16(clear, curve->hash_len);
951c1d255d3SCy Schubert 		wpabuf_put_data(clear, v, curve->hash_len - 1);
952c1d255d3SCy Schubert 		wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
953c1d255d3SCy Schubert 		goto skip_r_auth_tag;
954c1d255d3SCy Schubert 	}
955c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
956c1d255d3SCy Schubert 
957c1d255d3SCy Schubert 	/* v in R-Auth tag attribute */
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);
961c1d255d3SCy Schubert 
962c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
963c1d255d3SCy Schubert skip_r_auth_tag:
964c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
965c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
966c1d255d3SCy Schubert 		goto skip_wrapped_data;
967c1d255d3SCy Schubert 	}
968c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
969c1d255d3SCy Schubert 
970c1d255d3SCy Schubert 	addr[0] = wpabuf_head_u8(msg) + 2;
971c1d255d3SCy Schubert 	len[0] = DPP_HDR_LEN;
972c1d255d3SCy Schubert 	octet = 1;
973c1d255d3SCy Schubert 	addr[1] = &octet;
974c1d255d3SCy Schubert 	len[1] = sizeof(octet);
975c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
976c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
977c1d255d3SCy Schubert 
978c1d255d3SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
979c1d255d3SCy Schubert 	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
980c1d255d3SCy Schubert 	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
981c1d255d3SCy Schubert 
982c1d255d3SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
983c1d255d3SCy Schubert 	if (aes_siv_encrypt(pkex->z, curve->hash_len,
984c1d255d3SCy Schubert 			    wpabuf_head(clear), wpabuf_len(clear),
985c1d255d3SCy Schubert 			    2, addr, len, wrapped) < 0)
986c1d255d3SCy Schubert 		goto fail;
987c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
988c1d255d3SCy Schubert 		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
989c1d255d3SCy Schubert 
990c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
991c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
992c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
993c1d255d3SCy Schubert 		dpp_build_attr_status(msg, DPP_STATUS_OK);
994c1d255d3SCy Schubert 	}
995c1d255d3SCy Schubert skip_wrapped_data:
996c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
997c1d255d3SCy Schubert 
998c1d255d3SCy Schubert out:
999c1d255d3SCy Schubert 	wpabuf_free(clear);
1000c1d255d3SCy Schubert 	return msg;
1001c1d255d3SCy Schubert 
1002c1d255d3SCy Schubert fail:
1003c1d255d3SCy Schubert 	wpabuf_free(msg);
1004c1d255d3SCy Schubert 	msg = NULL;
1005c1d255d3SCy Schubert 	goto out;
1006c1d255d3SCy Schubert }
1007c1d255d3SCy Schubert 
1008c1d255d3SCy Schubert 
dpp_pkex_rx_commit_reveal_req(struct dpp_pkex * pkex,const u8 * hdr,const u8 * buf,size_t buflen)1009c1d255d3SCy Schubert struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
1010c1d255d3SCy Schubert 					      const u8 *hdr,
1011c1d255d3SCy Schubert 					      const u8 *buf, size_t buflen)
1012c1d255d3SCy Schubert {
1013c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
1014c1d255d3SCy Schubert 	size_t Jx_len, Lx_len;
1015c1d255d3SCy Schubert 	u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
1016c1d255d3SCy Schubert 	u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
1017c1d255d3SCy Schubert 	const u8 *wrapped_data, *b_key, *peer_u;
1018c1d255d3SCy Schubert 	u16 wrapped_data_len, b_key_len, peer_u_len = 0;
1019c1d255d3SCy Schubert 	const u8 *addr[4];
1020c1d255d3SCy Schubert 	size_t len[4];
102132a95656SCy Schubert 	size_t num_elem;
1022c1d255d3SCy Schubert 	u8 octet;
1023c1d255d3SCy Schubert 	u8 *unwrapped = NULL;
1024c1d255d3SCy Schubert 	size_t unwrapped_len = 0;
1025c1d255d3SCy Schubert 	struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
1026c1d255d3SCy Schubert 	struct wpabuf *B_pub = NULL;
1027c1d255d3SCy Schubert 	u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
1028c1d255d3SCy Schubert 
1029c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1030c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
1031c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
1032c1d255d3SCy Schubert 			   "DPP: TESTING - stop at PKEX CR Request");
1033c1d255d3SCy Schubert 		pkex->failed = 1;
1034c1d255d3SCy Schubert 		return NULL;
1035c1d255d3SCy Schubert 	}
1036c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1037c1d255d3SCy Schubert 
1038c1d255d3SCy Schubert 	if (!pkex->exchange_done || pkex->failed ||
1039c1d255d3SCy Schubert 	    pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
1040c1d255d3SCy Schubert 		goto fail;
1041c1d255d3SCy Schubert 
1042c1d255d3SCy Schubert 	wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
1043c1d255d3SCy Schubert 				    &wrapped_data_len);
1044c1d255d3SCy Schubert 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
1045c1d255d3SCy Schubert 		dpp_pkex_fail(pkex,
1046c1d255d3SCy Schubert 			      "Missing or invalid required Wrapped Data attribute");
1047c1d255d3SCy Schubert 		goto fail;
1048c1d255d3SCy Schubert 	}
1049c1d255d3SCy Schubert 
1050c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1051c1d255d3SCy Schubert 		    wrapped_data, wrapped_data_len);
1052c1d255d3SCy Schubert 	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1053c1d255d3SCy Schubert 	unwrapped = os_malloc(unwrapped_len);
1054c1d255d3SCy Schubert 	if (!unwrapped)
1055c1d255d3SCy Schubert 		goto fail;
1056c1d255d3SCy Schubert 
1057c1d255d3SCy Schubert 	addr[0] = hdr;
1058c1d255d3SCy Schubert 	len[0] = DPP_HDR_LEN;
1059c1d255d3SCy Schubert 	octet = 0;
1060c1d255d3SCy Schubert 	addr[1] = &octet;
1061c1d255d3SCy Schubert 	len[1] = sizeof(octet);
1062c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1063c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1064c1d255d3SCy Schubert 
1065c1d255d3SCy Schubert 	if (aes_siv_decrypt(pkex->z, curve->hash_len,
1066c1d255d3SCy Schubert 			    wrapped_data, wrapped_data_len,
1067c1d255d3SCy Schubert 			    2, addr, len, unwrapped) < 0) {
1068c1d255d3SCy Schubert 		dpp_pkex_fail(pkex,
1069c1d255d3SCy Schubert 			      "AES-SIV decryption failed - possible PKEX code mismatch");
1070c1d255d3SCy Schubert 		pkex->failed = 1;
1071c1d255d3SCy Schubert 		pkex->t++;
1072c1d255d3SCy Schubert 		goto fail;
1073c1d255d3SCy Schubert 	}
1074c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1075c1d255d3SCy Schubert 		    unwrapped, unwrapped_len);
1076c1d255d3SCy Schubert 
1077c1d255d3SCy Schubert 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1078c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
1079c1d255d3SCy Schubert 		goto fail;
1080c1d255d3SCy Schubert 	}
1081c1d255d3SCy Schubert 
1082c1d255d3SCy Schubert 	b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
1083c1d255d3SCy Schubert 			     &b_key_len);
1084c1d255d3SCy Schubert 	if (!b_key || b_key_len != 2 * curve->prime_len) {
1085c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
1086c1d255d3SCy Schubert 		goto fail;
1087c1d255d3SCy Schubert 	}
1088c1d255d3SCy Schubert 	pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
1089c1d255d3SCy Schubert 							b_key_len);
1090c1d255d3SCy Schubert 	if (!pkex->peer_bootstrap_key) {
1091c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
1092c1d255d3SCy Schubert 		goto fail;
1093c1d255d3SCy Schubert 	}
1094c1d255d3SCy Schubert 	dpp_debug_print_key("DPP: Peer bootstrap public key",
1095c1d255d3SCy Schubert 			    pkex->peer_bootstrap_key);
1096c1d255d3SCy Schubert 
1097c1d255d3SCy Schubert 	/* ECDH: J' = y * A' */
1098c1d255d3SCy Schubert 	if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
1099c1d255d3SCy Schubert 		goto fail;
1100c1d255d3SCy Schubert 
1101c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
1102c1d255d3SCy Schubert 			Jx, Jx_len);
1103c1d255d3SCy Schubert 
110432a95656SCy Schubert 	/* u' = HMAC(J'.x, [MAC-Initiator |] A'.x | Y.x | X'.x) */
11054b72b91aSCy Schubert 	A_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
11064b72b91aSCy Schubert 	Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
11074b72b91aSCy Schubert 	X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
1108c1d255d3SCy Schubert 	if (!A_pub || !Y_pub || !X_pub)
1109c1d255d3SCy Schubert 		goto fail;
111032a95656SCy Schubert 	num_elem = 0;
111132a95656SCy Schubert 	if (!pkex->v2) {
111232a95656SCy Schubert 		addr[num_elem] = pkex->peer_mac;
111332a95656SCy Schubert 		len[num_elem] = ETH_ALEN;
111432a95656SCy Schubert 		num_elem++;
111532a95656SCy Schubert 	}
111632a95656SCy Schubert 	addr[num_elem] = wpabuf_head(A_pub);
111732a95656SCy Schubert 	len[num_elem] = wpabuf_len(A_pub) / 2;
111832a95656SCy Schubert 	num_elem++;
111932a95656SCy Schubert 	addr[num_elem] = wpabuf_head(Y_pub);
112032a95656SCy Schubert 	len[num_elem] = wpabuf_len(Y_pub) / 2;
112132a95656SCy Schubert 	num_elem++;
112232a95656SCy Schubert 	addr[num_elem] = wpabuf_head(X_pub);
112332a95656SCy Schubert 	len[num_elem] = wpabuf_len(X_pub) / 2;
112432a95656SCy Schubert 	num_elem++;
112532a95656SCy Schubert 	if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u)
112632a95656SCy Schubert 	    < 0)
1127c1d255d3SCy Schubert 		goto fail;
1128c1d255d3SCy Schubert 
1129c1d255d3SCy Schubert 	peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
1130c1d255d3SCy Schubert 			      &peer_u_len);
1131c1d255d3SCy Schubert 	if (!peer_u || peer_u_len != curve->hash_len ||
1132c1d255d3SCy Schubert 	    os_memcmp(peer_u, u, curve->hash_len) != 0) {
1133c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
1134c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
1135c1d255d3SCy Schubert 			    u, curve->hash_len);
1136c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
1137c1d255d3SCy Schubert 		pkex->t++;
1138c1d255d3SCy Schubert 		goto fail;
1139c1d255d3SCy Schubert 	}
1140c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
1141c1d255d3SCy Schubert 
1142c1d255d3SCy Schubert 	/* ECDH: L = b * X' */
1143c1d255d3SCy Schubert 	if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
1144c1d255d3SCy Schubert 		goto fail;
1145c1d255d3SCy Schubert 
1146c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
1147c1d255d3SCy Schubert 			Lx, Lx_len);
1148c1d255d3SCy Schubert 
114932a95656SCy Schubert 	/* v = HMAC(L.x, [MAC-Responder |] B.x | X'.x | Y.x) */
11504b72b91aSCy Schubert 	B_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
1151c1d255d3SCy Schubert 	if (!B_pub)
1152c1d255d3SCy Schubert 		goto fail;
115332a95656SCy Schubert 	num_elem = 0;
115432a95656SCy Schubert 	if (!pkex->v2) {
115532a95656SCy Schubert 		addr[num_elem] = pkex->own_mac;
115632a95656SCy Schubert 		len[num_elem] = ETH_ALEN;
115732a95656SCy Schubert 		num_elem++;
115832a95656SCy Schubert 	}
115932a95656SCy Schubert 	addr[num_elem] = wpabuf_head(B_pub);
116032a95656SCy Schubert 	len[num_elem] = wpabuf_len(B_pub) / 2;
116132a95656SCy Schubert 	num_elem++;
116232a95656SCy Schubert 	addr[num_elem] = wpabuf_head(X_pub);
116332a95656SCy Schubert 	len[num_elem] = wpabuf_len(X_pub) / 2;
116432a95656SCy Schubert 	num_elem++;
116532a95656SCy Schubert 	addr[num_elem] = wpabuf_head(Y_pub);
116632a95656SCy Schubert 	len[num_elem] = wpabuf_len(Y_pub) / 2;
116732a95656SCy Schubert 	num_elem++;
116832a95656SCy Schubert 	if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v)
116932a95656SCy Schubert 	    < 0)
1170c1d255d3SCy Schubert 		goto fail;
1171c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
1172c1d255d3SCy Schubert 
1173c1d255d3SCy Schubert 	msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
1174c1d255d3SCy Schubert 	if (!msg)
1175c1d255d3SCy Schubert 		goto fail;
1176c1d255d3SCy Schubert 
1177c1d255d3SCy Schubert out:
1178c1d255d3SCy Schubert 	os_free(unwrapped);
1179c1d255d3SCy Schubert 	wpabuf_free(A_pub);
1180c1d255d3SCy Schubert 	wpabuf_free(B_pub);
1181c1d255d3SCy Schubert 	wpabuf_free(X_pub);
1182c1d255d3SCy Schubert 	wpabuf_free(Y_pub);
1183c1d255d3SCy Schubert 	return msg;
1184c1d255d3SCy Schubert fail:
1185c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG,
1186c1d255d3SCy Schubert 		   "DPP: PKEX Commit-Reveal Request processing failed");
1187c1d255d3SCy Schubert 	goto out;
1188c1d255d3SCy Schubert }
1189c1d255d3SCy Schubert 
1190c1d255d3SCy Schubert 
dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex * pkex,const u8 * hdr,const u8 * buf,size_t buflen)1191c1d255d3SCy Schubert int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
1192c1d255d3SCy Schubert 				   const u8 *buf, size_t buflen)
1193c1d255d3SCy Schubert {
1194c1d255d3SCy Schubert 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
1195c1d255d3SCy Schubert 	const u8 *wrapped_data, *b_key, *peer_v;
1196c1d255d3SCy Schubert 	u16 wrapped_data_len, b_key_len, peer_v_len = 0;
1197c1d255d3SCy Schubert 	const u8 *addr[4];
1198c1d255d3SCy Schubert 	size_t len[4];
119932a95656SCy Schubert 	size_t num_elem;
1200c1d255d3SCy Schubert 	u8 octet;
1201c1d255d3SCy Schubert 	u8 *unwrapped = NULL;
1202c1d255d3SCy Schubert 	size_t unwrapped_len = 0;
1203c1d255d3SCy Schubert 	int ret = -1;
1204c1d255d3SCy Schubert 	u8 v[DPP_MAX_HASH_LEN];
1205c1d255d3SCy Schubert 	size_t Lx_len;
1206c1d255d3SCy Schubert 	u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
1207c1d255d3SCy Schubert 	struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
1208c1d255d3SCy Schubert 
1209c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1210c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
1211c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
1212c1d255d3SCy Schubert 			   "DPP: TESTING - stop at PKEX CR Response");
1213c1d255d3SCy Schubert 		pkex->failed = 1;
1214c1d255d3SCy Schubert 		goto fail;
1215c1d255d3SCy Schubert 	}
1216c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1217c1d255d3SCy Schubert 
1218c1d255d3SCy Schubert 	if (!pkex->exchange_done || pkex->failed ||
1219c1d255d3SCy Schubert 	    pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
1220c1d255d3SCy Schubert 		goto fail;
1221c1d255d3SCy Schubert 
1222c1d255d3SCy Schubert 	wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
1223c1d255d3SCy Schubert 				    &wrapped_data_len);
1224c1d255d3SCy Schubert 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
1225c1d255d3SCy Schubert 		dpp_pkex_fail(pkex,
1226c1d255d3SCy Schubert 			      "Missing or invalid required Wrapped Data attribute");
1227c1d255d3SCy Schubert 		goto fail;
1228c1d255d3SCy Schubert 	}
1229c1d255d3SCy Schubert 
1230c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1231c1d255d3SCy Schubert 		    wrapped_data, wrapped_data_len);
1232c1d255d3SCy Schubert 	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1233c1d255d3SCy Schubert 	unwrapped = os_malloc(unwrapped_len);
1234c1d255d3SCy Schubert 	if (!unwrapped)
1235c1d255d3SCy Schubert 		goto fail;
1236c1d255d3SCy Schubert 
1237c1d255d3SCy Schubert 	addr[0] = hdr;
1238c1d255d3SCy Schubert 	len[0] = DPP_HDR_LEN;
1239c1d255d3SCy Schubert 	octet = 1;
1240c1d255d3SCy Schubert 	addr[1] = &octet;
1241c1d255d3SCy Schubert 	len[1] = sizeof(octet);
1242c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1243c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1244c1d255d3SCy Schubert 
1245c1d255d3SCy Schubert 	if (aes_siv_decrypt(pkex->z, curve->hash_len,
1246c1d255d3SCy Schubert 			    wrapped_data, wrapped_data_len,
1247c1d255d3SCy Schubert 			    2, addr, len, unwrapped) < 0) {
1248c1d255d3SCy Schubert 		dpp_pkex_fail(pkex,
1249c1d255d3SCy Schubert 			      "AES-SIV decryption failed - possible PKEX code mismatch");
1250c1d255d3SCy Schubert 		pkex->t++;
1251c1d255d3SCy Schubert 		goto fail;
1252c1d255d3SCy Schubert 	}
1253c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1254c1d255d3SCy Schubert 		    unwrapped, unwrapped_len);
1255c1d255d3SCy Schubert 
1256c1d255d3SCy Schubert 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1257c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
1258c1d255d3SCy Schubert 		goto fail;
1259c1d255d3SCy Schubert 	}
1260c1d255d3SCy Schubert 
1261c1d255d3SCy Schubert 	b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
1262c1d255d3SCy Schubert 			     &b_key_len);
1263c1d255d3SCy Schubert 	if (!b_key || b_key_len != 2 * curve->prime_len) {
1264c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
1265c1d255d3SCy Schubert 		goto fail;
1266c1d255d3SCy Schubert 	}
1267c1d255d3SCy Schubert 	pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
1268c1d255d3SCy Schubert 							b_key_len);
1269c1d255d3SCy Schubert 	if (!pkex->peer_bootstrap_key) {
1270c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
1271c1d255d3SCy Schubert 		goto fail;
1272c1d255d3SCy Schubert 	}
1273c1d255d3SCy Schubert 	dpp_debug_print_key("DPP: Peer bootstrap public key",
1274c1d255d3SCy Schubert 			    pkex->peer_bootstrap_key);
1275c1d255d3SCy Schubert 
1276c1d255d3SCy Schubert 	/* ECDH: L' = x * B' */
1277c1d255d3SCy Schubert 	if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
1278c1d255d3SCy Schubert 		goto fail;
1279c1d255d3SCy Schubert 
1280c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
1281c1d255d3SCy Schubert 			Lx, Lx_len);
1282c1d255d3SCy Schubert 
128332a95656SCy Schubert 	/* v' = HMAC(L.x, [MAC-Responder |] B'.x | X.x | Y'.x) */
12844b72b91aSCy Schubert 	B_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
12854b72b91aSCy Schubert 	X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
12864b72b91aSCy Schubert 	Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
1287c1d255d3SCy Schubert 	if (!B_pub || !X_pub || !Y_pub)
1288c1d255d3SCy Schubert 		goto fail;
128932a95656SCy Schubert 	num_elem = 0;
129032a95656SCy Schubert 	if (!pkex->v2) {
129132a95656SCy Schubert 		addr[num_elem] = pkex->peer_mac;
129232a95656SCy Schubert 		len[num_elem] = ETH_ALEN;
129332a95656SCy Schubert 		num_elem++;
129432a95656SCy Schubert 	}
129532a95656SCy Schubert 	addr[num_elem] = wpabuf_head(B_pub);
129632a95656SCy Schubert 	len[num_elem] = wpabuf_len(B_pub) / 2;
129732a95656SCy Schubert 	num_elem++;
129832a95656SCy Schubert 	addr[num_elem] = wpabuf_head(X_pub);
129932a95656SCy Schubert 	len[num_elem] = wpabuf_len(X_pub) / 2;
130032a95656SCy Schubert 	num_elem++;
130132a95656SCy Schubert 	addr[num_elem] = wpabuf_head(Y_pub);
130232a95656SCy Schubert 	len[num_elem] = wpabuf_len(Y_pub) / 2;
130332a95656SCy Schubert 	num_elem++;
130432a95656SCy Schubert 	if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v)
130532a95656SCy Schubert 	    < 0)
1306c1d255d3SCy Schubert 		goto fail;
1307c1d255d3SCy Schubert 
1308c1d255d3SCy Schubert 	peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
1309c1d255d3SCy Schubert 			      &peer_v_len);
1310c1d255d3SCy Schubert 	if (!peer_v || peer_v_len != curve->hash_len ||
1311c1d255d3SCy Schubert 	    os_memcmp(peer_v, v, curve->hash_len) != 0) {
1312c1d255d3SCy Schubert 		dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
1313c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
1314c1d255d3SCy Schubert 			    v, curve->hash_len);
1315c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
1316c1d255d3SCy Schubert 		pkex->t++;
1317c1d255d3SCy Schubert 		goto fail;
1318c1d255d3SCy Schubert 	}
1319c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
1320c1d255d3SCy Schubert 
1321c1d255d3SCy Schubert 	ret = 0;
1322c1d255d3SCy Schubert out:
1323c1d255d3SCy Schubert 	wpabuf_free(B_pub);
1324c1d255d3SCy Schubert 	wpabuf_free(X_pub);
1325c1d255d3SCy Schubert 	wpabuf_free(Y_pub);
1326c1d255d3SCy Schubert 	os_free(unwrapped);
1327c1d255d3SCy Schubert 	return ret;
1328c1d255d3SCy Schubert fail:
1329c1d255d3SCy Schubert 	goto out;
1330c1d255d3SCy Schubert }
1331c1d255d3SCy Schubert 
1332c1d255d3SCy Schubert 
1333c1d255d3SCy Schubert struct dpp_bootstrap_info *
dpp_pkex_finish(struct dpp_global * dpp,struct dpp_pkex * pkex,const u8 * peer,unsigned int freq)1334c1d255d3SCy Schubert dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
1335c1d255d3SCy Schubert 		unsigned int freq)
1336c1d255d3SCy Schubert {
1337c1d255d3SCy Schubert 	struct dpp_bootstrap_info *bi;
1338c1d255d3SCy Schubert 
1339c1d255d3SCy Schubert 	bi = os_zalloc(sizeof(*bi));
1340c1d255d3SCy Schubert 	if (!bi)
1341c1d255d3SCy Schubert 		return NULL;
1342c1d255d3SCy Schubert 	bi->id = dpp_next_id(dpp);
1343c1d255d3SCy Schubert 	bi->type = DPP_BOOTSTRAP_PKEX;
1344c1d255d3SCy Schubert 	os_memcpy(bi->mac_addr, peer, ETH_ALEN);
1345c1d255d3SCy Schubert 	bi->num_freq = 1;
1346c1d255d3SCy Schubert 	bi->freq[0] = freq;
1347c1d255d3SCy Schubert 	bi->curve = pkex->own_bi->curve;
1348c1d255d3SCy Schubert 	bi->pubkey = pkex->peer_bootstrap_key;
1349c1d255d3SCy Schubert 	pkex->peer_bootstrap_key = NULL;
1350c1d255d3SCy Schubert 	if (dpp_bootstrap_key_hash(bi) < 0) {
1351c1d255d3SCy Schubert 		dpp_bootstrap_info_free(bi);
1352c1d255d3SCy Schubert 		return NULL;
1353c1d255d3SCy Schubert 	}
1354c1d255d3SCy Schubert 	dpp_pkex_free(pkex);
1355c1d255d3SCy Schubert 	dl_list_add(&dpp->bootstrap, &bi->list);
1356c1d255d3SCy Schubert 	return bi;
1357c1d255d3SCy Schubert }
1358c1d255d3SCy Schubert 
1359c1d255d3SCy Schubert 
dpp_pkex_free(struct dpp_pkex * pkex)1360c1d255d3SCy Schubert void dpp_pkex_free(struct dpp_pkex *pkex)
1361c1d255d3SCy Schubert {
1362c1d255d3SCy Schubert 	if (!pkex)
1363c1d255d3SCy Schubert 		return;
1364c1d255d3SCy Schubert 
1365c1d255d3SCy Schubert 	os_free(pkex->identifier);
1366c1d255d3SCy Schubert 	os_free(pkex->code);
13674b72b91aSCy Schubert 	crypto_ec_key_deinit(pkex->x);
13684b72b91aSCy Schubert 	crypto_ec_key_deinit(pkex->y);
13694b72b91aSCy Schubert 	crypto_ec_key_deinit(pkex->peer_bootstrap_key);
1370c1d255d3SCy Schubert 	wpabuf_free(pkex->exchange_req);
1371c1d255d3SCy Schubert 	wpabuf_free(pkex->exchange_resp);
1372c1d255d3SCy Schubert 	os_free(pkex);
1373c1d255d3SCy Schubert }
1374