1 /* 2 * hostapd / DPP integration 3 * Copyright (c) 2017, Qualcomm Atheros, Inc. 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "utils/includes.h" 10 11 #include "utils/common.h" 12 #include "utils/eloop.h" 13 #include "common/dpp.h" 14 #include "common/gas.h" 15 #include "common/wpa_ctrl.h" 16 #include "hostapd.h" 17 #include "ap_drv_ops.h" 18 #include "gas_query_ap.h" 19 #include "wpa_auth.h" 20 #include "dpp_hostapd.h" 21 22 23 static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator); 24 25 static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 26 27 28 static struct dpp_configurator * 29 hostapd_dpp_configurator_get_id(struct hostapd_data *hapd, unsigned int id) 30 { 31 struct dpp_configurator *conf; 32 33 dl_list_for_each(conf, &hapd->dpp_configurator, 34 struct dpp_configurator, list) { 35 if (conf->id == id) 36 return conf; 37 } 38 return NULL; 39 } 40 41 42 static unsigned int hapd_dpp_next_id(struct hostapd_data *hapd) 43 { 44 struct dpp_bootstrap_info *bi; 45 unsigned int max_id = 0; 46 47 dl_list_for_each(bi, &hapd->dpp_bootstrap, struct dpp_bootstrap_info, 48 list) { 49 if (bi->id > max_id) 50 max_id = bi->id; 51 } 52 return max_id + 1; 53 } 54 55 56 /** 57 * hostapd_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code 58 * @hapd: Pointer to hostapd_data 59 * @cmd: DPP URI read from a QR Code 60 * Returns: Identifier of the stored info or -1 on failure 61 */ 62 int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd) 63 { 64 struct dpp_bootstrap_info *bi; 65 struct dpp_authentication *auth = hapd->dpp_auth; 66 67 bi = dpp_parse_qr_code(cmd); 68 if (!bi) 69 return -1; 70 71 bi->id = hapd_dpp_next_id(hapd); 72 dl_list_add(&hapd->dpp_bootstrap, &bi->list); 73 74 if (auth && auth->response_pending && 75 dpp_notify_new_qr_code(auth, bi) == 1) { 76 wpa_printf(MSG_DEBUG, 77 "DPP: Sending out pending authentication response"); 78 hostapd_drv_send_action(hapd, auth->curr_freq, 0, 79 auth->peer_mac_addr, 80 wpabuf_head(hapd->dpp_auth->resp_msg), 81 wpabuf_len(hapd->dpp_auth->resp_msg)); 82 } 83 84 return bi->id; 85 } 86 87 88 static char * get_param(const char *cmd, const char *param) 89 { 90 const char *pos, *end; 91 char *val; 92 size_t len; 93 94 pos = os_strstr(cmd, param); 95 if (!pos) 96 return NULL; 97 98 pos += os_strlen(param); 99 end = os_strchr(pos, ' '); 100 if (end) 101 len = end - pos; 102 else 103 len = os_strlen(pos); 104 val = os_malloc(len + 1); 105 if (!val) 106 return NULL; 107 os_memcpy(val, pos, len); 108 val[len] = '\0'; 109 return val; 110 } 111 112 113 int hostapd_dpp_bootstrap_gen(struct hostapd_data *hapd, const char *cmd) 114 { 115 char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL; 116 char *key = NULL; 117 u8 *privkey = NULL; 118 size_t privkey_len = 0; 119 size_t len; 120 int ret = -1; 121 struct dpp_bootstrap_info *bi; 122 123 bi = os_zalloc(sizeof(*bi)); 124 if (!bi) 125 goto fail; 126 127 if (os_strstr(cmd, "type=qrcode")) 128 bi->type = DPP_BOOTSTRAP_QR_CODE; 129 else if (os_strstr(cmd, "type=pkex")) 130 bi->type = DPP_BOOTSTRAP_PKEX; 131 else 132 goto fail; 133 134 chan = get_param(cmd, " chan="); 135 mac = get_param(cmd, " mac="); 136 info = get_param(cmd, " info="); 137 curve = get_param(cmd, " curve="); 138 key = get_param(cmd, " key="); 139 140 if (key) { 141 privkey_len = os_strlen(key) / 2; 142 privkey = os_malloc(privkey_len); 143 if (!privkey || 144 hexstr2bin(key, privkey, privkey_len) < 0) 145 goto fail; 146 } 147 148 pk = dpp_keygen(bi, curve, privkey, privkey_len); 149 if (!pk) 150 goto fail; 151 152 len = 4; /* "DPP:" */ 153 if (chan) { 154 if (dpp_parse_uri_chan_list(bi, chan) < 0) 155 goto fail; 156 len += 3 + os_strlen(chan); /* C:...; */ 157 } 158 if (mac) { 159 if (dpp_parse_uri_mac(bi, mac) < 0) 160 goto fail; 161 len += 3 + os_strlen(mac); /* M:...; */ 162 } 163 if (info) { 164 if (dpp_parse_uri_info(bi, info) < 0) 165 goto fail; 166 len += 3 + os_strlen(info); /* I:...; */ 167 } 168 len += 4 + os_strlen(pk); 169 bi->uri = os_malloc(len + 1); 170 if (!bi->uri) 171 goto fail; 172 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;", 173 chan ? "C:" : "", chan ? chan : "", chan ? ";" : "", 174 mac ? "M:" : "", mac ? mac : "", mac ? ";" : "", 175 info ? "I:" : "", info ? info : "", info ? ";" : "", 176 pk); 177 bi->id = hapd_dpp_next_id(hapd); 178 dl_list_add(&hapd->dpp_bootstrap, &bi->list); 179 ret = bi->id; 180 bi = NULL; 181 fail: 182 os_free(curve); 183 os_free(pk); 184 os_free(chan); 185 os_free(mac); 186 os_free(info); 187 str_clear_free(key); 188 bin_clear_free(privkey, privkey_len); 189 dpp_bootstrap_info_free(bi); 190 return ret; 191 } 192 193 194 static struct dpp_bootstrap_info * 195 dpp_bootstrap_get_id(struct hostapd_data *hapd, unsigned int id) 196 { 197 struct dpp_bootstrap_info *bi; 198 199 dl_list_for_each(bi, &hapd->dpp_bootstrap, struct dpp_bootstrap_info, 200 list) { 201 if (bi->id == id) 202 return bi; 203 } 204 return NULL; 205 } 206 207 208 static int dpp_bootstrap_del(struct hostapd_data *hapd, unsigned int id) 209 { 210 struct dpp_bootstrap_info *bi, *tmp; 211 int found = 0; 212 213 dl_list_for_each_safe(bi, tmp, &hapd->dpp_bootstrap, 214 struct dpp_bootstrap_info, list) { 215 if (id && bi->id != id) 216 continue; 217 found = 1; 218 dl_list_del(&bi->list); 219 dpp_bootstrap_info_free(bi); 220 } 221 222 if (id == 0) 223 return 0; /* flush succeeds regardless of entries found */ 224 return found ? 0 : -1; 225 } 226 227 228 int hostapd_dpp_bootstrap_remove(struct hostapd_data *hapd, const char *id) 229 { 230 unsigned int id_val; 231 232 if (os_strcmp(id, "*") == 0) { 233 id_val = 0; 234 } else { 235 id_val = atoi(id); 236 if (id_val == 0) 237 return -1; 238 } 239 240 return dpp_bootstrap_del(hapd, id_val); 241 } 242 243 244 const char * hostapd_dpp_bootstrap_get_uri(struct hostapd_data *hapd, 245 unsigned int id) 246 { 247 struct dpp_bootstrap_info *bi; 248 249 bi = dpp_bootstrap_get_id(hapd, id); 250 if (!bi) 251 return NULL; 252 return bi->uri; 253 } 254 255 256 int hostapd_dpp_bootstrap_info(struct hostapd_data *hapd, int id, 257 char *reply, int reply_size) 258 { 259 struct dpp_bootstrap_info *bi; 260 261 bi = dpp_bootstrap_get_id(hapd, id); 262 if (!bi) 263 return -1; 264 return os_snprintf(reply, reply_size, "type=%s\n" 265 "mac_addr=" MACSTR "\n" 266 "info=%s\n" 267 "num_freq=%u\n" 268 "curve=%s\n", 269 dpp_bootstrap_type_txt(bi->type), 270 MAC2STR(bi->mac_addr), 271 bi->info ? bi->info : "", 272 bi->num_freq, 273 bi->curve->name); 274 } 275 276 277 void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst, 278 const u8 *data, size_t data_len, int ok) 279 { 280 wpa_printf(MSG_DEBUG, "DPP: TX status: dst=" MACSTR " ok=%d", 281 MAC2STR(dst), ok); 282 283 if (!hapd->dpp_auth) { 284 wpa_printf(MSG_DEBUG, 285 "DPP: Ignore TX status since there is no ongoing authentication exchange"); 286 return; 287 } 288 289 if (hapd->dpp_auth->remove_on_tx_status) { 290 wpa_printf(MSG_DEBUG, 291 "DPP: Terminate authentication exchange due to an earlier error"); 292 dpp_auth_deinit(hapd->dpp_auth); 293 hapd->dpp_auth = NULL; 294 return; 295 } 296 297 if (hapd->dpp_auth_ok_on_ack) 298 hostapd_dpp_auth_success(hapd, 1); 299 } 300 301 302 static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd, 303 struct dpp_authentication *auth) 304 { 305 #ifdef CONFIG_TESTING_OPTIONS 306 if (hapd->dpp_config_obj_override) 307 auth->config_obj_override = 308 os_strdup(hapd->dpp_config_obj_override); 309 if (hapd->dpp_discovery_override) 310 auth->discovery_override = 311 os_strdup(hapd->dpp_discovery_override); 312 if (hapd->dpp_groups_override) 313 auth->groups_override = os_strdup(hapd->dpp_groups_override); 314 auth->ignore_netaccesskey_mismatch = 315 hapd->dpp_ignore_netaccesskey_mismatch; 316 #endif /* CONFIG_TESTING_OPTIONS */ 317 } 318 319 320 static void hostapd_dpp_set_configurator(struct hostapd_data *hapd, 321 struct dpp_authentication *auth, 322 const char *cmd) 323 { 324 const char *pos, *end; 325 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL; 326 struct dpp_configurator *conf = NULL; 327 u8 ssid[32] = { "test" }; 328 size_t ssid_len = 4; 329 char pass[64] = { }; 330 size_t pass_len = 0; 331 u8 psk[PMK_LEN]; 332 int psk_set = 0; 333 334 if (!cmd) 335 return; 336 337 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd); 338 pos = os_strstr(cmd, " ssid="); 339 if (pos) { 340 pos += 6; 341 end = os_strchr(pos, ' '); 342 ssid_len = end ? (size_t) (end - pos) : os_strlen(pos); 343 ssid_len /= 2; 344 if (ssid_len > sizeof(ssid) || 345 hexstr2bin(pos, ssid, ssid_len) < 0) 346 goto fail; 347 } 348 349 pos = os_strstr(cmd, " pass="); 350 if (pos) { 351 pos += 6; 352 end = os_strchr(pos, ' '); 353 pass_len = end ? (size_t) (end - pos) : os_strlen(pos); 354 pass_len /= 2; 355 if (pass_len > sizeof(pass) - 1 || pass_len < 8 || 356 hexstr2bin(pos, (u8 *) pass, pass_len) < 0) 357 goto fail; 358 } 359 360 pos = os_strstr(cmd, " psk="); 361 if (pos) { 362 pos += 5; 363 if (hexstr2bin(pos, psk, PMK_LEN) < 0) 364 goto fail; 365 psk_set = 1; 366 } 367 368 if (os_strstr(cmd, " conf=sta-")) { 369 conf_sta = os_zalloc(sizeof(struct dpp_configuration)); 370 if (!conf_sta) 371 goto fail; 372 os_memcpy(conf_sta->ssid, ssid, ssid_len); 373 conf_sta->ssid_len = ssid_len; 374 if (os_strstr(cmd, " conf=sta-psk")) { 375 conf_sta->dpp = 0; 376 if (psk_set) { 377 os_memcpy(conf_sta->psk, psk, PMK_LEN); 378 } else { 379 conf_sta->passphrase = os_strdup(pass); 380 if (!conf_sta->passphrase) 381 goto fail; 382 } 383 } else if (os_strstr(cmd, " conf=sta-dpp")) { 384 conf_sta->dpp = 1; 385 } else { 386 goto fail; 387 } 388 } 389 390 if (os_strstr(cmd, " conf=ap-")) { 391 conf_ap = os_zalloc(sizeof(struct dpp_configuration)); 392 if (!conf_ap) 393 goto fail; 394 os_memcpy(conf_ap->ssid, ssid, ssid_len); 395 conf_ap->ssid_len = ssid_len; 396 if (os_strstr(cmd, " conf=ap-psk")) { 397 conf_ap->dpp = 0; 398 if (psk_set) { 399 os_memcpy(conf_ap->psk, psk, PMK_LEN); 400 } else { 401 conf_ap->passphrase = os_strdup(pass); 402 if (!conf_ap->passphrase) 403 goto fail; 404 } 405 } else if (os_strstr(cmd, " conf=ap-dpp")) { 406 conf_ap->dpp = 1; 407 } else { 408 goto fail; 409 } 410 } 411 412 pos = os_strstr(cmd, " expiry="); 413 if (pos) { 414 long int val; 415 416 pos += 8; 417 val = strtol(pos, NULL, 0); 418 if (val <= 0) 419 goto fail; 420 if (conf_sta) 421 conf_sta->netaccesskey_expiry = val; 422 if (conf_ap) 423 conf_ap->netaccesskey_expiry = val; 424 } 425 426 pos = os_strstr(cmd, " configurator="); 427 if (pos) { 428 auth->configurator = 1; 429 pos += 14; 430 conf = hostapd_dpp_configurator_get_id(hapd, atoi(pos)); 431 if (!conf) { 432 wpa_printf(MSG_INFO, 433 "DPP: Could not find the specified configurator"); 434 goto fail; 435 } 436 } 437 auth->conf_sta = conf_sta; 438 auth->conf_ap = conf_ap; 439 auth->conf = conf; 440 return; 441 442 fail: 443 wpa_printf(MSG_DEBUG, "DPP: Failed to set configurator parameters"); 444 dpp_configuration_free(conf_sta); 445 dpp_configuration_free(conf_ap); 446 } 447 448 449 int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd) 450 { 451 const char *pos; 452 struct dpp_bootstrap_info *peer_bi, *own_bi = NULL; 453 const u8 *dst; 454 int res; 455 int configurator = 1; 456 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL; 457 458 pos = os_strstr(cmd, " peer="); 459 if (!pos) 460 return -1; 461 pos += 6; 462 peer_bi = dpp_bootstrap_get_id(hapd, atoi(pos)); 463 if (!peer_bi) { 464 wpa_printf(MSG_INFO, 465 "DPP: Could not find bootstrapping info for the identified peer"); 466 return -1; 467 } 468 469 pos = os_strstr(cmd, " own="); 470 if (pos) { 471 pos += 5; 472 own_bi = dpp_bootstrap_get_id(hapd, atoi(pos)); 473 if (!own_bi) { 474 wpa_printf(MSG_INFO, 475 "DPP: Could not find bootstrapping info for the identified local entry"); 476 return -1; 477 } 478 479 if (peer_bi->curve != own_bi->curve) { 480 wpa_printf(MSG_INFO, 481 "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)", 482 peer_bi->curve->name, own_bi->curve->name); 483 return -1; 484 } 485 } 486 487 pos = os_strstr(cmd, " role="); 488 if (pos) { 489 pos += 6; 490 if (os_strncmp(pos, "configurator", 12) == 0) 491 configurator = 1; 492 else if (os_strncmp(pos, "enrollee", 8) == 0) 493 configurator = 0; 494 else 495 goto fail; 496 } 497 498 if (hapd->dpp_auth) 499 dpp_auth_deinit(hapd->dpp_auth); 500 hapd->dpp_auth = dpp_auth_init(hapd, peer_bi, own_bi, configurator); 501 if (!hapd->dpp_auth) 502 goto fail; 503 hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth); 504 hostapd_dpp_set_configurator(hapd, hapd->dpp_auth, cmd); 505 506 /* TODO: Support iteration over all frequencies and filtering of 507 * frequencies based on locally enabled channels that allow initiation 508 * of transmission. */ 509 if (peer_bi->num_freq > 0) 510 hapd->dpp_auth->curr_freq = peer_bi->freq[0]; 511 else 512 hapd->dpp_auth->curr_freq = 2412; 513 514 if (is_zero_ether_addr(peer_bi->mac_addr)) { 515 dst = broadcast; 516 } else { 517 dst = peer_bi->mac_addr; 518 os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr, 519 ETH_ALEN); 520 } 521 hapd->dpp_auth_ok_on_ack = 0; 522 523 res = hostapd_drv_send_action(hapd, hapd->dpp_auth->curr_freq, 0, 524 dst, wpabuf_head(hapd->dpp_auth->req_msg), 525 wpabuf_len(hapd->dpp_auth->req_msg)); 526 527 return res; 528 fail: 529 dpp_configuration_free(conf_sta); 530 dpp_configuration_free(conf_ap); 531 return -1; 532 } 533 534 535 static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src, 536 const u8 *hdr, const u8 *buf, size_t len, 537 unsigned int freq) 538 { 539 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data; 540 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len; 541 struct dpp_bootstrap_info *bi, *own_bi = NULL, *peer_bi = NULL; 542 543 wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR, 544 MAC2STR(src)); 545 546 wrapped_data = dpp_get_attr(buf, len, DPP_ATTR_WRAPPED_DATA, 547 &wrapped_data_len); 548 if (!wrapped_data) { 549 wpa_printf(MSG_DEBUG, 550 "DPP: Missing required Wrapped data attribute"); 551 return; 552 } 553 wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped data", 554 wrapped_data, wrapped_data_len); 555 556 r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, 557 &r_bootstrap_len); 558 if (!r_bootstrap || r_bootstrap > wrapped_data || 559 r_bootstrap_len != SHA256_MAC_LEN) { 560 wpa_printf(MSG_DEBUG, 561 "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute"); 562 return; 563 } 564 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", 565 r_bootstrap, r_bootstrap_len); 566 567 i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH, 568 &i_bootstrap_len); 569 if (!i_bootstrap || i_bootstrap > wrapped_data || 570 i_bootstrap_len != SHA256_MAC_LEN) { 571 wpa_printf(MSG_DEBUG, 572 "DPP: Missing or invalid required Initiator Bootstrapping Key Hash attribute"); 573 return; 574 } 575 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash", 576 i_bootstrap, i_bootstrap_len); 577 578 /* Try to find own and peer bootstrapping key matches based on the 579 * received hash values */ 580 dl_list_for_each(bi, &hapd->dpp_bootstrap, struct dpp_bootstrap_info, 581 list) { 582 if (!own_bi && bi->own && 583 os_memcmp(bi->pubkey_hash, r_bootstrap, 584 SHA256_MAC_LEN) == 0) { 585 wpa_printf(MSG_DEBUG, 586 "DPP: Found matching own bootstrapping information"); 587 own_bi = bi; 588 } 589 590 if (!peer_bi && !bi->own && 591 os_memcmp(bi->pubkey_hash, i_bootstrap, 592 SHA256_MAC_LEN) == 0) { 593 wpa_printf(MSG_DEBUG, 594 "DPP: Found matching peer bootstrapping information"); 595 peer_bi = bi; 596 } 597 598 if (own_bi && peer_bi) 599 break; 600 } 601 602 if (!own_bi) { 603 wpa_printf(MSG_DEBUG, 604 "DPP: No matching own bootstrapping key found - ignore message"); 605 return; 606 } 607 608 if (hapd->dpp_auth) { 609 wpa_printf(MSG_DEBUG, 610 "DPP: Already in DPP authentication exchange - ignore new one"); 611 return; 612 } 613 614 hapd->dpp_auth_ok_on_ack = 0; 615 hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles, 616 hapd->dpp_qr_mutual, 617 peer_bi, own_bi, freq, hdr, buf, 618 wrapped_data, wrapped_data_len); 619 if (!hapd->dpp_auth) { 620 wpa_printf(MSG_DEBUG, "DPP: No response generated"); 621 return; 622 } 623 hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth); 624 hostapd_dpp_set_configurator(hapd, hapd->dpp_auth, 625 hapd->dpp_configurator_params); 626 os_memcpy(hapd->dpp_auth->peer_mac_addr, src, ETH_ALEN); 627 628 hostapd_drv_send_action(hapd, hapd->dpp_auth->curr_freq, 0, 629 src, wpabuf_head(hapd->dpp_auth->resp_msg), 630 wpabuf_len(hapd->dpp_auth->resp_msg)); 631 } 632 633 634 static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, 635 enum gas_query_ap_result result, 636 const struct wpabuf *adv_proto, 637 const struct wpabuf *resp, u16 status_code) 638 { 639 struct hostapd_data *hapd = ctx; 640 const u8 *pos; 641 struct dpp_authentication *auth = hapd->dpp_auth; 642 643 if (!auth || !auth->auth_success) { 644 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); 645 return; 646 } 647 if (!resp || status_code != WLAN_STATUS_SUCCESS) { 648 wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed"); 649 goto fail; 650 } 651 652 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto", 653 adv_proto); 654 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)", 655 resp); 656 657 if (wpabuf_len(adv_proto) != 10 || 658 !(pos = wpabuf_head(adv_proto)) || 659 pos[0] != WLAN_EID_ADV_PROTO || 660 pos[1] != 8 || 661 pos[3] != WLAN_EID_VENDOR_SPECIFIC || 662 pos[4] != 5 || 663 WPA_GET_BE24(&pos[5]) != OUI_WFA || 664 pos[8] != 0x1a || 665 pos[9] != 1) { 666 wpa_printf(MSG_DEBUG, 667 "DPP: Not a DPP Advertisement Protocol ID"); 668 goto fail; 669 } 670 671 if (dpp_conf_resp_rx(auth, resp) < 0) { 672 wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); 673 goto fail; 674 } 675 676 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED); 677 if (auth->ssid_len) 678 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s", 679 wpa_ssid_txt(auth->ssid, auth->ssid_len)); 680 if (auth->connector) { 681 /* TODO: Save the Connector and consider using a command 682 * to fetch the value instead of sending an event with 683 * it. The Connector could end up being larger than what 684 * most clients are ready to receive as an event 685 * message. */ 686 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s", 687 auth->connector); 688 } else if (auth->passphrase[0]) { 689 char hex[64 * 2 + 1]; 690 691 wpa_snprintf_hex(hex, sizeof(hex), 692 (const u8 *) auth->passphrase, 693 os_strlen(auth->passphrase)); 694 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s", 695 hex); 696 } else if (auth->psk_set) { 697 char hex[PMK_LEN * 2 + 1]; 698 699 wpa_snprintf_hex(hex, sizeof(hex), auth->psk, PMK_LEN); 700 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s", 701 hex); 702 } 703 if (auth->c_sign_key) { 704 char *hex; 705 size_t hexlen; 706 707 hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1; 708 hex = os_malloc(hexlen); 709 if (hex) { 710 wpa_snprintf_hex(hex, hexlen, 711 wpabuf_head(auth->c_sign_key), 712 wpabuf_len(auth->c_sign_key)); 713 wpa_msg(hapd->msg_ctx, MSG_INFO, 714 DPP_EVENT_C_SIGN_KEY "%s", hex); 715 os_free(hex); 716 } 717 } 718 if (auth->net_access_key) { 719 char *hex; 720 size_t hexlen; 721 722 hexlen = 2 * wpabuf_len(auth->net_access_key) + 1; 723 hex = os_malloc(hexlen); 724 if (hex) { 725 wpa_snprintf_hex(hex, hexlen, 726 wpabuf_head(auth->net_access_key), 727 wpabuf_len(auth->net_access_key)); 728 if (auth->net_access_key_expiry) 729 wpa_msg(hapd->msg_ctx, MSG_INFO, 730 DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex, 731 (unsigned long) 732 auth->net_access_key_expiry); 733 else 734 wpa_msg(hapd->msg_ctx, MSG_INFO, 735 DPP_EVENT_NET_ACCESS_KEY "%s", hex); 736 os_free(hex); 737 } 738 } 739 dpp_auth_deinit(hapd->dpp_auth); 740 hapd->dpp_auth = NULL; 741 return; 742 743 fail: 744 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); 745 dpp_auth_deinit(hapd->dpp_auth); 746 hapd->dpp_auth = NULL; 747 } 748 749 750 static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd) 751 { 752 struct dpp_authentication *auth = hapd->dpp_auth; 753 struct wpabuf *buf, *conf_req; 754 char json[100]; 755 int res; 756 int netrole_ap = 1; 757 758 os_snprintf(json, sizeof(json), 759 "{\"name\":\"Test\"," 760 "\"wi-fi_tech\":\"infra\"," 761 "\"netRole\":\"%s\"}", 762 netrole_ap ? "ap" : "sta"); 763 wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json); 764 765 conf_req = dpp_build_conf_req(auth, json); 766 if (!conf_req) { 767 wpa_printf(MSG_DEBUG, 768 "DPP: No configuration request data available"); 769 return; 770 } 771 772 buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req)); 773 if (!buf) { 774 wpabuf_free(conf_req); 775 return; 776 } 777 778 /* Advertisement Protocol IE */ 779 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); 780 wpabuf_put_u8(buf, 8); /* Length */ 781 wpabuf_put_u8(buf, 0x7f); 782 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); 783 wpabuf_put_u8(buf, 5); 784 wpabuf_put_be24(buf, OUI_WFA); 785 wpabuf_put_u8(buf, DPP_OUI_TYPE); 786 wpabuf_put_u8(buf, 0x01); 787 788 /* GAS Query */ 789 wpabuf_put_le16(buf, wpabuf_len(conf_req)); 790 wpabuf_put_buf(buf, conf_req); 791 wpabuf_free(conf_req); 792 793 wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)", 794 MAC2STR(auth->peer_mac_addr), auth->curr_freq); 795 796 res = gas_query_ap_req(hapd->gas, auth->peer_mac_addr, auth->curr_freq, 797 buf, hostapd_dpp_gas_resp_cb, hapd); 798 if (res < 0) { 799 wpa_msg(hapd->msg_ctx, MSG_DEBUG, 800 "GAS: Failed to send Query Request"); 801 wpabuf_free(buf); 802 } else { 803 wpa_printf(MSG_DEBUG, 804 "DPP: GAS query started with dialog token %u", res); 805 } 806 } 807 808 809 static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator) 810 { 811 wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded"); 812 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", 813 initiator); 814 815 if (!hapd->dpp_auth->configurator) 816 hostapd_dpp_start_gas_client(hapd); 817 } 818 819 820 static void hostapd_dpp_rx_auth_resp(struct hostapd_data *hapd, const u8 *src, 821 const u8 *hdr, const u8 *buf, size_t len) 822 { 823 struct dpp_authentication *auth = hapd->dpp_auth; 824 struct wpabuf *msg; 825 826 wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR, 827 MAC2STR(src)); 828 829 if (!auth) { 830 wpa_printf(MSG_DEBUG, 831 "DPP: No DPP Authentication in progress - drop"); 832 return; 833 } 834 835 if (!is_zero_ether_addr(auth->peer_mac_addr) && 836 os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { 837 wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " 838 MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); 839 return; 840 } 841 842 msg = dpp_auth_resp_rx(auth, hdr, buf, len); 843 if (!msg) { 844 if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) { 845 wpa_printf(MSG_DEBUG, "DPP: Wait for full response"); 846 return; 847 } 848 wpa_printf(MSG_DEBUG, "DPP: No confirm generated"); 849 return; 850 } 851 os_memcpy(auth->peer_mac_addr, src, ETH_ALEN); 852 853 hostapd_drv_send_action(hapd, auth->curr_freq, 0, src, 854 wpabuf_head(msg), wpabuf_len(msg)); 855 wpabuf_free(msg); 856 hapd->dpp_auth_ok_on_ack = 1; 857 } 858 859 860 static void hostapd_dpp_rx_auth_conf(struct hostapd_data *hapd, const u8 *src, 861 const u8 *hdr, const u8 *buf, size_t len) 862 { 863 struct dpp_authentication *auth = hapd->dpp_auth; 864 865 wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR, 866 MAC2STR(src)); 867 868 if (!auth) { 869 wpa_printf(MSG_DEBUG, 870 "DPP: No DPP Authentication in progress - drop"); 871 return; 872 } 873 874 if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { 875 wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " 876 MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); 877 return; 878 } 879 880 if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) { 881 wpa_printf(MSG_DEBUG, "DPP: Authentication failed"); 882 return; 883 } 884 885 hostapd_dpp_auth_success(hapd, 0); 886 } 887 888 889 static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, 890 const u8 *src, 891 const u8 *buf, size_t len, 892 unsigned int freq) 893 { 894 const u8 *connector, *trans_id; 895 u16 connector_len, trans_id_len; 896 struct os_time now; 897 struct dpp_introduction intro; 898 os_time_t expire; 899 int expiration; 900 struct wpabuf *msg; 901 902 wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR, 903 MAC2STR(src)); 904 if (!hapd->wpa_auth || 905 !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) || 906 !(hapd->conf->wpa & WPA_PROTO_RSN)) { 907 wpa_printf(MSG_DEBUG, "DPP: DPP AKM not in use"); 908 return; 909 } 910 911 if (!hapd->conf->dpp_connector || !hapd->conf->dpp_netaccesskey || 912 !hapd->conf->dpp_csign) { 913 wpa_printf(MSG_DEBUG, "DPP: No own Connector/keys set"); 914 return; 915 } 916 917 os_get_time(&now); 918 919 if (hapd->conf->dpp_netaccesskey_expiry && 920 hapd->conf->dpp_netaccesskey_expiry < now.sec) { 921 wpa_printf(MSG_INFO, "DPP: Own netAccessKey expired"); 922 return; 923 } 924 925 trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID, 926 &trans_id_len); 927 if (!trans_id || trans_id_len != 1) { 928 wpa_printf(MSG_DEBUG, 929 "DPP: Peer did not include Transaction ID"); 930 return; 931 } 932 933 connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len); 934 if (!connector) { 935 wpa_printf(MSG_DEBUG, 936 "DPP: Peer did not include its Connector"); 937 return; 938 } 939 940 if (dpp_peer_intro(&intro, hapd->conf->dpp_connector, 941 wpabuf_head(hapd->conf->dpp_netaccesskey), 942 wpabuf_len(hapd->conf->dpp_netaccesskey), 943 wpabuf_head(hapd->conf->dpp_csign), 944 wpabuf_len(hapd->conf->dpp_csign), 945 connector, connector_len, &expire) < 0) { 946 wpa_printf(MSG_INFO, 947 "DPP: Network Introduction protocol resulted in failure"); 948 return; 949 } 950 951 if (!expire || hapd->conf->dpp_netaccesskey_expiry < expire) 952 expire = hapd->conf->dpp_netaccesskey_expiry; 953 if (expire) 954 expiration = expire - now.sec; 955 else 956 expiration = 0; 957 958 if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len, 959 intro.pmkid, expiration, 960 WPA_KEY_MGMT_DPP) < 0) { 961 wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry"); 962 return; 963 } 964 965 msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP, 966 5 + 4 + os_strlen(hapd->conf->dpp_connector)); 967 if (!msg) 968 return; 969 970 /* Transaction ID */ 971 wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); 972 wpabuf_put_le16(msg, 1); 973 wpabuf_put_u8(msg, trans_id[0]); 974 975 /* DPP Connector */ 976 wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); 977 wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector)); 978 wpabuf_put_str(msg, hapd->conf->dpp_connector); 979 980 wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR, 981 MAC2STR(src)); 982 hostapd_drv_send_action(hapd, freq, 0, src, 983 wpabuf_head(msg), wpabuf_len(msg)); 984 wpabuf_free(msg); 985 } 986 987 988 static void 989 hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src, 990 const u8 *buf, size_t len, 991 unsigned int freq) 992 { 993 struct wpabuf *msg; 994 995 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR, 996 MAC2STR(src)); 997 998 /* TODO: Support multiple PKEX codes by iterating over all the enabled 999 * values here */ 1000 1001 if (!hapd->dpp_pkex_code || !hapd->dpp_pkex_bi) { 1002 wpa_printf(MSG_DEBUG, 1003 "DPP: No PKEX code configured - ignore request"); 1004 return; 1005 } 1006 1007 if (hapd->dpp_pkex) { 1008 /* TODO: Support parallel operations */ 1009 wpa_printf(MSG_DEBUG, 1010 "DPP: Already in PKEX session - ignore new request"); 1011 return; 1012 } 1013 1014 hapd->dpp_pkex = dpp_pkex_rx_exchange_req(hapd->dpp_pkex_bi, 1015 hapd->own_addr, src, 1016 hapd->dpp_pkex_identifier, 1017 hapd->dpp_pkex_code, 1018 buf, len); 1019 if (!hapd->dpp_pkex) { 1020 wpa_printf(MSG_DEBUG, 1021 "DPP: Failed to process the request - ignore it"); 1022 return; 1023 } 1024 1025 msg = hapd->dpp_pkex->exchange_resp; 1026 hostapd_drv_send_action(hapd, freq, 0, src, 1027 wpabuf_head(msg), wpabuf_len(msg)); 1028 } 1029 1030 1031 static void 1032 hostapd_dpp_rx_pkex_exchange_resp(struct hostapd_data *hapd, const u8 *src, 1033 const u8 *buf, size_t len, unsigned int freq) 1034 { 1035 struct wpabuf *msg; 1036 1037 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response from " MACSTR, 1038 MAC2STR(src)); 1039 1040 /* TODO: Support multiple PKEX codes by iterating over all the enabled 1041 * values here */ 1042 1043 if (!hapd->dpp_pkex || !hapd->dpp_pkex->initiator || 1044 hapd->dpp_pkex->exchange_done) { 1045 wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); 1046 return; 1047 } 1048 1049 os_memcpy(hapd->dpp_pkex->peer_mac, src, ETH_ALEN); 1050 msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, buf, len); 1051 if (!msg) { 1052 wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); 1053 return; 1054 } 1055 1056 wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR, 1057 MAC2STR(src)); 1058 1059 hostapd_drv_send_action(hapd, freq, 0, src, 1060 wpabuf_head(msg), wpabuf_len(msg)); 1061 wpabuf_free(msg); 1062 } 1063 1064 1065 static void 1066 hostapd_dpp_rx_pkex_commit_reveal_req(struct hostapd_data *hapd, const u8 *src, 1067 const u8 *hdr, const u8 *buf, size_t len, 1068 unsigned int freq) 1069 { 1070 struct wpabuf *msg; 1071 struct dpp_pkex *pkex = hapd->dpp_pkex; 1072 struct dpp_bootstrap_info *bi; 1073 1074 wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR, 1075 MAC2STR(src)); 1076 1077 if (!pkex || pkex->initiator || !pkex->exchange_done) { 1078 wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); 1079 return; 1080 } 1081 1082 msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len); 1083 if (!msg) { 1084 wpa_printf(MSG_DEBUG, "DPP: Failed to process the request"); 1085 return; 1086 } 1087 1088 wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to " 1089 MACSTR, MAC2STR(src)); 1090 1091 hostapd_drv_send_action(hapd, freq, 0, src, 1092 wpabuf_head(msg), wpabuf_len(msg)); 1093 wpabuf_free(msg); 1094 1095 bi = os_zalloc(sizeof(*bi)); 1096 if (!bi) 1097 return; 1098 bi->id = hapd_dpp_next_id(hapd); 1099 bi->type = DPP_BOOTSTRAP_PKEX; 1100 os_memcpy(bi->mac_addr, src, ETH_ALEN); 1101 bi->num_freq = 1; 1102 bi->freq[0] = freq; 1103 bi->curve = pkex->own_bi->curve; 1104 bi->pubkey = pkex->peer_bootstrap_key; 1105 pkex->peer_bootstrap_key = NULL; 1106 dpp_pkex_free(pkex); 1107 hapd->dpp_pkex = NULL; 1108 if (dpp_bootstrap_key_hash(bi) < 0) { 1109 dpp_bootstrap_info_free(bi); 1110 return; 1111 } 1112 dl_list_add(&hapd->dpp_bootstrap, &bi->list); 1113 } 1114 1115 1116 static void 1117 hostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src, 1118 const u8 *hdr, const u8 *buf, size_t len, 1119 unsigned int freq) 1120 { 1121 int res; 1122 struct dpp_bootstrap_info *bi, *own_bi; 1123 struct dpp_pkex *pkex = hapd->dpp_pkex; 1124 char cmd[500]; 1125 1126 wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response from " MACSTR, 1127 MAC2STR(src)); 1128 1129 if (!pkex || !pkex->initiator || !pkex->exchange_done) { 1130 wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); 1131 return; 1132 } 1133 1134 res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len); 1135 if (res < 0) { 1136 wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); 1137 return; 1138 } 1139 1140 own_bi = pkex->own_bi; 1141 1142 bi = os_zalloc(sizeof(*bi)); 1143 if (!bi) 1144 return; 1145 bi->id = hapd_dpp_next_id(hapd); 1146 bi->type = DPP_BOOTSTRAP_PKEX; 1147 os_memcpy(bi->mac_addr, src, ETH_ALEN); 1148 bi->num_freq = 1; 1149 bi->freq[0] = freq; 1150 bi->curve = own_bi->curve; 1151 bi->pubkey = pkex->peer_bootstrap_key; 1152 pkex->peer_bootstrap_key = NULL; 1153 dpp_pkex_free(pkex); 1154 hapd->dpp_pkex = NULL; 1155 if (dpp_bootstrap_key_hash(bi) < 0) { 1156 dpp_bootstrap_info_free(bi); 1157 return; 1158 } 1159 dl_list_add(&hapd->dpp_bootstrap, &bi->list); 1160 1161 os_snprintf(cmd, sizeof(cmd), " peer=%u %s", 1162 bi->id, 1163 hapd->dpp_pkex_auth_cmd ? hapd->dpp_pkex_auth_cmd : ""); 1164 wpa_printf(MSG_DEBUG, 1165 "DPP: Start authentication after PKEX with parameters: %s", 1166 cmd); 1167 if (hostapd_dpp_auth_init(hapd, cmd) < 0) { 1168 wpa_printf(MSG_DEBUG, 1169 "DPP: Authentication initialization failed"); 1170 return; 1171 } 1172 } 1173 1174 1175 void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, 1176 const u8 *buf, size_t len, unsigned int freq) 1177 { 1178 u8 crypto_suite; 1179 enum dpp_public_action_frame_type type; 1180 const u8 *hdr; 1181 1182 if (len < DPP_HDR_LEN) 1183 return; 1184 if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE) 1185 return; 1186 hdr = buf; 1187 buf += 4; 1188 len -= 4; 1189 crypto_suite = *buf++; 1190 type = *buf++; 1191 len -= 2; 1192 1193 wpa_printf(MSG_DEBUG, 1194 "DPP: Received DPP Public Action frame crypto suite %u type %d from " 1195 MACSTR " freq=%u", 1196 crypto_suite, type, MAC2STR(src), freq); 1197 if (crypto_suite != 1) { 1198 wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u", 1199 crypto_suite); 1200 return; 1201 } 1202 wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len); 1203 if (dpp_check_attrs(buf, len) < 0) 1204 return; 1205 1206 switch (type) { 1207 case DPP_PA_AUTHENTICATION_REQ: 1208 hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq); 1209 break; 1210 case DPP_PA_AUTHENTICATION_RESP: 1211 hostapd_dpp_rx_auth_resp(hapd, src, hdr, buf, len); 1212 break; 1213 case DPP_PA_AUTHENTICATION_CONF: 1214 hostapd_dpp_rx_auth_conf(hapd, src, hdr, buf, len); 1215 break; 1216 case DPP_PA_PEER_DISCOVERY_REQ: 1217 hostapd_dpp_rx_peer_disc_req(hapd, src, buf, len, freq); 1218 break; 1219 case DPP_PA_PKEX_EXCHANGE_REQ: 1220 hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq); 1221 break; 1222 case DPP_PA_PKEX_EXCHANGE_RESP: 1223 hostapd_dpp_rx_pkex_exchange_resp(hapd, src, buf, len, freq); 1224 break; 1225 case DPP_PA_PKEX_COMMIT_REVEAL_REQ: 1226 hostapd_dpp_rx_pkex_commit_reveal_req(hapd, src, hdr, buf, len, 1227 freq); 1228 break; 1229 case DPP_PA_PKEX_COMMIT_REVEAL_RESP: 1230 hostapd_dpp_rx_pkex_commit_reveal_resp(hapd, src, hdr, buf, len, 1231 freq); 1232 break; 1233 default: 1234 wpa_printf(MSG_DEBUG, 1235 "DPP: Ignored unsupported frame subtype %d", type); 1236 break; 1237 } 1238 } 1239 1240 1241 struct wpabuf * 1242 hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa, 1243 const u8 *query, size_t query_len) 1244 { 1245 struct dpp_authentication *auth = hapd->dpp_auth; 1246 struct wpabuf *resp; 1247 1248 wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa)); 1249 if (!auth || !auth->auth_success || 1250 os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) { 1251 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); 1252 return NULL; 1253 } 1254 wpa_hexdump(MSG_DEBUG, 1255 "DPP: Received Configuration Request (GAS Query Request)", 1256 query, query_len); 1257 resp = dpp_conf_req_rx(auth, query, query_len); 1258 if (!resp) 1259 wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); 1260 return resp; 1261 } 1262 1263 1264 static unsigned int hostapd_dpp_next_configurator_id(struct hostapd_data *hapd) 1265 { 1266 struct dpp_configurator *conf; 1267 unsigned int max_id = 0; 1268 1269 dl_list_for_each(conf, &hapd->dpp_configurator, 1270 struct dpp_configurator, list) { 1271 if (conf->id > max_id) 1272 max_id = conf->id; 1273 } 1274 return max_id + 1; 1275 } 1276 1277 1278 int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd) 1279 { 1280 char *curve = NULL; 1281 char *key = NULL; 1282 u8 *privkey = NULL; 1283 size_t privkey_len = 0; 1284 int ret = -1; 1285 struct dpp_configurator *conf = NULL; 1286 1287 curve = get_param(cmd, " curve="); 1288 key = get_param(cmd, " key="); 1289 1290 if (key) { 1291 privkey_len = os_strlen(key) / 2; 1292 privkey = os_malloc(privkey_len); 1293 if (!privkey || 1294 hexstr2bin(key, privkey, privkey_len) < 0) 1295 goto fail; 1296 } 1297 1298 conf = dpp_keygen_configurator(curve, privkey, privkey_len); 1299 if (!conf) 1300 goto fail; 1301 1302 conf->id = hostapd_dpp_next_configurator_id(hapd); 1303 dl_list_add(&hapd->dpp_configurator, &conf->list); 1304 ret = conf->id; 1305 conf = NULL; 1306 fail: 1307 os_free(curve); 1308 str_clear_free(key); 1309 bin_clear_free(privkey, privkey_len); 1310 dpp_configurator_free(conf); 1311 return ret; 1312 } 1313 1314 1315 static int dpp_configurator_del(struct hostapd_data *hapd, unsigned int id) 1316 { 1317 struct dpp_configurator *conf, *tmp; 1318 int found = 0; 1319 1320 dl_list_for_each_safe(conf, tmp, &hapd->dpp_configurator, 1321 struct dpp_configurator, list) { 1322 if (id && conf->id != id) 1323 continue; 1324 found = 1; 1325 dl_list_del(&conf->list); 1326 dpp_configurator_free(conf); 1327 } 1328 1329 if (id == 0) 1330 return 0; /* flush succeeds regardless of entries found */ 1331 return found ? 0 : -1; 1332 } 1333 1334 1335 int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id) 1336 { 1337 unsigned int id_val; 1338 1339 if (os_strcmp(id, "*") == 0) { 1340 id_val = 0; 1341 } else { 1342 id_val = atoi(id); 1343 if (id_val == 0) 1344 return -1; 1345 } 1346 1347 return dpp_configurator_del(hapd, id_val); 1348 } 1349 1350 1351 int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd) 1352 { 1353 struct dpp_bootstrap_info *own_bi; 1354 const char *pos, *end; 1355 1356 pos = os_strstr(cmd, " own="); 1357 if (!pos) 1358 return -1; 1359 pos += 5; 1360 own_bi = dpp_bootstrap_get_id(hapd, atoi(pos)); 1361 if (!own_bi) { 1362 wpa_printf(MSG_DEBUG, 1363 "DPP: Identified bootstrap info not found"); 1364 return -1; 1365 } 1366 if (own_bi->type != DPP_BOOTSTRAP_PKEX) { 1367 wpa_printf(MSG_DEBUG, 1368 "DPP: Identified bootstrap info not for PKEX"); 1369 return -1; 1370 } 1371 hapd->dpp_pkex_bi = own_bi; 1372 1373 os_free(hapd->dpp_pkex_identifier); 1374 hapd->dpp_pkex_identifier = NULL; 1375 pos = os_strstr(cmd, " identifier="); 1376 if (pos) { 1377 pos += 12; 1378 end = os_strchr(pos, ' '); 1379 if (!end) 1380 return -1; 1381 hapd->dpp_pkex_identifier = os_malloc(end - pos + 1); 1382 if (!hapd->dpp_pkex_identifier) 1383 return -1; 1384 os_memcpy(hapd->dpp_pkex_identifier, pos, end - pos); 1385 hapd->dpp_pkex_identifier[end - pos] = '\0'; 1386 } 1387 1388 pos = os_strstr(cmd, " code="); 1389 if (!pos) 1390 return -1; 1391 os_free(hapd->dpp_pkex_code); 1392 hapd->dpp_pkex_code = os_strdup(pos + 6); 1393 if (!hapd->dpp_pkex_code) 1394 return -1; 1395 1396 if (os_strstr(cmd, " init=1")) { 1397 struct wpabuf *msg; 1398 1399 wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX"); 1400 dpp_pkex_free(hapd->dpp_pkex); 1401 hapd->dpp_pkex = dpp_pkex_init(own_bi, hapd->own_addr, 1402 hapd->dpp_pkex_identifier, 1403 hapd->dpp_pkex_code); 1404 if (!hapd->dpp_pkex) 1405 return -1; 1406 1407 msg = hapd->dpp_pkex->exchange_req; 1408 /* TODO: Which channel to use? */ 1409 hostapd_drv_send_action(hapd, 2437, 0, broadcast, 1410 wpabuf_head(msg), wpabuf_len(msg)); 1411 } 1412 1413 /* TODO: Support multiple PKEX info entries */ 1414 1415 os_free(hapd->dpp_pkex_auth_cmd); 1416 hapd->dpp_pkex_auth_cmd = os_strdup(cmd); 1417 1418 return 1; 1419 } 1420 1421 1422 int hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id) 1423 { 1424 unsigned int id_val; 1425 1426 if (os_strcmp(id, "*") == 0) { 1427 id_val = 0; 1428 } else { 1429 id_val = atoi(id); 1430 if (id_val == 0) 1431 return -1; 1432 } 1433 1434 if ((id_val != 0 && id_val != 1) || !hapd->dpp_pkex_code) 1435 return -1; 1436 1437 /* TODO: Support multiple PKEX entries */ 1438 os_free(hapd->dpp_pkex_code); 1439 hapd->dpp_pkex_code = NULL; 1440 os_free(hapd->dpp_pkex_identifier); 1441 hapd->dpp_pkex_identifier = NULL; 1442 os_free(hapd->dpp_pkex_auth_cmd); 1443 hapd->dpp_pkex_auth_cmd = NULL; 1444 hapd->dpp_pkex_bi = NULL; 1445 /* TODO: Remove dpp_pkex only if it is for the identified PKEX code */ 1446 dpp_pkex_free(hapd->dpp_pkex); 1447 hapd->dpp_pkex = NULL; 1448 return 0; 1449 } 1450 1451 1452 int hostapd_dpp_init(struct hostapd_data *hapd) 1453 { 1454 dl_list_init(&hapd->dpp_bootstrap); 1455 dl_list_init(&hapd->dpp_configurator); 1456 hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE; 1457 hapd->dpp_init_done = 1; 1458 return 0; 1459 } 1460 1461 1462 void hostapd_dpp_deinit(struct hostapd_data *hapd) 1463 { 1464 #ifdef CONFIG_TESTING_OPTIONS 1465 os_free(hapd->dpp_config_obj_override); 1466 hapd->dpp_config_obj_override = NULL; 1467 os_free(hapd->dpp_discovery_override); 1468 hapd->dpp_discovery_override = NULL; 1469 os_free(hapd->dpp_groups_override); 1470 hapd->dpp_groups_override = NULL; 1471 hapd->dpp_ignore_netaccesskey_mismatch = 0; 1472 #endif /* CONFIG_TESTING_OPTIONS */ 1473 if (!hapd->dpp_init_done) 1474 return; 1475 dpp_bootstrap_del(hapd, 0); 1476 dpp_configurator_del(hapd, 0); 1477 dpp_auth_deinit(hapd->dpp_auth); 1478 hapd->dpp_auth = NULL; 1479 hostapd_dpp_pkex_remove(hapd, "*"); 1480 hapd->dpp_pkex = NULL; 1481 os_free(hapd->dpp_configurator_params); 1482 hapd->dpp_configurator_params = NULL; 1483 } 1484