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