1 /* 2 * DPP reconfiguration 3 * Copyright (c) 2020, The Linux Foundation 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "utils/includes.h" 10 11 #include "utils/common.h" 12 #include "utils/json.h" 13 #include "crypto/crypto.h" 14 #include "crypto/random.h" 15 #include "crypto/aes.h" 16 #include "crypto/aes_siv.h" 17 #include "dpp.h" 18 #include "dpp_i.h" 19 20 21 #ifdef CONFIG_DPP2 22 23 static void dpp_build_attr_csign_key_hash(struct wpabuf *msg, const u8 *hash) 24 { 25 if (hash) { 26 wpa_printf(MSG_DEBUG, "DPP: Configurator C-sign key Hash"); 27 wpabuf_put_le16(msg, DPP_ATTR_C_SIGN_KEY_HASH); 28 wpabuf_put_le16(msg, SHA256_MAC_LEN); 29 wpabuf_put_data(msg, hash, SHA256_MAC_LEN); 30 } 31 } 32 33 34 struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key, 35 size_t csign_key_len, 36 const u8 *net_access_key, 37 size_t net_access_key_len, 38 struct dpp_reconfig_id *id) 39 { 40 struct wpabuf *msg = NULL; 41 struct crypto_ec_key *csign = NULL; 42 struct wpabuf *uncomp; 43 u8 hash[SHA256_MAC_LEN]; 44 const u8 *addr[1]; 45 size_t len[1]; 46 int res; 47 size_t attr_len; 48 const struct dpp_curve_params *own_curve; 49 struct crypto_ec_key *own_key; 50 struct wpabuf *a_nonce = NULL, *e_id = NULL; 51 52 wpa_printf(MSG_DEBUG, "DPP: Build Reconfig Announcement frame"); 53 54 own_key = dpp_set_keypair(&own_curve, net_access_key, 55 net_access_key_len); 56 if (!own_key) { 57 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey"); 58 goto fail; 59 } 60 61 csign = crypto_ec_key_parse_pub(csign_key, csign_key_len); 62 if (!csign) { 63 wpa_printf(MSG_ERROR, 64 "DPP: Failed to parse local C-sign-key information"); 65 goto fail; 66 } 67 68 uncomp = crypto_ec_key_get_pubkey_point(csign, 1); 69 crypto_ec_key_deinit(csign); 70 if (!uncomp) 71 goto fail; 72 addr[0] = wpabuf_head(uncomp); 73 len[0] = wpabuf_len(uncomp); 74 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed C-sign key", addr[0], len[0]); 75 res = sha256_vector(1, addr, len, hash); 76 wpabuf_free(uncomp); 77 if (res < 0) 78 goto fail; 79 wpa_hexdump(MSG_DEBUG, "DPP: kid = SHA256(uncompressed C-sign key)", 80 hash, SHA256_MAC_LEN); 81 82 if (dpp_update_reconfig_id(id) < 0) { 83 wpa_printf(MSG_ERROR, "DPP: Failed to generate E'-id"); 84 goto fail; 85 } 86 87 a_nonce = crypto_ec_key_get_pubkey_point(id->a_nonce, 0); 88 e_id = crypto_ec_key_get_pubkey_point(id->e_prime_id, 0); 89 if (!a_nonce || !e_id) 90 goto fail; 91 92 attr_len = 4 + SHA256_MAC_LEN; 93 attr_len += 4 + 2; 94 attr_len += 4 + wpabuf_len(a_nonce); 95 attr_len += 4 + wpabuf_len(e_id); 96 msg = dpp_alloc_msg(DPP_PA_RECONFIG_ANNOUNCEMENT, attr_len); 97 if (!msg) 98 goto fail; 99 100 /* Configurator C-sign key Hash */ 101 dpp_build_attr_csign_key_hash(msg, hash); 102 103 /* Finite Cyclic Group attribute */ 104 wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u", 105 own_curve->ike_group); 106 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP); 107 wpabuf_put_le16(msg, 2); 108 wpabuf_put_le16(msg, own_curve->ike_group); 109 110 /* A-NONCE */ 111 wpabuf_put_le16(msg, DPP_ATTR_A_NONCE); 112 wpabuf_put_le16(msg, wpabuf_len(a_nonce)); 113 wpabuf_put_buf(msg, a_nonce); 114 115 /* E'-id */ 116 wpabuf_put_le16(msg, DPP_ATTR_E_PRIME_ID); 117 wpabuf_put_le16(msg, wpabuf_len(e_id)); 118 wpabuf_put_buf(msg, e_id); 119 120 wpa_hexdump_buf(MSG_DEBUG, 121 "DPP: Reconfig Announcement frame attributes", msg); 122 fail: 123 wpabuf_free(a_nonce); 124 wpabuf_free(e_id); 125 crypto_ec_key_deinit(own_key); 126 return msg; 127 } 128 129 130 static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth) 131 { 132 struct wpabuf *msg; 133 size_t attr_len; 134 u8 ver = DPP_VERSION; 135 136 /* Build DPP Reconfig Authentication Request frame attributes */ 137 attr_len = 4 + 1 + 4 + 1 + 4 + os_strlen(auth->conf->connector) + 138 4 + auth->curve->nonce_len; 139 msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_REQ, attr_len); 140 if (!msg) 141 return NULL; 142 143 /* Transaction ID */ 144 wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); 145 wpabuf_put_le16(msg, 1); 146 wpabuf_put_u8(msg, auth->transaction_id); 147 148 #ifdef CONFIG_TESTING_OPTIONS 149 if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) { 150 wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version"); 151 goto skip_proto_ver; 152 } 153 if (dpp_test == DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) { 154 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Protocol Version"); 155 ver = 1; 156 } 157 #endif /* CONFIG_TESTING_OPTIONS */ 158 159 /* Protocol Version */ 160 wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); 161 wpabuf_put_le16(msg, 1); 162 wpabuf_put_u8(msg, ver); 163 164 #ifdef CONFIG_TESTING_OPTIONS 165 skip_proto_ver: 166 #endif /* CONFIG_TESTING_OPTIONS */ 167 168 /* DPP Connector */ 169 wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); 170 wpabuf_put_le16(msg, os_strlen(auth->conf->connector)); 171 wpabuf_put_str(msg, auth->conf->connector); 172 173 /* C-nonce */ 174 wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE); 175 wpabuf_put_le16(msg, auth->curve->nonce_len); 176 wpabuf_put_data(msg, auth->c_nonce, auth->curve->nonce_len); 177 178 wpa_hexdump_buf(MSG_DEBUG, 179 "DPP: Reconfig Authentication Request frame attributes", 180 msg); 181 182 return msg; 183 } 184 185 186 static int 187 dpp_configurator_build_own_connector(struct dpp_configurator *conf, 188 const struct dpp_curve_params *curve) 189 { 190 struct wpabuf *dppcon = NULL; 191 int ret = -1; 192 193 if (conf->connector) 194 return 0; /* already generated */ 195 196 wpa_printf(MSG_DEBUG, 197 "DPP: Sign own Configurator Connector for reconfiguration with curve %s", 198 conf->curve->name); 199 conf->connector_key = dpp_gen_keypair(curve); 200 if (!conf->connector_key) 201 goto fail; 202 203 /* Connector (JSON dppCon object) */ 204 dppcon = wpabuf_alloc(1000 + 2 * curve->prime_len * 4 / 3); 205 if (!dppcon) 206 goto fail; 207 json_start_object(dppcon, NULL); 208 json_start_array(dppcon, "groups"); 209 json_start_object(dppcon, NULL); 210 json_add_string(dppcon, "groupId", "*"); 211 json_value_sep(dppcon); 212 json_add_string(dppcon, "netRole", "configurator"); 213 json_end_object(dppcon); 214 json_end_array(dppcon); 215 json_value_sep(dppcon); 216 if (dpp_build_jwk(dppcon, "netAccessKey", conf->connector_key, NULL, 217 curve) < 0) { 218 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK"); 219 goto fail; 220 } 221 json_end_object(dppcon); 222 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s", 223 (const char *) wpabuf_head(dppcon)); 224 225 conf->connector = dpp_sign_connector(conf, dppcon); 226 if (!conf->connector) 227 goto fail; 228 wpa_printf(MSG_DEBUG, "DPP: signedConnector: %s", conf->connector); 229 230 ret = 0; 231 fail: 232 wpabuf_free(dppcon); 233 return ret; 234 } 235 236 237 struct dpp_authentication * 238 dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx, 239 struct dpp_configurator *conf, unsigned int freq, u16 group, 240 const u8 *a_nonce_attr, size_t a_nonce_len, 241 const u8 *e_id_attr, size_t e_id_len) 242 { 243 struct dpp_authentication *auth; 244 const struct dpp_curve_params *curve; 245 struct crypto_ec_key *a_nonce, *e_prime_id; 246 struct crypto_ec_point *e_id; 247 248 curve = dpp_get_curve_ike_group(group); 249 if (!curve) { 250 wpa_printf(MSG_DEBUG, 251 "DPP: Unsupported group %u - cannot reconfigure", 252 group); 253 return NULL; 254 } 255 256 if (!a_nonce_attr) { 257 wpa_printf(MSG_INFO, "DPP: Missing required A-NONCE attribute"); 258 return NULL; 259 } 260 wpa_hexdump(MSG_MSGDUMP, "DPP: A-NONCE", a_nonce_attr, a_nonce_len); 261 a_nonce = dpp_set_pubkey_point(conf->csign, a_nonce_attr, a_nonce_len); 262 if (!a_nonce) { 263 wpa_printf(MSG_INFO, "DPP: Invalid A-NONCE"); 264 return NULL; 265 } 266 dpp_debug_print_key("A-NONCE", a_nonce); 267 268 if (!e_id_attr) { 269 wpa_printf(MSG_INFO, "DPP: Missing required E'-id attribute"); 270 return NULL; 271 } 272 e_prime_id = dpp_set_pubkey_point(conf->csign, e_id_attr, e_id_len); 273 if (!e_prime_id) { 274 wpa_printf(MSG_INFO, "DPP: Invalid E'-id"); 275 crypto_ec_key_deinit(a_nonce); 276 return NULL; 277 } 278 dpp_debug_print_key("E'-id", e_prime_id); 279 e_id = dpp_decrypt_e_id(conf->pp_key, a_nonce, e_prime_id); 280 crypto_ec_key_deinit(a_nonce); 281 crypto_ec_key_deinit(e_prime_id); 282 if (!e_id) { 283 wpa_printf(MSG_INFO, "DPP: Could not decrypt E'-id"); 284 return NULL; 285 } 286 /* TODO: could use E-id to determine whether reconfiguration with this 287 * Enrollee has already been started and is waiting for updated 288 * configuration instead of replying again before such configuration 289 * becomes available */ 290 crypto_ec_point_deinit(e_id, 1); 291 292 auth = dpp_alloc_auth(dpp, msg_ctx); 293 if (!auth) 294 return NULL; 295 296 auth->conf = conf; 297 auth->reconfig = 1; 298 auth->initiator = 1; 299 auth->waiting_auth_resp = 1; 300 auth->allowed_roles = DPP_CAPAB_CONFIGURATOR; 301 auth->configurator = 1; 302 auth->curve = curve; 303 auth->transaction_id = 1; 304 if (freq && dpp_prepare_channel_list(auth, freq, NULL, 0) < 0) 305 goto fail; 306 307 if (dpp_configurator_build_own_connector(conf, curve) < 0) 308 goto fail; 309 310 if (random_get_bytes(auth->c_nonce, auth->curve->nonce_len)) { 311 wpa_printf(MSG_ERROR, "DPP: Failed to generate C-nonce"); 312 goto fail; 313 } 314 315 auth->reconfig_req_msg = dpp_reconfig_build_req(auth); 316 if (!auth->reconfig_req_msg) 317 goto fail; 318 319 out: 320 return auth; 321 fail: 322 dpp_auth_deinit(auth); 323 auth = NULL; 324 goto out; 325 } 326 327 328 static int dpp_reconfig_build_resp(struct dpp_authentication *auth, 329 const char *own_connector, 330 struct wpabuf *conn_status) 331 { 332 struct wpabuf *msg = NULL, *clear, *pr = NULL; 333 u8 *attr_start, *attr_end; 334 size_t clear_len, attr_len, len[2]; 335 const u8 *addr[2]; 336 u8 *wrapped; 337 int res = -1; 338 339 /* Build DPP Reconfig Authentication Response frame attributes */ 340 clear_len = 4 + auth->curve->nonce_len + 341 4 + wpabuf_len(conn_status); 342 clear = wpabuf_alloc(clear_len); 343 if (!clear) 344 goto fail; 345 346 /* C-nonce (wrapped) */ 347 wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE); 348 wpabuf_put_le16(clear, auth->curve->nonce_len); 349 wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len); 350 351 /* Connection Status (wrapped) */ 352 wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS); 353 wpabuf_put_le16(clear, wpabuf_len(conn_status)); 354 wpabuf_put_buf(clear, conn_status); 355 356 pr = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0); 357 if (!pr) 358 goto fail; 359 360 attr_len = 4 + 1 + 4 + 1 + 361 4 + os_strlen(own_connector) + 362 4 + auth->curve->nonce_len + 363 4 + wpabuf_len(pr) + 364 4 + wpabuf_len(clear) + AES_BLOCK_SIZE; 365 msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_RESP, attr_len); 366 if (!msg) 367 goto fail; 368 369 attr_start = wpabuf_put(msg, 0); 370 371 /* Transaction ID */ 372 wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); 373 wpabuf_put_le16(msg, 1); 374 wpabuf_put_u8(msg, auth->transaction_id); 375 376 /* Protocol Version */ 377 wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); 378 wpabuf_put_le16(msg, 1); 379 wpabuf_put_u8(msg, DPP_VERSION); 380 381 /* R-Connector */ 382 wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); 383 wpabuf_put_le16(msg, os_strlen(own_connector)); 384 wpabuf_put_str(msg, own_connector); 385 386 /* E-nonce */ 387 wpabuf_put_le16(msg, DPP_ATTR_ENROLLEE_NONCE); 388 wpabuf_put_le16(msg, auth->curve->nonce_len); 389 wpabuf_put_data(msg, auth->e_nonce, auth->curve->nonce_len); 390 391 /* Responder Protocol Key (Pr) */ 392 wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY); 393 wpabuf_put_le16(msg, wpabuf_len(pr)); 394 wpabuf_put_buf(msg, pr); 395 396 attr_end = wpabuf_put(msg, 0); 397 398 /* OUI, OUI type, Crypto Suite, DPP frame type */ 399 addr[0] = wpabuf_head_u8(msg) + 2; 400 len[0] = 3 + 1 + 1 + 1; 401 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 402 403 /* Attributes before Wrapped Data */ 404 addr[1] = attr_start; 405 len[1] = attr_end - attr_start; 406 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 407 408 /* Wrapped Data: {C-nonce, E-nonce, Connection Status}ke */ 409 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 410 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 411 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 412 413 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 414 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 415 wpabuf_head(clear), wpabuf_len(clear), 416 2, addr, len, wrapped) < 0) 417 goto fail; 418 419 wpa_hexdump_buf(MSG_DEBUG, 420 "DPP: Reconfig Authentication Response frame attributes", 421 msg); 422 423 wpabuf_free(auth->reconfig_resp_msg); 424 auth->reconfig_resp_msg = msg; 425 426 res = 0; 427 out: 428 wpabuf_free(clear); 429 wpabuf_free(pr); 430 return res; 431 fail: 432 wpabuf_free(msg); 433 goto out; 434 } 435 436 437 struct dpp_authentication * 438 dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, 439 const char *own_connector, 440 const u8 *net_access_key, size_t net_access_key_len, 441 const u8 *csign_key, size_t csign_key_len, 442 unsigned int freq, const u8 *hdr, 443 const u8 *attr_start, size_t attr_len) 444 { 445 struct dpp_authentication *auth = NULL; 446 const u8 *trans_id, *version, *i_connector, *c_nonce; 447 u16 trans_id_len, version_len, i_connector_len, c_nonce_len; 448 struct dpp_signed_connector_info info; 449 enum dpp_status_error res; 450 struct json_token *root = NULL, *own_root = NULL, *token; 451 unsigned char *own_conn = NULL; 452 struct wpabuf *conn_status = NULL; 453 454 os_memset(&info, 0, sizeof(info)); 455 456 trans_id = dpp_get_attr(attr_start, attr_len, DPP_ATTR_TRANSACTION_ID, 457 &trans_id_len); 458 if (!trans_id || trans_id_len != 1) { 459 wpa_printf(MSG_DEBUG, 460 "DPP: Peer did not include Transaction ID"); 461 goto fail; 462 } 463 464 version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION, 465 &version_len); 466 if (!version || version_len < 1 || version[0] < 2) { 467 wpa_printf(MSG_DEBUG, 468 "DPP: Missing or invalid Protocol Version attribute"); 469 goto fail; 470 } 471 472 i_connector = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CONNECTOR, 473 &i_connector_len); 474 if (!i_connector) { 475 wpa_printf(MSG_DEBUG, "DPP: Missing I-Connector attribute"); 476 goto fail; 477 } 478 wpa_hexdump_ascii(MSG_DEBUG, "DPP: I-Connector", 479 i_connector, i_connector_len); 480 481 c_nonce = dpp_get_attr(attr_start, attr_len, 482 DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len); 483 if (!c_nonce || c_nonce_len > DPP_MAX_NONCE_LEN) { 484 wpa_printf(MSG_DEBUG, 485 "DPP: Missing or invalid C-nonce attribute"); 486 goto fail; 487 } 488 wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len); 489 490 res = dpp_check_signed_connector(&info, csign_key, csign_key_len, 491 i_connector, i_connector_len); 492 if (res != DPP_STATUS_OK) { 493 wpa_printf(MSG_DEBUG, "DPP: Invalid I-Connector"); 494 goto fail; 495 } 496 497 root = json_parse((const char *) info.payload, info.payload_len); 498 own_root = dpp_parse_own_connector(own_connector); 499 if (!root || !own_root || 500 !dpp_connector_match_groups(own_root, root, true)) { 501 wpa_printf(MSG_DEBUG, 502 "DPP: I-Connector does not include compatible group netrole with own connector"); 503 goto fail; 504 } 505 506 token = json_get_member(root, "expiry"); 507 if (token && token->type == JSON_STRING && 508 dpp_key_expired(token->string, NULL)) { 509 wpa_printf(MSG_DEBUG, 510 "DPP: I-Connector (netAccessKey) has expired"); 511 goto fail; 512 } 513 514 token = json_get_member(root, "netAccessKey"); 515 if (!token || token->type != JSON_OBJECT) { 516 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found"); 517 goto fail; 518 } 519 520 auth = dpp_alloc_auth(dpp, msg_ctx); 521 if (!auth) 522 return NULL; 523 524 auth->reconfig = 1; 525 auth->allowed_roles = DPP_CAPAB_ENROLLEE; 526 if (dpp_prepare_channel_list(auth, freq, NULL, 0) < 0) 527 goto fail; 528 529 auth->transaction_id = trans_id[0]; 530 531 auth->peer_version = version[0]; 532 wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u", 533 auth->peer_version); 534 535 os_memcpy(auth->c_nonce, c_nonce, c_nonce_len); 536 537 if (dpp_reconfig_derive_ke_responder(auth, net_access_key, 538 net_access_key_len, token) < 0) 539 goto fail; 540 541 if (c_nonce_len != auth->curve->nonce_len) { 542 wpa_printf(MSG_DEBUG, 543 "DPP: Unexpected C-nonce length %u (curve nonce len %zu)", 544 c_nonce_len, auth->curve->nonce_len); 545 goto fail; 546 } 547 548 /* Build Connection Status object */ 549 /* TODO: Get appropriate result value */ 550 /* TODO: ssid64 and channelList */ 551 conn_status = dpp_build_conn_status(DPP_STATUS_NO_AP, NULL, 0, NULL); 552 if (!conn_status) 553 goto fail; 554 555 if (dpp_reconfig_build_resp(auth, own_connector, conn_status) < 0) 556 goto fail; 557 558 out: 559 os_free(info.payload); 560 os_free(own_conn); 561 json_free(root); 562 json_free(own_root); 563 wpabuf_free(conn_status); 564 return auth; 565 fail: 566 dpp_auth_deinit(auth); 567 auth = NULL; 568 goto out; 569 } 570 571 572 struct wpabuf * 573 dpp_reconfig_build_conf(struct dpp_authentication *auth) 574 { 575 struct wpabuf *msg = NULL, *clear; 576 u8 *attr_start, *attr_end; 577 size_t clear_len, attr_len, len[2]; 578 const u8 *addr[2]; 579 u8 *wrapped; 580 u8 flags; 581 582 /* Build DPP Reconfig Authentication Confirm frame attributes */ 583 clear_len = 4 + 1 + 4 + 1 + 2 * (4 + auth->curve->nonce_len) + 584 4 + 1; 585 clear = wpabuf_alloc(clear_len); 586 if (!clear) 587 goto fail; 588 589 /* Transaction ID */ 590 wpabuf_put_le16(clear, DPP_ATTR_TRANSACTION_ID); 591 wpabuf_put_le16(clear, 1); 592 wpabuf_put_u8(clear, auth->transaction_id); 593 594 /* Protocol Version */ 595 wpabuf_put_le16(clear, DPP_ATTR_PROTOCOL_VERSION); 596 wpabuf_put_le16(clear, 1); 597 wpabuf_put_u8(clear, auth->peer_version); 598 599 /* C-nonce (wrapped) */ 600 wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE); 601 wpabuf_put_le16(clear, auth->curve->nonce_len); 602 wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len); 603 604 /* E-nonce (wrapped) */ 605 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 606 wpabuf_put_le16(clear, auth->curve->nonce_len); 607 wpabuf_put_data(clear, auth->e_nonce, auth->curve->nonce_len); 608 609 /* Reconfig-Flags (wrapped) */ 610 flags = DPP_CONFIG_REPLACEKEY; 611 wpabuf_put_le16(clear, DPP_ATTR_RECONFIG_FLAGS); 612 wpabuf_put_le16(clear, 1); 613 wpabuf_put_u8(clear, flags); 614 615 attr_len = 4 + wpabuf_len(clear) + AES_BLOCK_SIZE; 616 attr_len += 4 + 1; 617 msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_CONF, attr_len); 618 if (!msg) 619 goto fail; 620 621 attr_start = wpabuf_put(msg, 0); 622 623 /* DPP Status */ 624 dpp_build_attr_status(msg, DPP_STATUS_OK); 625 626 attr_end = wpabuf_put(msg, 0); 627 628 /* OUI, OUI type, Crypto Suite, DPP frame type */ 629 addr[0] = wpabuf_head_u8(msg) + 2; 630 len[0] = 3 + 1 + 1 + 1; 631 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 632 633 /* Attributes before Wrapped Data */ 634 addr[1] = attr_start; 635 len[1] = attr_end - attr_start; 636 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 637 638 /* Wrapped Data */ 639 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 640 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 641 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 642 643 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 644 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 645 wpabuf_head(clear), wpabuf_len(clear), 646 2, addr, len, wrapped) < 0) 647 goto fail; 648 649 wpa_hexdump_buf(MSG_DEBUG, 650 "DPP: Reconfig Authentication Confirm frame attributes", 651 msg); 652 653 out: 654 wpabuf_free(clear); 655 return msg; 656 fail: 657 wpabuf_free(msg); 658 msg = NULL; 659 goto out; 660 } 661 662 663 struct wpabuf * 664 dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr, 665 const u8 *attr_start, size_t attr_len) 666 { 667 const u8 *trans_id, *version, *r_connector, *r_proto, *wrapped_data, 668 *c_nonce, *e_nonce, *conn_status; 669 u16 trans_id_len, version_len, r_connector_len, r_proto_len, 670 wrapped_data_len, c_nonce_len, e_nonce_len, conn_status_len; 671 struct wpabuf *conf = NULL; 672 char *signed_connector = NULL; 673 struct dpp_signed_connector_info info; 674 enum dpp_status_error res; 675 struct json_token *root = NULL, *token, *conn_status_json = NULL; 676 const u8 *addr[2]; 677 size_t len[2]; 678 u8 *unwrapped = NULL; 679 size_t unwrapped_len = 0; 680 681 os_memset(&info, 0, sizeof(info)); 682 683 if (!auth->reconfig || !auth->configurator) 684 goto fail; 685 686 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 687 &wrapped_data_len); 688 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 689 dpp_auth_fail(auth, 690 "Missing or invalid required Wrapped Data attribute"); 691 goto fail; 692 } 693 wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data", 694 wrapped_data, wrapped_data_len); 695 attr_len = wrapped_data - 4 - attr_start; 696 697 trans_id = dpp_get_attr(attr_start, attr_len, DPP_ATTR_TRANSACTION_ID, 698 &trans_id_len); 699 if (!trans_id || trans_id_len != 1) { 700 dpp_auth_fail(auth, "Peer did not include Transaction ID"); 701 goto fail; 702 } 703 if (trans_id[0] != auth->transaction_id) { 704 dpp_auth_fail(auth, "Transaction ID mismatch"); 705 goto fail; 706 } 707 708 version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION, 709 &version_len); 710 if (!version || version_len < 1 || version[0] < 2) { 711 dpp_auth_fail(auth, 712 "Missing or invalid Protocol Version attribute"); 713 goto fail; 714 } 715 auth->peer_version = version[0]; 716 wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u", 717 auth->peer_version); 718 719 r_connector = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CONNECTOR, 720 &r_connector_len); 721 if (!r_connector) { 722 dpp_auth_fail(auth, " Missing R-Connector attribute"); 723 goto fail; 724 } 725 wpa_hexdump_ascii(MSG_DEBUG, "DPP: R-Connector", 726 r_connector, r_connector_len); 727 728 e_nonce = dpp_get_attr(attr_start, attr_len, 729 DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len); 730 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) { 731 dpp_auth_fail(auth, "Missing or invalid E-nonce"); 732 goto fail; 733 } 734 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len); 735 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len); 736 737 r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY, 738 &r_proto_len); 739 if (!r_proto) { 740 dpp_auth_fail(auth, 741 "Missing required Responder Protocol Key attribute"); 742 goto fail; 743 } 744 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key", 745 r_proto, r_proto_len); 746 747 signed_connector = os_malloc(r_connector_len + 1); 748 if (!signed_connector) 749 goto fail; 750 os_memcpy(signed_connector, r_connector, r_connector_len); 751 signed_connector[r_connector_len] = '\0'; 752 753 res = dpp_process_signed_connector(&info, auth->conf->csign, 754 signed_connector); 755 if (res != DPP_STATUS_OK) { 756 dpp_auth_fail(auth, "Invalid R-Connector"); 757 goto fail; 758 } 759 760 root = json_parse((const char *) info.payload, info.payload_len); 761 if (!root) { 762 dpp_auth_fail(auth, "Invalid Connector payload"); 763 goto fail; 764 } 765 766 /* Do not check netAccessKey expiration for reconfiguration to allow 767 * expired Connector to be updated. */ 768 769 token = json_get_member(root, "netAccessKey"); 770 if (!token || token->type != JSON_OBJECT) { 771 dpp_auth_fail(auth, "No netAccessKey object found"); 772 goto fail; 773 } 774 775 if (dpp_reconfig_derive_ke_initiator(auth, r_proto, r_proto_len, 776 token) < 0) 777 goto fail; 778 779 addr[0] = hdr; 780 len[0] = DPP_HDR_LEN; 781 addr[1] = attr_start; 782 len[1] = attr_len; 783 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 784 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 785 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 786 wrapped_data, wrapped_data_len); 787 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 788 unwrapped = os_malloc(unwrapped_len); 789 if (!unwrapped) 790 goto fail; 791 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 792 wrapped_data, wrapped_data_len, 793 2, addr, len, unwrapped) < 0) { 794 dpp_auth_fail(auth, "AES-SIV decryption failed"); 795 goto fail; 796 } 797 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 798 unwrapped, unwrapped_len); 799 800 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 801 dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 802 goto fail; 803 } 804 805 c_nonce = dpp_get_attr(unwrapped, unwrapped_len, 806 DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len); 807 if (!c_nonce || c_nonce_len != auth->curve->nonce_len || 808 os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) { 809 dpp_auth_fail(auth, "Missing or invalid C-nonce"); 810 goto fail; 811 } 812 wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len); 813 814 conn_status = dpp_get_attr(unwrapped, unwrapped_len, 815 DPP_ATTR_CONN_STATUS, &conn_status_len); 816 if (!conn_status) { 817 dpp_auth_fail(auth, "Missing Connection Status attribute"); 818 goto fail; 819 } 820 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus", 821 conn_status, conn_status_len); 822 823 conn_status_json = json_parse((const char *) conn_status, 824 conn_status_len); 825 if (!conn_status_json) { 826 dpp_auth_fail(auth, "Could not parse connStatus"); 827 goto fail; 828 } 829 /* TODO: use connStatus information */ 830 831 conf = dpp_reconfig_build_conf(auth); 832 if (conf) 833 auth->reconfig_success = true; 834 835 out: 836 json_free(root); 837 json_free(conn_status_json); 838 bin_clear_free(unwrapped, unwrapped_len); 839 os_free(info.payload); 840 os_free(signed_connector); 841 return conf; 842 fail: 843 wpabuf_free(conf); 844 conf = NULL; 845 goto out; 846 } 847 848 849 int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr, 850 const u8 *attr_start, size_t attr_len) 851 { 852 const u8 *trans_id, *version, *wrapped_data, *c_nonce, *e_nonce, 853 *reconfig_flags, *status; 854 u16 trans_id_len, version_len, wrapped_data_len, c_nonce_len, 855 e_nonce_len, reconfig_flags_len, status_len; 856 const u8 *addr[2]; 857 size_t len[2]; 858 u8 *unwrapped = NULL; 859 size_t unwrapped_len = 0; 860 int res = -1; 861 u8 flags; 862 863 if (!auth->reconfig || auth->configurator) 864 goto fail; 865 866 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 867 &wrapped_data_len); 868 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 869 dpp_auth_fail(auth, 870 "Missing or invalid required Wrapped Data attribute"); 871 goto fail; 872 } 873 wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data", 874 wrapped_data, wrapped_data_len); 875 attr_len = wrapped_data - 4 - attr_start; 876 877 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS, 878 &status_len); 879 if (!status || status_len < 1) { 880 dpp_auth_fail(auth, 881 "Missing or invalid required DPP Status attribute"); 882 goto fail; 883 } 884 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); 885 if (status[0] != DPP_STATUS_OK) { 886 dpp_auth_fail(auth, 887 "Reconfiguration did not complete successfully"); 888 goto fail; 889 } 890 891 addr[0] = hdr; 892 len[0] = DPP_HDR_LEN; 893 addr[1] = attr_start; 894 len[1] = attr_len; 895 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 896 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 897 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 898 wrapped_data, wrapped_data_len); 899 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 900 unwrapped = os_malloc(unwrapped_len); 901 if (!unwrapped) 902 goto fail; 903 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 904 wrapped_data, wrapped_data_len, 905 2, addr, len, unwrapped) < 0) { 906 dpp_auth_fail(auth, "AES-SIV decryption failed"); 907 goto fail; 908 } 909 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 910 unwrapped, unwrapped_len); 911 912 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 913 dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 914 goto fail; 915 } 916 917 trans_id = dpp_get_attr(unwrapped, unwrapped_len, 918 DPP_ATTR_TRANSACTION_ID, &trans_id_len); 919 if (!trans_id || trans_id_len != 1 || 920 trans_id[0] != auth->transaction_id) { 921 dpp_auth_fail(auth, 922 "Peer did not include valid Transaction ID"); 923 goto fail; 924 } 925 926 version = dpp_get_attr(unwrapped, unwrapped_len, 927 DPP_ATTR_PROTOCOL_VERSION, &version_len); 928 if (!version || version_len < 1 || version[0] != DPP_VERSION) { 929 dpp_auth_fail(auth, 930 "Missing or invalid Protocol Version attribute"); 931 goto fail; 932 } 933 934 c_nonce = dpp_get_attr(unwrapped, unwrapped_len, 935 DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len); 936 if (!c_nonce || c_nonce_len != auth->curve->nonce_len || 937 os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) { 938 dpp_auth_fail(auth, "Missing or invalid C-nonce"); 939 goto fail; 940 } 941 wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len); 942 943 e_nonce = dpp_get_attr(unwrapped, unwrapped_len, 944 DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len); 945 if (!e_nonce || e_nonce_len != auth->curve->nonce_len || 946 os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) { 947 dpp_auth_fail(auth, "Missing or invalid E-nonce"); 948 goto fail; 949 } 950 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len); 951 952 reconfig_flags = dpp_get_attr(unwrapped, unwrapped_len, 953 DPP_ATTR_RECONFIG_FLAGS, 954 &reconfig_flags_len); 955 if (!reconfig_flags || reconfig_flags_len < 1) { 956 dpp_auth_fail(auth, "Missing or invalid Reconfig-Flags"); 957 goto fail; 958 } 959 flags = reconfig_flags[0] & BIT(0); 960 wpa_printf(MSG_DEBUG, "DPP: Reconfig Flags connectorKey=%u", flags); 961 auth->reconfig_connector_key = flags; 962 963 auth->reconfig_success = true; 964 res = 0; 965 fail: 966 bin_clear_free(unwrapped, unwrapped_len); 967 return res; 968 } 969 970 #endif /* CONFIG_DPP2 */ 971