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