1 /* 2 * DPP functionality shared between hostapd and wpa_supplicant 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 "utils/base64.h" 16 #include "utils/json.h" 17 #include "common/ieee802_11_common.h" 18 #include "common/wpa_ctrl.h" 19 #include "common/gas.h" 20 #include "eap_common/eap_defs.h" 21 #include "crypto/crypto.h" 22 #include "crypto/random.h" 23 #include "crypto/aes.h" 24 #include "crypto/aes_siv.h" 25 #include "drivers/driver.h" 26 #include "dpp.h" 27 #include "dpp_i.h" 28 29 30 static const char * dpp_netrole_str(enum dpp_netrole netrole); 31 32 #ifdef CONFIG_TESTING_OPTIONS 33 #ifdef CONFIG_DPP2 34 int dpp_version_override = 2; 35 #else 36 int dpp_version_override = 1; 37 #endif 38 enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED; 39 #endif /* CONFIG_TESTING_OPTIONS */ 40 41 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \ 42 (defined(LIBRESSL_VERSION_NUMBER) && \ 43 LIBRESSL_VERSION_NUMBER < 0x20700000L) 44 /* Compatibility wrappers for older versions. */ 45 46 #ifdef CONFIG_DPP2 47 static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey) 48 { 49 if (pkey->type != EVP_PKEY_EC) 50 return NULL; 51 return pkey->pkey.ec; 52 } 53 #endif /* CONFIG_DPP2 */ 54 55 #endif 56 57 58 void dpp_auth_fail(struct dpp_authentication *auth, const char *txt) 59 { 60 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt); 61 } 62 63 64 struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type, 65 size_t len) 66 { 67 struct wpabuf *msg; 68 69 msg = wpabuf_alloc(8 + len); 70 if (!msg) 71 return NULL; 72 wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC); 73 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC); 74 wpabuf_put_be24(msg, OUI_WFA); 75 wpabuf_put_u8(msg, DPP_OUI_TYPE); 76 wpabuf_put_u8(msg, 1); /* Crypto Suite */ 77 wpabuf_put_u8(msg, type); 78 return msg; 79 } 80 81 82 const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len) 83 { 84 u16 id, alen; 85 const u8 *pos = buf, *end = buf + len; 86 87 while (end - pos >= 4) { 88 id = WPA_GET_LE16(pos); 89 pos += 2; 90 alen = WPA_GET_LE16(pos); 91 pos += 2; 92 if (alen > end - pos) 93 return NULL; 94 if (id == req_id) { 95 *ret_len = alen; 96 return pos; 97 } 98 pos += alen; 99 } 100 101 return NULL; 102 } 103 104 105 static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len, 106 u16 req_id, u16 *ret_len) 107 { 108 u16 id, alen; 109 const u8 *pos, *end = buf + len; 110 111 if (!prev) 112 pos = buf; 113 else 114 pos = prev + WPA_GET_LE16(prev - 2); 115 while (end - pos >= 4) { 116 id = WPA_GET_LE16(pos); 117 pos += 2; 118 alen = WPA_GET_LE16(pos); 119 pos += 2; 120 if (alen > end - pos) 121 return NULL; 122 if (id == req_id) { 123 *ret_len = alen; 124 return pos; 125 } 126 pos += alen; 127 } 128 129 return NULL; 130 } 131 132 133 int dpp_check_attrs(const u8 *buf, size_t len) 134 { 135 const u8 *pos, *end; 136 int wrapped_data = 0; 137 138 pos = buf; 139 end = buf + len; 140 while (end - pos >= 4) { 141 u16 id, alen; 142 143 id = WPA_GET_LE16(pos); 144 pos += 2; 145 alen = WPA_GET_LE16(pos); 146 pos += 2; 147 wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u", 148 id, alen); 149 if (alen > end - pos) { 150 wpa_printf(MSG_DEBUG, 151 "DPP: Truncated message - not enough room for the attribute - dropped"); 152 return -1; 153 } 154 if (wrapped_data) { 155 wpa_printf(MSG_DEBUG, 156 "DPP: An unexpected attribute included after the Wrapped Data attribute"); 157 return -1; 158 } 159 if (id == DPP_ATTR_WRAPPED_DATA) 160 wrapped_data = 1; 161 pos += alen; 162 } 163 164 if (end != pos) { 165 wpa_printf(MSG_DEBUG, 166 "DPP: Unexpected octets (%d) after the last attribute", 167 (int) (end - pos)); 168 return -1; 169 } 170 171 return 0; 172 } 173 174 175 void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info) 176 { 177 if (!info) 178 return; 179 os_free(info->uri); 180 os_free(info->info); 181 os_free(info->chan); 182 os_free(info->pk); 183 EVP_PKEY_free(info->pubkey); 184 str_clear_free(info->configurator_params); 185 os_free(info); 186 } 187 188 189 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type) 190 { 191 switch (type) { 192 case DPP_BOOTSTRAP_QR_CODE: 193 return "QRCODE"; 194 case DPP_BOOTSTRAP_PKEX: 195 return "PKEX"; 196 case DPP_BOOTSTRAP_NFC_URI: 197 return "NFC-URI"; 198 } 199 return "??"; 200 } 201 202 203 static int dpp_uri_valid_info(const char *info) 204 { 205 while (*info) { 206 unsigned char val = *info++; 207 208 if (val < 0x20 || val > 0x7e || val == 0x3b) 209 return 0; 210 } 211 212 return 1; 213 } 214 215 216 static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri) 217 { 218 bi->uri = os_strdup(uri); 219 return bi->uri ? 0 : -1; 220 } 221 222 223 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi, 224 const char *chan_list) 225 { 226 const char *pos = chan_list, *pos2; 227 int opclass = -1, channel, freq; 228 229 while (pos && *pos && *pos != ';') { 230 pos2 = pos; 231 while (*pos2 >= '0' && *pos2 <= '9') 232 pos2++; 233 if (*pos2 == '/') { 234 opclass = atoi(pos); 235 pos = pos2 + 1; 236 } 237 if (opclass <= 0) 238 goto fail; 239 channel = atoi(pos); 240 if (channel <= 0) 241 goto fail; 242 while (*pos >= '0' && *pos <= '9') 243 pos++; 244 freq = ieee80211_chan_to_freq(NULL, opclass, channel); 245 wpa_printf(MSG_DEBUG, 246 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d", 247 opclass, channel, freq); 248 bi->channels_listed = true; 249 if (freq < 0) { 250 wpa_printf(MSG_DEBUG, 251 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)", 252 opclass, channel); 253 } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) { 254 wpa_printf(MSG_DEBUG, 255 "DPP: Too many channels in URI channel-list - ignore list"); 256 bi->num_freq = 0; 257 break; 258 } else { 259 bi->freq[bi->num_freq++] = freq; 260 } 261 262 if (*pos == ';' || *pos == '\0') 263 break; 264 if (*pos != ',') 265 goto fail; 266 pos++; 267 } 268 269 return 0; 270 fail: 271 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list"); 272 return -1; 273 } 274 275 276 int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac) 277 { 278 if (!mac) 279 return 0; 280 281 if (hwaddr_aton2(mac, bi->mac_addr) < 0) { 282 wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac"); 283 return -1; 284 } 285 286 wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr)); 287 288 return 0; 289 } 290 291 292 int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info) 293 { 294 const char *end; 295 296 if (!info) 297 return 0; 298 299 end = os_strchr(info, ';'); 300 if (!end) 301 end = info + os_strlen(info); 302 bi->info = os_malloc(end - info + 1); 303 if (!bi->info) 304 return -1; 305 os_memcpy(bi->info, info, end - info); 306 bi->info[end - info] = '\0'; 307 wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info); 308 if (!dpp_uri_valid_info(bi->info)) { 309 wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload"); 310 return -1; 311 } 312 313 return 0; 314 } 315 316 317 int dpp_parse_uri_version(struct dpp_bootstrap_info *bi, const char *version) 318 { 319 #ifdef CONFIG_DPP2 320 if (!version || DPP_VERSION < 2) 321 return 0; 322 323 if (*version == '1') 324 bi->version = 1; 325 else if (*version == '2') 326 bi->version = 2; 327 else 328 wpa_printf(MSG_DEBUG, "DPP: Unknown URI version"); 329 330 wpa_printf(MSG_DEBUG, "DPP: URI version: %d", bi->version); 331 #endif /* CONFIG_DPP2 */ 332 333 return 0; 334 } 335 336 337 static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info) 338 { 339 u8 *data; 340 size_t data_len; 341 int res; 342 const char *end; 343 344 end = os_strchr(info, ';'); 345 if (!end) 346 return -1; 347 348 data = base64_decode(info, end - info, &data_len); 349 if (!data) { 350 wpa_printf(MSG_DEBUG, 351 "DPP: Invalid base64 encoding on URI public-key"); 352 return -1; 353 } 354 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key", 355 data, data_len); 356 357 res = dpp_get_subject_public_key(bi, data, data_len); 358 os_free(data); 359 return res; 360 } 361 362 363 static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri) 364 { 365 const char *pos = uri; 366 const char *end; 367 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL; 368 const char *version = NULL; 369 struct dpp_bootstrap_info *bi; 370 371 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri)); 372 373 if (os_strncmp(pos, "DPP:", 4) != 0) { 374 wpa_printf(MSG_INFO, "DPP: Not a DPP URI"); 375 return NULL; 376 } 377 pos += 4; 378 379 for (;;) { 380 end = os_strchr(pos, ';'); 381 if (!end) 382 break; 383 384 if (end == pos) { 385 /* Handle terminating ";;" and ignore unexpected ";" 386 * for parsing robustness. */ 387 pos++; 388 continue; 389 } 390 391 if (pos[0] == 'C' && pos[1] == ':' && !chan_list) 392 chan_list = pos + 2; 393 else if (pos[0] == 'M' && pos[1] == ':' && !mac) 394 mac = pos + 2; 395 else if (pos[0] == 'I' && pos[1] == ':' && !info) 396 info = pos + 2; 397 else if (pos[0] == 'K' && pos[1] == ':' && !pk) 398 pk = pos + 2; 399 else if (pos[0] == 'V' && pos[1] == ':' && !version) 400 version = pos + 2; 401 else 402 wpa_hexdump_ascii(MSG_DEBUG, 403 "DPP: Ignore unrecognized URI parameter", 404 pos, end - pos); 405 pos = end + 1; 406 } 407 408 if (!pk) { 409 wpa_printf(MSG_INFO, "DPP: URI missing public-key"); 410 return NULL; 411 } 412 413 bi = os_zalloc(sizeof(*bi)); 414 if (!bi) 415 return NULL; 416 417 if (dpp_clone_uri(bi, uri) < 0 || 418 dpp_parse_uri_chan_list(bi, chan_list) < 0 || 419 dpp_parse_uri_mac(bi, mac) < 0 || 420 dpp_parse_uri_info(bi, info) < 0 || 421 dpp_parse_uri_version(bi, version) < 0 || 422 dpp_parse_uri_pk(bi, pk) < 0) { 423 dpp_bootstrap_info_free(bi); 424 bi = NULL; 425 } 426 427 return bi; 428 } 429 430 431 void dpp_build_attr_status(struct wpabuf *msg, enum dpp_status_error status) 432 { 433 wpa_printf(MSG_DEBUG, "DPP: Status %d", status); 434 wpabuf_put_le16(msg, DPP_ATTR_STATUS); 435 wpabuf_put_le16(msg, 1); 436 wpabuf_put_u8(msg, status); 437 } 438 439 440 void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash) 441 { 442 if (hash) { 443 wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash"); 444 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH); 445 wpabuf_put_le16(msg, SHA256_MAC_LEN); 446 wpabuf_put_data(msg, hash, SHA256_MAC_LEN); 447 } 448 } 449 450 451 static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes, 452 u16 num_modes, unsigned int freq) 453 { 454 u16 m; 455 int c, flag; 456 457 if (!own_modes || !num_modes) 458 return 1; 459 460 for (m = 0; m < num_modes; m++) { 461 for (c = 0; c < own_modes[m].num_channels; c++) { 462 if ((unsigned int) own_modes[m].channels[c].freq != 463 freq) 464 continue; 465 flag = own_modes[m].channels[c].flag; 466 if (!(flag & (HOSTAPD_CHAN_DISABLED | 467 HOSTAPD_CHAN_NO_IR | 468 HOSTAPD_CHAN_RADAR))) 469 return 1; 470 } 471 } 472 473 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq); 474 return 0; 475 } 476 477 478 static int freq_included(const unsigned int freqs[], unsigned int num, 479 unsigned int freq) 480 { 481 while (num > 0) { 482 if (freqs[--num] == freq) 483 return 1; 484 } 485 return 0; 486 } 487 488 489 static void freq_to_start(unsigned int freqs[], unsigned int num, 490 unsigned int freq) 491 { 492 unsigned int i; 493 494 for (i = 0; i < num; i++) { 495 if (freqs[i] == freq) 496 break; 497 } 498 if (i == 0 || i >= num) 499 return; 500 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0])); 501 freqs[0] = freq; 502 } 503 504 505 static int dpp_channel_intersect(struct dpp_authentication *auth, 506 struct hostapd_hw_modes *own_modes, 507 u16 num_modes) 508 { 509 struct dpp_bootstrap_info *peer_bi = auth->peer_bi; 510 unsigned int i, freq; 511 512 for (i = 0; i < peer_bi->num_freq; i++) { 513 freq = peer_bi->freq[i]; 514 if (freq_included(auth->freq, auth->num_freq, freq)) 515 continue; 516 if (dpp_channel_ok_init(own_modes, num_modes, freq)) 517 auth->freq[auth->num_freq++] = freq; 518 } 519 if (!auth->num_freq) { 520 wpa_printf(MSG_INFO, 521 "DPP: No available channels for initiating DPP Authentication"); 522 return -1; 523 } 524 auth->curr_freq = auth->freq[0]; 525 return 0; 526 } 527 528 529 static int dpp_channel_local_list(struct dpp_authentication *auth, 530 struct hostapd_hw_modes *own_modes, 531 u16 num_modes) 532 { 533 u16 m; 534 int c, flag; 535 unsigned int freq; 536 537 auth->num_freq = 0; 538 539 if (!own_modes || !num_modes) { 540 auth->freq[0] = 2412; 541 auth->freq[1] = 2437; 542 auth->freq[2] = 2462; 543 auth->num_freq = 3; 544 return 0; 545 } 546 547 for (m = 0; m < num_modes; m++) { 548 for (c = 0; c < own_modes[m].num_channels; c++) { 549 freq = own_modes[m].channels[c].freq; 550 flag = own_modes[m].channels[c].flag; 551 if (flag & (HOSTAPD_CHAN_DISABLED | 552 HOSTAPD_CHAN_NO_IR | 553 HOSTAPD_CHAN_RADAR)) 554 continue; 555 if (freq_included(auth->freq, auth->num_freq, freq)) 556 continue; 557 auth->freq[auth->num_freq++] = freq; 558 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) { 559 m = num_modes; 560 break; 561 } 562 } 563 } 564 565 return auth->num_freq == 0 ? -1 : 0; 566 } 567 568 569 int dpp_prepare_channel_list(struct dpp_authentication *auth, 570 unsigned int neg_freq, 571 struct hostapd_hw_modes *own_modes, u16 num_modes) 572 { 573 int res; 574 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end; 575 unsigned int i; 576 577 if (!own_modes) { 578 if (!neg_freq) 579 return -1; 580 auth->num_freq = 1; 581 auth->freq[0] = neg_freq; 582 auth->curr_freq = neg_freq; 583 return 0; 584 } 585 586 if (auth->peer_bi->num_freq > 0) 587 res = dpp_channel_intersect(auth, own_modes, num_modes); 588 else 589 res = dpp_channel_local_list(auth, own_modes, num_modes); 590 if (res < 0) 591 return res; 592 593 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most 594 * likely channels first. */ 595 freq_to_start(auth->freq, auth->num_freq, 2462); 596 freq_to_start(auth->freq, auth->num_freq, 2412); 597 freq_to_start(auth->freq, auth->num_freq, 2437); 598 599 auth->freq_idx = 0; 600 auth->curr_freq = auth->freq[0]; 601 602 pos = freqs; 603 end = pos + sizeof(freqs); 604 for (i = 0; i < auth->num_freq; i++) { 605 res = os_snprintf(pos, end - pos, " %u", auth->freq[i]); 606 if (os_snprintf_error(end - pos, res)) 607 break; 608 pos += res; 609 } 610 *pos = '\0'; 611 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s", 612 freqs); 613 614 return 0; 615 } 616 617 618 int dpp_gen_uri(struct dpp_bootstrap_info *bi) 619 { 620 char macstr[ETH_ALEN * 2 + 10]; 621 size_t len; 622 623 len = 4; /* "DPP:" */ 624 if (bi->chan) 625 len += 3 + os_strlen(bi->chan); /* C:...; */ 626 if (is_zero_ether_addr(bi->mac_addr)) 627 macstr[0] = '\0'; 628 else 629 os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";", 630 MAC2STR(bi->mac_addr)); 631 len += os_strlen(macstr); /* M:...; */ 632 if (bi->info) 633 len += 3 + os_strlen(bi->info); /* I:...; */ 634 #ifdef CONFIG_DPP2 635 len += 4; /* V:2; */ 636 #endif /* CONFIG_DPP2 */ 637 len += 4 + os_strlen(bi->pk); /* K:...;; */ 638 639 os_free(bi->uri); 640 bi->uri = os_malloc(len + 1); 641 if (!bi->uri) 642 return -1; 643 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%sK:%s;;", 644 bi->chan ? "C:" : "", bi->chan ? bi->chan : "", 645 bi->chan ? ";" : "", 646 macstr, 647 bi->info ? "I:" : "", bi->info ? bi->info : "", 648 bi->info ? ";" : "", 649 DPP_VERSION == 2 ? "V:2;" : "", 650 bi->pk); 651 return 0; 652 } 653 654 655 struct dpp_authentication * 656 dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx) 657 { 658 struct dpp_authentication *auth; 659 660 auth = os_zalloc(sizeof(*auth)); 661 if (!auth) 662 return NULL; 663 auth->global = dpp; 664 auth->msg_ctx = msg_ctx; 665 auth->conf_resp_status = 255; 666 return auth; 667 } 668 669 670 static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth, 671 const char *json) 672 { 673 size_t nonce_len; 674 size_t json_len, clear_len; 675 struct wpabuf *clear = NULL, *msg = NULL; 676 u8 *wrapped; 677 size_t attr_len; 678 679 wpa_printf(MSG_DEBUG, "DPP: Build configuration request"); 680 681 nonce_len = auth->curve->nonce_len; 682 if (random_get_bytes(auth->e_nonce, nonce_len)) { 683 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce"); 684 goto fail; 685 } 686 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len); 687 json_len = os_strlen(json); 688 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len); 689 690 /* { E-nonce, configAttrib }ke */ 691 clear_len = 4 + nonce_len + 4 + json_len; 692 clear = wpabuf_alloc(clear_len); 693 attr_len = 4 + clear_len + AES_BLOCK_SIZE; 694 #ifdef CONFIG_TESTING_OPTIONS 695 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) 696 attr_len += 5; 697 #endif /* CONFIG_TESTING_OPTIONS */ 698 msg = wpabuf_alloc(attr_len); 699 if (!clear || !msg) 700 goto fail; 701 702 #ifdef CONFIG_TESTING_OPTIONS 703 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) { 704 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce"); 705 goto skip_e_nonce; 706 } 707 if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) { 708 wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce"); 709 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 710 wpabuf_put_le16(clear, nonce_len - 1); 711 wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1); 712 goto skip_e_nonce; 713 } 714 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) { 715 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data"); 716 goto skip_wrapped_data; 717 } 718 #endif /* CONFIG_TESTING_OPTIONS */ 719 720 /* E-nonce */ 721 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 722 wpabuf_put_le16(clear, nonce_len); 723 wpabuf_put_data(clear, auth->e_nonce, nonce_len); 724 725 #ifdef CONFIG_TESTING_OPTIONS 726 skip_e_nonce: 727 if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) { 728 wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib"); 729 goto skip_conf_attr_obj; 730 } 731 #endif /* CONFIG_TESTING_OPTIONS */ 732 733 /* configAttrib */ 734 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ); 735 wpabuf_put_le16(clear, json_len); 736 wpabuf_put_data(clear, json, json_len); 737 738 #ifdef CONFIG_TESTING_OPTIONS 739 skip_conf_attr_obj: 740 #endif /* CONFIG_TESTING_OPTIONS */ 741 742 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 743 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 744 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 745 746 /* No AES-SIV AD */ 747 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 748 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 749 wpabuf_head(clear), wpabuf_len(clear), 750 0, NULL, NULL, wrapped) < 0) 751 goto fail; 752 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 753 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 754 755 #ifdef CONFIG_TESTING_OPTIONS 756 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) { 757 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); 758 dpp_build_attr_status(msg, DPP_STATUS_OK); 759 } 760 skip_wrapped_data: 761 #endif /* CONFIG_TESTING_OPTIONS */ 762 763 wpa_hexdump_buf(MSG_DEBUG, 764 "DPP: Configuration Request frame attributes", msg); 765 wpabuf_free(clear); 766 return msg; 767 768 fail: 769 wpabuf_free(clear); 770 wpabuf_free(msg); 771 return NULL; 772 } 773 774 775 void dpp_write_adv_proto(struct wpabuf *buf) 776 { 777 /* Advertisement Protocol IE */ 778 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); 779 wpabuf_put_u8(buf, 8); /* Length */ 780 wpabuf_put_u8(buf, 0x7f); 781 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); 782 wpabuf_put_u8(buf, 5); 783 wpabuf_put_be24(buf, OUI_WFA); 784 wpabuf_put_u8(buf, DPP_OUI_TYPE); 785 wpabuf_put_u8(buf, 0x01); 786 } 787 788 789 void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query) 790 { 791 /* GAS Query */ 792 wpabuf_put_le16(buf, wpabuf_len(query)); 793 wpabuf_put_buf(buf, query); 794 } 795 796 797 struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth, 798 const char *json) 799 { 800 struct wpabuf *buf, *conf_req; 801 802 conf_req = dpp_build_conf_req_attr(auth, json); 803 if (!conf_req) { 804 wpa_printf(MSG_DEBUG, 805 "DPP: No configuration request data available"); 806 return NULL; 807 } 808 809 buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req)); 810 if (!buf) { 811 wpabuf_free(conf_req); 812 return NULL; 813 } 814 815 dpp_write_adv_proto(buf); 816 dpp_write_gas_query(buf, conf_req); 817 wpabuf_free(conf_req); 818 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf); 819 820 return buf; 821 } 822 823 824 struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth, 825 const char *name, 826 enum dpp_netrole netrole, 827 const char *mud_url, int *opclasses) 828 { 829 size_t len, name_len; 830 const char *tech = "infra"; 831 const char *dpp_name; 832 struct wpabuf *buf, *json; 833 char *csr = NULL; 834 835 #ifdef CONFIG_TESTING_OPTIONS 836 if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) { 837 static const char *bogus_tech = "knfra"; 838 839 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr"); 840 tech = bogus_tech; 841 } 842 #endif /* CONFIG_TESTING_OPTIONS */ 843 844 dpp_name = name ? name : "Test"; 845 name_len = os_strlen(dpp_name); 846 847 len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4; 848 if (mud_url && mud_url[0]) 849 len += 10 + os_strlen(mud_url); 850 #ifdef CONFIG_DPP2 851 if (auth->csr) { 852 size_t csr_len; 853 854 csr = base64_encode_no_lf(wpabuf_head(auth->csr), 855 wpabuf_len(auth->csr), &csr_len); 856 if (!csr) 857 return NULL; 858 len += 30 + csr_len; 859 } 860 #endif /* CONFIG_DPP2 */ 861 json = wpabuf_alloc(len); 862 if (!json) 863 return NULL; 864 865 json_start_object(json, NULL); 866 if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) { 867 wpabuf_free(json); 868 return NULL; 869 } 870 json_value_sep(json); 871 json_add_string(json, "wi-fi_tech", tech); 872 json_value_sep(json); 873 json_add_string(json, "netRole", dpp_netrole_str(netrole)); 874 if (mud_url && mud_url[0]) { 875 json_value_sep(json); 876 json_add_string(json, "mudurl", mud_url); 877 } 878 if (opclasses) { 879 int i; 880 881 json_value_sep(json); 882 json_start_array(json, "bandSupport"); 883 for (i = 0; opclasses[i]; i++) 884 wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]); 885 json_end_array(json); 886 } 887 if (csr) { 888 json_value_sep(json); 889 json_add_string(json, "pkcs10", csr); 890 } 891 json_end_object(json); 892 893 buf = dpp_build_conf_req(auth, wpabuf_head(json)); 894 wpabuf_free(json); 895 os_free(csr); 896 897 return buf; 898 } 899 900 901 static int bin_str_eq(const char *val, size_t len, const char *cmp) 902 { 903 return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0; 904 } 905 906 907 struct dpp_configuration * dpp_configuration_alloc(const char *type) 908 { 909 struct dpp_configuration *conf; 910 const char *end; 911 size_t len; 912 913 conf = os_zalloc(sizeof(*conf)); 914 if (!conf) 915 goto fail; 916 917 end = os_strchr(type, ' '); 918 if (end) 919 len = end - type; 920 else 921 len = os_strlen(type); 922 923 if (bin_str_eq(type, len, "psk")) 924 conf->akm = DPP_AKM_PSK; 925 else if (bin_str_eq(type, len, "sae")) 926 conf->akm = DPP_AKM_SAE; 927 else if (bin_str_eq(type, len, "psk-sae") || 928 bin_str_eq(type, len, "psk+sae")) 929 conf->akm = DPP_AKM_PSK_SAE; 930 else if (bin_str_eq(type, len, "sae-dpp") || 931 bin_str_eq(type, len, "dpp+sae")) 932 conf->akm = DPP_AKM_SAE_DPP; 933 else if (bin_str_eq(type, len, "psk-sae-dpp") || 934 bin_str_eq(type, len, "dpp+psk+sae")) 935 conf->akm = DPP_AKM_PSK_SAE_DPP; 936 else if (bin_str_eq(type, len, "dpp")) 937 conf->akm = DPP_AKM_DPP; 938 else if (bin_str_eq(type, len, "dot1x")) 939 conf->akm = DPP_AKM_DOT1X; 940 else 941 goto fail; 942 943 return conf; 944 fail: 945 dpp_configuration_free(conf); 946 return NULL; 947 } 948 949 950 int dpp_akm_psk(enum dpp_akm akm) 951 { 952 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE || 953 akm == DPP_AKM_PSK_SAE_DPP; 954 } 955 956 957 int dpp_akm_sae(enum dpp_akm akm) 958 { 959 return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE || 960 akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP; 961 } 962 963 964 int dpp_akm_legacy(enum dpp_akm akm) 965 { 966 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE || 967 akm == DPP_AKM_SAE; 968 } 969 970 971 int dpp_akm_dpp(enum dpp_akm akm) 972 { 973 return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP || 974 akm == DPP_AKM_PSK_SAE_DPP; 975 } 976 977 978 int dpp_akm_ver2(enum dpp_akm akm) 979 { 980 return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP; 981 } 982 983 984 int dpp_configuration_valid(const struct dpp_configuration *conf) 985 { 986 if (conf->ssid_len == 0) 987 return 0; 988 if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set) 989 return 0; 990 if (dpp_akm_sae(conf->akm) && !conf->passphrase) 991 return 0; 992 return 1; 993 } 994 995 996 void dpp_configuration_free(struct dpp_configuration *conf) 997 { 998 if (!conf) 999 return; 1000 str_clear_free(conf->passphrase); 1001 os_free(conf->group_id); 1002 os_free(conf->csrattrs); 1003 bin_clear_free(conf, sizeof(*conf)); 1004 } 1005 1006 1007 static int dpp_configuration_parse_helper(struct dpp_authentication *auth, 1008 const char *cmd, int idx) 1009 { 1010 const char *pos, *end; 1011 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL; 1012 struct dpp_configuration *conf = NULL; 1013 size_t len; 1014 1015 pos = os_strstr(cmd, " conf=sta-"); 1016 if (pos) { 1017 conf_sta = dpp_configuration_alloc(pos + 10); 1018 if (!conf_sta) 1019 goto fail; 1020 conf_sta->netrole = DPP_NETROLE_STA; 1021 conf = conf_sta; 1022 } 1023 1024 pos = os_strstr(cmd, " conf=ap-"); 1025 if (pos) { 1026 conf_ap = dpp_configuration_alloc(pos + 9); 1027 if (!conf_ap) 1028 goto fail; 1029 conf_ap->netrole = DPP_NETROLE_AP; 1030 conf = conf_ap; 1031 } 1032 1033 pos = os_strstr(cmd, " conf=configurator"); 1034 if (pos) 1035 auth->provision_configurator = 1; 1036 1037 if (!conf) 1038 return 0; 1039 1040 pos = os_strstr(cmd, " ssid="); 1041 if (pos) { 1042 pos += 6; 1043 end = os_strchr(pos, ' '); 1044 conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos); 1045 conf->ssid_len /= 2; 1046 if (conf->ssid_len > sizeof(conf->ssid) || 1047 hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0) 1048 goto fail; 1049 } else { 1050 #ifdef CONFIG_TESTING_OPTIONS 1051 /* use a default SSID for legacy testing reasons */ 1052 os_memcpy(conf->ssid, "test", 4); 1053 conf->ssid_len = 4; 1054 #else /* CONFIG_TESTING_OPTIONS */ 1055 goto fail; 1056 #endif /* CONFIG_TESTING_OPTIONS */ 1057 } 1058 1059 pos = os_strstr(cmd, " ssid_charset="); 1060 if (pos) { 1061 if (conf_ap) { 1062 wpa_printf(MSG_INFO, 1063 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee"); 1064 goto fail; 1065 } 1066 conf->ssid_charset = atoi(pos + 14); 1067 } 1068 1069 pos = os_strstr(cmd, " pass="); 1070 if (pos) { 1071 size_t pass_len; 1072 1073 pos += 6; 1074 end = os_strchr(pos, ' '); 1075 pass_len = end ? (size_t) (end - pos) : os_strlen(pos); 1076 pass_len /= 2; 1077 if (pass_len > 63 || pass_len < 8) 1078 goto fail; 1079 conf->passphrase = os_zalloc(pass_len + 1); 1080 if (!conf->passphrase || 1081 hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0) 1082 goto fail; 1083 } 1084 1085 pos = os_strstr(cmd, " psk="); 1086 if (pos) { 1087 pos += 5; 1088 if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0) 1089 goto fail; 1090 conf->psk_set = 1; 1091 } 1092 1093 pos = os_strstr(cmd, " group_id="); 1094 if (pos) { 1095 size_t group_id_len; 1096 1097 pos += 10; 1098 end = os_strchr(pos, ' '); 1099 group_id_len = end ? (size_t) (end - pos) : os_strlen(pos); 1100 conf->group_id = os_malloc(group_id_len + 1); 1101 if (!conf->group_id) 1102 goto fail; 1103 os_memcpy(conf->group_id, pos, group_id_len); 1104 conf->group_id[group_id_len] = '\0'; 1105 } 1106 1107 pos = os_strstr(cmd, " expiry="); 1108 if (pos) { 1109 long int val; 1110 1111 pos += 8; 1112 val = strtol(pos, NULL, 0); 1113 if (val <= 0) 1114 goto fail; 1115 conf->netaccesskey_expiry = val; 1116 } 1117 1118 pos = os_strstr(cmd, " csrattrs="); 1119 if (pos) { 1120 pos += 10; 1121 end = os_strchr(pos, ' '); 1122 len = end ? (size_t) (end - pos) : os_strlen(pos); 1123 conf->csrattrs = os_zalloc(len + 1); 1124 if (!conf->csrattrs) 1125 goto fail; 1126 os_memcpy(conf->csrattrs, pos, len); 1127 } 1128 1129 if (!dpp_configuration_valid(conf)) 1130 goto fail; 1131 1132 if (idx == 0) { 1133 auth->conf_sta = conf_sta; 1134 auth->conf_ap = conf_ap; 1135 } else if (idx == 1) { 1136 auth->conf2_sta = conf_sta; 1137 auth->conf2_ap = conf_ap; 1138 } else { 1139 goto fail; 1140 } 1141 return 0; 1142 1143 fail: 1144 dpp_configuration_free(conf_sta); 1145 dpp_configuration_free(conf_ap); 1146 return -1; 1147 } 1148 1149 1150 static int dpp_configuration_parse(struct dpp_authentication *auth, 1151 const char *cmd) 1152 { 1153 const char *pos; 1154 char *tmp; 1155 size_t len; 1156 int res; 1157 1158 pos = os_strstr(cmd, " @CONF-OBJ-SEP@ "); 1159 if (!pos) 1160 return dpp_configuration_parse_helper(auth, cmd, 0); 1161 1162 len = pos - cmd; 1163 tmp = os_malloc(len + 1); 1164 if (!tmp) 1165 goto fail; 1166 os_memcpy(tmp, cmd, len); 1167 tmp[len] = '\0'; 1168 res = dpp_configuration_parse_helper(auth, cmd, 0); 1169 str_clear_free(tmp); 1170 if (res) 1171 goto fail; 1172 res = dpp_configuration_parse_helper(auth, cmd + len, 1); 1173 if (res) 1174 goto fail; 1175 return 0; 1176 fail: 1177 dpp_configuration_free(auth->conf_sta); 1178 dpp_configuration_free(auth->conf2_sta); 1179 dpp_configuration_free(auth->conf_ap); 1180 dpp_configuration_free(auth->conf2_ap); 1181 return -1; 1182 } 1183 1184 1185 static struct dpp_configurator * 1186 dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id) 1187 { 1188 struct dpp_configurator *conf; 1189 1190 if (!dpp) 1191 return NULL; 1192 1193 dl_list_for_each(conf, &dpp->configurator, 1194 struct dpp_configurator, list) { 1195 if (conf->id == id) 1196 return conf; 1197 } 1198 return NULL; 1199 } 1200 1201 1202 int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd) 1203 { 1204 const char *pos; 1205 char *tmp = NULL; 1206 int ret = -1; 1207 1208 if (!cmd || auth->configurator_set) 1209 return 0; 1210 auth->configurator_set = 1; 1211 1212 if (cmd[0] != ' ') { 1213 size_t len; 1214 1215 len = os_strlen(cmd); 1216 tmp = os_malloc(len + 2); 1217 if (!tmp) 1218 goto fail; 1219 tmp[0] = ' '; 1220 os_memcpy(tmp + 1, cmd, len + 1); 1221 cmd = tmp; 1222 } 1223 1224 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd); 1225 1226 pos = os_strstr(cmd, " configurator="); 1227 if (!auth->conf && pos) { 1228 pos += 14; 1229 auth->conf = dpp_configurator_get_id(auth->global, atoi(pos)); 1230 if (!auth->conf) { 1231 wpa_printf(MSG_INFO, 1232 "DPP: Could not find the specified configurator"); 1233 goto fail; 1234 } 1235 } 1236 1237 pos = os_strstr(cmd, " conn_status="); 1238 if (pos) { 1239 pos += 13; 1240 auth->send_conn_status = atoi(pos); 1241 } 1242 1243 pos = os_strstr(cmd, " akm_use_selector="); 1244 if (pos) { 1245 pos += 18; 1246 auth->akm_use_selector = atoi(pos); 1247 } 1248 1249 if (dpp_configuration_parse(auth, cmd) < 0) { 1250 wpa_msg(auth->msg_ctx, MSG_INFO, 1251 "DPP: Failed to set configurator parameters"); 1252 goto fail; 1253 } 1254 ret = 0; 1255 fail: 1256 os_free(tmp); 1257 return ret; 1258 } 1259 1260 1261 void dpp_auth_deinit(struct dpp_authentication *auth) 1262 { 1263 unsigned int i; 1264 1265 if (!auth) 1266 return; 1267 dpp_configuration_free(auth->conf_ap); 1268 dpp_configuration_free(auth->conf2_ap); 1269 dpp_configuration_free(auth->conf_sta); 1270 dpp_configuration_free(auth->conf2_sta); 1271 EVP_PKEY_free(auth->own_protocol_key); 1272 EVP_PKEY_free(auth->peer_protocol_key); 1273 EVP_PKEY_free(auth->reconfig_old_protocol_key); 1274 wpabuf_free(auth->req_msg); 1275 wpabuf_free(auth->resp_msg); 1276 wpabuf_free(auth->conf_req); 1277 wpabuf_free(auth->reconfig_req_msg); 1278 wpabuf_free(auth->reconfig_resp_msg); 1279 for (i = 0; i < auth->num_conf_obj; i++) { 1280 struct dpp_config_obj *conf = &auth->conf_obj[i]; 1281 1282 os_free(conf->connector); 1283 wpabuf_free(conf->c_sign_key); 1284 wpabuf_free(conf->certbag); 1285 wpabuf_free(conf->certs); 1286 wpabuf_free(conf->cacert); 1287 os_free(conf->server_name); 1288 wpabuf_free(conf->pp_key); 1289 } 1290 #ifdef CONFIG_DPP2 1291 dpp_free_asymmetric_key(auth->conf_key_pkg); 1292 os_free(auth->csrattrs); 1293 wpabuf_free(auth->csr); 1294 wpabuf_free(auth->priv_key); 1295 wpabuf_free(auth->cacert); 1296 wpabuf_free(auth->certbag); 1297 os_free(auth->trusted_eap_server_name); 1298 wpabuf_free(auth->conf_resp_tcp); 1299 #endif /* CONFIG_DPP2 */ 1300 wpabuf_free(auth->net_access_key); 1301 dpp_bootstrap_info_free(auth->tmp_own_bi); 1302 if (auth->tmp_peer_bi) { 1303 dl_list_del(&auth->tmp_peer_bi->list); 1304 dpp_bootstrap_info_free(auth->tmp_peer_bi); 1305 } 1306 #ifdef CONFIG_TESTING_OPTIONS 1307 os_free(auth->config_obj_override); 1308 os_free(auth->discovery_override); 1309 os_free(auth->groups_override); 1310 #endif /* CONFIG_TESTING_OPTIONS */ 1311 bin_clear_free(auth, sizeof(*auth)); 1312 } 1313 1314 1315 static struct wpabuf * 1316 dpp_build_conf_start(struct dpp_authentication *auth, 1317 struct dpp_configuration *conf, size_t tailroom) 1318 { 1319 struct wpabuf *buf; 1320 1321 #ifdef CONFIG_TESTING_OPTIONS 1322 if (auth->discovery_override) 1323 tailroom += os_strlen(auth->discovery_override); 1324 #endif /* CONFIG_TESTING_OPTIONS */ 1325 1326 buf = wpabuf_alloc(200 + tailroom); 1327 if (!buf) 1328 return NULL; 1329 json_start_object(buf, NULL); 1330 json_add_string(buf, "wi-fi_tech", "infra"); 1331 json_value_sep(buf); 1332 #ifdef CONFIG_TESTING_OPTIONS 1333 if (auth->discovery_override) { 1334 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'", 1335 auth->discovery_override); 1336 wpabuf_put_str(buf, "\"discovery\":"); 1337 wpabuf_put_str(buf, auth->discovery_override); 1338 json_value_sep(buf); 1339 return buf; 1340 } 1341 #endif /* CONFIG_TESTING_OPTIONS */ 1342 json_start_object(buf, "discovery"); 1343 if (((!conf->ssid_charset || auth->peer_version < 2) && 1344 json_add_string_escape(buf, "ssid", conf->ssid, 1345 conf->ssid_len) < 0) || 1346 ((conf->ssid_charset && auth->peer_version >= 2) && 1347 json_add_base64url(buf, "ssid64", conf->ssid, 1348 conf->ssid_len) < 0)) { 1349 wpabuf_free(buf); 1350 return NULL; 1351 } 1352 if (conf->ssid_charset > 0) { 1353 json_value_sep(buf); 1354 json_add_int(buf, "ssid_charset", conf->ssid_charset); 1355 } 1356 json_end_object(buf); 1357 json_value_sep(buf); 1358 1359 return buf; 1360 } 1361 1362 1363 int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key, 1364 const char *kid, const struct dpp_curve_params *curve) 1365 { 1366 struct wpabuf *pub; 1367 const u8 *pos; 1368 int ret = -1; 1369 1370 pub = dpp_get_pubkey_point(key, 0); 1371 if (!pub) 1372 goto fail; 1373 1374 json_start_object(buf, name); 1375 json_add_string(buf, "kty", "EC"); 1376 json_value_sep(buf); 1377 json_add_string(buf, "crv", curve->jwk_crv); 1378 json_value_sep(buf); 1379 pos = wpabuf_head(pub); 1380 if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0) 1381 goto fail; 1382 json_value_sep(buf); 1383 pos += curve->prime_len; 1384 if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0) 1385 goto fail; 1386 if (kid) { 1387 json_value_sep(buf); 1388 json_add_string(buf, "kid", kid); 1389 } 1390 json_end_object(buf); 1391 ret = 0; 1392 fail: 1393 wpabuf_free(pub); 1394 return ret; 1395 } 1396 1397 1398 static void dpp_build_legacy_cred_params(struct wpabuf *buf, 1399 struct dpp_configuration *conf) 1400 { 1401 if (conf->passphrase && os_strlen(conf->passphrase) < 64) { 1402 json_add_string_escape(buf, "pass", conf->passphrase, 1403 os_strlen(conf->passphrase)); 1404 } else if (conf->psk_set) { 1405 char psk[2 * sizeof(conf->psk) + 1]; 1406 1407 wpa_snprintf_hex(psk, sizeof(psk), 1408 conf->psk, sizeof(conf->psk)); 1409 json_add_string(buf, "psk_hex", psk); 1410 forced_memzero(psk, sizeof(psk)); 1411 } 1412 } 1413 1414 1415 static const char * dpp_netrole_str(enum dpp_netrole netrole) 1416 { 1417 switch (netrole) { 1418 case DPP_NETROLE_STA: 1419 return "sta"; 1420 case DPP_NETROLE_AP: 1421 return "ap"; 1422 case DPP_NETROLE_CONFIGURATOR: 1423 return "configurator"; 1424 default: 1425 return "??"; 1426 } 1427 } 1428 1429 1430 static struct wpabuf * 1431 dpp_build_conf_obj_dpp(struct dpp_authentication *auth, 1432 struct dpp_configuration *conf) 1433 { 1434 struct wpabuf *buf = NULL; 1435 char *signed_conn = NULL; 1436 size_t tailroom; 1437 const struct dpp_curve_params *curve; 1438 struct wpabuf *dppcon = NULL; 1439 size_t extra_len = 1000; 1440 int incl_legacy; 1441 enum dpp_akm akm; 1442 const char *akm_str; 1443 1444 if (!auth->conf) { 1445 wpa_printf(MSG_INFO, 1446 "DPP: No configurator specified - cannot generate DPP config object"); 1447 goto fail; 1448 } 1449 curve = auth->conf->curve; 1450 1451 akm = conf->akm; 1452 if (dpp_akm_ver2(akm) && auth->peer_version < 2) { 1453 wpa_printf(MSG_DEBUG, 1454 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2"); 1455 akm = DPP_AKM_DPP; 1456 } 1457 1458 #ifdef CONFIG_TESTING_OPTIONS 1459 if (auth->groups_override) 1460 extra_len += os_strlen(auth->groups_override); 1461 #endif /* CONFIG_TESTING_OPTIONS */ 1462 1463 if (conf->group_id) 1464 extra_len += os_strlen(conf->group_id); 1465 1466 /* Connector (JSON dppCon object) */ 1467 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3); 1468 if (!dppcon) 1469 goto fail; 1470 #ifdef CONFIG_TESTING_OPTIONS 1471 if (auth->groups_override) { 1472 wpabuf_put_u8(dppcon, '{'); 1473 if (auth->groups_override) { 1474 wpa_printf(MSG_DEBUG, 1475 "DPP: TESTING - groups override: '%s'", 1476 auth->groups_override); 1477 wpabuf_put_str(dppcon, "\"groups\":"); 1478 wpabuf_put_str(dppcon, auth->groups_override); 1479 json_value_sep(dppcon); 1480 } 1481 goto skip_groups; 1482 } 1483 #endif /* CONFIG_TESTING_OPTIONS */ 1484 json_start_object(dppcon, NULL); 1485 json_start_array(dppcon, "groups"); 1486 json_start_object(dppcon, NULL); 1487 json_add_string(dppcon, "groupId", 1488 conf->group_id ? conf->group_id : "*"); 1489 json_value_sep(dppcon); 1490 json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole)); 1491 json_end_object(dppcon); 1492 json_end_array(dppcon); 1493 json_value_sep(dppcon); 1494 #ifdef CONFIG_TESTING_OPTIONS 1495 skip_groups: 1496 #endif /* CONFIG_TESTING_OPTIONS */ 1497 if (!auth->peer_protocol_key || 1498 dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL, 1499 auth->curve) < 0) { 1500 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK"); 1501 goto fail; 1502 } 1503 if (conf->netaccesskey_expiry) { 1504 struct os_tm tm; 1505 char expiry[30]; 1506 1507 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) { 1508 wpa_printf(MSG_DEBUG, 1509 "DPP: Failed to generate expiry string"); 1510 goto fail; 1511 } 1512 os_snprintf(expiry, sizeof(expiry), 1513 "%04u-%02u-%02uT%02u:%02u:%02uZ", 1514 tm.year, tm.month, tm.day, 1515 tm.hour, tm.min, tm.sec); 1516 json_value_sep(dppcon); 1517 json_add_string(dppcon, "expiry", expiry); 1518 } 1519 json_end_object(dppcon); 1520 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s", 1521 (const char *) wpabuf_head(dppcon)); 1522 1523 signed_conn = dpp_sign_connector(auth->conf, dppcon); 1524 if (!signed_conn) 1525 goto fail; 1526 1527 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm); 1528 tailroom = 1000; 1529 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid); 1530 tailroom += os_strlen(signed_conn); 1531 if (incl_legacy) 1532 tailroom += 1000; 1533 if (akm == DPP_AKM_DOT1X) { 1534 if (auth->certbag) 1535 tailroom += 2 * wpabuf_len(auth->certbag); 1536 if (auth->cacert) 1537 tailroom += 2 * wpabuf_len(auth->cacert); 1538 if (auth->trusted_eap_server_name) 1539 tailroom += os_strlen(auth->trusted_eap_server_name); 1540 tailroom += 1000; 1541 } 1542 buf = dpp_build_conf_start(auth, conf, tailroom); 1543 if (!buf) 1544 goto fail; 1545 1546 if (auth->akm_use_selector && dpp_akm_ver2(akm)) 1547 akm_str = dpp_akm_selector_str(akm); 1548 else 1549 akm_str = dpp_akm_str(akm); 1550 json_start_object(buf, "cred"); 1551 json_add_string(buf, "akm", akm_str); 1552 json_value_sep(buf); 1553 if (incl_legacy) { 1554 dpp_build_legacy_cred_params(buf, conf); 1555 json_value_sep(buf); 1556 } 1557 if (akm == DPP_AKM_DOT1X) { 1558 json_start_object(buf, "entCreds"); 1559 if (!auth->certbag) 1560 goto fail; 1561 json_add_base64(buf, "certBag", wpabuf_head(auth->certbag), 1562 wpabuf_len(auth->certbag)); 1563 if (auth->cacert) { 1564 json_value_sep(buf); 1565 json_add_base64(buf, "caCert", 1566 wpabuf_head(auth->cacert), 1567 wpabuf_len(auth->cacert)); 1568 } 1569 if (auth->trusted_eap_server_name) { 1570 json_value_sep(buf); 1571 json_add_string(buf, "trustedEapServerName", 1572 auth->trusted_eap_server_name); 1573 } 1574 json_value_sep(buf); 1575 json_start_array(buf, "eapMethods"); 1576 wpabuf_printf(buf, "%d", EAP_TYPE_TLS); 1577 json_end_array(buf); 1578 json_end_object(buf); 1579 json_value_sep(buf); 1580 } 1581 wpabuf_put_str(buf, "\"signedConnector\":\""); 1582 wpabuf_put_str(buf, signed_conn); 1583 wpabuf_put_str(buf, "\""); 1584 json_value_sep(buf); 1585 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid, 1586 curve) < 0) { 1587 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK"); 1588 goto fail; 1589 } 1590 #ifdef CONFIG_DPP2 1591 if (auth->peer_version >= 2 && auth->conf->pp_key) { 1592 json_value_sep(buf); 1593 if (dpp_build_jwk(buf, "ppKey", auth->conf->pp_key, NULL, 1594 curve) < 0) { 1595 wpa_printf(MSG_DEBUG, "DPP: Failed to build ppKey JWK"); 1596 goto fail; 1597 } 1598 } 1599 #endif /* CONFIG_DPP2 */ 1600 1601 json_end_object(buf); 1602 json_end_object(buf); 1603 1604 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object", 1605 wpabuf_head(buf), wpabuf_len(buf)); 1606 1607 out: 1608 os_free(signed_conn); 1609 wpabuf_free(dppcon); 1610 return buf; 1611 fail: 1612 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object"); 1613 wpabuf_free(buf); 1614 buf = NULL; 1615 goto out; 1616 } 1617 1618 1619 static struct wpabuf * 1620 dpp_build_conf_obj_legacy(struct dpp_authentication *auth, 1621 struct dpp_configuration *conf) 1622 { 1623 struct wpabuf *buf; 1624 const char *akm_str; 1625 1626 buf = dpp_build_conf_start(auth, conf, 1000); 1627 if (!buf) 1628 return NULL; 1629 1630 if (auth->akm_use_selector && dpp_akm_ver2(conf->akm)) 1631 akm_str = dpp_akm_selector_str(conf->akm); 1632 else 1633 akm_str = dpp_akm_str(conf->akm); 1634 json_start_object(buf, "cred"); 1635 json_add_string(buf, "akm", akm_str); 1636 json_value_sep(buf); 1637 dpp_build_legacy_cred_params(buf, conf); 1638 json_end_object(buf); 1639 json_end_object(buf); 1640 1641 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)", 1642 wpabuf_head(buf), wpabuf_len(buf)); 1643 1644 return buf; 1645 } 1646 1647 1648 static struct wpabuf * 1649 dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole, 1650 int idx, bool cert_req) 1651 { 1652 struct dpp_configuration *conf = NULL; 1653 1654 #ifdef CONFIG_TESTING_OPTIONS 1655 if (auth->config_obj_override) { 1656 if (idx != 0) 1657 return NULL; 1658 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override"); 1659 return wpabuf_alloc_copy(auth->config_obj_override, 1660 os_strlen(auth->config_obj_override)); 1661 } 1662 #endif /* CONFIG_TESTING_OPTIONS */ 1663 1664 if (idx == 0) { 1665 if (netrole == DPP_NETROLE_STA) 1666 conf = auth->conf_sta; 1667 else if (netrole == DPP_NETROLE_AP) 1668 conf = auth->conf_ap; 1669 } else if (idx == 1) { 1670 if (netrole == DPP_NETROLE_STA) 1671 conf = auth->conf2_sta; 1672 else if (netrole == DPP_NETROLE_AP) 1673 conf = auth->conf2_ap; 1674 } 1675 if (!conf) { 1676 if (idx == 0) 1677 wpa_printf(MSG_DEBUG, 1678 "DPP: No configuration available for Enrollee(%s) - reject configuration request", 1679 dpp_netrole_str(netrole)); 1680 return NULL; 1681 } 1682 1683 if (conf->akm == DPP_AKM_DOT1X) { 1684 if (!auth->conf) { 1685 wpa_printf(MSG_DEBUG, 1686 "DPP: No Configurator data available"); 1687 return NULL; 1688 } 1689 if (!cert_req && !auth->certbag) { 1690 wpa_printf(MSG_DEBUG, 1691 "DPP: No certificate data available for dot1x configuration"); 1692 return NULL; 1693 } 1694 return dpp_build_conf_obj_dpp(auth, conf); 1695 } 1696 if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf)) 1697 return dpp_build_conf_obj_dpp(auth, conf); 1698 return dpp_build_conf_obj_legacy(auth, conf); 1699 } 1700 1701 1702 struct wpabuf * 1703 dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, 1704 u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req) 1705 { 1706 struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL; 1707 size_t clear_len, attr_len; 1708 struct wpabuf *clear = NULL, *msg = NULL; 1709 u8 *wrapped; 1710 const u8 *addr[1]; 1711 size_t len[1]; 1712 enum dpp_status_error status; 1713 1714 if (auth->force_conf_resp_status != DPP_STATUS_OK) { 1715 status = auth->force_conf_resp_status; 1716 goto forced_status; 1717 } 1718 1719 if (netrole == DPP_NETROLE_CONFIGURATOR) { 1720 #ifdef CONFIG_DPP2 1721 env_data = dpp_build_enveloped_data(auth); 1722 #endif /* CONFIG_DPP2 */ 1723 } else { 1724 conf = dpp_build_conf_obj(auth, netrole, 0, cert_req); 1725 if (conf) { 1726 wpa_hexdump_ascii(MSG_DEBUG, 1727 "DPP: configurationObject JSON", 1728 wpabuf_head(conf), wpabuf_len(conf)); 1729 conf2 = dpp_build_conf_obj(auth, netrole, 1, cert_req); 1730 } 1731 } 1732 1733 if (conf || env_data) 1734 status = DPP_STATUS_OK; 1735 else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta && 1736 auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr) 1737 status = DPP_STATUS_CSR_NEEDED; 1738 else 1739 status = DPP_STATUS_CONFIGURE_FAILURE; 1740 forced_status: 1741 auth->conf_resp_status = status; 1742 1743 /* { E-nonce, configurationObject[, sendConnStatus]}ke */ 1744 clear_len = 4 + e_nonce_len; 1745 if (conf) 1746 clear_len += 4 + wpabuf_len(conf); 1747 if (conf2) 1748 clear_len += 4 + wpabuf_len(conf2); 1749 if (env_data) 1750 clear_len += 4 + wpabuf_len(env_data); 1751 if (auth->peer_version >= 2 && auth->send_conn_status && 1752 netrole == DPP_NETROLE_STA) 1753 clear_len += 4; 1754 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta && 1755 auth->conf_sta->csrattrs) 1756 clear_len += 4 + os_strlen(auth->conf_sta->csrattrs); 1757 clear = wpabuf_alloc(clear_len); 1758 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE; 1759 #ifdef CONFIG_TESTING_OPTIONS 1760 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) 1761 attr_len += 5; 1762 #endif /* CONFIG_TESTING_OPTIONS */ 1763 msg = wpabuf_alloc(attr_len); 1764 if (!clear || !msg) 1765 goto fail; 1766 1767 #ifdef CONFIG_TESTING_OPTIONS 1768 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) { 1769 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce"); 1770 goto skip_e_nonce; 1771 } 1772 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) { 1773 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch"); 1774 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 1775 wpabuf_put_le16(clear, e_nonce_len); 1776 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1); 1777 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01); 1778 goto skip_e_nonce; 1779 } 1780 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) { 1781 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data"); 1782 goto skip_wrapped_data; 1783 } 1784 #endif /* CONFIG_TESTING_OPTIONS */ 1785 1786 /* E-nonce */ 1787 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 1788 wpabuf_put_le16(clear, e_nonce_len); 1789 wpabuf_put_data(clear, e_nonce, e_nonce_len); 1790 1791 #ifdef CONFIG_TESTING_OPTIONS 1792 skip_e_nonce: 1793 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) { 1794 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object"); 1795 goto skip_config_obj; 1796 } 1797 #endif /* CONFIG_TESTING_OPTIONS */ 1798 1799 if (conf) { 1800 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ); 1801 wpabuf_put_le16(clear, wpabuf_len(conf)); 1802 wpabuf_put_buf(clear, conf); 1803 } 1804 if (auth->peer_version >= 2 && conf2) { 1805 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ); 1806 wpabuf_put_le16(clear, wpabuf_len(conf2)); 1807 wpabuf_put_buf(clear, conf2); 1808 } else if (conf2) { 1809 wpa_printf(MSG_DEBUG, 1810 "DPP: Second Config Object available, but peer does not support more than one"); 1811 } 1812 if (env_data) { 1813 wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA); 1814 wpabuf_put_le16(clear, wpabuf_len(env_data)); 1815 wpabuf_put_buf(clear, env_data); 1816 } 1817 1818 if (auth->peer_version >= 2 && auth->send_conn_status && 1819 netrole == DPP_NETROLE_STA && status == DPP_STATUS_OK) { 1820 wpa_printf(MSG_DEBUG, "DPP: sendConnStatus"); 1821 wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS); 1822 wpabuf_put_le16(clear, 0); 1823 } 1824 1825 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta && 1826 auth->conf_sta->csrattrs) { 1827 auth->waiting_csr = true; 1828 wpa_printf(MSG_DEBUG, "DPP: CSR Attributes Request"); 1829 wpabuf_put_le16(clear, DPP_ATTR_CSR_ATTR_REQ); 1830 wpabuf_put_le16(clear, os_strlen(auth->conf_sta->csrattrs)); 1831 wpabuf_put_str(clear, auth->conf_sta->csrattrs); 1832 } 1833 1834 #ifdef CONFIG_TESTING_OPTIONS 1835 skip_config_obj: 1836 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) { 1837 wpa_printf(MSG_INFO, "DPP: TESTING - Status"); 1838 goto skip_status; 1839 } 1840 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) { 1841 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status"); 1842 status = 255; 1843 } 1844 #endif /* CONFIG_TESTING_OPTIONS */ 1845 1846 /* DPP Status */ 1847 dpp_build_attr_status(msg, status); 1848 1849 #ifdef CONFIG_TESTING_OPTIONS 1850 skip_status: 1851 #endif /* CONFIG_TESTING_OPTIONS */ 1852 1853 addr[0] = wpabuf_head(msg); 1854 len[0] = wpabuf_len(msg); 1855 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]); 1856 1857 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 1858 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 1859 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 1860 1861 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 1862 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 1863 wpabuf_head(clear), wpabuf_len(clear), 1864 1, addr, len, wrapped) < 0) 1865 goto fail; 1866 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 1867 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 1868 1869 #ifdef CONFIG_TESTING_OPTIONS 1870 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) { 1871 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); 1872 dpp_build_attr_status(msg, DPP_STATUS_OK); 1873 } 1874 skip_wrapped_data: 1875 #endif /* CONFIG_TESTING_OPTIONS */ 1876 1877 wpa_hexdump_buf(MSG_DEBUG, 1878 "DPP: Configuration Response attributes", msg); 1879 out: 1880 wpabuf_clear_free(conf); 1881 wpabuf_clear_free(conf2); 1882 wpabuf_clear_free(env_data); 1883 wpabuf_clear_free(clear); 1884 1885 return msg; 1886 fail: 1887 wpabuf_free(msg); 1888 msg = NULL; 1889 goto out; 1890 } 1891 1892 1893 struct wpabuf * 1894 dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, 1895 size_t attr_len) 1896 { 1897 const u8 *wrapped_data, *e_nonce, *config_attr; 1898 u16 wrapped_data_len, e_nonce_len, config_attr_len; 1899 u8 *unwrapped = NULL; 1900 size_t unwrapped_len = 0; 1901 struct wpabuf *resp = NULL; 1902 struct json_token *root = NULL, *token; 1903 enum dpp_netrole netrole; 1904 struct wpabuf *cert_req = NULL; 1905 1906 #ifdef CONFIG_TESTING_OPTIONS 1907 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) { 1908 wpa_printf(MSG_INFO, 1909 "DPP: TESTING - stop at Config Request"); 1910 return NULL; 1911 } 1912 #endif /* CONFIG_TESTING_OPTIONS */ 1913 1914 if (dpp_check_attrs(attr_start, attr_len) < 0) { 1915 dpp_auth_fail(auth, "Invalid attribute in config request"); 1916 return NULL; 1917 } 1918 1919 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 1920 &wrapped_data_len); 1921 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 1922 dpp_auth_fail(auth, 1923 "Missing or invalid required Wrapped Data attribute"); 1924 return NULL; 1925 } 1926 1927 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 1928 wrapped_data, wrapped_data_len); 1929 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 1930 unwrapped = os_malloc(unwrapped_len); 1931 if (!unwrapped) 1932 return NULL; 1933 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 1934 wrapped_data, wrapped_data_len, 1935 0, NULL, NULL, unwrapped) < 0) { 1936 dpp_auth_fail(auth, "AES-SIV decryption failed"); 1937 goto fail; 1938 } 1939 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 1940 unwrapped, unwrapped_len); 1941 1942 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 1943 dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 1944 goto fail; 1945 } 1946 1947 e_nonce = dpp_get_attr(unwrapped, unwrapped_len, 1948 DPP_ATTR_ENROLLEE_NONCE, 1949 &e_nonce_len); 1950 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) { 1951 dpp_auth_fail(auth, 1952 "Missing or invalid Enrollee Nonce attribute"); 1953 goto fail; 1954 } 1955 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); 1956 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len); 1957 1958 config_attr = dpp_get_attr(unwrapped, unwrapped_len, 1959 DPP_ATTR_CONFIG_ATTR_OBJ, 1960 &config_attr_len); 1961 if (!config_attr) { 1962 dpp_auth_fail(auth, 1963 "Missing or invalid Config Attributes attribute"); 1964 goto fail; 1965 } 1966 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes", 1967 config_attr, config_attr_len); 1968 1969 root = json_parse((const char *) config_attr, config_attr_len); 1970 if (!root) { 1971 dpp_auth_fail(auth, "Could not parse Config Attributes"); 1972 goto fail; 1973 } 1974 1975 token = json_get_member(root, "name"); 1976 if (!token || token->type != JSON_STRING) { 1977 dpp_auth_fail(auth, "No Config Attributes - name"); 1978 goto fail; 1979 } 1980 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string); 1981 1982 token = json_get_member(root, "wi-fi_tech"); 1983 if (!token || token->type != JSON_STRING) { 1984 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech"); 1985 goto fail; 1986 } 1987 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string); 1988 if (os_strcmp(token->string, "infra") != 0) { 1989 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'", 1990 token->string); 1991 dpp_auth_fail(auth, "Unsupported wi-fi_tech"); 1992 goto fail; 1993 } 1994 1995 token = json_get_member(root, "netRole"); 1996 if (!token || token->type != JSON_STRING) { 1997 dpp_auth_fail(auth, "No Config Attributes - netRole"); 1998 goto fail; 1999 } 2000 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string); 2001 if (os_strcmp(token->string, "sta") == 0) { 2002 netrole = DPP_NETROLE_STA; 2003 } else if (os_strcmp(token->string, "ap") == 0) { 2004 netrole = DPP_NETROLE_AP; 2005 } else if (os_strcmp(token->string, "configurator") == 0) { 2006 netrole = DPP_NETROLE_CONFIGURATOR; 2007 } else { 2008 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'", 2009 token->string); 2010 dpp_auth_fail(auth, "Unsupported netRole"); 2011 goto fail; 2012 } 2013 auth->e_netrole = netrole; 2014 2015 token = json_get_member(root, "mudurl"); 2016 if (token && token->type == JSON_STRING) { 2017 wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string); 2018 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_MUD_URL "%s", 2019 token->string); 2020 } 2021 2022 token = json_get_member(root, "bandSupport"); 2023 if (token && token->type == JSON_ARRAY) { 2024 int *opclass = NULL; 2025 char txt[200], *pos, *end; 2026 int i, res; 2027 2028 wpa_printf(MSG_DEBUG, "DPP: bandSupport"); 2029 token = token->child; 2030 while (token) { 2031 if (token->type != JSON_NUMBER) { 2032 wpa_printf(MSG_DEBUG, 2033 "DPP: Invalid bandSupport array member type"); 2034 } else { 2035 wpa_printf(MSG_DEBUG, 2036 "DPP: Supported global operating class: %d", 2037 token->number); 2038 int_array_add_unique(&opclass, token->number); 2039 } 2040 token = token->sibling; 2041 } 2042 2043 txt[0] = '\0'; 2044 pos = txt; 2045 end = txt + sizeof(txt); 2046 for (i = 0; opclass && opclass[i]; i++) { 2047 res = os_snprintf(pos, end - pos, "%s%d", 2048 pos == txt ? "" : ",", opclass[i]); 2049 if (os_snprintf_error(end - pos, res)) { 2050 *pos = '\0'; 2051 break; 2052 } 2053 pos += res; 2054 } 2055 os_free(opclass); 2056 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_BAND_SUPPORT "%s", 2057 txt); 2058 } 2059 2060 #ifdef CONFIG_DPP2 2061 cert_req = json_get_member_base64(root, "pkcs10"); 2062 if (cert_req) { 2063 char *txt; 2064 int id; 2065 2066 wpa_hexdump_buf(MSG_DEBUG, "DPP: CertificateRequest", cert_req); 2067 if (dpp_validate_csr(auth, cert_req) < 0) { 2068 wpa_printf(MSG_DEBUG, "DPP: CSR is not valid"); 2069 auth->force_conf_resp_status = DPP_STATUS_CSR_BAD; 2070 goto cont; 2071 } 2072 2073 if (auth->peer_bi) { 2074 id = auth->peer_bi->id; 2075 } else if (auth->tmp_peer_bi) { 2076 id = auth->tmp_peer_bi->id; 2077 } else { 2078 struct dpp_bootstrap_info *bi; 2079 2080 bi = os_zalloc(sizeof(*bi)); 2081 if (!bi) 2082 goto fail; 2083 bi->id = dpp_next_id(auth->global); 2084 dl_list_add(&auth->global->bootstrap, &bi->list); 2085 auth->tmp_peer_bi = bi; 2086 id = bi->id; 2087 } 2088 2089 wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA"); 2090 txt = base64_encode_no_lf(wpabuf_head(cert_req), 2091 wpabuf_len(cert_req), NULL); 2092 if (!txt) 2093 goto fail; 2094 2095 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_CSR "peer=%d csr=%s", 2096 id, txt); 2097 os_free(txt); 2098 auth->waiting_csr = false; 2099 auth->waiting_cert = true; 2100 goto fail; 2101 } 2102 cont: 2103 #endif /* CONFIG_DPP2 */ 2104 2105 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole, 2106 cert_req); 2107 2108 fail: 2109 wpabuf_free(cert_req); 2110 json_free(root); 2111 os_free(unwrapped); 2112 return resp; 2113 } 2114 2115 2116 static int dpp_parse_cred_legacy(struct dpp_config_obj *conf, 2117 struct json_token *cred) 2118 { 2119 struct json_token *pass, *psk_hex; 2120 2121 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential"); 2122 2123 pass = json_get_member(cred, "pass"); 2124 psk_hex = json_get_member(cred, "psk_hex"); 2125 2126 if (pass && pass->type == JSON_STRING) { 2127 size_t len = os_strlen(pass->string); 2128 2129 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase", 2130 pass->string, len); 2131 if (len < 8 || len > 63) 2132 return -1; 2133 os_strlcpy(conf->passphrase, pass->string, 2134 sizeof(conf->passphrase)); 2135 } else if (psk_hex && psk_hex->type == JSON_STRING) { 2136 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) { 2137 wpa_printf(MSG_DEBUG, 2138 "DPP: Unexpected psk_hex with akm=sae"); 2139 return -1; 2140 } 2141 if (os_strlen(psk_hex->string) != PMK_LEN * 2 || 2142 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) { 2143 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding"); 2144 return -1; 2145 } 2146 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK", 2147 conf->psk, PMK_LEN); 2148 conf->psk_set = 1; 2149 } else { 2150 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found"); 2151 return -1; 2152 } 2153 2154 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) { 2155 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found"); 2156 return -1; 2157 } 2158 2159 return 0; 2160 } 2161 2162 2163 EVP_PKEY * dpp_parse_jwk(struct json_token *jwk, 2164 const struct dpp_curve_params **key_curve) 2165 { 2166 struct json_token *token; 2167 const struct dpp_curve_params *curve; 2168 struct wpabuf *x = NULL, *y = NULL; 2169 EC_GROUP *group; 2170 EVP_PKEY *pkey = NULL; 2171 2172 token = json_get_member(jwk, "kty"); 2173 if (!token || token->type != JSON_STRING) { 2174 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK"); 2175 goto fail; 2176 } 2177 if (os_strcmp(token->string, "EC") != 0) { 2178 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'", 2179 token->string); 2180 goto fail; 2181 } 2182 2183 token = json_get_member(jwk, "crv"); 2184 if (!token || token->type != JSON_STRING) { 2185 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK"); 2186 goto fail; 2187 } 2188 curve = dpp_get_curve_jwk_crv(token->string); 2189 if (!curve) { 2190 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'", 2191 token->string); 2192 goto fail; 2193 } 2194 2195 x = json_get_member_base64url(jwk, "x"); 2196 if (!x) { 2197 wpa_printf(MSG_DEBUG, "DPP: No x in JWK"); 2198 goto fail; 2199 } 2200 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x); 2201 if (wpabuf_len(x) != curve->prime_len) { 2202 wpa_printf(MSG_DEBUG, 2203 "DPP: Unexpected JWK x length %u (expected %u for curve %s)", 2204 (unsigned int) wpabuf_len(x), 2205 (unsigned int) curve->prime_len, curve->name); 2206 goto fail; 2207 } 2208 2209 y = json_get_member_base64url(jwk, "y"); 2210 if (!y) { 2211 wpa_printf(MSG_DEBUG, "DPP: No y in JWK"); 2212 goto fail; 2213 } 2214 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y); 2215 if (wpabuf_len(y) != curve->prime_len) { 2216 wpa_printf(MSG_DEBUG, 2217 "DPP: Unexpected JWK y length %u (expected %u for curve %s)", 2218 (unsigned int) wpabuf_len(y), 2219 (unsigned int) curve->prime_len, curve->name); 2220 goto fail; 2221 } 2222 2223 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name)); 2224 if (!group) { 2225 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK"); 2226 goto fail; 2227 } 2228 2229 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y), 2230 wpabuf_len(x)); 2231 EC_GROUP_free(group); 2232 *key_curve = curve; 2233 2234 fail: 2235 wpabuf_free(x); 2236 wpabuf_free(y); 2237 2238 return pkey; 2239 } 2240 2241 2242 int dpp_key_expired(const char *timestamp, os_time_t *expiry) 2243 { 2244 struct os_time now; 2245 unsigned int year, month, day, hour, min, sec; 2246 os_time_t utime; 2247 const char *pos; 2248 2249 /* ISO 8601 date and time: 2250 * <date>T<time> 2251 * YYYY-MM-DDTHH:MM:SSZ 2252 * YYYY-MM-DDTHH:MM:SS+03:00 2253 */ 2254 if (os_strlen(timestamp) < 19) { 2255 wpa_printf(MSG_DEBUG, 2256 "DPP: Too short timestamp - assume expired key"); 2257 return 1; 2258 } 2259 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u", 2260 &year, &month, &day, &hour, &min, &sec) != 6) { 2261 wpa_printf(MSG_DEBUG, 2262 "DPP: Failed to parse expiration day - assume expired key"); 2263 return 1; 2264 } 2265 2266 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) { 2267 wpa_printf(MSG_DEBUG, 2268 "DPP: Invalid date/time information - assume expired key"); 2269 return 1; 2270 } 2271 2272 pos = timestamp + 19; 2273 if (*pos == 'Z' || *pos == '\0') { 2274 /* In UTC - no need to adjust */ 2275 } else if (*pos == '-' || *pos == '+') { 2276 int items; 2277 2278 /* Adjust local time to UTC */ 2279 items = sscanf(pos + 1, "%02u:%02u", &hour, &min); 2280 if (items < 1) { 2281 wpa_printf(MSG_DEBUG, 2282 "DPP: Invalid time zone designator (%s) - assume expired key", 2283 pos); 2284 return 1; 2285 } 2286 if (*pos == '-') 2287 utime += 3600 * hour; 2288 if (*pos == '+') 2289 utime -= 3600 * hour; 2290 if (items > 1) { 2291 if (*pos == '-') 2292 utime += 60 * min; 2293 if (*pos == '+') 2294 utime -= 60 * min; 2295 } 2296 } else { 2297 wpa_printf(MSG_DEBUG, 2298 "DPP: Invalid time zone designator (%s) - assume expired key", 2299 pos); 2300 return 1; 2301 } 2302 if (expiry) 2303 *expiry = utime; 2304 2305 if (os_get_time(&now) < 0) { 2306 wpa_printf(MSG_DEBUG, 2307 "DPP: Cannot get current time - assume expired key"); 2308 return 1; 2309 } 2310 2311 if (now.sec > utime) { 2312 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)", 2313 utime, now.sec); 2314 return 1; 2315 } 2316 2317 return 0; 2318 } 2319 2320 2321 static int dpp_parse_connector(struct dpp_authentication *auth, 2322 struct dpp_config_obj *conf, 2323 const unsigned char *payload, 2324 u16 payload_len) 2325 { 2326 struct json_token *root, *groups, *netkey, *token; 2327 int ret = -1; 2328 EVP_PKEY *key = NULL; 2329 const struct dpp_curve_params *curve; 2330 unsigned int rules = 0; 2331 2332 root = json_parse((const char *) payload, payload_len); 2333 if (!root) { 2334 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed"); 2335 goto fail; 2336 } 2337 2338 groups = json_get_member(root, "groups"); 2339 if (!groups || groups->type != JSON_ARRAY) { 2340 wpa_printf(MSG_DEBUG, "DPP: No groups array found"); 2341 goto skip_groups; 2342 } 2343 for (token = groups->child; token; token = token->sibling) { 2344 struct json_token *id, *role; 2345 2346 id = json_get_member(token, "groupId"); 2347 if (!id || id->type != JSON_STRING) { 2348 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string"); 2349 goto fail; 2350 } 2351 2352 role = json_get_member(token, "netRole"); 2353 if (!role || role->type != JSON_STRING) { 2354 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string"); 2355 goto fail; 2356 } 2357 wpa_printf(MSG_DEBUG, 2358 "DPP: connector group: groupId='%s' netRole='%s'", 2359 id->string, role->string); 2360 rules++; 2361 } 2362 skip_groups: 2363 2364 if (!rules) { 2365 wpa_printf(MSG_DEBUG, 2366 "DPP: Connector includes no groups"); 2367 goto fail; 2368 } 2369 2370 token = json_get_member(root, "expiry"); 2371 if (!token || token->type != JSON_STRING) { 2372 wpa_printf(MSG_DEBUG, 2373 "DPP: No expiry string found - connector does not expire"); 2374 } else { 2375 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string); 2376 if (dpp_key_expired(token->string, 2377 &auth->net_access_key_expiry)) { 2378 wpa_printf(MSG_DEBUG, 2379 "DPP: Connector (netAccessKey) has expired"); 2380 goto fail; 2381 } 2382 } 2383 2384 netkey = json_get_member(root, "netAccessKey"); 2385 if (!netkey || netkey->type != JSON_OBJECT) { 2386 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found"); 2387 goto fail; 2388 } 2389 2390 key = dpp_parse_jwk(netkey, &curve); 2391 if (!key) 2392 goto fail; 2393 dpp_debug_print_key("DPP: Received netAccessKey", key); 2394 2395 if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) { 2396 wpa_printf(MSG_DEBUG, 2397 "DPP: netAccessKey in connector does not match own protocol key"); 2398 #ifdef CONFIG_TESTING_OPTIONS 2399 if (auth->ignore_netaccesskey_mismatch) { 2400 wpa_printf(MSG_DEBUG, 2401 "DPP: TESTING - skip netAccessKey mismatch"); 2402 } else { 2403 goto fail; 2404 } 2405 #else /* CONFIG_TESTING_OPTIONS */ 2406 goto fail; 2407 #endif /* CONFIG_TESTING_OPTIONS */ 2408 } 2409 2410 ret = 0; 2411 fail: 2412 EVP_PKEY_free(key); 2413 json_free(root); 2414 return ret; 2415 } 2416 2417 2418 static void dpp_copy_csign(struct dpp_config_obj *conf, EVP_PKEY *csign) 2419 { 2420 unsigned char *der = NULL; 2421 int der_len; 2422 2423 der_len = i2d_PUBKEY(csign, &der); 2424 if (der_len <= 0) 2425 return; 2426 wpabuf_free(conf->c_sign_key); 2427 conf->c_sign_key = wpabuf_alloc_copy(der, der_len); 2428 OPENSSL_free(der); 2429 } 2430 2431 2432 static void dpp_copy_ppkey(struct dpp_config_obj *conf, EVP_PKEY *ppkey) 2433 { 2434 unsigned char *der = NULL; 2435 int der_len; 2436 2437 der_len = i2d_PUBKEY(ppkey, &der); 2438 if (der_len <= 0) 2439 return; 2440 wpabuf_free(conf->pp_key); 2441 conf->pp_key = wpabuf_alloc_copy(der, der_len); 2442 OPENSSL_free(der); 2443 } 2444 2445 2446 static void dpp_copy_netaccesskey(struct dpp_authentication *auth, 2447 struct dpp_config_obj *conf) 2448 { 2449 unsigned char *der = NULL; 2450 int der_len; 2451 EC_KEY *eckey; 2452 EVP_PKEY *own_key; 2453 2454 own_key = auth->own_protocol_key; 2455 #ifdef CONFIG_DPP2 2456 if (auth->reconfig_connector_key == DPP_CONFIG_REUSEKEY && 2457 auth->reconfig_old_protocol_key) 2458 own_key = auth->reconfig_old_protocol_key; 2459 #endif /* CONFIG_DPP2 */ 2460 eckey = EVP_PKEY_get1_EC_KEY(own_key); 2461 if (!eckey) 2462 return; 2463 2464 der_len = i2d_ECPrivateKey(eckey, &der); 2465 if (der_len <= 0) { 2466 EC_KEY_free(eckey); 2467 return; 2468 } 2469 wpabuf_free(auth->net_access_key); 2470 auth->net_access_key = wpabuf_alloc_copy(der, der_len); 2471 OPENSSL_free(der); 2472 EC_KEY_free(eckey); 2473 } 2474 2475 2476 static int dpp_parse_cred_dpp(struct dpp_authentication *auth, 2477 struct dpp_config_obj *conf, 2478 struct json_token *cred) 2479 { 2480 struct dpp_signed_connector_info info; 2481 struct json_token *token, *csign, *ppkey; 2482 int ret = -1; 2483 EVP_PKEY *csign_pub = NULL, *pp_pub = NULL; 2484 const struct dpp_curve_params *key_curve = NULL, *pp_curve = NULL; 2485 const char *signed_connector; 2486 2487 os_memset(&info, 0, sizeof(info)); 2488 2489 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) { 2490 wpa_printf(MSG_DEBUG, 2491 "DPP: Legacy credential included in Connector credential"); 2492 if (dpp_parse_cred_legacy(conf, cred) < 0) 2493 return -1; 2494 } 2495 2496 wpa_printf(MSG_DEBUG, "DPP: Connector credential"); 2497 2498 csign = json_get_member(cred, "csign"); 2499 if (!csign || csign->type != JSON_OBJECT) { 2500 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON"); 2501 goto fail; 2502 } 2503 2504 csign_pub = dpp_parse_jwk(csign, &key_curve); 2505 if (!csign_pub) { 2506 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK"); 2507 goto fail; 2508 } 2509 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub); 2510 2511 ppkey = json_get_member(cred, "ppKey"); 2512 if (ppkey && ppkey->type == JSON_OBJECT) { 2513 pp_pub = dpp_parse_jwk(ppkey, &pp_curve); 2514 if (!pp_pub) { 2515 wpa_printf(MSG_DEBUG, "DPP: Failed to parse ppKey JWK"); 2516 goto fail; 2517 } 2518 dpp_debug_print_key("DPP: Received ppKey", pp_pub); 2519 if (key_curve != pp_curve) { 2520 wpa_printf(MSG_DEBUG, 2521 "DPP: C-sign-key and ppKey do not use the same curve"); 2522 goto fail; 2523 } 2524 } 2525 2526 token = json_get_member(cred, "signedConnector"); 2527 if (!token || token->type != JSON_STRING) { 2528 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found"); 2529 goto fail; 2530 } 2531 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector", 2532 token->string, os_strlen(token->string)); 2533 signed_connector = token->string; 2534 2535 if (os_strchr(signed_connector, '"') || 2536 os_strchr(signed_connector, '\n')) { 2537 wpa_printf(MSG_DEBUG, 2538 "DPP: Unexpected character in signedConnector"); 2539 goto fail; 2540 } 2541 2542 if (dpp_process_signed_connector(&info, csign_pub, 2543 signed_connector) != DPP_STATUS_OK) 2544 goto fail; 2545 2546 if (dpp_parse_connector(auth, conf, 2547 info.payload, info.payload_len) < 0) { 2548 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector"); 2549 goto fail; 2550 } 2551 2552 os_free(conf->connector); 2553 conf->connector = os_strdup(signed_connector); 2554 2555 dpp_copy_csign(conf, csign_pub); 2556 if (pp_pub) 2557 dpp_copy_ppkey(conf, pp_pub); 2558 if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2) 2559 dpp_copy_netaccesskey(auth, conf); 2560 2561 ret = 0; 2562 fail: 2563 EVP_PKEY_free(csign_pub); 2564 EVP_PKEY_free(pp_pub); 2565 os_free(info.payload); 2566 return ret; 2567 } 2568 2569 2570 #ifdef CONFIG_DPP2 2571 static int dpp_parse_cred_dot1x(struct dpp_authentication *auth, 2572 struct dpp_config_obj *conf, 2573 struct json_token *cred) 2574 { 2575 struct json_token *ent, *name; 2576 2577 ent = json_get_member(cred, "entCreds"); 2578 if (!ent || ent->type != JSON_OBJECT) { 2579 dpp_auth_fail(auth, "No entCreds in JSON"); 2580 return -1; 2581 } 2582 2583 conf->certbag = json_get_member_base64(ent, "certBag"); 2584 if (!conf->certbag) { 2585 dpp_auth_fail(auth, "No certBag in JSON"); 2586 return -1; 2587 } 2588 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received certBag", conf->certbag); 2589 conf->certs = dpp_pkcs7_certs(conf->certbag); 2590 if (!conf->certs) { 2591 dpp_auth_fail(auth, "No certificates in certBag"); 2592 return -1; 2593 } 2594 2595 conf->cacert = json_get_member_base64(ent, "caCert"); 2596 if (conf->cacert) 2597 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received caCert", 2598 conf->cacert); 2599 2600 name = json_get_member(ent, "trustedEapServerName"); 2601 if (name && 2602 (name->type != JSON_STRING || 2603 has_ctrl_char((const u8 *) name->string, 2604 os_strlen(name->string)))) { 2605 dpp_auth_fail(auth, 2606 "Invalid trustedEapServerName type in JSON"); 2607 return -1; 2608 } 2609 if (name && name->string) { 2610 wpa_printf(MSG_DEBUG, "DPP: Received trustedEapServerName: %s", 2611 name->string); 2612 conf->server_name = os_strdup(name->string); 2613 if (!conf->server_name) 2614 return -1; 2615 } 2616 2617 return 0; 2618 } 2619 #endif /* CONFIG_DPP2 */ 2620 2621 2622 const char * dpp_akm_str(enum dpp_akm akm) 2623 { 2624 switch (akm) { 2625 case DPP_AKM_DPP: 2626 return "dpp"; 2627 case DPP_AKM_PSK: 2628 return "psk"; 2629 case DPP_AKM_SAE: 2630 return "sae"; 2631 case DPP_AKM_PSK_SAE: 2632 return "psk+sae"; 2633 case DPP_AKM_SAE_DPP: 2634 return "dpp+sae"; 2635 case DPP_AKM_PSK_SAE_DPP: 2636 return "dpp+psk+sae"; 2637 case DPP_AKM_DOT1X: 2638 return "dot1x"; 2639 default: 2640 return "??"; 2641 } 2642 } 2643 2644 2645 const char * dpp_akm_selector_str(enum dpp_akm akm) 2646 { 2647 switch (akm) { 2648 case DPP_AKM_DPP: 2649 return "506F9A02"; 2650 case DPP_AKM_PSK: 2651 return "000FAC02+000FAC06"; 2652 case DPP_AKM_SAE: 2653 return "000FAC08"; 2654 case DPP_AKM_PSK_SAE: 2655 return "000FAC02+000FAC06+000FAC08"; 2656 case DPP_AKM_SAE_DPP: 2657 return "506F9A02+000FAC08"; 2658 case DPP_AKM_PSK_SAE_DPP: 2659 return "506F9A02+000FAC08+000FAC02+000FAC06"; 2660 case DPP_AKM_DOT1X: 2661 return "000FAC01+000FAC05"; 2662 default: 2663 return "??"; 2664 } 2665 } 2666 2667 2668 static enum dpp_akm dpp_akm_from_str(const char *akm) 2669 { 2670 const char *pos; 2671 int dpp = 0, psk = 0, sae = 0, dot1x = 0; 2672 2673 if (os_strcmp(akm, "psk") == 0) 2674 return DPP_AKM_PSK; 2675 if (os_strcmp(akm, "sae") == 0) 2676 return DPP_AKM_SAE; 2677 if (os_strcmp(akm, "psk+sae") == 0) 2678 return DPP_AKM_PSK_SAE; 2679 if (os_strcmp(akm, "dpp") == 0) 2680 return DPP_AKM_DPP; 2681 if (os_strcmp(akm, "dpp+sae") == 0) 2682 return DPP_AKM_SAE_DPP; 2683 if (os_strcmp(akm, "dpp+psk+sae") == 0) 2684 return DPP_AKM_PSK_SAE_DPP; 2685 if (os_strcmp(akm, "dot1x") == 0) 2686 return DPP_AKM_DOT1X; 2687 2688 pos = akm; 2689 while (*pos) { 2690 if (os_strlen(pos) < 8) 2691 break; 2692 if (os_strncasecmp(pos, "506F9A02", 8) == 0) 2693 dpp = 1; 2694 else if (os_strncasecmp(pos, "000FAC02", 8) == 0) 2695 psk = 1; 2696 else if (os_strncasecmp(pos, "000FAC06", 8) == 0) 2697 psk = 1; 2698 else if (os_strncasecmp(pos, "000FAC08", 8) == 0) 2699 sae = 1; 2700 else if (os_strncasecmp(pos, "000FAC01", 8) == 0) 2701 dot1x = 1; 2702 else if (os_strncasecmp(pos, "000FAC05", 8) == 0) 2703 dot1x = 1; 2704 pos += 8; 2705 if (*pos != '+') 2706 break; 2707 pos++; 2708 } 2709 2710 if (dpp && psk && sae) 2711 return DPP_AKM_PSK_SAE_DPP; 2712 if (dpp && sae) 2713 return DPP_AKM_SAE_DPP; 2714 if (dpp) 2715 return DPP_AKM_DPP; 2716 if (psk && sae) 2717 return DPP_AKM_PSK_SAE; 2718 if (sae) 2719 return DPP_AKM_SAE; 2720 if (psk) 2721 return DPP_AKM_PSK; 2722 if (dot1x) 2723 return DPP_AKM_DOT1X; 2724 2725 return DPP_AKM_UNKNOWN; 2726 } 2727 2728 2729 static int dpp_parse_conf_obj(struct dpp_authentication *auth, 2730 const u8 *conf_obj, u16 conf_obj_len) 2731 { 2732 int ret = -1; 2733 struct json_token *root, *token, *discovery, *cred; 2734 struct dpp_config_obj *conf; 2735 struct wpabuf *ssid64 = NULL; 2736 int legacy; 2737 2738 root = json_parse((const char *) conf_obj, conf_obj_len); 2739 if (!root) 2740 return -1; 2741 if (root->type != JSON_OBJECT) { 2742 dpp_auth_fail(auth, "JSON root is not an object"); 2743 goto fail; 2744 } 2745 2746 token = json_get_member(root, "wi-fi_tech"); 2747 if (!token || token->type != JSON_STRING) { 2748 dpp_auth_fail(auth, "No wi-fi_tech string value found"); 2749 goto fail; 2750 } 2751 if (os_strcmp(token->string, "infra") != 0) { 2752 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'", 2753 token->string); 2754 dpp_auth_fail(auth, "Unsupported wi-fi_tech value"); 2755 goto fail; 2756 } 2757 2758 discovery = json_get_member(root, "discovery"); 2759 if (!discovery || discovery->type != JSON_OBJECT) { 2760 dpp_auth_fail(auth, "No discovery object in JSON"); 2761 goto fail; 2762 } 2763 2764 ssid64 = json_get_member_base64url(discovery, "ssid64"); 2765 if (ssid64) { 2766 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64", 2767 wpabuf_head(ssid64), wpabuf_len(ssid64)); 2768 if (wpabuf_len(ssid64) > SSID_MAX_LEN) { 2769 dpp_auth_fail(auth, "Too long discovery::ssid64 value"); 2770 goto fail; 2771 } 2772 } else { 2773 token = json_get_member(discovery, "ssid"); 2774 if (!token || token->type != JSON_STRING) { 2775 dpp_auth_fail(auth, 2776 "No discovery::ssid string value found"); 2777 goto fail; 2778 } 2779 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid", 2780 token->string, os_strlen(token->string)); 2781 if (os_strlen(token->string) > SSID_MAX_LEN) { 2782 dpp_auth_fail(auth, 2783 "Too long discovery::ssid string value"); 2784 goto fail; 2785 } 2786 } 2787 2788 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) { 2789 wpa_printf(MSG_DEBUG, 2790 "DPP: No room for this many Config Objects - ignore this one"); 2791 ret = 0; 2792 goto fail; 2793 } 2794 conf = &auth->conf_obj[auth->num_conf_obj++]; 2795 2796 if (ssid64) { 2797 conf->ssid_len = wpabuf_len(ssid64); 2798 os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len); 2799 } else { 2800 conf->ssid_len = os_strlen(token->string); 2801 os_memcpy(conf->ssid, token->string, conf->ssid_len); 2802 } 2803 2804 token = json_get_member(discovery, "ssid_charset"); 2805 if (token && token->type == JSON_NUMBER) { 2806 conf->ssid_charset = token->number; 2807 wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d", 2808 conf->ssid_charset); 2809 } 2810 2811 cred = json_get_member(root, "cred"); 2812 if (!cred || cred->type != JSON_OBJECT) { 2813 dpp_auth_fail(auth, "No cred object in JSON"); 2814 goto fail; 2815 } 2816 2817 token = json_get_member(cred, "akm"); 2818 if (!token || token->type != JSON_STRING) { 2819 dpp_auth_fail(auth, "No cred::akm string value found"); 2820 goto fail; 2821 } 2822 conf->akm = dpp_akm_from_str(token->string); 2823 2824 legacy = dpp_akm_legacy(conf->akm); 2825 if (legacy && auth->peer_version >= 2) { 2826 struct json_token *csign, *s_conn; 2827 2828 csign = json_get_member(cred, "csign"); 2829 s_conn = json_get_member(cred, "signedConnector"); 2830 if (csign && csign->type == JSON_OBJECT && 2831 s_conn && s_conn->type == JSON_STRING) 2832 legacy = 0; 2833 } 2834 if (legacy) { 2835 if (dpp_parse_cred_legacy(conf, cred) < 0) 2836 goto fail; 2837 } else if (dpp_akm_dpp(conf->akm) || 2838 (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) { 2839 if (dpp_parse_cred_dpp(auth, conf, cred) < 0) 2840 goto fail; 2841 #ifdef CONFIG_DPP2 2842 } else if (conf->akm == DPP_AKM_DOT1X) { 2843 if (dpp_parse_cred_dot1x(auth, conf, cred) < 0 || 2844 dpp_parse_cred_dpp(auth, conf, cred) < 0) 2845 goto fail; 2846 #endif /* CONFIG_DPP2 */ 2847 } else { 2848 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s", 2849 token->string); 2850 dpp_auth_fail(auth, "Unsupported akm"); 2851 goto fail; 2852 } 2853 2854 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully"); 2855 ret = 0; 2856 fail: 2857 wpabuf_free(ssid64); 2858 json_free(root); 2859 return ret; 2860 } 2861 2862 2863 #ifdef CONFIG_DPP2 2864 static u8 * dpp_get_csr_attrs(const u8 *attrs, size_t attrs_len, size_t *len) 2865 { 2866 const u8 *b64; 2867 u16 b64_len; 2868 2869 b64 = dpp_get_attr(attrs, attrs_len, DPP_ATTR_CSR_ATTR_REQ, &b64_len); 2870 if (!b64) 2871 return NULL; 2872 return base64_decode((const char *) b64, b64_len, len); 2873 } 2874 #endif /* CONFIG_DPP2 */ 2875 2876 2877 int dpp_conf_resp_rx(struct dpp_authentication *auth, 2878 const struct wpabuf *resp) 2879 { 2880 const u8 *wrapped_data, *e_nonce, *status, *conf_obj; 2881 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len; 2882 const u8 *env_data; 2883 u16 env_data_len; 2884 const u8 *addr[1]; 2885 size_t len[1]; 2886 u8 *unwrapped = NULL; 2887 size_t unwrapped_len = 0; 2888 int ret = -1; 2889 2890 auth->conf_resp_status = 255; 2891 2892 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) { 2893 dpp_auth_fail(auth, "Invalid attribute in config response"); 2894 return -1; 2895 } 2896 2897 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp), 2898 DPP_ATTR_WRAPPED_DATA, 2899 &wrapped_data_len); 2900 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 2901 dpp_auth_fail(auth, 2902 "Missing or invalid required Wrapped Data attribute"); 2903 return -1; 2904 } 2905 2906 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 2907 wrapped_data, wrapped_data_len); 2908 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 2909 unwrapped = os_malloc(unwrapped_len); 2910 if (!unwrapped) 2911 return -1; 2912 2913 addr[0] = wpabuf_head(resp); 2914 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp); 2915 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]); 2916 2917 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 2918 wrapped_data, wrapped_data_len, 2919 1, addr, len, unwrapped) < 0) { 2920 dpp_auth_fail(auth, "AES-SIV decryption failed"); 2921 goto fail; 2922 } 2923 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 2924 unwrapped, unwrapped_len); 2925 2926 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 2927 dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 2928 goto fail; 2929 } 2930 2931 e_nonce = dpp_get_attr(unwrapped, unwrapped_len, 2932 DPP_ATTR_ENROLLEE_NONCE, 2933 &e_nonce_len); 2934 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) { 2935 dpp_auth_fail(auth, 2936 "Missing or invalid Enrollee Nonce attribute"); 2937 goto fail; 2938 } 2939 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); 2940 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) { 2941 dpp_auth_fail(auth, "Enrollee Nonce mismatch"); 2942 goto fail; 2943 } 2944 2945 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp), 2946 DPP_ATTR_STATUS, &status_len); 2947 if (!status || status_len < 1) { 2948 dpp_auth_fail(auth, 2949 "Missing or invalid required DPP Status attribute"); 2950 goto fail; 2951 } 2952 auth->conf_resp_status = status[0]; 2953 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); 2954 #ifdef CONFIG_DPP2 2955 if (status[0] == DPP_STATUS_CSR_NEEDED) { 2956 u8 *csrattrs; 2957 size_t csrattrs_len; 2958 2959 wpa_printf(MSG_DEBUG, "DPP: Configurator requested CSR"); 2960 2961 csrattrs = dpp_get_csr_attrs(unwrapped, unwrapped_len, 2962 &csrattrs_len); 2963 if (!csrattrs) { 2964 dpp_auth_fail(auth, 2965 "Missing or invalid CSR Attributes Request attribute"); 2966 goto fail; 2967 } 2968 wpa_hexdump(MSG_DEBUG, "DPP: CsrAttrs", csrattrs, csrattrs_len); 2969 os_free(auth->csrattrs); 2970 auth->csrattrs = csrattrs; 2971 auth->csrattrs_len = csrattrs_len; 2972 ret = -2; 2973 goto fail; 2974 } 2975 #endif /* CONFIG_DPP2 */ 2976 if (status[0] != DPP_STATUS_OK) { 2977 dpp_auth_fail(auth, "Configurator rejected configuration"); 2978 goto fail; 2979 } 2980 2981 env_data = dpp_get_attr(unwrapped, unwrapped_len, 2982 DPP_ATTR_ENVELOPED_DATA, &env_data_len); 2983 #ifdef CONFIG_DPP2 2984 if (env_data && 2985 dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0) 2986 goto fail; 2987 #endif /* CONFIG_DPP2 */ 2988 2989 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ, 2990 &conf_obj_len); 2991 if (!conf_obj && !env_data) { 2992 dpp_auth_fail(auth, 2993 "Missing required Configuration Object attribute"); 2994 goto fail; 2995 } 2996 while (conf_obj) { 2997 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON", 2998 conf_obj, conf_obj_len); 2999 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0) 3000 goto fail; 3001 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len, 3002 DPP_ATTR_CONFIG_OBJ, 3003 &conf_obj_len); 3004 } 3005 3006 #ifdef CONFIG_DPP2 3007 status = dpp_get_attr(unwrapped, unwrapped_len, 3008 DPP_ATTR_SEND_CONN_STATUS, &status_len); 3009 if (status) { 3010 wpa_printf(MSG_DEBUG, 3011 "DPP: Configurator requested connection status result"); 3012 auth->conn_status_requested = 1; 3013 } 3014 #endif /* CONFIG_DPP2 */ 3015 3016 ret = 0; 3017 3018 fail: 3019 os_free(unwrapped); 3020 return ret; 3021 } 3022 3023 3024 #ifdef CONFIG_DPP2 3025 3026 enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth, 3027 const u8 *hdr, 3028 const u8 *attr_start, size_t attr_len) 3029 { 3030 const u8 *wrapped_data, *status, *e_nonce; 3031 u16 wrapped_data_len, status_len, e_nonce_len; 3032 const u8 *addr[2]; 3033 size_t len[2]; 3034 u8 *unwrapped = NULL; 3035 size_t unwrapped_len = 0; 3036 enum dpp_status_error ret = 256; 3037 3038 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 3039 &wrapped_data_len); 3040 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 3041 dpp_auth_fail(auth, 3042 "Missing or invalid required Wrapped Data attribute"); 3043 goto fail; 3044 } 3045 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data", 3046 wrapped_data, wrapped_data_len); 3047 3048 attr_len = wrapped_data - 4 - attr_start; 3049 3050 addr[0] = hdr; 3051 len[0] = DPP_HDR_LEN; 3052 addr[1] = attr_start; 3053 len[1] = attr_len; 3054 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 3055 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 3056 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 3057 wrapped_data, wrapped_data_len); 3058 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 3059 unwrapped = os_malloc(unwrapped_len); 3060 if (!unwrapped) 3061 goto fail; 3062 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 3063 wrapped_data, wrapped_data_len, 3064 2, addr, len, unwrapped) < 0) { 3065 dpp_auth_fail(auth, "AES-SIV decryption failed"); 3066 goto fail; 3067 } 3068 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 3069 unwrapped, unwrapped_len); 3070 3071 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 3072 dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 3073 goto fail; 3074 } 3075 3076 e_nonce = dpp_get_attr(unwrapped, unwrapped_len, 3077 DPP_ATTR_ENROLLEE_NONCE, 3078 &e_nonce_len); 3079 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) { 3080 dpp_auth_fail(auth, 3081 "Missing or invalid Enrollee Nonce attribute"); 3082 goto fail; 3083 } 3084 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); 3085 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) { 3086 dpp_auth_fail(auth, "Enrollee Nonce mismatch"); 3087 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce", 3088 auth->e_nonce, e_nonce_len); 3089 goto fail; 3090 } 3091 3092 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS, 3093 &status_len); 3094 if (!status || status_len < 1) { 3095 dpp_auth_fail(auth, 3096 "Missing or invalid required DPP Status attribute"); 3097 goto fail; 3098 } 3099 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); 3100 ret = status[0]; 3101 3102 fail: 3103 bin_clear_free(unwrapped, unwrapped_len); 3104 return ret; 3105 } 3106 3107 3108 struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth, 3109 enum dpp_status_error status) 3110 { 3111 struct wpabuf *msg, *clear; 3112 size_t nonce_len, clear_len, attr_len; 3113 const u8 *addr[2]; 3114 size_t len[2]; 3115 u8 *wrapped; 3116 3117 nonce_len = auth->curve->nonce_len; 3118 clear_len = 5 + 4 + nonce_len; 3119 attr_len = 4 + clear_len + AES_BLOCK_SIZE; 3120 clear = wpabuf_alloc(clear_len); 3121 msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len); 3122 if (!clear || !msg) 3123 goto fail; 3124 3125 /* DPP Status */ 3126 dpp_build_attr_status(clear, status); 3127 3128 /* E-nonce */ 3129 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 3130 wpabuf_put_le16(clear, nonce_len); 3131 wpabuf_put_data(clear, auth->e_nonce, nonce_len); 3132 3133 /* OUI, OUI type, Crypto Suite, DPP frame type */ 3134 addr[0] = wpabuf_head_u8(msg) + 2; 3135 len[0] = 3 + 1 + 1 + 1; 3136 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 3137 3138 /* Attributes before Wrapped Data (none) */ 3139 addr[1] = wpabuf_put(msg, 0); 3140 len[1] = 0; 3141 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 3142 3143 /* Wrapped Data */ 3144 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 3145 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 3146 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 3147 3148 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 3149 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 3150 wpabuf_head(clear), wpabuf_len(clear), 3151 2, addr, len, wrapped) < 0) 3152 goto fail; 3153 3154 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg); 3155 wpabuf_free(clear); 3156 return msg; 3157 fail: 3158 wpabuf_free(clear); 3159 wpabuf_free(msg); 3160 return NULL; 3161 } 3162 3163 3164 static int valid_channel_list(const char *val) 3165 { 3166 while (*val) { 3167 if (!((*val >= '0' && *val <= '9') || 3168 *val == '/' || *val == ',')) 3169 return 0; 3170 val++; 3171 } 3172 3173 return 1; 3174 } 3175 3176 3177 enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth, 3178 const u8 *hdr, 3179 const u8 *attr_start, 3180 size_t attr_len, 3181 u8 *ssid, size_t *ssid_len, 3182 char **channel_list) 3183 { 3184 const u8 *wrapped_data, *status, *e_nonce; 3185 u16 wrapped_data_len, status_len, e_nonce_len; 3186 const u8 *addr[2]; 3187 size_t len[2]; 3188 u8 *unwrapped = NULL; 3189 size_t unwrapped_len = 0; 3190 enum dpp_status_error ret = 256; 3191 struct json_token *root = NULL, *token; 3192 struct wpabuf *ssid64; 3193 3194 *ssid_len = 0; 3195 *channel_list = NULL; 3196 3197 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 3198 &wrapped_data_len); 3199 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 3200 dpp_auth_fail(auth, 3201 "Missing or invalid required Wrapped Data attribute"); 3202 goto fail; 3203 } 3204 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data", 3205 wrapped_data, wrapped_data_len); 3206 3207 attr_len = wrapped_data - 4 - attr_start; 3208 3209 addr[0] = hdr; 3210 len[0] = DPP_HDR_LEN; 3211 addr[1] = attr_start; 3212 len[1] = attr_len; 3213 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 3214 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 3215 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 3216 wrapped_data, wrapped_data_len); 3217 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 3218 unwrapped = os_malloc(unwrapped_len); 3219 if (!unwrapped) 3220 goto fail; 3221 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 3222 wrapped_data, wrapped_data_len, 3223 2, addr, len, unwrapped) < 0) { 3224 dpp_auth_fail(auth, "AES-SIV decryption failed"); 3225 goto fail; 3226 } 3227 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 3228 unwrapped, unwrapped_len); 3229 3230 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 3231 dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 3232 goto fail; 3233 } 3234 3235 e_nonce = dpp_get_attr(unwrapped, unwrapped_len, 3236 DPP_ATTR_ENROLLEE_NONCE, 3237 &e_nonce_len); 3238 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) { 3239 dpp_auth_fail(auth, 3240 "Missing or invalid Enrollee Nonce attribute"); 3241 goto fail; 3242 } 3243 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); 3244 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) { 3245 dpp_auth_fail(auth, "Enrollee Nonce mismatch"); 3246 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce", 3247 auth->e_nonce, e_nonce_len); 3248 goto fail; 3249 } 3250 3251 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS, 3252 &status_len); 3253 if (!status) { 3254 dpp_auth_fail(auth, 3255 "Missing required DPP Connection Status attribute"); 3256 goto fail; 3257 } 3258 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON", 3259 status, status_len); 3260 3261 root = json_parse((const char *) status, status_len); 3262 if (!root) { 3263 dpp_auth_fail(auth, "Could not parse connStatus"); 3264 goto fail; 3265 } 3266 3267 ssid64 = json_get_member_base64url(root, "ssid64"); 3268 if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) { 3269 *ssid_len = wpabuf_len(ssid64); 3270 os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len); 3271 } 3272 wpabuf_free(ssid64); 3273 3274 token = json_get_member(root, "channelList"); 3275 if (token && token->type == JSON_STRING && 3276 valid_channel_list(token->string)) 3277 *channel_list = os_strdup(token->string); 3278 3279 token = json_get_member(root, "result"); 3280 if (!token || token->type != JSON_NUMBER) { 3281 dpp_auth_fail(auth, "No connStatus - result"); 3282 goto fail; 3283 } 3284 wpa_printf(MSG_DEBUG, "DPP: result %d", token->number); 3285 ret = token->number; 3286 3287 fail: 3288 json_free(root); 3289 bin_clear_free(unwrapped, unwrapped_len); 3290 return ret; 3291 } 3292 3293 3294 struct wpabuf * dpp_build_conn_status(enum dpp_status_error result, 3295 const u8 *ssid, size_t ssid_len, 3296 const char *channel_list) 3297 { 3298 struct wpabuf *json; 3299 3300 json = wpabuf_alloc(1000); 3301 if (!json) 3302 return NULL; 3303 json_start_object(json, NULL); 3304 json_add_int(json, "result", result); 3305 if (ssid) { 3306 json_value_sep(json); 3307 if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0) { 3308 wpabuf_free(json); 3309 return NULL; 3310 } 3311 } 3312 if (channel_list) { 3313 json_value_sep(json); 3314 json_add_string(json, "channelList", channel_list); 3315 } 3316 json_end_object(json); 3317 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON", 3318 wpabuf_head(json), wpabuf_len(json)); 3319 3320 return json; 3321 } 3322 3323 3324 struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth, 3325 enum dpp_status_error result, 3326 const u8 *ssid, size_t ssid_len, 3327 const char *channel_list) 3328 { 3329 struct wpabuf *msg = NULL, *clear = NULL, *json; 3330 size_t nonce_len, clear_len, attr_len; 3331 const u8 *addr[2]; 3332 size_t len[2]; 3333 u8 *wrapped; 3334 3335 json = dpp_build_conn_status(result, ssid, ssid_len, channel_list); 3336 if (!json) 3337 return NULL; 3338 3339 nonce_len = auth->curve->nonce_len; 3340 clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json); 3341 attr_len = 4 + clear_len + AES_BLOCK_SIZE; 3342 clear = wpabuf_alloc(clear_len); 3343 msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len); 3344 if (!clear || !msg) 3345 goto fail; 3346 3347 /* E-nonce */ 3348 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 3349 wpabuf_put_le16(clear, nonce_len); 3350 wpabuf_put_data(clear, auth->e_nonce, nonce_len); 3351 3352 /* DPP Connection Status */ 3353 wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS); 3354 wpabuf_put_le16(clear, wpabuf_len(json)); 3355 wpabuf_put_buf(clear, json); 3356 3357 /* OUI, OUI type, Crypto Suite, DPP frame type */ 3358 addr[0] = wpabuf_head_u8(msg) + 2; 3359 len[0] = 3 + 1 + 1 + 1; 3360 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 3361 3362 /* Attributes before Wrapped Data (none) */ 3363 addr[1] = wpabuf_put(msg, 0); 3364 len[1] = 0; 3365 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 3366 3367 /* Wrapped Data */ 3368 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 3369 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 3370 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 3371 3372 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 3373 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 3374 wpabuf_head(clear), wpabuf_len(clear), 3375 2, addr, len, wrapped) < 0) 3376 goto fail; 3377 3378 wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes", 3379 msg); 3380 wpabuf_free(json); 3381 wpabuf_free(clear); 3382 return msg; 3383 fail: 3384 wpabuf_free(json); 3385 wpabuf_free(clear); 3386 wpabuf_free(msg); 3387 return NULL; 3388 } 3389 3390 #endif /* CONFIG_DPP2 */ 3391 3392 3393 void dpp_configurator_free(struct dpp_configurator *conf) 3394 { 3395 if (!conf) 3396 return; 3397 EVP_PKEY_free(conf->csign); 3398 os_free(conf->kid); 3399 os_free(conf->connector); 3400 EVP_PKEY_free(conf->connector_key); 3401 EVP_PKEY_free(conf->pp_key); 3402 os_free(conf); 3403 } 3404 3405 3406 int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf, 3407 size_t buflen) 3408 { 3409 EC_KEY *eckey; 3410 int key_len, ret = -1; 3411 unsigned char *key = NULL; 3412 3413 if (!conf->csign) 3414 return -1; 3415 3416 eckey = EVP_PKEY_get1_EC_KEY(conf->csign); 3417 if (!eckey) 3418 return -1; 3419 3420 key_len = i2d_ECPrivateKey(eckey, &key); 3421 if (key_len > 0) 3422 ret = wpa_snprintf_hex(buf, buflen, key, key_len); 3423 3424 EC_KEY_free(eckey); 3425 OPENSSL_free(key); 3426 return ret; 3427 } 3428 3429 3430 static int dpp_configurator_gen_kid(struct dpp_configurator *conf) 3431 { 3432 struct wpabuf *csign_pub = NULL; 3433 const u8 *addr[1]; 3434 size_t len[1]; 3435 int res; 3436 3437 csign_pub = dpp_get_pubkey_point(conf->csign, 1); 3438 if (!csign_pub) { 3439 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key"); 3440 return -1; 3441 } 3442 3443 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */ 3444 addr[0] = wpabuf_head(csign_pub); 3445 len[0] = wpabuf_len(csign_pub); 3446 res = sha256_vector(1, addr, len, conf->kid_hash); 3447 wpabuf_free(csign_pub); 3448 if (res < 0) { 3449 wpa_printf(MSG_DEBUG, 3450 "DPP: Failed to derive kid for C-sign-key"); 3451 return -1; 3452 } 3453 3454 conf->kid = base64_url_encode(conf->kid_hash, sizeof(conf->kid_hash), 3455 NULL); 3456 return conf->kid ? 0 : -1; 3457 } 3458 3459 3460 static struct dpp_configurator * 3461 dpp_keygen_configurator(const char *curve, const u8 *privkey, 3462 size_t privkey_len, const u8 *pp_key, size_t pp_key_len) 3463 { 3464 struct dpp_configurator *conf; 3465 3466 conf = os_zalloc(sizeof(*conf)); 3467 if (!conf) 3468 return NULL; 3469 3470 conf->curve = dpp_get_curve_name(curve); 3471 if (!conf->curve) { 3472 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve); 3473 os_free(conf); 3474 return NULL; 3475 } 3476 3477 if (privkey) 3478 conf->csign = dpp_set_keypair(&conf->curve, privkey, 3479 privkey_len); 3480 else 3481 conf->csign = dpp_gen_keypair(conf->curve); 3482 if (pp_key) 3483 conf->pp_key = dpp_set_keypair(&conf->curve, pp_key, 3484 pp_key_len); 3485 else 3486 conf->pp_key = dpp_gen_keypair(conf->curve); 3487 if (!conf->csign || !conf->pp_key) 3488 goto fail; 3489 conf->own = 1; 3490 3491 if (dpp_configurator_gen_kid(conf) < 0) 3492 goto fail; 3493 return conf; 3494 fail: 3495 dpp_configurator_free(conf); 3496 return NULL; 3497 } 3498 3499 3500 int dpp_configurator_own_config(struct dpp_authentication *auth, 3501 const char *curve, int ap) 3502 { 3503 struct wpabuf *conf_obj; 3504 int ret = -1; 3505 3506 if (!auth->conf) { 3507 wpa_printf(MSG_DEBUG, "DPP: No configurator specified"); 3508 return -1; 3509 } 3510 3511 auth->curve = dpp_get_curve_name(curve); 3512 if (!auth->curve) { 3513 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve); 3514 return -1; 3515 } 3516 3517 wpa_printf(MSG_DEBUG, 3518 "DPP: Building own configuration/connector with curve %s", 3519 auth->curve->name); 3520 3521 auth->own_protocol_key = dpp_gen_keypair(auth->curve); 3522 if (!auth->own_protocol_key) 3523 return -1; 3524 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]); 3525 auth->peer_protocol_key = auth->own_protocol_key; 3526 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign); 3527 3528 conf_obj = dpp_build_conf_obj(auth, ap, 0, NULL); 3529 if (!conf_obj) { 3530 wpabuf_free(auth->conf_obj[0].c_sign_key); 3531 auth->conf_obj[0].c_sign_key = NULL; 3532 goto fail; 3533 } 3534 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj), 3535 wpabuf_len(conf_obj)); 3536 fail: 3537 wpabuf_free(conf_obj); 3538 auth->peer_protocol_key = NULL; 3539 return ret; 3540 } 3541 3542 3543 static int dpp_compatible_netrole(const char *role1, const char *role2) 3544 { 3545 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) || 3546 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0); 3547 } 3548 3549 3550 static int dpp_connector_compatible_group(struct json_token *root, 3551 const char *group_id, 3552 const char *net_role, 3553 bool reconfig) 3554 { 3555 struct json_token *groups, *token; 3556 3557 groups = json_get_member(root, "groups"); 3558 if (!groups || groups->type != JSON_ARRAY) 3559 return 0; 3560 3561 for (token = groups->child; token; token = token->sibling) { 3562 struct json_token *id, *role; 3563 3564 id = json_get_member(token, "groupId"); 3565 if (!id || id->type != JSON_STRING) 3566 continue; 3567 3568 role = json_get_member(token, "netRole"); 3569 if (!role || role->type != JSON_STRING) 3570 continue; 3571 3572 if (os_strcmp(id->string, "*") != 0 && 3573 os_strcmp(group_id, "*") != 0 && 3574 os_strcmp(id->string, group_id) != 0) 3575 continue; 3576 3577 if (reconfig && os_strcmp(net_role, "configurator") == 0) 3578 return 1; 3579 if (!reconfig && dpp_compatible_netrole(role->string, net_role)) 3580 return 1; 3581 } 3582 3583 return 0; 3584 } 3585 3586 3587 int dpp_connector_match_groups(struct json_token *own_root, 3588 struct json_token *peer_root, bool reconfig) 3589 { 3590 struct json_token *groups, *token; 3591 3592 groups = json_get_member(peer_root, "groups"); 3593 if (!groups || groups->type != JSON_ARRAY) { 3594 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found"); 3595 return 0; 3596 } 3597 3598 for (token = groups->child; token; token = token->sibling) { 3599 struct json_token *id, *role; 3600 3601 id = json_get_member(token, "groupId"); 3602 if (!id || id->type != JSON_STRING) { 3603 wpa_printf(MSG_DEBUG, 3604 "DPP: Missing peer groupId string"); 3605 continue; 3606 } 3607 3608 role = json_get_member(token, "netRole"); 3609 if (!role || role->type != JSON_STRING) { 3610 wpa_printf(MSG_DEBUG, 3611 "DPP: Missing peer groups::netRole string"); 3612 continue; 3613 } 3614 wpa_printf(MSG_DEBUG, 3615 "DPP: peer connector group: groupId='%s' netRole='%s'", 3616 id->string, role->string); 3617 if (dpp_connector_compatible_group(own_root, id->string, 3618 role->string, reconfig)) { 3619 wpa_printf(MSG_DEBUG, 3620 "DPP: Compatible group/netRole in own connector"); 3621 return 1; 3622 } 3623 } 3624 3625 return 0; 3626 } 3627 3628 3629 struct json_token * dpp_parse_own_connector(const char *own_connector) 3630 { 3631 unsigned char *own_conn; 3632 size_t own_conn_len; 3633 const char *pos, *end; 3634 struct json_token *own_root; 3635 3636 pos = os_strchr(own_connector, '.'); 3637 if (!pos) { 3638 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)"); 3639 return NULL; 3640 } 3641 pos++; 3642 end = os_strchr(pos, '.'); 3643 if (!end) { 3644 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)"); 3645 return NULL; 3646 } 3647 own_conn = base64_url_decode(pos, end - pos, &own_conn_len); 3648 if (!own_conn) { 3649 wpa_printf(MSG_DEBUG, 3650 "DPP: Failed to base64url decode own signedConnector JWS Payload"); 3651 return NULL; 3652 } 3653 3654 own_root = json_parse((const char *) own_conn, own_conn_len); 3655 os_free(own_conn); 3656 if (!own_root) 3657 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector"); 3658 3659 return own_root; 3660 } 3661 3662 3663 enum dpp_status_error 3664 dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, 3665 const u8 *net_access_key, size_t net_access_key_len, 3666 const u8 *csign_key, size_t csign_key_len, 3667 const u8 *peer_connector, size_t peer_connector_len, 3668 os_time_t *expiry) 3669 { 3670 struct json_token *root = NULL, *netkey, *token; 3671 struct json_token *own_root = NULL; 3672 enum dpp_status_error ret = 255, res; 3673 EVP_PKEY *own_key = NULL, *peer_key = NULL; 3674 struct wpabuf *own_key_pub = NULL; 3675 const struct dpp_curve_params *curve, *own_curve; 3676 struct dpp_signed_connector_info info; 3677 size_t Nx_len; 3678 u8 Nx[DPP_MAX_SHARED_SECRET_LEN]; 3679 3680 os_memset(intro, 0, sizeof(*intro)); 3681 os_memset(&info, 0, sizeof(info)); 3682 if (expiry) 3683 *expiry = 0; 3684 3685 own_key = dpp_set_keypair(&own_curve, net_access_key, 3686 net_access_key_len); 3687 if (!own_key) { 3688 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey"); 3689 goto fail; 3690 } 3691 3692 own_root = dpp_parse_own_connector(own_connector); 3693 if (!own_root) 3694 goto fail; 3695 3696 res = dpp_check_signed_connector(&info, csign_key, csign_key_len, 3697 peer_connector, peer_connector_len); 3698 if (res != DPP_STATUS_OK) { 3699 ret = res; 3700 goto fail; 3701 } 3702 3703 root = json_parse((const char *) info.payload, info.payload_len); 3704 if (!root) { 3705 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed"); 3706 ret = DPP_STATUS_INVALID_CONNECTOR; 3707 goto fail; 3708 } 3709 3710 if (!dpp_connector_match_groups(own_root, root, false)) { 3711 wpa_printf(MSG_DEBUG, 3712 "DPP: Peer connector does not include compatible group netrole with own connector"); 3713 ret = DPP_STATUS_NO_MATCH; 3714 goto fail; 3715 } 3716 3717 token = json_get_member(root, "expiry"); 3718 if (!token || token->type != JSON_STRING) { 3719 wpa_printf(MSG_DEBUG, 3720 "DPP: No expiry string found - connector does not expire"); 3721 } else { 3722 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string); 3723 if (dpp_key_expired(token->string, expiry)) { 3724 wpa_printf(MSG_DEBUG, 3725 "DPP: Connector (netAccessKey) has expired"); 3726 ret = DPP_STATUS_INVALID_CONNECTOR; 3727 goto fail; 3728 } 3729 } 3730 3731 netkey = json_get_member(root, "netAccessKey"); 3732 if (!netkey || netkey->type != JSON_OBJECT) { 3733 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found"); 3734 ret = DPP_STATUS_INVALID_CONNECTOR; 3735 goto fail; 3736 } 3737 3738 peer_key = dpp_parse_jwk(netkey, &curve); 3739 if (!peer_key) { 3740 ret = DPP_STATUS_INVALID_CONNECTOR; 3741 goto fail; 3742 } 3743 dpp_debug_print_key("DPP: Received netAccessKey", peer_key); 3744 3745 if (own_curve != curve) { 3746 wpa_printf(MSG_DEBUG, 3747 "DPP: Mismatching netAccessKey curves (%s != %s)", 3748 own_curve->name, curve->name); 3749 ret = DPP_STATUS_INVALID_CONNECTOR; 3750 goto fail; 3751 } 3752 3753 /* ECDH: N = nk * PK */ 3754 if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0) 3755 goto fail; 3756 3757 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)", 3758 Nx, Nx_len); 3759 3760 /* PMK = HKDF(<>, "DPP PMK", N.x) */ 3761 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) { 3762 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK"); 3763 goto fail; 3764 } 3765 intro->pmk_len = curve->hash_len; 3766 3767 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */ 3768 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) { 3769 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID"); 3770 goto fail; 3771 } 3772 3773 ret = DPP_STATUS_OK; 3774 fail: 3775 if (ret != DPP_STATUS_OK) 3776 os_memset(intro, 0, sizeof(*intro)); 3777 os_memset(Nx, 0, sizeof(Nx)); 3778 os_free(info.payload); 3779 EVP_PKEY_free(own_key); 3780 wpabuf_free(own_key_pub); 3781 EVP_PKEY_free(peer_key); 3782 json_free(root); 3783 json_free(own_root); 3784 return ret; 3785 } 3786 3787 3788 unsigned int dpp_next_id(struct dpp_global *dpp) 3789 { 3790 struct dpp_bootstrap_info *bi; 3791 unsigned int max_id = 0; 3792 3793 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) { 3794 if (bi->id > max_id) 3795 max_id = bi->id; 3796 } 3797 return max_id + 1; 3798 } 3799 3800 3801 static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id) 3802 { 3803 struct dpp_bootstrap_info *bi, *tmp; 3804 int found = 0; 3805 3806 if (!dpp) 3807 return -1; 3808 3809 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap, 3810 struct dpp_bootstrap_info, list) { 3811 if (id && bi->id != id) 3812 continue; 3813 found = 1; 3814 #ifdef CONFIG_DPP2 3815 if (dpp->remove_bi) 3816 dpp->remove_bi(dpp->cb_ctx, bi); 3817 #endif /* CONFIG_DPP2 */ 3818 dl_list_del(&bi->list); 3819 dpp_bootstrap_info_free(bi); 3820 } 3821 3822 if (id == 0) 3823 return 0; /* flush succeeds regardless of entries found */ 3824 return found ? 0 : -1; 3825 } 3826 3827 3828 struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp, 3829 const char *uri) 3830 { 3831 struct dpp_bootstrap_info *bi; 3832 3833 if (!dpp) 3834 return NULL; 3835 3836 bi = dpp_parse_uri(uri); 3837 if (!bi) 3838 return NULL; 3839 3840 bi->type = DPP_BOOTSTRAP_QR_CODE; 3841 bi->id = dpp_next_id(dpp); 3842 dl_list_add(&dpp->bootstrap, &bi->list); 3843 return bi; 3844 } 3845 3846 3847 struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp, 3848 const char *uri) 3849 { 3850 struct dpp_bootstrap_info *bi; 3851 3852 if (!dpp) 3853 return NULL; 3854 3855 bi = dpp_parse_uri(uri); 3856 if (!bi) 3857 return NULL; 3858 3859 bi->type = DPP_BOOTSTRAP_NFC_URI; 3860 bi->id = dpp_next_id(dpp); 3861 dl_list_add(&dpp->bootstrap, &bi->list); 3862 return bi; 3863 } 3864 3865 3866 int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) 3867 { 3868 char *mac = NULL, *info = NULL, *curve = NULL; 3869 char *key = NULL; 3870 u8 *privkey = NULL; 3871 size_t privkey_len = 0; 3872 int ret = -1; 3873 struct dpp_bootstrap_info *bi; 3874 3875 if (!dpp) 3876 return -1; 3877 3878 bi = os_zalloc(sizeof(*bi)); 3879 if (!bi) 3880 goto fail; 3881 3882 if (os_strstr(cmd, "type=qrcode")) 3883 bi->type = DPP_BOOTSTRAP_QR_CODE; 3884 else if (os_strstr(cmd, "type=pkex")) 3885 bi->type = DPP_BOOTSTRAP_PKEX; 3886 else if (os_strstr(cmd, "type=nfc-uri")) 3887 bi->type = DPP_BOOTSTRAP_NFC_URI; 3888 else 3889 goto fail; 3890 3891 bi->chan = get_param(cmd, " chan="); 3892 mac = get_param(cmd, " mac="); 3893 info = get_param(cmd, " info="); 3894 curve = get_param(cmd, " curve="); 3895 key = get_param(cmd, " key="); 3896 3897 if (key) { 3898 privkey_len = os_strlen(key) / 2; 3899 privkey = os_malloc(privkey_len); 3900 if (!privkey || 3901 hexstr2bin(key, privkey, privkey_len) < 0) 3902 goto fail; 3903 } 3904 3905 if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 || 3906 dpp_parse_uri_chan_list(bi, bi->chan) < 0 || 3907 dpp_parse_uri_mac(bi, mac) < 0 || 3908 dpp_parse_uri_info(bi, info) < 0 || 3909 dpp_gen_uri(bi) < 0) 3910 goto fail; 3911 3912 bi->id = dpp_next_id(dpp); 3913 dl_list_add(&dpp->bootstrap, &bi->list); 3914 ret = bi->id; 3915 bi = NULL; 3916 fail: 3917 os_free(curve); 3918 os_free(mac); 3919 os_free(info); 3920 str_clear_free(key); 3921 bin_clear_free(privkey, privkey_len); 3922 dpp_bootstrap_info_free(bi); 3923 return ret; 3924 } 3925 3926 3927 struct dpp_bootstrap_info * 3928 dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id) 3929 { 3930 struct dpp_bootstrap_info *bi; 3931 3932 if (!dpp) 3933 return NULL; 3934 3935 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) { 3936 if (bi->id == id) 3937 return bi; 3938 } 3939 return NULL; 3940 } 3941 3942 3943 int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id) 3944 { 3945 unsigned int id_val; 3946 3947 if (os_strcmp(id, "*") == 0) { 3948 id_val = 0; 3949 } else { 3950 id_val = atoi(id); 3951 if (id_val == 0) 3952 return -1; 3953 } 3954 3955 return dpp_bootstrap_del(dpp, id_val); 3956 } 3957 3958 3959 const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id) 3960 { 3961 struct dpp_bootstrap_info *bi; 3962 3963 bi = dpp_bootstrap_get_id(dpp, id); 3964 if (!bi) 3965 return NULL; 3966 return bi->uri; 3967 } 3968 3969 3970 int dpp_bootstrap_info(struct dpp_global *dpp, int id, 3971 char *reply, int reply_size) 3972 { 3973 struct dpp_bootstrap_info *bi; 3974 char pkhash[2 * SHA256_MAC_LEN + 1]; 3975 3976 bi = dpp_bootstrap_get_id(dpp, id); 3977 if (!bi) 3978 return -1; 3979 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash, 3980 SHA256_MAC_LEN); 3981 return os_snprintf(reply, reply_size, "type=%s\n" 3982 "mac_addr=" MACSTR "\n" 3983 "info=%s\n" 3984 "num_freq=%u\n" 3985 "use_freq=%u\n" 3986 "curve=%s\n" 3987 "pkhash=%s\n" 3988 "version=%d\n", 3989 dpp_bootstrap_type_txt(bi->type), 3990 MAC2STR(bi->mac_addr), 3991 bi->info ? bi->info : "", 3992 bi->num_freq, 3993 bi->num_freq == 1 ? bi->freq[0] : 0, 3994 bi->curve->name, 3995 pkhash, 3996 bi->version); 3997 } 3998 3999 4000 int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params) 4001 { 4002 struct dpp_bootstrap_info *bi; 4003 4004 bi = dpp_bootstrap_get_id(dpp, id); 4005 if (!bi) 4006 return -1; 4007 4008 str_clear_free(bi->configurator_params); 4009 4010 if (params) { 4011 bi->configurator_params = os_strdup(params); 4012 return bi->configurator_params ? 0 : -1; 4013 } 4014 4015 bi->configurator_params = NULL; 4016 return 0; 4017 } 4018 4019 4020 void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap, 4021 const u8 *r_bootstrap, 4022 struct dpp_bootstrap_info **own_bi, 4023 struct dpp_bootstrap_info **peer_bi) 4024 { 4025 struct dpp_bootstrap_info *bi; 4026 4027 *own_bi = NULL; 4028 *peer_bi = NULL; 4029 if (!dpp) 4030 return; 4031 4032 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) { 4033 if (!*own_bi && bi->own && 4034 os_memcmp(bi->pubkey_hash, r_bootstrap, 4035 SHA256_MAC_LEN) == 0) { 4036 wpa_printf(MSG_DEBUG, 4037 "DPP: Found matching own bootstrapping information"); 4038 *own_bi = bi; 4039 } 4040 4041 if (!*peer_bi && !bi->own && 4042 os_memcmp(bi->pubkey_hash, i_bootstrap, 4043 SHA256_MAC_LEN) == 0) { 4044 wpa_printf(MSG_DEBUG, 4045 "DPP: Found matching peer bootstrapping information"); 4046 *peer_bi = bi; 4047 } 4048 4049 if (*own_bi && *peer_bi) 4050 break; 4051 } 4052 } 4053 4054 4055 #ifdef CONFIG_DPP2 4056 struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp, 4057 const u8 *hash) 4058 { 4059 struct dpp_bootstrap_info *bi; 4060 4061 if (!dpp) 4062 return NULL; 4063 4064 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) { 4065 if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash, 4066 SHA256_MAC_LEN) == 0) 4067 return bi; 4068 } 4069 4070 return NULL; 4071 } 4072 #endif /* CONFIG_DPP2 */ 4073 4074 4075 static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi, 4076 struct dpp_bootstrap_info *peer_bi) 4077 { 4078 unsigned int i, freq = 0; 4079 enum hostapd_hw_mode mode; 4080 u8 op_class, channel; 4081 char chan[20]; 4082 4083 if (peer_bi->num_freq == 0 && !peer_bi->channels_listed) 4084 return 0; /* no channel preference/constraint */ 4085 4086 for (i = 0; i < peer_bi->num_freq; i++) { 4087 if ((own_bi->num_freq == 0 && !own_bi->channels_listed) || 4088 freq_included(own_bi->freq, own_bi->num_freq, 4089 peer_bi->freq[i])) { 4090 freq = peer_bi->freq[i]; 4091 break; 4092 } 4093 } 4094 if (!freq) { 4095 wpa_printf(MSG_DEBUG, "DPP: No common channel found"); 4096 return -1; 4097 } 4098 4099 mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel); 4100 if (mode == NUM_HOSTAPD_MODES) { 4101 wpa_printf(MSG_DEBUG, 4102 "DPP: Could not determine operating class or channel number for %u MHz", 4103 freq); 4104 } 4105 4106 wpa_printf(MSG_DEBUG, 4107 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover", 4108 freq, op_class, channel); 4109 os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel); 4110 os_free(own_bi->chan); 4111 own_bi->chan = os_strdup(chan); 4112 own_bi->freq[0] = freq; 4113 own_bi->num_freq = 1; 4114 os_free(peer_bi->chan); 4115 peer_bi->chan = os_strdup(chan); 4116 peer_bi->freq[0] = freq; 4117 peer_bi->num_freq = 1; 4118 4119 return dpp_gen_uri(own_bi); 4120 } 4121 4122 4123 static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi, 4124 struct dpp_bootstrap_info *peer_bi) 4125 { 4126 if (peer_bi->curve == own_bi->curve) 4127 return 0; 4128 4129 wpa_printf(MSG_DEBUG, 4130 "DPP: Update own bootstrapping key to match peer curve from NFC handover"); 4131 4132 EVP_PKEY_free(own_bi->pubkey); 4133 own_bi->pubkey = NULL; 4134 4135 if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 || 4136 dpp_gen_uri(own_bi) < 0) 4137 goto fail; 4138 4139 return 0; 4140 fail: 4141 dl_list_del(&own_bi->list); 4142 dpp_bootstrap_info_free(own_bi); 4143 return -1; 4144 } 4145 4146 4147 int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi, 4148 struct dpp_bootstrap_info *peer_bi) 4149 { 4150 if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 || 4151 dpp_nfc_update_bi_key(own_bi, peer_bi) < 0) 4152 return -1; 4153 return 0; 4154 } 4155 4156 4157 static unsigned int dpp_next_configurator_id(struct dpp_global *dpp) 4158 { 4159 struct dpp_configurator *conf; 4160 unsigned int max_id = 0; 4161 4162 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator, 4163 list) { 4164 if (conf->id > max_id) 4165 max_id = conf->id; 4166 } 4167 return max_id + 1; 4168 } 4169 4170 4171 int dpp_configurator_add(struct dpp_global *dpp, const char *cmd) 4172 { 4173 char *curve = NULL; 4174 char *key = NULL, *ppkey = NULL; 4175 u8 *privkey = NULL, *pp_key = NULL; 4176 size_t privkey_len = 0, pp_key_len = 0; 4177 int ret = -1; 4178 struct dpp_configurator *conf = NULL; 4179 4180 curve = get_param(cmd, " curve="); 4181 key = get_param(cmd, " key="); 4182 ppkey = get_param(cmd, " ppkey="); 4183 4184 if (key) { 4185 privkey_len = os_strlen(key) / 2; 4186 privkey = os_malloc(privkey_len); 4187 if (!privkey || 4188 hexstr2bin(key, privkey, privkey_len) < 0) 4189 goto fail; 4190 } 4191 4192 if (ppkey) { 4193 pp_key_len = os_strlen(ppkey) / 2; 4194 pp_key = os_malloc(pp_key_len); 4195 if (!pp_key || 4196 hexstr2bin(ppkey, pp_key, pp_key_len) < 0) 4197 goto fail; 4198 } 4199 4200 conf = dpp_keygen_configurator(curve, privkey, privkey_len, 4201 pp_key, pp_key_len); 4202 if (!conf) 4203 goto fail; 4204 4205 conf->id = dpp_next_configurator_id(dpp); 4206 dl_list_add(&dpp->configurator, &conf->list); 4207 ret = conf->id; 4208 conf = NULL; 4209 fail: 4210 os_free(curve); 4211 str_clear_free(key); 4212 str_clear_free(ppkey); 4213 bin_clear_free(privkey, privkey_len); 4214 bin_clear_free(pp_key, pp_key_len); 4215 dpp_configurator_free(conf); 4216 return ret; 4217 } 4218 4219 4220 static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id) 4221 { 4222 struct dpp_configurator *conf, *tmp; 4223 int found = 0; 4224 4225 if (!dpp) 4226 return -1; 4227 4228 dl_list_for_each_safe(conf, tmp, &dpp->configurator, 4229 struct dpp_configurator, list) { 4230 if (id && conf->id != id) 4231 continue; 4232 found = 1; 4233 dl_list_del(&conf->list); 4234 dpp_configurator_free(conf); 4235 } 4236 4237 if (id == 0) 4238 return 0; /* flush succeeds regardless of entries found */ 4239 return found ? 0 : -1; 4240 } 4241 4242 4243 int dpp_configurator_remove(struct dpp_global *dpp, const char *id) 4244 { 4245 unsigned int id_val; 4246 4247 if (os_strcmp(id, "*") == 0) { 4248 id_val = 0; 4249 } else { 4250 id_val = atoi(id); 4251 if (id_val == 0) 4252 return -1; 4253 } 4254 4255 return dpp_configurator_del(dpp, id_val); 4256 } 4257 4258 4259 int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id, 4260 char *buf, size_t buflen) 4261 { 4262 struct dpp_configurator *conf; 4263 4264 conf = dpp_configurator_get_id(dpp, id); 4265 if (!conf) 4266 return -1; 4267 4268 return dpp_configurator_get_key(conf, buf, buflen); 4269 } 4270 4271 4272 #ifdef CONFIG_DPP2 4273 4274 int dpp_configurator_from_backup(struct dpp_global *dpp, 4275 struct dpp_asymmetric_key *key) 4276 { 4277 struct dpp_configurator *conf; 4278 const EC_KEY *eckey, *eckey_pp; 4279 const EC_GROUP *group, *group_pp; 4280 int nid; 4281 const struct dpp_curve_params *curve; 4282 4283 if (!key->csign || !key->pp_key) 4284 return -1; 4285 eckey = EVP_PKEY_get0_EC_KEY(key->csign); 4286 if (!eckey) 4287 return -1; 4288 group = EC_KEY_get0_group(eckey); 4289 if (!group) 4290 return -1; 4291 nid = EC_GROUP_get_curve_name(group); 4292 curve = dpp_get_curve_nid(nid); 4293 if (!curve) { 4294 wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key"); 4295 return -1; 4296 } 4297 eckey_pp = EVP_PKEY_get0_EC_KEY(key->pp_key); 4298 if (!eckey_pp) 4299 return -1; 4300 group_pp = EC_KEY_get0_group(eckey_pp); 4301 if (!group_pp) 4302 return -1; 4303 if (EC_GROUP_get_curve_name(group) != 4304 EC_GROUP_get_curve_name(group_pp)) { 4305 wpa_printf(MSG_INFO, 4306 "DPP: Mismatch in c-sign-key and ppKey groups"); 4307 return -1; 4308 } 4309 4310 conf = os_zalloc(sizeof(*conf)); 4311 if (!conf) 4312 return -1; 4313 conf->curve = curve; 4314 conf->csign = key->csign; 4315 key->csign = NULL; 4316 conf->pp_key = key->pp_key; 4317 key->pp_key = NULL; 4318 conf->own = 1; 4319 if (dpp_configurator_gen_kid(conf) < 0) { 4320 dpp_configurator_free(conf); 4321 return -1; 4322 } 4323 4324 conf->id = dpp_next_configurator_id(dpp); 4325 dl_list_add(&dpp->configurator, &conf->list); 4326 return conf->id; 4327 } 4328 4329 4330 struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp, 4331 const u8 *kid) 4332 { 4333 struct dpp_configurator *conf; 4334 4335 if (!dpp) 4336 return NULL; 4337 4338 dl_list_for_each(conf, &dpp->configurator, 4339 struct dpp_configurator, list) { 4340 if (os_memcmp(conf->kid_hash, kid, SHA256_MAC_LEN) == 0) 4341 return conf; 4342 } 4343 return NULL; 4344 } 4345 4346 #endif /* CONFIG_DPP2 */ 4347 4348 4349 struct dpp_global * dpp_global_init(struct dpp_global_config *config) 4350 { 4351 struct dpp_global *dpp; 4352 4353 dpp = os_zalloc(sizeof(*dpp)); 4354 if (!dpp) 4355 return NULL; 4356 #ifdef CONFIG_DPP2 4357 dpp->cb_ctx = config->cb_ctx; 4358 dpp->remove_bi = config->remove_bi; 4359 #endif /* CONFIG_DPP2 */ 4360 4361 dl_list_init(&dpp->bootstrap); 4362 dl_list_init(&dpp->configurator); 4363 #ifdef CONFIG_DPP2 4364 dl_list_init(&dpp->controllers); 4365 dl_list_init(&dpp->tcp_init); 4366 #endif /* CONFIG_DPP2 */ 4367 4368 return dpp; 4369 } 4370 4371 4372 void dpp_global_clear(struct dpp_global *dpp) 4373 { 4374 if (!dpp) 4375 return; 4376 4377 dpp_bootstrap_del(dpp, 0); 4378 dpp_configurator_del(dpp, 0); 4379 #ifdef CONFIG_DPP2 4380 dpp_tcp_init_flush(dpp); 4381 dpp_relay_flush_controllers(dpp); 4382 dpp_controller_stop(dpp); 4383 #endif /* CONFIG_DPP2 */ 4384 } 4385 4386 4387 void dpp_global_deinit(struct dpp_global *dpp) 4388 { 4389 dpp_global_clear(dpp); 4390 os_free(dpp); 4391 } 4392 4393 4394 #ifdef CONFIG_DPP2 4395 4396 struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi) 4397 { 4398 struct wpabuf *msg; 4399 4400 wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame"); 4401 4402 msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN); 4403 if (!msg) 4404 return NULL; 4405 4406 /* Responder Bootstrapping Key Hash */ 4407 dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp); 4408 wpa_hexdump_buf(MSG_DEBUG, 4409 "DPP: Presence Announcement frame attributes", msg); 4410 return msg; 4411 } 4412 4413 4414 void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src, 4415 unsigned int freq, const u8 *hash) 4416 { 4417 char hex[SHA256_MAC_LEN * 2 + 1]; 4418 4419 wpa_snprintf_hex(hex, sizeof(hex), hash, SHA256_MAC_LEN); 4420 wpa_msg(msg_ctx, MSG_INFO, 4421 DPP_EVENT_CHIRP_RX "id=%d src=" MACSTR " freq=%u hash=%s", 4422 id, MAC2STR(src), freq, hex); 4423 } 4424 4425 #endif /* CONFIG_DPP2 */ 4426