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