blob: 72084d9fbc6dae5becad86b76bd375f76214fed2 [file] [log] [blame]
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001/*
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"
Hai Shalom4fbc08f2020-05-18 12:37:00 -070011
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
22u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
23u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
24u8 dpp_pkex_ephemeral_key_override[600];
25size_t dpp_pkex_ephemeral_key_override_len = 0;
26#endif /* CONFIG_TESTING_OPTIONS */
27
Hai Shalom4fbc08f2020-05-18 12:37:00 -070028
Hai Shaloma20dcd72022-02-04 13:43:00 -080029static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex,
30 bool v2)
Hai Shalom4fbc08f2020-05-18 12:37:00 -070031{
Hai Shaloma20dcd72022-02-04 13:43:00 -080032 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;
Hai Shalom4fbc08f2020-05-18 12:37:00 -070036 struct wpabuf *msg = NULL;
37 size_t attr_len;
38 const struct dpp_curve_params *curve = pkex->own_bi->curve;
39
Hai Shaloma20dcd72022-02-04 13:43:00 -080040 wpa_printf(MSG_DEBUG, "DPP: Build PKEX %sExchange Request",
41 v2 ? "" : "Version 1 ");
Hai Shalom4fbc08f2020-05-18 12:37:00 -070042
Hai Shaloma20dcd72022-02-04 13:43:00 -080043 /* 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);
Hai Shalom4fbc08f2020-05-18 12:37:00 -070046 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 */
Hai Shaloma20dcd72022-02-04 13:43:00 -080069 X = crypto_ec_key_get_public_key(pkex->x);
70 M = crypto_ec_point_init(ec);
71 if (!X || !M)
Hai Shalom4fbc08f2020-05-18 12:37:00 -070072 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -080073 crypto_ec_point_debug_print(ec, X, "DPP: X");
74
75 if (crypto_ec_point_add(ec, X, Qi, M))
Hai Shalom4fbc08f2020-05-18 12:37:00 -070076 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -080077 crypto_ec_point_debug_print(ec, M, "DPP: M");
Hai Shalom4fbc08f2020-05-18 12:37:00 -070078
79 /* Initiator -> Responder: group, [identifier,] M */
80 attr_len = 4 + 2;
Hai Shaloma20dcd72022-02-04 13:43:00 -080081#ifdef CONFIG_DPP2
82 if (v2)
83 attr_len += 4 + 1;
84#endif /* CONFIG_DPP2 */
Hai Shalom4fbc08f2020-05-18 12:37:00 -070085 if (pkex->identifier)
86 attr_len += 4 + os_strlen(pkex->identifier);
87 attr_len += 4 + 2 * curve->prime_len;
Hai Shaloma20dcd72022-02-04 13:43:00 -080088 msg = dpp_alloc_msg(v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
89 DPP_PA_PKEX_V1_EXCHANGE_REQ, attr_len);
Hai Shalom4fbc08f2020-05-18 12:37:00 -070090 if (!msg)
91 goto fail;
92
Hai Shaloma20dcd72022-02-04 13:43:00 -080093#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
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700102#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
115skip_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
Hai Shaloma20dcd72022-02-04 13:43:00 -0800145 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))
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700148 goto fail;
149
Hai Shaloma20dcd72022-02-04 13:43:00 -0800150 os_memcpy(pkex->Mx, Mx, curve->prime_len);
151
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700152out:
Hai Shaloma20dcd72022-02-04 13:43:00 -0800153 crypto_ec_point_deinit(M, 1);
154 crypto_ec_point_deinit(Qi, 1);
155 crypto_ec_deinit(ec);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700156 return msg;
157fail:
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
165static 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
171struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
172 const u8 *own_mac,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800173 const char *identifier, const char *code,
174 bool v2)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700175{
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;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800191 pkex->v2 = v2;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700192 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;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800202 pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700203 if (!pkex->exchange_req)
204 goto fail;
205 return pkex;
206fail:
207 dpp_pkex_free(pkex);
208 return NULL;
209}
210
211
212static struct wpabuf *
213dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
214 enum dpp_status_error status,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800215 const u8 *Nx, const u8 *Ny)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700216{
217 struct wpabuf *msg = NULL;
218 size_t attr_len;
219 const struct dpp_curve_params *curve = pkex->own_bi->curve;
220
Hai Shaloma20dcd72022-02-04 13:43:00 -0800221 /* Initiator -> Responder: DPP Status, [Protocol Version,] [identifier,]
222 * N */
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700223 attr_len = 4 + 1;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800224#ifdef CONFIG_DPP2
225 if (pkex->v2)
226 attr_len += 4 + 1;
227#endif /* CONFIG_DPP2 */
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700228 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
251skip_status:
252#endif /* CONFIG_TESTING_OPTIONS */
253
Hai Shaloma20dcd72022-02-04 13:43:00 -0800254#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
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700263 /* 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
Hai Shaloma20dcd72022-02-04 13:43:00 -0800293 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);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700296
297skip_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;
306fail:
307 wpabuf_free(msg);
308 return NULL;
309}
310
311
312static 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
338struct 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,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800344 const u8 *buf, size_t len, bool v2)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700345{
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;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800351 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;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700356 u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
357 size_t Kx_len;
358 int res;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800359 u8 peer_version = 0;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700360
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
Hai Shaloma20dcd72022-02-04 13:43:00 -0800367#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
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700385#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;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800419 pkex->v2 = v2;
420 pkex->peer_version = peer_version;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700421 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
Hai Shaloma20dcd72022-02-04 13:43:00 -0800440 /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
441 Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, identifier,
442 &ec);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700443 if (!Qi)
444 goto fail;
445
446 /* X' = M - Qi */
Hai Shaloma20dcd72022-02-04 13:43:00 -0800447 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)) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700456 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
457 "Invalid Encrypted Key value");
458 bi->pkex_t++;
459 goto fail;
460 }
Hai Shaloma20dcd72022-02-04 13:43:00 -0800461 crypto_ec_point_debug_print(ec, M, "DPP: M");
462 crypto_ec_point_debug_print(ec, X, "DPP: X'");
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700463
464 pkex = os_zalloc(sizeof(*pkex));
465 if (!pkex)
466 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800467 pkex->v2 = v2;
468 pkex->peer_version = peer_version;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700469 pkex->t = bi->pkex_t;
470 pkex->msg_ctx = msg_ctx;
471 pkex->own_bi = bi;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800472 if (own_mac)
473 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
474 if (peer_mac)
475 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700476 if (identifier) {
477 pkex->identifier = os_strdup(identifier);
478 if (!pkex->identifier)
479 goto fail;
480 }
481 pkex->code = os_strdup(code);
482 if (!pkex->code)
483 goto fail;
484
485 os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
486
Hai Shaloma20dcd72022-02-04 13:43:00 -0800487 x_coord = os_malloc(curve->prime_len);
488 y_coord = os_malloc(curve->prime_len);
489 if (!x_coord || !y_coord ||
490 crypto_ec_point_to_bin(ec, X, x_coord, y_coord))
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700491 goto fail;
492
Hai Shaloma20dcd72022-02-04 13:43:00 -0800493 pkex->x = crypto_ec_key_set_pub(curve->ike_group, x_coord,
494 y_coord, crypto_ec_prime_len(ec));
495 if (!pkex->x)
496 goto fail;
497
498 /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
499 Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, identifier,
500 NULL);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700501 if (!Qr)
502 goto fail;
503
504 /* Generate a random ephemeral keypair y/Y */
505#ifdef CONFIG_TESTING_OPTIONS
506 if (dpp_pkex_ephemeral_key_override_len) {
507 const struct dpp_curve_params *tmp_curve;
508
509 wpa_printf(MSG_INFO,
510 "DPP: TESTING - override ephemeral key y/Y");
511 pkex->y = dpp_set_keypair(&tmp_curve,
512 dpp_pkex_ephemeral_key_override,
513 dpp_pkex_ephemeral_key_override_len);
514 } else {
515 pkex->y = dpp_gen_keypair(curve);
516 }
517#else /* CONFIG_TESTING_OPTIONS */
518 pkex->y = dpp_gen_keypair(curve);
519#endif /* CONFIG_TESTING_OPTIONS */
520 if (!pkex->y)
521 goto fail;
522
523 /* N = Y + Qr */
Hai Shaloma20dcd72022-02-04 13:43:00 -0800524 Y = crypto_ec_key_get_public_key(pkex->y);
525 if (!Y)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700526 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800527 crypto_ec_point_debug_print(ec, Y, "DPP: Y");
528
529 N = crypto_ec_point_init(ec);
530 if (!N ||
531 crypto_ec_point_add(ec, Y, Qr, N) ||
532 crypto_ec_point_to_bin(ec, N, x_coord, y_coord))
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700533 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800534 crypto_ec_point_debug_print(ec, N, "DPP: N");
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700535
536 pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800537 x_coord, y_coord);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700538 if (!pkex->exchange_resp)
539 goto fail;
540
541 /* K = y * X' */
542 if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
543 goto fail;
544
545 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
546 Kx, Kx_len);
547
Hai Shaloma20dcd72022-02-04 13:43:00 -0800548 /* z = HKDF(<>, info | M.x | N.x | code, K.x) */
549 res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->peer_mac,
550 pkex->v2 ? NULL : pkex->own_mac,
551 pkex->peer_version, DPP_VERSION,
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700552 pkex->Mx, curve->prime_len,
553 pkex->Nx, curve->prime_len, pkex->code,
554 Kx, Kx_len, pkex->z, curve->hash_len);
555 os_memset(Kx, 0, Kx_len);
556 if (res < 0)
557 goto fail;
558
559 pkex->exchange_done = 1;
560
561out:
Hai Shaloma20dcd72022-02-04 13:43:00 -0800562 os_free(x_coord);
563 os_free(y_coord);
564 crypto_ec_point_deinit(Qi, 1);
565 crypto_ec_point_deinit(Qr, 1);
566 crypto_ec_point_deinit(M, 1);
567 crypto_ec_point_deinit(N, 1);
568 crypto_ec_point_deinit(X, 1);
569 crypto_ec_deinit(ec);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700570 return pkex;
571fail:
572 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
573 dpp_pkex_free(pkex);
574 pkex = NULL;
575 goto out;
576}
577
578
579static struct wpabuf *
580dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
581 const struct wpabuf *A_pub, const u8 *u)
582{
583 const struct dpp_curve_params *curve = pkex->own_bi->curve;
584 struct wpabuf *msg = NULL;
585 size_t clear_len, attr_len;
586 struct wpabuf *clear = NULL;
587 u8 *wrapped;
588 u8 octet;
589 const u8 *addr[2];
590 size_t len[2];
591
592 /* {A, u, [bootstrapping info]}z */
593 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
594 clear = wpabuf_alloc(clear_len);
595 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
596#ifdef CONFIG_TESTING_OPTIONS
597 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
598 attr_len += 5;
599#endif /* CONFIG_TESTING_OPTIONS */
600 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
601 if (!clear || !msg)
602 goto fail;
603
604#ifdef CONFIG_TESTING_OPTIONS
605 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
606 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
607 goto skip_bootstrap_key;
608 }
609 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
610 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
611 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
612 wpabuf_put_le16(clear, 2 * curve->prime_len);
613 if (dpp_test_gen_invalid_key(clear, curve) < 0)
614 goto fail;
615 goto skip_bootstrap_key;
616 }
617#endif /* CONFIG_TESTING_OPTIONS */
618
619 /* A in Bootstrap Key attribute */
620 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
621 wpabuf_put_le16(clear, wpabuf_len(A_pub));
622 wpabuf_put_buf(clear, A_pub);
623
624#ifdef CONFIG_TESTING_OPTIONS
625skip_bootstrap_key:
626 if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
627 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
628 goto skip_i_auth_tag;
629 }
630 if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
631 wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
632 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
633 wpabuf_put_le16(clear, curve->hash_len);
634 wpabuf_put_data(clear, u, curve->hash_len - 1);
635 wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
636 goto skip_i_auth_tag;
637 }
638#endif /* CONFIG_TESTING_OPTIONS */
639
640 /* u in I-Auth tag attribute */
641 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
642 wpabuf_put_le16(clear, curve->hash_len);
643 wpabuf_put_data(clear, u, curve->hash_len);
644
645#ifdef CONFIG_TESTING_OPTIONS
646skip_i_auth_tag:
647 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
648 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
649 goto skip_wrapped_data;
650 }
651#endif /* CONFIG_TESTING_OPTIONS */
652
653 addr[0] = wpabuf_head_u8(msg) + 2;
654 len[0] = DPP_HDR_LEN;
655 octet = 0;
656 addr[1] = &octet;
657 len[1] = sizeof(octet);
658 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
659 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
660
661 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
662 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
663 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
664
665 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
666 if (aes_siv_encrypt(pkex->z, curve->hash_len,
667 wpabuf_head(clear), wpabuf_len(clear),
668 2, addr, len, wrapped) < 0)
669 goto fail;
670 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
671 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
672
673#ifdef CONFIG_TESTING_OPTIONS
674 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
675 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
676 dpp_build_attr_status(msg, DPP_STATUS_OK);
677 }
678skip_wrapped_data:
679#endif /* CONFIG_TESTING_OPTIONS */
680
681out:
682 wpabuf_free(clear);
683 return msg;
684
685fail:
686 wpabuf_free(msg);
687 msg = NULL;
688 goto out;
689}
690
691
692struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
693 const u8 *peer_mac,
694 const u8 *buf, size_t buflen)
695{
696 const u8 *attr_status, *attr_id, *attr_key, *attr_group;
697 u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800698 struct crypto_ec *ec = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700699 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
700 const struct dpp_curve_params *curve = pkex->own_bi->curve;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800701 struct crypto_ec_point *Qr = NULL, *Y = NULL, *N = NULL;
702 u8 *x_coord = NULL, *y_coord = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700703 size_t Jx_len, Kx_len;
704 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
705 const u8 *addr[4];
706 size_t len[4];
Hai Shaloma20dcd72022-02-04 13:43:00 -0800707 size_t num_elem;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700708 u8 u[DPP_MAX_HASH_LEN];
709 int res;
710
711 if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
712 return NULL;
713
714#ifdef CONFIG_TESTING_OPTIONS
715 if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
716 wpa_printf(MSG_INFO,
717 "DPP: TESTING - stop at PKEX Exchange Response");
718 pkex->failed = 1;
719 return NULL;
720 }
721
722 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
723 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
724 MAC2STR(dpp_pkex_peer_mac_override));
725 peer_mac = dpp_pkex_peer_mac_override;
726 }
727#endif /* CONFIG_TESTING_OPTIONS */
728
Hai Shaloma20dcd72022-02-04 13:43:00 -0800729#ifdef CONFIG_DPP2
730 if (pkex->v2) {
731 const u8 *version;
732 u16 version_len;
733
734 version = dpp_get_attr(buf, buflen, DPP_ATTR_PROTOCOL_VERSION,
735 &version_len);
736 if (!version || version_len < 1 || version[0] == 0) {
737 dpp_pkex_fail(pkex,
738 "Missing or invalid Protocol Version attribute");
739 return NULL;
740 }
741 pkex->peer_version = version[0];
742 wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
743 pkex->peer_version);
744 }
745#endif /* CONFIG_DPP2 */
746
747 if (peer_mac)
748 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700749
750 attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
751 &attr_status_len);
752 if (!attr_status || attr_status_len != 1) {
753 dpp_pkex_fail(pkex, "No DPP Status attribute");
754 return NULL;
755 }
756 wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
757
758 if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
759 attr_group = dpp_get_attr(buf, buflen,
760 DPP_ATTR_FINITE_CYCLIC_GROUP,
761 &attr_group_len);
762 if (attr_group && attr_group_len == 2) {
763 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
764 "Peer indicated mismatching PKEX group - proposed %u",
765 WPA_GET_LE16(attr_group));
766 return NULL;
767 }
768 }
769
770 if (attr_status[0] != DPP_STATUS_OK) {
771 dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
772 return NULL;
773 }
774
775 attr_id_len = 0;
776 attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
777 &attr_id_len);
778 if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
779 pkex->identifier)) {
780 dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
781 return NULL;
782 }
783
784 /* N in Encrypted Key attribute */
785 attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
786 &attr_key_len);
787 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
788 dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
789 return NULL;
790 }
791
Hai Shaloma20dcd72022-02-04 13:43:00 -0800792 /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
793 Qr = dpp_pkex_derive_Qr(curve, pkex->v2 ? NULL : pkex->peer_mac,
794 pkex->code, pkex->identifier, &ec);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700795 if (!Qr)
796 goto fail;
797
798 /* Y' = N - Qr */
Hai Shaloma20dcd72022-02-04 13:43:00 -0800799 Y = crypto_ec_point_init(ec);
800 N = crypto_ec_point_from_bin(ec, attr_key);
801 if (!Y || !N ||
802 crypto_ec_point_is_at_infinity(ec, N) ||
803 !crypto_ec_point_is_on_curve(ec, N) ||
804 crypto_ec_point_invert(ec, Qr) ||
805 crypto_ec_point_add(ec, N, Qr, Y) ||
806 crypto_ec_point_is_at_infinity(ec, Y) ||
807 !crypto_ec_point_is_on_curve(ec, Y)) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700808 dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
809 pkex->t++;
810 goto fail;
811 }
Hai Shaloma20dcd72022-02-04 13:43:00 -0800812 crypto_ec_point_debug_print(ec, N, "DPP: N");
813 crypto_ec_point_debug_print(ec, Y, "DPP: Y'");
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700814
815 pkex->exchange_done = 1;
816
817 /* ECDH: J = a * Y' */
Hai Shaloma20dcd72022-02-04 13:43:00 -0800818 x_coord = os_malloc(curve->prime_len);
819 y_coord = os_malloc(curve->prime_len);
820 if (!x_coord || !y_coord ||
821 crypto_ec_point_to_bin(ec, Y, x_coord, y_coord))
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700822 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800823 pkex->y = crypto_ec_key_set_pub(curve->ike_group, x_coord, y_coord,
824 curve->prime_len);
825 if (!pkex->y)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700826 goto fail;
827 if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
828 goto fail;
829
830 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
831 Jx, Jx_len);
832
Hai Shaloma20dcd72022-02-04 13:43:00 -0800833 /* u = HMAC(J.x, [MAC-Initiator |] A.x | Y'.x | X.x) */
834 A_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
835 Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
836 X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700837 if (!A_pub || !Y_pub || !X_pub)
838 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800839 num_elem = 0;
840 if (!pkex->v2) {
841 addr[num_elem] = pkex->own_mac;
842 len[num_elem] = ETH_ALEN;
843 num_elem++;
844 }
845 addr[num_elem] = wpabuf_head(A_pub);
846 len[num_elem] = wpabuf_len(A_pub) / 2;
847 num_elem++;
848 addr[num_elem] = wpabuf_head(Y_pub);
849 len[num_elem] = wpabuf_len(Y_pub) / 2;
850 num_elem++;
851 addr[num_elem] = wpabuf_head(X_pub);
852 len[num_elem] = wpabuf_len(X_pub) / 2;
853 num_elem++;
854 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u)
855 < 0)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700856 goto fail;
857 wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
858
859 /* K = x * Y' */
860 if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
861 goto fail;
862
863 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
864 Kx, Kx_len);
865
Hai Shaloma20dcd72022-02-04 13:43:00 -0800866 /* z = HKDF(<>, info | M.x | N.x | code, K.x) */
867 res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->own_mac,
868 pkex->v2 ? NULL : pkex->peer_mac,
869 DPP_VERSION, pkex->peer_version,
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700870 pkex->Mx, curve->prime_len,
871 attr_key /* N.x */, attr_key_len / 2,
872 pkex->code, Kx, Kx_len,
873 pkex->z, curve->hash_len);
874 os_memset(Kx, 0, Kx_len);
875 if (res < 0)
876 goto fail;
877
878 msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
879 if (!msg)
880 goto fail;
881
882out:
883 wpabuf_free(A_pub);
884 wpabuf_free(X_pub);
885 wpabuf_free(Y_pub);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800886 os_free(x_coord);
887 os_free(y_coord);
888 crypto_ec_point_deinit(Qr, 1);
889 crypto_ec_point_deinit(Y, 1);
890 crypto_ec_point_deinit(N, 1);
891 crypto_ec_deinit(ec);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700892 return msg;
893fail:
894 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
895 goto out;
896}
897
898
899static struct wpabuf *
900dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
901 const struct wpabuf *B_pub, const u8 *v)
902{
903 const struct dpp_curve_params *curve = pkex->own_bi->curve;
904 struct wpabuf *msg = NULL;
905 const u8 *addr[2];
906 size_t len[2];
907 u8 octet;
908 u8 *wrapped;
909 struct wpabuf *clear = NULL;
910 size_t clear_len, attr_len;
911
912 /* {B, v [bootstrapping info]}z */
913 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
914 clear = wpabuf_alloc(clear_len);
915 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
916#ifdef CONFIG_TESTING_OPTIONS
917 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
918 attr_len += 5;
919#endif /* CONFIG_TESTING_OPTIONS */
920 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
921 if (!clear || !msg)
922 goto fail;
923
924#ifdef CONFIG_TESTING_OPTIONS
925 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
926 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
927 goto skip_bootstrap_key;
928 }
929 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
930 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
931 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
932 wpabuf_put_le16(clear, 2 * curve->prime_len);
933 if (dpp_test_gen_invalid_key(clear, curve) < 0)
934 goto fail;
935 goto skip_bootstrap_key;
936 }
937#endif /* CONFIG_TESTING_OPTIONS */
938
939 /* B in Bootstrap Key attribute */
940 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
941 wpabuf_put_le16(clear, wpabuf_len(B_pub));
942 wpabuf_put_buf(clear, B_pub);
943
944#ifdef CONFIG_TESTING_OPTIONS
945skip_bootstrap_key:
946 if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
947 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
948 goto skip_r_auth_tag;
949 }
950 if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
951 wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
952 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
953 wpabuf_put_le16(clear, curve->hash_len);
954 wpabuf_put_data(clear, v, curve->hash_len - 1);
955 wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
956 goto skip_r_auth_tag;
957 }
958#endif /* CONFIG_TESTING_OPTIONS */
959
960 /* v in R-Auth tag attribute */
961 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
962 wpabuf_put_le16(clear, curve->hash_len);
963 wpabuf_put_data(clear, v, curve->hash_len);
964
965#ifdef CONFIG_TESTING_OPTIONS
966skip_r_auth_tag:
967 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
968 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
969 goto skip_wrapped_data;
970 }
971#endif /* CONFIG_TESTING_OPTIONS */
972
973 addr[0] = wpabuf_head_u8(msg) + 2;
974 len[0] = DPP_HDR_LEN;
975 octet = 1;
976 addr[1] = &octet;
977 len[1] = sizeof(octet);
978 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
979 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
980
981 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
982 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
983 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
984
985 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
986 if (aes_siv_encrypt(pkex->z, curve->hash_len,
987 wpabuf_head(clear), wpabuf_len(clear),
988 2, addr, len, wrapped) < 0)
989 goto fail;
990 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
991 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
992
993#ifdef CONFIG_TESTING_OPTIONS
994 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
995 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
996 dpp_build_attr_status(msg, DPP_STATUS_OK);
997 }
998skip_wrapped_data:
999#endif /* CONFIG_TESTING_OPTIONS */
1000
1001out:
1002 wpabuf_free(clear);
1003 return msg;
1004
1005fail:
1006 wpabuf_free(msg);
1007 msg = NULL;
1008 goto out;
1009}
1010
1011
1012struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
1013 const u8 *hdr,
1014 const u8 *buf, size_t buflen)
1015{
1016 const struct dpp_curve_params *curve = pkex->own_bi->curve;
1017 size_t Jx_len, Lx_len;
1018 u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
1019 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
1020 const u8 *wrapped_data, *b_key, *peer_u;
1021 u16 wrapped_data_len, b_key_len, peer_u_len = 0;
1022 const u8 *addr[4];
1023 size_t len[4];
Hai Shaloma20dcd72022-02-04 13:43:00 -08001024 size_t num_elem;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001025 u8 octet;
1026 u8 *unwrapped = NULL;
1027 size_t unwrapped_len = 0;
1028 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
1029 struct wpabuf *B_pub = NULL;
1030 u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
1031
1032#ifdef CONFIG_TESTING_OPTIONS
1033 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
1034 wpa_printf(MSG_INFO,
1035 "DPP: TESTING - stop at PKEX CR Request");
1036 pkex->failed = 1;
1037 return NULL;
1038 }
1039#endif /* CONFIG_TESTING_OPTIONS */
1040
1041 if (!pkex->exchange_done || pkex->failed ||
1042 pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
1043 goto fail;
1044
1045 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
1046 &wrapped_data_len);
1047 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
1048 dpp_pkex_fail(pkex,
1049 "Missing or invalid required Wrapped Data attribute");
1050 goto fail;
1051 }
1052
1053 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1054 wrapped_data, wrapped_data_len);
1055 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1056 unwrapped = os_malloc(unwrapped_len);
1057 if (!unwrapped)
1058 goto fail;
1059
1060 addr[0] = hdr;
1061 len[0] = DPP_HDR_LEN;
1062 octet = 0;
1063 addr[1] = &octet;
1064 len[1] = sizeof(octet);
1065 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1066 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1067
1068 if (aes_siv_decrypt(pkex->z, curve->hash_len,
1069 wrapped_data, wrapped_data_len,
1070 2, addr, len, unwrapped) < 0) {
1071 dpp_pkex_fail(pkex,
1072 "AES-SIV decryption failed - possible PKEX code mismatch");
1073 pkex->failed = 1;
1074 pkex->t++;
1075 goto fail;
1076 }
1077 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1078 unwrapped, unwrapped_len);
1079
1080 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1081 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
1082 goto fail;
1083 }
1084
1085 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
1086 &b_key_len);
1087 if (!b_key || b_key_len != 2 * curve->prime_len) {
1088 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
1089 goto fail;
1090 }
1091 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
1092 b_key_len);
1093 if (!pkex->peer_bootstrap_key) {
1094 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
1095 goto fail;
1096 }
1097 dpp_debug_print_key("DPP: Peer bootstrap public key",
1098 pkex->peer_bootstrap_key);
1099
1100 /* ECDH: J' = y * A' */
1101 if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
1102 goto fail;
1103
1104 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
1105 Jx, Jx_len);
1106
Hai Shaloma20dcd72022-02-04 13:43:00 -08001107 /* u' = HMAC(J'.x, [MAC-Initiator |] A'.x | Y.x | X'.x) */
1108 A_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
1109 Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
1110 X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001111 if (!A_pub || !Y_pub || !X_pub)
1112 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001113 num_elem = 0;
1114 if (!pkex->v2) {
1115 addr[num_elem] = pkex->peer_mac;
1116 len[num_elem] = ETH_ALEN;
1117 num_elem++;
1118 }
1119 addr[num_elem] = wpabuf_head(A_pub);
1120 len[num_elem] = wpabuf_len(A_pub) / 2;
1121 num_elem++;
1122 addr[num_elem] = wpabuf_head(Y_pub);
1123 len[num_elem] = wpabuf_len(Y_pub) / 2;
1124 num_elem++;
1125 addr[num_elem] = wpabuf_head(X_pub);
1126 len[num_elem] = wpabuf_len(X_pub) / 2;
1127 num_elem++;
1128 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u)
1129 < 0)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001130 goto fail;
1131
1132 peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
1133 &peer_u_len);
1134 if (!peer_u || peer_u_len != curve->hash_len ||
1135 os_memcmp(peer_u, u, curve->hash_len) != 0) {
1136 dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
1137 wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
1138 u, curve->hash_len);
1139 wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
1140 pkex->t++;
1141 goto fail;
1142 }
1143 wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
1144
1145 /* ECDH: L = b * X' */
1146 if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
1147 goto fail;
1148
1149 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
1150 Lx, Lx_len);
1151
Hai Shaloma20dcd72022-02-04 13:43:00 -08001152 /* v = HMAC(L.x, [MAC-Responder |] B.x | X'.x | Y.x) */
1153 B_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001154 if (!B_pub)
1155 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001156 num_elem = 0;
1157 if (!pkex->v2) {
1158 addr[num_elem] = pkex->own_mac;
1159 len[num_elem] = ETH_ALEN;
1160 num_elem++;
1161 }
1162 addr[num_elem] = wpabuf_head(B_pub);
1163 len[num_elem] = wpabuf_len(B_pub) / 2;
1164 num_elem++;
1165 addr[num_elem] = wpabuf_head(X_pub);
1166 len[num_elem] = wpabuf_len(X_pub) / 2;
1167 num_elem++;
1168 addr[num_elem] = wpabuf_head(Y_pub);
1169 len[num_elem] = wpabuf_len(Y_pub) / 2;
1170 num_elem++;
1171 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v)
1172 < 0)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001173 goto fail;
1174 wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
1175
1176 msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
1177 if (!msg)
1178 goto fail;
1179
1180out:
1181 os_free(unwrapped);
1182 wpabuf_free(A_pub);
1183 wpabuf_free(B_pub);
1184 wpabuf_free(X_pub);
1185 wpabuf_free(Y_pub);
1186 return msg;
1187fail:
1188 wpa_printf(MSG_DEBUG,
1189 "DPP: PKEX Commit-Reveal Request processing failed");
1190 goto out;
1191}
1192
1193
1194int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
1195 const u8 *buf, size_t buflen)
1196{
1197 const struct dpp_curve_params *curve = pkex->own_bi->curve;
1198 const u8 *wrapped_data, *b_key, *peer_v;
1199 u16 wrapped_data_len, b_key_len, peer_v_len = 0;
1200 const u8 *addr[4];
1201 size_t len[4];
Hai Shaloma20dcd72022-02-04 13:43:00 -08001202 size_t num_elem;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001203 u8 octet;
1204 u8 *unwrapped = NULL;
1205 size_t unwrapped_len = 0;
1206 int ret = -1;
1207 u8 v[DPP_MAX_HASH_LEN];
1208 size_t Lx_len;
1209 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
1210 struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
1211
1212#ifdef CONFIG_TESTING_OPTIONS
1213 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
1214 wpa_printf(MSG_INFO,
1215 "DPP: TESTING - stop at PKEX CR Response");
1216 pkex->failed = 1;
1217 goto fail;
1218 }
1219#endif /* CONFIG_TESTING_OPTIONS */
1220
1221 if (!pkex->exchange_done || pkex->failed ||
1222 pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
1223 goto fail;
1224
1225 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
1226 &wrapped_data_len);
1227 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
1228 dpp_pkex_fail(pkex,
1229 "Missing or invalid required Wrapped Data attribute");
1230 goto fail;
1231 }
1232
1233 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1234 wrapped_data, wrapped_data_len);
1235 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1236 unwrapped = os_malloc(unwrapped_len);
1237 if (!unwrapped)
1238 goto fail;
1239
1240 addr[0] = hdr;
1241 len[0] = DPP_HDR_LEN;
1242 octet = 1;
1243 addr[1] = &octet;
1244 len[1] = sizeof(octet);
1245 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1246 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1247
1248 if (aes_siv_decrypt(pkex->z, curve->hash_len,
1249 wrapped_data, wrapped_data_len,
1250 2, addr, len, unwrapped) < 0) {
1251 dpp_pkex_fail(pkex,
1252 "AES-SIV decryption failed - possible PKEX code mismatch");
1253 pkex->t++;
1254 goto fail;
1255 }
1256 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1257 unwrapped, unwrapped_len);
1258
1259 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1260 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
1261 goto fail;
1262 }
1263
1264 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
1265 &b_key_len);
1266 if (!b_key || b_key_len != 2 * curve->prime_len) {
1267 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
1268 goto fail;
1269 }
1270 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
1271 b_key_len);
1272 if (!pkex->peer_bootstrap_key) {
1273 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
1274 goto fail;
1275 }
1276 dpp_debug_print_key("DPP: Peer bootstrap public key",
1277 pkex->peer_bootstrap_key);
1278
1279 /* ECDH: L' = x * B' */
1280 if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
1281 goto fail;
1282
1283 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
1284 Lx, Lx_len);
1285
Hai Shaloma20dcd72022-02-04 13:43:00 -08001286 /* v' = HMAC(L.x, [MAC-Responder |] B'.x | X.x | Y'.x) */
1287 B_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
1288 X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
1289 Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001290 if (!B_pub || !X_pub || !Y_pub)
1291 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001292 num_elem = 0;
1293 if (!pkex->v2) {
1294 addr[num_elem] = pkex->peer_mac;
1295 len[num_elem] = ETH_ALEN;
1296 num_elem++;
1297 }
1298 addr[num_elem] = wpabuf_head(B_pub);
1299 len[num_elem] = wpabuf_len(B_pub) / 2;
1300 num_elem++;
1301 addr[num_elem] = wpabuf_head(X_pub);
1302 len[num_elem] = wpabuf_len(X_pub) / 2;
1303 num_elem++;
1304 addr[num_elem] = wpabuf_head(Y_pub);
1305 len[num_elem] = wpabuf_len(Y_pub) / 2;
1306 num_elem++;
1307 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v)
1308 < 0)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001309 goto fail;
1310
1311 peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
1312 &peer_v_len);
1313 if (!peer_v || peer_v_len != curve->hash_len ||
1314 os_memcmp(peer_v, v, curve->hash_len) != 0) {
1315 dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
1316 wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
1317 v, curve->hash_len);
1318 wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
1319 pkex->t++;
1320 goto fail;
1321 }
1322 wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
1323
1324 ret = 0;
1325out:
1326 wpabuf_free(B_pub);
1327 wpabuf_free(X_pub);
1328 wpabuf_free(Y_pub);
1329 os_free(unwrapped);
1330 return ret;
1331fail:
1332 goto out;
1333}
1334
1335
1336struct dpp_bootstrap_info *
1337dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
1338 unsigned int freq)
1339{
1340 struct dpp_bootstrap_info *bi;
1341
1342 bi = os_zalloc(sizeof(*bi));
1343 if (!bi)
1344 return NULL;
1345 bi->id = dpp_next_id(dpp);
1346 bi->type = DPP_BOOTSTRAP_PKEX;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001347 if (peer)
1348 os_memcpy(bi->mac_addr, peer, ETH_ALEN);
1349 if (freq) {
1350 bi->num_freq = 1;
1351 bi->freq[0] = freq;
1352 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001353 bi->curve = pkex->own_bi->curve;
1354 bi->pubkey = pkex->peer_bootstrap_key;
1355 pkex->peer_bootstrap_key = NULL;
1356 if (dpp_bootstrap_key_hash(bi) < 0) {
1357 dpp_bootstrap_info_free(bi);
1358 return NULL;
1359 }
1360 dpp_pkex_free(pkex);
1361 dl_list_add(&dpp->bootstrap, &bi->list);
1362 return bi;
1363}
1364
1365
1366void dpp_pkex_free(struct dpp_pkex *pkex)
1367{
1368 if (!pkex)
1369 return;
1370
1371 os_free(pkex->identifier);
1372 os_free(pkex->code);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001373 crypto_ec_key_deinit(pkex->x);
1374 crypto_ec_key_deinit(pkex->y);
1375 crypto_ec_key_deinit(pkex->peer_bootstrap_key);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001376 wpabuf_free(pkex->exchange_req);
1377 wpabuf_free(pkex->exchange_resp);
1378 os_free(pkex);
1379}