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