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