xref: /freebsd/contrib/wpa/src/common/dpp_pkex.c (revision 266f97b5)
1 /*
2  * DPP PKEX functionality
3  * Copyright (c) 2017, Qualcomm Atheros, Inc.
4  * Copyright (c) 2018-2020, The Linux Foundation
5  *
6  * This software may be distributed under the terms of the BSD license.
7  * See README for more details.
8  */
9 
10 #include "utils/includes.h"
11 
12 #include "utils/common.h"
13 #include "common/wpa_ctrl.h"
14 #include "crypto/aes.h"
15 #include "crypto/aes_siv.h"
16 #include "crypto/crypto.h"
17 #include "dpp.h"
18 #include "dpp_i.h"
19 
20 
21 #ifdef CONFIG_TESTING_OPTIONS
22 u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
23 u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
24 u8 dpp_pkex_ephemeral_key_override[600];
25 size_t dpp_pkex_ephemeral_key_override_len = 0;
26 #endif /* CONFIG_TESTING_OPTIONS */
27 
28 
29 static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
30 {
31 	struct crypto_ec *ec = NULL;
32 	const struct crypto_ec_point *X;
33 	struct crypto_ec_point *Qi = NULL, *M = NULL;
34 	u8 *Mx, *My;
35 	struct wpabuf *msg = NULL;
36 	size_t attr_len;
37 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
38 
39 	wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
40 
41 	/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
42 	Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
43 				pkex->identifier, &ec);
44 	if (!Qi)
45 		goto fail;
46 
47 	/* Generate a random ephemeral keypair x/X */
48 #ifdef CONFIG_TESTING_OPTIONS
49 	if (dpp_pkex_ephemeral_key_override_len) {
50 		const struct dpp_curve_params *tmp_curve;
51 
52 		wpa_printf(MSG_INFO,
53 			   "DPP: TESTING - override ephemeral key x/X");
54 		pkex->x = dpp_set_keypair(&tmp_curve,
55 					  dpp_pkex_ephemeral_key_override,
56 					  dpp_pkex_ephemeral_key_override_len);
57 	} else {
58 		pkex->x = dpp_gen_keypair(curve);
59 	}
60 #else /* CONFIG_TESTING_OPTIONS */
61 	pkex->x = dpp_gen_keypair(curve);
62 #endif /* CONFIG_TESTING_OPTIONS */
63 	if (!pkex->x)
64 		goto fail;
65 
66 	/* M = X + Qi */
67 	X = crypto_ec_key_get_public_key(pkex->x);
68 	M = crypto_ec_point_init(ec);
69 	if (!X || !M)
70 		goto fail;
71 	crypto_ec_point_debug_print(ec, X, "DPP: X");
72 
73 	if (crypto_ec_point_add(ec, X, Qi, M))
74 		goto fail;
75 	crypto_ec_point_debug_print(ec, M, "DPP: M");
76 
77 	/* Initiator -> Responder: group, [identifier,] M */
78 	attr_len = 4 + 2;
79 	if (pkex->identifier)
80 		attr_len += 4 + os_strlen(pkex->identifier);
81 	attr_len += 4 + 2 * curve->prime_len;
82 	msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
83 	if (!msg)
84 		goto fail;
85 
86 #ifdef CONFIG_TESTING_OPTIONS
87 	if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
88 		wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
89 		goto skip_finite_cyclic_group;
90 	}
91 #endif /* CONFIG_TESTING_OPTIONS */
92 
93 	/* Finite Cyclic Group attribute */
94 	wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
95 	wpabuf_put_le16(msg, 2);
96 	wpabuf_put_le16(msg, curve->ike_group);
97 
98 #ifdef CONFIG_TESTING_OPTIONS
99 skip_finite_cyclic_group:
100 #endif /* CONFIG_TESTING_OPTIONS */
101 
102 	/* Code Identifier attribute */
103 	if (pkex->identifier) {
104 		wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
105 		wpabuf_put_le16(msg, os_strlen(pkex->identifier));
106 		wpabuf_put_str(msg, pkex->identifier);
107 	}
108 
109 #ifdef CONFIG_TESTING_OPTIONS
110 	if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
111 		wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
112 		goto out;
113 	}
114 #endif /* CONFIG_TESTING_OPTIONS */
115 
116 	/* M in Encrypted Key attribute */
117 	wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
118 	wpabuf_put_le16(msg, 2 * curve->prime_len);
119 
120 #ifdef CONFIG_TESTING_OPTIONS
121 	if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
122 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
123 		if (dpp_test_gen_invalid_key(msg, curve) < 0)
124 			goto fail;
125 		goto out;
126 	}
127 #endif /* CONFIG_TESTING_OPTIONS */
128 
129 	Mx = wpabuf_put(msg, curve->prime_len);
130 	My = wpabuf_put(msg, curve->prime_len);
131 	if (crypto_ec_point_to_bin(ec, M, Mx, My))
132 		goto fail;
133 
134 	os_memcpy(pkex->Mx, Mx, curve->prime_len);
135 
136 out:
137 	crypto_ec_point_deinit(M, 1);
138 	crypto_ec_point_deinit(Qi, 1);
139 	crypto_ec_deinit(ec);
140 	return msg;
141 fail:
142 	wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
143 	wpabuf_free(msg);
144 	msg = NULL;
145 	goto out;
146 }
147 
148 
149 static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
150 {
151 	wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
152 }
153 
154 
155 struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
156 				const u8 *own_mac,
157 				const char *identifier,
158 				const char *code)
159 {
160 	struct dpp_pkex *pkex;
161 
162 #ifdef CONFIG_TESTING_OPTIONS
163 	if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
164 		wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
165 			   MAC2STR(dpp_pkex_own_mac_override));
166 		own_mac = dpp_pkex_own_mac_override;
167 	}
168 #endif /* CONFIG_TESTING_OPTIONS */
169 
170 	pkex = os_zalloc(sizeof(*pkex));
171 	if (!pkex)
172 		return NULL;
173 	pkex->msg_ctx = msg_ctx;
174 	pkex->initiator = 1;
175 	pkex->own_bi = bi;
176 	os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
177 	if (identifier) {
178 		pkex->identifier = os_strdup(identifier);
179 		if (!pkex->identifier)
180 			goto fail;
181 	}
182 	pkex->code = os_strdup(code);
183 	if (!pkex->code)
184 		goto fail;
185 	pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
186 	if (!pkex->exchange_req)
187 		goto fail;
188 	return pkex;
189 fail:
190 	dpp_pkex_free(pkex);
191 	return NULL;
192 }
193 
194 
195 static struct wpabuf *
196 dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
197 			     enum dpp_status_error status,
198 			     const u8 *Nx, const u8 *Ny)
199 {
200 	struct wpabuf *msg = NULL;
201 	size_t attr_len;
202 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
203 
204 	/* Initiator -> Responder: DPP Status, [identifier,] N */
205 	attr_len = 4 + 1;
206 	if (pkex->identifier)
207 		attr_len += 4 + os_strlen(pkex->identifier);
208 	attr_len += 4 + 2 * curve->prime_len;
209 	msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
210 	if (!msg)
211 		goto fail;
212 
213 #ifdef CONFIG_TESTING_OPTIONS
214 	if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
215 		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
216 		goto skip_status;
217 	}
218 
219 	if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
220 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
221 		status = 255;
222 	}
223 #endif /* CONFIG_TESTING_OPTIONS */
224 
225 	/* DPP Status */
226 	dpp_build_attr_status(msg, status);
227 
228 #ifdef CONFIG_TESTING_OPTIONS
229 skip_status:
230 #endif /* CONFIG_TESTING_OPTIONS */
231 
232 	/* Code Identifier attribute */
233 	if (pkex->identifier) {
234 		wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
235 		wpabuf_put_le16(msg, os_strlen(pkex->identifier));
236 		wpabuf_put_str(msg, pkex->identifier);
237 	}
238 
239 	if (status != DPP_STATUS_OK)
240 		goto skip_encrypted_key;
241 
242 #ifdef CONFIG_TESTING_OPTIONS
243 	if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
244 		wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
245 		goto skip_encrypted_key;
246 	}
247 #endif /* CONFIG_TESTING_OPTIONS */
248 
249 	/* N in Encrypted Key attribute */
250 	wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
251 	wpabuf_put_le16(msg, 2 * curve->prime_len);
252 
253 #ifdef CONFIG_TESTING_OPTIONS
254 	if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
255 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
256 		if (dpp_test_gen_invalid_key(msg, curve) < 0)
257 			goto fail;
258 		goto skip_encrypted_key;
259 	}
260 #endif /* CONFIG_TESTING_OPTIONS */
261 
262 	wpabuf_put_data(msg, Nx, curve->prime_len);
263 	wpabuf_put_data(msg, Ny, curve->prime_len);
264 	os_memcpy(pkex->Nx, Nx, curve->prime_len);
265 
266 skip_encrypted_key:
267 	if (status == DPP_STATUS_BAD_GROUP) {
268 		/* Finite Cyclic Group attribute */
269 		wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
270 		wpabuf_put_le16(msg, 2);
271 		wpabuf_put_le16(msg, curve->ike_group);
272 	}
273 
274 	return msg;
275 fail:
276 	wpabuf_free(msg);
277 	return NULL;
278 }
279 
280 
281 static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
282 				     const char *identifier)
283 {
284 	if (!attr_id && identifier) {
285 		wpa_printf(MSG_DEBUG,
286 			   "DPP: No PKEX code identifier received, but expected one");
287 		return 0;
288 	}
289 
290 	if (attr_id && !identifier) {
291 		wpa_printf(MSG_DEBUG,
292 			   "DPP: PKEX code identifier received, but not expecting one");
293 		return 0;
294 	}
295 
296 	if (attr_id && identifier &&
297 	    (os_strlen(identifier) != attr_id_len ||
298 	     os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
299 		wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
300 		return 0;
301 	}
302 
303 	return 1;
304 }
305 
306 
307 struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
308 					   struct dpp_bootstrap_info *bi,
309 					   const u8 *own_mac,
310 					   const u8 *peer_mac,
311 					   const char *identifier,
312 					   const char *code,
313 					   const u8 *buf, size_t len)
314 {
315 	const u8 *attr_group, *attr_id, *attr_key;
316 	u16 attr_group_len, attr_id_len, attr_key_len;
317 	const struct dpp_curve_params *curve = bi->curve;
318 	u16 ike_group;
319 	struct dpp_pkex *pkex = NULL;
320 	struct crypto_ec_point *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL,
321 		*N = NULL;
322 	struct crypto_ec *ec = NULL;
323 	const struct crypto_ec_point *Y;
324 	u8 *x_coord = NULL, *y_coord = NULL;
325 	u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
326 	size_t Kx_len;
327 	int res;
328 
329 	if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
330 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
331 			"PKEX counter t limit reached - ignore message");
332 		return NULL;
333 	}
334 
335 #ifdef CONFIG_TESTING_OPTIONS
336 	if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
337 		wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
338 			   MAC2STR(dpp_pkex_peer_mac_override));
339 		peer_mac = dpp_pkex_peer_mac_override;
340 	}
341 	if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
342 		wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
343 			   MAC2STR(dpp_pkex_own_mac_override));
344 		own_mac = dpp_pkex_own_mac_override;
345 	}
346 #endif /* CONFIG_TESTING_OPTIONS */
347 
348 	attr_id_len = 0;
349 	attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
350 			       &attr_id_len);
351 	if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
352 		return NULL;
353 
354 	attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
355 				  &attr_group_len);
356 	if (!attr_group || attr_group_len != 2) {
357 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
358 			"Missing or invalid Finite Cyclic Group attribute");
359 		return NULL;
360 	}
361 	ike_group = WPA_GET_LE16(attr_group);
362 	if (ike_group != curve->ike_group) {
363 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
364 			"Mismatching PKEX curve: peer=%u own=%u",
365 			ike_group, curve->ike_group);
366 		pkex = os_zalloc(sizeof(*pkex));
367 		if (!pkex)
368 			goto fail;
369 		pkex->own_bi = bi;
370 		pkex->failed = 1;
371 		pkex->exchange_resp = dpp_pkex_build_exchange_resp(
372 			pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
373 		if (!pkex->exchange_resp)
374 			goto fail;
375 		return pkex;
376 	}
377 
378 	/* M in Encrypted Key attribute */
379 	attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
380 				&attr_key_len);
381 	if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
382 	    attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
383 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
384 			"Missing Encrypted Key attribute");
385 		return NULL;
386 	}
387 
388 	/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
389 	Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, &ec);
390 	if (!Qi)
391 		goto fail;
392 
393 	/* X' = M - Qi */
394 	X = crypto_ec_point_init(ec);
395 	M = crypto_ec_point_from_bin(ec, attr_key);
396 	if (!X || !M ||
397 	    crypto_ec_point_is_at_infinity(ec, M) ||
398 	    !crypto_ec_point_is_on_curve(ec, M) ||
399 	    crypto_ec_point_invert(ec, Qi) ||
400 	    crypto_ec_point_add(ec, M, Qi, X) ||
401 	    crypto_ec_point_is_at_infinity(ec, X) ||
402 	    !crypto_ec_point_is_on_curve(ec, X)) {
403 		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
404 			"Invalid Encrypted Key value");
405 		bi->pkex_t++;
406 		goto fail;
407 	}
408 	crypto_ec_point_debug_print(ec, M, "DPP: M");
409 	crypto_ec_point_debug_print(ec, X, "DPP: X'");
410 
411 	pkex = os_zalloc(sizeof(*pkex));
412 	if (!pkex)
413 		goto fail;
414 	pkex->t = bi->pkex_t;
415 	pkex->msg_ctx = msg_ctx;
416 	pkex->own_bi = bi;
417 	os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
418 	os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
419 	if (identifier) {
420 		pkex->identifier = os_strdup(identifier);
421 		if (!pkex->identifier)
422 			goto fail;
423 	}
424 	pkex->code = os_strdup(code);
425 	if (!pkex->code)
426 		goto fail;
427 
428 	os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
429 
430 	x_coord = os_malloc(curve->prime_len);
431 	y_coord = os_malloc(curve->prime_len);
432 	if (!x_coord || !y_coord ||
433 	    crypto_ec_point_to_bin(ec, X, x_coord, y_coord))
434 		goto fail;
435 
436 	pkex->x = crypto_ec_key_set_pub(curve->ike_group, x_coord,
437 					y_coord, crypto_ec_prime_len(ec));
438 	if (!pkex->x)
439 		goto fail;
440 
441 	/* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
442 	Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, NULL);
443 	if (!Qr)
444 		goto fail;
445 
446 	/* Generate a random ephemeral keypair y/Y */
447 #ifdef CONFIG_TESTING_OPTIONS
448 	if (dpp_pkex_ephemeral_key_override_len) {
449 		const struct dpp_curve_params *tmp_curve;
450 
451 		wpa_printf(MSG_INFO,
452 			   "DPP: TESTING - override ephemeral key y/Y");
453 		pkex->y = dpp_set_keypair(&tmp_curve,
454 					  dpp_pkex_ephemeral_key_override,
455 					  dpp_pkex_ephemeral_key_override_len);
456 	} else {
457 		pkex->y = dpp_gen_keypair(curve);
458 	}
459 #else /* CONFIG_TESTING_OPTIONS */
460 	pkex->y = dpp_gen_keypair(curve);
461 #endif /* CONFIG_TESTING_OPTIONS */
462 	if (!pkex->y)
463 		goto fail;
464 
465 	/* N = Y + Qr */
466 	Y = crypto_ec_key_get_public_key(pkex->y);
467 	if (!Y)
468 		goto fail;
469 	crypto_ec_point_debug_print(ec, Y, "DPP: Y");
470 
471 	N = crypto_ec_point_init(ec);
472 	if (!N ||
473 	    crypto_ec_point_add(ec, Y, Qr, N) ||
474 	    crypto_ec_point_to_bin(ec, N, x_coord, y_coord))
475 		goto fail;
476 	crypto_ec_point_debug_print(ec, N, "DPP: N");
477 
478 	pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
479 							   x_coord, y_coord);
480 	if (!pkex->exchange_resp)
481 		goto fail;
482 
483 	/* K = y * X' */
484 	if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
485 		goto fail;
486 
487 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
488 			Kx, Kx_len);
489 
490 	/* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
491 	 */
492 	res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
493 				pkex->Mx, curve->prime_len,
494 				pkex->Nx, curve->prime_len, pkex->code,
495 				Kx, Kx_len, pkex->z, curve->hash_len);
496 	os_memset(Kx, 0, Kx_len);
497 	if (res < 0)
498 		goto fail;
499 
500 	pkex->exchange_done = 1;
501 
502 out:
503 	os_free(x_coord);
504 	os_free(y_coord);
505 	crypto_ec_point_deinit(Qi, 1);
506 	crypto_ec_point_deinit(Qr, 1);
507 	crypto_ec_point_deinit(M, 1);
508 	crypto_ec_point_deinit(N, 1);
509 	crypto_ec_point_deinit(X, 1);
510 	crypto_ec_deinit(ec);
511 	return pkex;
512 fail:
513 	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
514 	dpp_pkex_free(pkex);
515 	pkex = NULL;
516 	goto out;
517 }
518 
519 
520 static struct wpabuf *
521 dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
522 				 const struct wpabuf *A_pub, const u8 *u)
523 {
524 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
525 	struct wpabuf *msg = NULL;
526 	size_t clear_len, attr_len;
527 	struct wpabuf *clear = NULL;
528 	u8 *wrapped;
529 	u8 octet;
530 	const u8 *addr[2];
531 	size_t len[2];
532 
533 	/* {A, u, [bootstrapping info]}z */
534 	clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
535 	clear = wpabuf_alloc(clear_len);
536 	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
537 #ifdef CONFIG_TESTING_OPTIONS
538 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
539 		attr_len += 5;
540 #endif /* CONFIG_TESTING_OPTIONS */
541 	msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
542 	if (!clear || !msg)
543 		goto fail;
544 
545 #ifdef CONFIG_TESTING_OPTIONS
546 	if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
547 		wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
548 		goto skip_bootstrap_key;
549 	}
550 	if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
551 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
552 		wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
553 		wpabuf_put_le16(clear, 2 * curve->prime_len);
554 		if (dpp_test_gen_invalid_key(clear, curve) < 0)
555 			goto fail;
556 		goto skip_bootstrap_key;
557 	}
558 #endif /* CONFIG_TESTING_OPTIONS */
559 
560 	/* A in Bootstrap Key attribute */
561 	wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
562 	wpabuf_put_le16(clear, wpabuf_len(A_pub));
563 	wpabuf_put_buf(clear, A_pub);
564 
565 #ifdef CONFIG_TESTING_OPTIONS
566 skip_bootstrap_key:
567 	if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
568 		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
569 		goto skip_i_auth_tag;
570 	}
571 	if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
572 		wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
573 		wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
574 		wpabuf_put_le16(clear, curve->hash_len);
575 		wpabuf_put_data(clear, u, curve->hash_len - 1);
576 		wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
577 		goto skip_i_auth_tag;
578 	}
579 #endif /* CONFIG_TESTING_OPTIONS */
580 
581 	/* u in I-Auth tag attribute */
582 	wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
583 	wpabuf_put_le16(clear, curve->hash_len);
584 	wpabuf_put_data(clear, u, curve->hash_len);
585 
586 #ifdef CONFIG_TESTING_OPTIONS
587 skip_i_auth_tag:
588 	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
589 		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
590 		goto skip_wrapped_data;
591 	}
592 #endif /* CONFIG_TESTING_OPTIONS */
593 
594 	addr[0] = wpabuf_head_u8(msg) + 2;
595 	len[0] = DPP_HDR_LEN;
596 	octet = 0;
597 	addr[1] = &octet;
598 	len[1] = sizeof(octet);
599 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
600 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
601 
602 	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
603 	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
604 	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
605 
606 	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
607 	if (aes_siv_encrypt(pkex->z, curve->hash_len,
608 			    wpabuf_head(clear), wpabuf_len(clear),
609 			    2, addr, len, wrapped) < 0)
610 		goto fail;
611 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
612 		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
613 
614 #ifdef CONFIG_TESTING_OPTIONS
615 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
616 		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
617 		dpp_build_attr_status(msg, DPP_STATUS_OK);
618 	}
619 skip_wrapped_data:
620 #endif /* CONFIG_TESTING_OPTIONS */
621 
622 out:
623 	wpabuf_free(clear);
624 	return msg;
625 
626 fail:
627 	wpabuf_free(msg);
628 	msg = NULL;
629 	goto out;
630 }
631 
632 
633 struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
634 					  const u8 *peer_mac,
635 					  const u8 *buf, size_t buflen)
636 {
637 	const u8 *attr_status, *attr_id, *attr_key, *attr_group;
638 	u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
639 	struct crypto_ec *ec = NULL;
640 	struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
641 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
642 	struct crypto_ec_point *Qr = NULL, *Y = NULL, *N = NULL;
643 	u8 *x_coord = NULL, *y_coord = NULL;
644 	size_t Jx_len, Kx_len;
645 	u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
646 	const u8 *addr[4];
647 	size_t len[4];
648 	u8 u[DPP_MAX_HASH_LEN];
649 	int res;
650 
651 	if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
652 		return NULL;
653 
654 #ifdef CONFIG_TESTING_OPTIONS
655 	if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
656 		wpa_printf(MSG_INFO,
657 			   "DPP: TESTING - stop at PKEX Exchange Response");
658 		pkex->failed = 1;
659 		return NULL;
660 	}
661 
662 	if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
663 		wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
664 			   MAC2STR(dpp_pkex_peer_mac_override));
665 		peer_mac = dpp_pkex_peer_mac_override;
666 	}
667 #endif /* CONFIG_TESTING_OPTIONS */
668 
669 	os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
670 
671 	attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
672 				   &attr_status_len);
673 	if (!attr_status || attr_status_len != 1) {
674 		dpp_pkex_fail(pkex, "No DPP Status attribute");
675 		return NULL;
676 	}
677 	wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
678 
679 	if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
680 		attr_group = dpp_get_attr(buf, buflen,
681 					  DPP_ATTR_FINITE_CYCLIC_GROUP,
682 					  &attr_group_len);
683 		if (attr_group && attr_group_len == 2) {
684 			wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
685 				"Peer indicated mismatching PKEX group - proposed %u",
686 				WPA_GET_LE16(attr_group));
687 			return NULL;
688 		}
689 	}
690 
691 	if (attr_status[0] != DPP_STATUS_OK) {
692 		dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
693 		return NULL;
694 	}
695 
696 	attr_id_len = 0;
697 	attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
698 			       &attr_id_len);
699 	if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
700 				       pkex->identifier)) {
701 		dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
702 		return NULL;
703 	}
704 
705 	/* N in Encrypted Key attribute */
706 	attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
707 				&attr_key_len);
708 	if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
709 		dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
710 		return NULL;
711 	}
712 
713 	/* Qr = H(MAC-Responder | [identifier |] code) * Pr */
714 	Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
715 				pkex->identifier, &ec);
716 	if (!Qr)
717 		goto fail;
718 
719 	/* Y' = N - Qr */
720 	Y = crypto_ec_point_init(ec);
721 	N = crypto_ec_point_from_bin(ec, attr_key);
722 	if (!Y || !N ||
723 	    crypto_ec_point_is_at_infinity(ec, N) ||
724 	    !crypto_ec_point_is_on_curve(ec, N) ||
725 	    crypto_ec_point_invert(ec, Qr) ||
726 	    crypto_ec_point_add(ec, N, Qr, Y) ||
727 	    crypto_ec_point_is_at_infinity(ec, Y) ||
728 	    !crypto_ec_point_is_on_curve(ec, Y)) {
729 		dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
730 		pkex->t++;
731 		goto fail;
732 	}
733 	crypto_ec_point_debug_print(ec, N, "DPP: N");
734 	crypto_ec_point_debug_print(ec, Y, "DPP: Y'");
735 
736 	pkex->exchange_done = 1;
737 
738 	/* ECDH: J = a * Y' */
739 	x_coord = os_malloc(curve->prime_len);
740 	y_coord = os_malloc(curve->prime_len);
741 	if (!x_coord || !y_coord ||
742 	    crypto_ec_point_to_bin(ec, Y, x_coord, y_coord))
743 		goto fail;
744 	pkex->y = crypto_ec_key_set_pub(curve->ike_group, x_coord, y_coord,
745 					curve->prime_len);
746 	if (!pkex->y)
747 		goto fail;
748 	if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
749 		goto fail;
750 
751 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
752 			Jx, Jx_len);
753 
754 	/* u = HMAC(J.x, MAC-Initiator | A.x | Y'.x | X.x) */
755 	A_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
756 	Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
757 	X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
758 	if (!A_pub || !Y_pub || !X_pub)
759 		goto fail;
760 	addr[0] = pkex->own_mac;
761 	len[0] = ETH_ALEN;
762 	addr[1] = wpabuf_head(A_pub);
763 	len[1] = wpabuf_len(A_pub) / 2;
764 	addr[2] = wpabuf_head(Y_pub);
765 	len[2] = wpabuf_len(Y_pub) / 2;
766 	addr[3] = wpabuf_head(X_pub);
767 	len[3] = wpabuf_len(X_pub) / 2;
768 	if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
769 		goto fail;
770 	wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
771 
772 	/* K = x * Y' */
773 	if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
774 		goto fail;
775 
776 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
777 			Kx, Kx_len);
778 
779 	/* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
780 	 */
781 	res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
782 				pkex->Mx, curve->prime_len,
783 				attr_key /* N.x */, attr_key_len / 2,
784 				pkex->code, Kx, Kx_len,
785 				pkex->z, curve->hash_len);
786 	os_memset(Kx, 0, Kx_len);
787 	if (res < 0)
788 		goto fail;
789 
790 	msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
791 	if (!msg)
792 		goto fail;
793 
794 out:
795 	wpabuf_free(A_pub);
796 	wpabuf_free(X_pub);
797 	wpabuf_free(Y_pub);
798 	os_free(x_coord);
799 	os_free(y_coord);
800 	crypto_ec_point_deinit(Qr, 1);
801 	crypto_ec_point_deinit(Y, 1);
802 	crypto_ec_point_deinit(N, 1);
803 	crypto_ec_deinit(ec);
804 	return msg;
805 fail:
806 	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
807 	goto out;
808 }
809 
810 
811 static struct wpabuf *
812 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
813 				  const struct wpabuf *B_pub, const u8 *v)
814 {
815 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
816 	struct wpabuf *msg = NULL;
817 	const u8 *addr[2];
818 	size_t len[2];
819 	u8 octet;
820 	u8 *wrapped;
821 	struct wpabuf *clear = NULL;
822 	size_t clear_len, attr_len;
823 
824 	/* {B, v [bootstrapping info]}z */
825 	clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
826 	clear = wpabuf_alloc(clear_len);
827 	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
828 #ifdef CONFIG_TESTING_OPTIONS
829 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
830 		attr_len += 5;
831 #endif /* CONFIG_TESTING_OPTIONS */
832 	msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
833 	if (!clear || !msg)
834 		goto fail;
835 
836 #ifdef CONFIG_TESTING_OPTIONS
837 	if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
838 		wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
839 		goto skip_bootstrap_key;
840 	}
841 	if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
842 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
843 		wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
844 		wpabuf_put_le16(clear, 2 * curve->prime_len);
845 		if (dpp_test_gen_invalid_key(clear, curve) < 0)
846 			goto fail;
847 		goto skip_bootstrap_key;
848 	}
849 #endif /* CONFIG_TESTING_OPTIONS */
850 
851 	/* B in Bootstrap Key attribute */
852 	wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
853 	wpabuf_put_le16(clear, wpabuf_len(B_pub));
854 	wpabuf_put_buf(clear, B_pub);
855 
856 #ifdef CONFIG_TESTING_OPTIONS
857 skip_bootstrap_key:
858 	if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
859 		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
860 		goto skip_r_auth_tag;
861 	}
862 	if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
863 		wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
864 		wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
865 		wpabuf_put_le16(clear, curve->hash_len);
866 		wpabuf_put_data(clear, v, curve->hash_len - 1);
867 		wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
868 		goto skip_r_auth_tag;
869 	}
870 #endif /* CONFIG_TESTING_OPTIONS */
871 
872 	/* v in R-Auth tag attribute */
873 	wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
874 	wpabuf_put_le16(clear, curve->hash_len);
875 	wpabuf_put_data(clear, v, curve->hash_len);
876 
877 #ifdef CONFIG_TESTING_OPTIONS
878 skip_r_auth_tag:
879 	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
880 		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
881 		goto skip_wrapped_data;
882 	}
883 #endif /* CONFIG_TESTING_OPTIONS */
884 
885 	addr[0] = wpabuf_head_u8(msg) + 2;
886 	len[0] = DPP_HDR_LEN;
887 	octet = 1;
888 	addr[1] = &octet;
889 	len[1] = sizeof(octet);
890 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
891 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
892 
893 	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
894 	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
895 	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
896 
897 	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
898 	if (aes_siv_encrypt(pkex->z, curve->hash_len,
899 			    wpabuf_head(clear), wpabuf_len(clear),
900 			    2, addr, len, wrapped) < 0)
901 		goto fail;
902 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
903 		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
904 
905 #ifdef CONFIG_TESTING_OPTIONS
906 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
907 		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
908 		dpp_build_attr_status(msg, DPP_STATUS_OK);
909 	}
910 skip_wrapped_data:
911 #endif /* CONFIG_TESTING_OPTIONS */
912 
913 out:
914 	wpabuf_free(clear);
915 	return msg;
916 
917 fail:
918 	wpabuf_free(msg);
919 	msg = NULL;
920 	goto out;
921 }
922 
923 
924 struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
925 					      const u8 *hdr,
926 					      const u8 *buf, size_t buflen)
927 {
928 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
929 	size_t Jx_len, Lx_len;
930 	u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
931 	u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
932 	const u8 *wrapped_data, *b_key, *peer_u;
933 	u16 wrapped_data_len, b_key_len, peer_u_len = 0;
934 	const u8 *addr[4];
935 	size_t len[4];
936 	u8 octet;
937 	u8 *unwrapped = NULL;
938 	size_t unwrapped_len = 0;
939 	struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
940 	struct wpabuf *B_pub = NULL;
941 	u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
942 
943 #ifdef CONFIG_TESTING_OPTIONS
944 	if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
945 		wpa_printf(MSG_INFO,
946 			   "DPP: TESTING - stop at PKEX CR Request");
947 		pkex->failed = 1;
948 		return NULL;
949 	}
950 #endif /* CONFIG_TESTING_OPTIONS */
951 
952 	if (!pkex->exchange_done || pkex->failed ||
953 	    pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
954 		goto fail;
955 
956 	wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
957 				    &wrapped_data_len);
958 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
959 		dpp_pkex_fail(pkex,
960 			      "Missing or invalid required Wrapped Data attribute");
961 		goto fail;
962 	}
963 
964 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
965 		    wrapped_data, wrapped_data_len);
966 	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
967 	unwrapped = os_malloc(unwrapped_len);
968 	if (!unwrapped)
969 		goto fail;
970 
971 	addr[0] = hdr;
972 	len[0] = DPP_HDR_LEN;
973 	octet = 0;
974 	addr[1] = &octet;
975 	len[1] = sizeof(octet);
976 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
977 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
978 
979 	if (aes_siv_decrypt(pkex->z, curve->hash_len,
980 			    wrapped_data, wrapped_data_len,
981 			    2, addr, len, unwrapped) < 0) {
982 		dpp_pkex_fail(pkex,
983 			      "AES-SIV decryption failed - possible PKEX code mismatch");
984 		pkex->failed = 1;
985 		pkex->t++;
986 		goto fail;
987 	}
988 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
989 		    unwrapped, unwrapped_len);
990 
991 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
992 		dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
993 		goto fail;
994 	}
995 
996 	b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
997 			     &b_key_len);
998 	if (!b_key || b_key_len != 2 * curve->prime_len) {
999 		dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
1000 		goto fail;
1001 	}
1002 	pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
1003 							b_key_len);
1004 	if (!pkex->peer_bootstrap_key) {
1005 		dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
1006 		goto fail;
1007 	}
1008 	dpp_debug_print_key("DPP: Peer bootstrap public key",
1009 			    pkex->peer_bootstrap_key);
1010 
1011 	/* ECDH: J' = y * A' */
1012 	if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
1013 		goto fail;
1014 
1015 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
1016 			Jx, Jx_len);
1017 
1018 	/* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
1019 	A_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
1020 	Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
1021 	X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
1022 	if (!A_pub || !Y_pub || !X_pub)
1023 		goto fail;
1024 	addr[0] = pkex->peer_mac;
1025 	len[0] = ETH_ALEN;
1026 	addr[1] = wpabuf_head(A_pub);
1027 	len[1] = wpabuf_len(A_pub) / 2;
1028 	addr[2] = wpabuf_head(Y_pub);
1029 	len[2] = wpabuf_len(Y_pub) / 2;
1030 	addr[3] = wpabuf_head(X_pub);
1031 	len[3] = wpabuf_len(X_pub) / 2;
1032 	if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
1033 		goto fail;
1034 
1035 	peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
1036 			      &peer_u_len);
1037 	if (!peer_u || peer_u_len != curve->hash_len ||
1038 	    os_memcmp(peer_u, u, curve->hash_len) != 0) {
1039 		dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
1040 		wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
1041 			    u, curve->hash_len);
1042 		wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
1043 		pkex->t++;
1044 		goto fail;
1045 	}
1046 	wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
1047 
1048 	/* ECDH: L = b * X' */
1049 	if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
1050 		goto fail;
1051 
1052 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
1053 			Lx, Lx_len);
1054 
1055 	/* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
1056 	B_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
1057 	if (!B_pub)
1058 		goto fail;
1059 	addr[0] = pkex->own_mac;
1060 	len[0] = ETH_ALEN;
1061 	addr[1] = wpabuf_head(B_pub);
1062 	len[1] = wpabuf_len(B_pub) / 2;
1063 	addr[2] = wpabuf_head(X_pub);
1064 	len[2] = wpabuf_len(X_pub) / 2;
1065 	addr[3] = wpabuf_head(Y_pub);
1066 	len[3] = wpabuf_len(Y_pub) / 2;
1067 	if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
1068 		goto fail;
1069 	wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
1070 
1071 	msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
1072 	if (!msg)
1073 		goto fail;
1074 
1075 out:
1076 	os_free(unwrapped);
1077 	wpabuf_free(A_pub);
1078 	wpabuf_free(B_pub);
1079 	wpabuf_free(X_pub);
1080 	wpabuf_free(Y_pub);
1081 	return msg;
1082 fail:
1083 	wpa_printf(MSG_DEBUG,
1084 		   "DPP: PKEX Commit-Reveal Request processing failed");
1085 	goto out;
1086 }
1087 
1088 
1089 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
1090 				   const u8 *buf, size_t buflen)
1091 {
1092 	const struct dpp_curve_params *curve = pkex->own_bi->curve;
1093 	const u8 *wrapped_data, *b_key, *peer_v;
1094 	u16 wrapped_data_len, b_key_len, peer_v_len = 0;
1095 	const u8 *addr[4];
1096 	size_t len[4];
1097 	u8 octet;
1098 	u8 *unwrapped = NULL;
1099 	size_t unwrapped_len = 0;
1100 	int ret = -1;
1101 	u8 v[DPP_MAX_HASH_LEN];
1102 	size_t Lx_len;
1103 	u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
1104 	struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
1105 
1106 #ifdef CONFIG_TESTING_OPTIONS
1107 	if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
1108 		wpa_printf(MSG_INFO,
1109 			   "DPP: TESTING - stop at PKEX CR Response");
1110 		pkex->failed = 1;
1111 		goto fail;
1112 	}
1113 #endif /* CONFIG_TESTING_OPTIONS */
1114 
1115 	if (!pkex->exchange_done || pkex->failed ||
1116 	    pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
1117 		goto fail;
1118 
1119 	wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
1120 				    &wrapped_data_len);
1121 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
1122 		dpp_pkex_fail(pkex,
1123 			      "Missing or invalid required Wrapped Data attribute");
1124 		goto fail;
1125 	}
1126 
1127 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1128 		    wrapped_data, wrapped_data_len);
1129 	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1130 	unwrapped = os_malloc(unwrapped_len);
1131 	if (!unwrapped)
1132 		goto fail;
1133 
1134 	addr[0] = hdr;
1135 	len[0] = DPP_HDR_LEN;
1136 	octet = 1;
1137 	addr[1] = &octet;
1138 	len[1] = sizeof(octet);
1139 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1140 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1141 
1142 	if (aes_siv_decrypt(pkex->z, curve->hash_len,
1143 			    wrapped_data, wrapped_data_len,
1144 			    2, addr, len, unwrapped) < 0) {
1145 		dpp_pkex_fail(pkex,
1146 			      "AES-SIV decryption failed - possible PKEX code mismatch");
1147 		pkex->t++;
1148 		goto fail;
1149 	}
1150 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1151 		    unwrapped, unwrapped_len);
1152 
1153 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1154 		dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
1155 		goto fail;
1156 	}
1157 
1158 	b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
1159 			     &b_key_len);
1160 	if (!b_key || b_key_len != 2 * curve->prime_len) {
1161 		dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
1162 		goto fail;
1163 	}
1164 	pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
1165 							b_key_len);
1166 	if (!pkex->peer_bootstrap_key) {
1167 		dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
1168 		goto fail;
1169 	}
1170 	dpp_debug_print_key("DPP: Peer bootstrap public key",
1171 			    pkex->peer_bootstrap_key);
1172 
1173 	/* ECDH: L' = x * B' */
1174 	if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
1175 		goto fail;
1176 
1177 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
1178 			Lx, Lx_len);
1179 
1180 	/* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
1181 	B_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
1182 	X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
1183 	Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
1184 	if (!B_pub || !X_pub || !Y_pub)
1185 		goto fail;
1186 	addr[0] = pkex->peer_mac;
1187 	len[0] = ETH_ALEN;
1188 	addr[1] = wpabuf_head(B_pub);
1189 	len[1] = wpabuf_len(B_pub) / 2;
1190 	addr[2] = wpabuf_head(X_pub);
1191 	len[2] = wpabuf_len(X_pub) / 2;
1192 	addr[3] = wpabuf_head(Y_pub);
1193 	len[3] = wpabuf_len(Y_pub) / 2;
1194 	if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
1195 		goto fail;
1196 
1197 	peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
1198 			      &peer_v_len);
1199 	if (!peer_v || peer_v_len != curve->hash_len ||
1200 	    os_memcmp(peer_v, v, curve->hash_len) != 0) {
1201 		dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
1202 		wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
1203 			    v, curve->hash_len);
1204 		wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
1205 		pkex->t++;
1206 		goto fail;
1207 	}
1208 	wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
1209 
1210 	ret = 0;
1211 out:
1212 	wpabuf_free(B_pub);
1213 	wpabuf_free(X_pub);
1214 	wpabuf_free(Y_pub);
1215 	os_free(unwrapped);
1216 	return ret;
1217 fail:
1218 	goto out;
1219 }
1220 
1221 
1222 struct dpp_bootstrap_info *
1223 dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
1224 		unsigned int freq)
1225 {
1226 	struct dpp_bootstrap_info *bi;
1227 
1228 	bi = os_zalloc(sizeof(*bi));
1229 	if (!bi)
1230 		return NULL;
1231 	bi->id = dpp_next_id(dpp);
1232 	bi->type = DPP_BOOTSTRAP_PKEX;
1233 	os_memcpy(bi->mac_addr, peer, ETH_ALEN);
1234 	bi->num_freq = 1;
1235 	bi->freq[0] = freq;
1236 	bi->curve = pkex->own_bi->curve;
1237 	bi->pubkey = pkex->peer_bootstrap_key;
1238 	pkex->peer_bootstrap_key = NULL;
1239 	if (dpp_bootstrap_key_hash(bi) < 0) {
1240 		dpp_bootstrap_info_free(bi);
1241 		return NULL;
1242 	}
1243 	dpp_pkex_free(pkex);
1244 	dl_list_add(&dpp->bootstrap, &bi->list);
1245 	return bi;
1246 }
1247 
1248 
1249 void dpp_pkex_free(struct dpp_pkex *pkex)
1250 {
1251 	if (!pkex)
1252 		return;
1253 
1254 	os_free(pkex->identifier);
1255 	os_free(pkex->code);
1256 	crypto_ec_key_deinit(pkex->x);
1257 	crypto_ec_key_deinit(pkex->y);
1258 	crypto_ec_key_deinit(pkex->peer_bootstrap_key);
1259 	wpabuf_free(pkex->exchange_req);
1260 	wpabuf_free(pkex->exchange_resp);
1261 	os_free(pkex);
1262 }
1263