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