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