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