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