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