1341618Scy/* 2341618Scy * hostapd / DPP integration 3341618Scy * Copyright (c) 2017, Qualcomm Atheros, Inc. 4341618Scy * 5341618Scy * This software may be distributed under the terms of the BSD license. 6341618Scy * See README for more details. 7341618Scy */ 8341618Scy 9341618Scy#include "utils/includes.h" 10341618Scy 11341618Scy#include "utils/common.h" 12341618Scy#include "utils/eloop.h" 13341618Scy#include "common/dpp.h" 14341618Scy#include "common/gas.h" 15341618Scy#include "common/wpa_ctrl.h" 16341618Scy#include "hostapd.h" 17341618Scy#include "ap_drv_ops.h" 18341618Scy#include "gas_query_ap.h" 19351611Scy#include "gas_serv.h" 20341618Scy#include "wpa_auth.h" 21341618Scy#include "dpp_hostapd.h" 22341618Scy 23341618Scy 24341618Scystatic void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx); 25341618Scystatic void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator); 26341618Scystatic void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx); 27341618Scystatic int hostapd_dpp_auth_init_next(struct hostapd_data *hapd); 28341618Scy 29341618Scystatic const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 30341618Scy 31341618Scy 32341618Scy/** 33341618Scy * hostapd_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code 34341618Scy * @hapd: Pointer to hostapd_data 35341618Scy * @cmd: DPP URI read from a QR Code 36341618Scy * Returns: Identifier of the stored info or -1 on failure 37341618Scy */ 38341618Scyint hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd) 39341618Scy{ 40341618Scy struct dpp_bootstrap_info *bi; 41341618Scy struct dpp_authentication *auth = hapd->dpp_auth; 42341618Scy 43346981Scy bi = dpp_add_qr_code(hapd->iface->interfaces->dpp, cmd); 44341618Scy if (!bi) 45341618Scy return -1; 46341618Scy 47341618Scy if (auth && auth->response_pending && 48341618Scy dpp_notify_new_qr_code(auth, bi) == 1) { 49341618Scy wpa_printf(MSG_DEBUG, 50341618Scy "DPP: Sending out pending authentication response"); 51341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 52341618Scy " freq=%u type=%d", 53341618Scy MAC2STR(auth->peer_mac_addr), auth->curr_freq, 54341618Scy DPP_PA_AUTHENTICATION_RESP); 55341618Scy hostapd_drv_send_action(hapd, auth->curr_freq, 0, 56341618Scy auth->peer_mac_addr, 57341618Scy wpabuf_head(hapd->dpp_auth->resp_msg), 58341618Scy wpabuf_len(hapd->dpp_auth->resp_msg)); 59341618Scy } 60341618Scy 61341618Scy return bi->id; 62341618Scy} 63341618Scy 64341618Scy 65341618Scystatic void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx, 66341618Scy void *timeout_ctx) 67341618Scy{ 68341618Scy struct hostapd_data *hapd = eloop_ctx; 69341618Scy struct dpp_authentication *auth = hapd->dpp_auth; 70341618Scy 71341618Scy if (!auth || !auth->resp_msg) 72341618Scy return; 73341618Scy 74341618Scy wpa_printf(MSG_DEBUG, 75341618Scy "DPP: Retry Authentication Response after timeout"); 76341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 77341618Scy " freq=%u type=%d", 78341618Scy MAC2STR(auth->peer_mac_addr), auth->curr_freq, 79341618Scy DPP_PA_AUTHENTICATION_RESP); 80341618Scy hostapd_drv_send_action(hapd, auth->curr_freq, 500, auth->peer_mac_addr, 81341618Scy wpabuf_head(auth->resp_msg), 82341618Scy wpabuf_len(auth->resp_msg)); 83341618Scy} 84341618Scy 85341618Scy 86341618Scystatic void hostapd_dpp_auth_resp_retry(struct hostapd_data *hapd) 87341618Scy{ 88341618Scy struct dpp_authentication *auth = hapd->dpp_auth; 89341618Scy unsigned int wait_time, max_tries; 90341618Scy 91341618Scy if (!auth || !auth->resp_msg) 92341618Scy return; 93341618Scy 94341618Scy if (hapd->dpp_resp_max_tries) 95341618Scy max_tries = hapd->dpp_resp_max_tries; 96341618Scy else 97341618Scy max_tries = 5; 98341618Scy auth->auth_resp_tries++; 99341618Scy if (auth->auth_resp_tries >= max_tries) { 100341618Scy wpa_printf(MSG_INFO, 101341618Scy "DPP: No confirm received from initiator - stopping exchange"); 102341618Scy hostapd_drv_send_action_cancel_wait(hapd); 103341618Scy dpp_auth_deinit(hapd->dpp_auth); 104341618Scy hapd->dpp_auth = NULL; 105341618Scy return; 106341618Scy } 107341618Scy 108341618Scy if (hapd->dpp_resp_retry_time) 109341618Scy wait_time = hapd->dpp_resp_retry_time; 110341618Scy else 111341618Scy wait_time = 1000; 112341618Scy wpa_printf(MSG_DEBUG, 113341618Scy "DPP: Schedule retransmission of Authentication Response frame in %u ms", 114341618Scy wait_time); 115341618Scy eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); 116341618Scy eloop_register_timeout(wait_time / 1000, 117341618Scy (wait_time % 1000) * 1000, 118341618Scy hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); 119341618Scy} 120341618Scy 121341618Scy 122341618Scyvoid hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst, 123341618Scy const u8 *data, size_t data_len, int ok) 124341618Scy{ 125341618Scy struct dpp_authentication *auth = hapd->dpp_auth; 126341618Scy 127341618Scy wpa_printf(MSG_DEBUG, "DPP: TX status: dst=" MACSTR " ok=%d", 128341618Scy MAC2STR(dst), ok); 129341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR 130341618Scy " result=%s", MAC2STR(dst), ok ? "SUCCESS" : "FAILED"); 131341618Scy 132341618Scy if (!hapd->dpp_auth) { 133341618Scy wpa_printf(MSG_DEBUG, 134341618Scy "DPP: Ignore TX status since there is no ongoing authentication exchange"); 135341618Scy return; 136341618Scy } 137341618Scy 138346981Scy#ifdef CONFIG_DPP2 139346981Scy if (auth->connect_on_tx_status) { 140346981Scy wpa_printf(MSG_DEBUG, 141346981Scy "DPP: Complete exchange on configuration result"); 142346981Scy dpp_auth_deinit(hapd->dpp_auth); 143346981Scy hapd->dpp_auth = NULL; 144346981Scy return; 145346981Scy } 146346981Scy#endif /* CONFIG_DPP2 */ 147346981Scy 148341618Scy if (hapd->dpp_auth->remove_on_tx_status) { 149341618Scy wpa_printf(MSG_DEBUG, 150341618Scy "DPP: Terminate authentication exchange due to an earlier error"); 151341618Scy eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL); 152341618Scy eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, 153341618Scy hapd, NULL); 154341618Scy eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, 155341618Scy NULL); 156341618Scy hostapd_drv_send_action_cancel_wait(hapd); 157341618Scy dpp_auth_deinit(hapd->dpp_auth); 158341618Scy hapd->dpp_auth = NULL; 159341618Scy return; 160341618Scy } 161341618Scy 162341618Scy if (hapd->dpp_auth_ok_on_ack) 163341618Scy hostapd_dpp_auth_success(hapd, 1); 164341618Scy 165341618Scy if (!is_broadcast_ether_addr(dst) && !ok) { 166341618Scy wpa_printf(MSG_DEBUG, 167341618Scy "DPP: Unicast DPP Action frame was not ACKed"); 168341618Scy if (auth->waiting_auth_resp) { 169341618Scy /* In case of DPP Authentication Request frame, move to 170341618Scy * the next channel immediately. */ 171341618Scy hostapd_drv_send_action_cancel_wait(hapd); 172341618Scy hostapd_dpp_auth_init_next(hapd); 173341618Scy return; 174341618Scy } 175341618Scy if (auth->waiting_auth_conf) { 176341618Scy hostapd_dpp_auth_resp_retry(hapd); 177341618Scy return; 178341618Scy } 179341618Scy } 180341618Scy 181341618Scy if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp && ok) { 182341618Scy /* Allow timeout handling to stop iteration if no response is 183341618Scy * received from a peer that has ACKed a request. */ 184341618Scy auth->auth_req_ack = 1; 185341618Scy } 186341618Scy 187341618Scy if (!hapd->dpp_auth_ok_on_ack && hapd->dpp_auth->neg_freq > 0 && 188341618Scy hapd->dpp_auth->curr_freq != hapd->dpp_auth->neg_freq) { 189341618Scy wpa_printf(MSG_DEBUG, 190341618Scy "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response", 191341618Scy hapd->dpp_auth->curr_freq, 192341618Scy hapd->dpp_auth->neg_freq); 193341618Scy hostapd_drv_send_action_cancel_wait(hapd); 194341618Scy 195341618Scy if (hapd->dpp_auth->neg_freq != 196341618Scy (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) { 197341618Scy /* TODO: Listen operation on non-operating channel */ 198341618Scy wpa_printf(MSG_INFO, 199341618Scy "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)", 200341618Scy hapd->dpp_auth->neg_freq, hapd->iface->freq); 201341618Scy } 202341618Scy } 203341618Scy 204341618Scy if (hapd->dpp_auth_ok_on_ack) 205341618Scy hapd->dpp_auth_ok_on_ack = 0; 206341618Scy} 207341618Scy 208341618Scy 209341618Scystatic void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx) 210341618Scy{ 211341618Scy struct hostapd_data *hapd = eloop_ctx; 212341618Scy struct dpp_authentication *auth = hapd->dpp_auth; 213341618Scy unsigned int freq; 214341618Scy struct os_reltime now, diff; 215341618Scy unsigned int wait_time, diff_ms; 216341618Scy 217341618Scy if (!auth || !auth->waiting_auth_resp) 218341618Scy return; 219341618Scy 220341618Scy wait_time = hapd->dpp_resp_wait_time ? 221341618Scy hapd->dpp_resp_wait_time : 2000; 222341618Scy os_get_reltime(&now); 223341618Scy os_reltime_sub(&now, &hapd->dpp_last_init, &diff); 224341618Scy diff_ms = diff.sec * 1000 + diff.usec / 1000; 225341618Scy wpa_printf(MSG_DEBUG, 226341618Scy "DPP: Reply wait timeout - wait_time=%u diff_ms=%u", 227341618Scy wait_time, diff_ms); 228341618Scy 229341618Scy if (auth->auth_req_ack && diff_ms >= wait_time) { 230341618Scy /* Peer ACK'ed Authentication Request frame, but did not reply 231341618Scy * with Authentication Response frame within two seconds. */ 232341618Scy wpa_printf(MSG_INFO, 233341618Scy "DPP: No response received from responder - stopping initiation attempt"); 234341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED); 235341618Scy hostapd_drv_send_action_cancel_wait(hapd); 236341618Scy hostapd_dpp_listen_stop(hapd); 237341618Scy dpp_auth_deinit(auth); 238341618Scy hapd->dpp_auth = NULL; 239341618Scy return; 240341618Scy } 241341618Scy 242341618Scy if (diff_ms >= wait_time) { 243341618Scy /* Authentication Request frame was not ACK'ed and no reply 244341618Scy * was receiving within two seconds. */ 245341618Scy wpa_printf(MSG_DEBUG, 246341618Scy "DPP: Continue Initiator channel iteration"); 247341618Scy hostapd_drv_send_action_cancel_wait(hapd); 248341618Scy hostapd_dpp_listen_stop(hapd); 249341618Scy hostapd_dpp_auth_init_next(hapd); 250341618Scy return; 251341618Scy } 252341618Scy 253341618Scy /* Driver did not support 2000 ms long wait_time with TX command, so 254341618Scy * schedule listen operation to continue waiting for the response. 255341618Scy * 256341618Scy * DPP listen operations continue until stopped, so simply schedule a 257341618Scy * new call to this function at the point when the two second reply 258341618Scy * wait has expired. */ 259341618Scy wait_time -= diff_ms; 260341618Scy 261341618Scy freq = auth->curr_freq; 262341618Scy if (auth->neg_freq > 0) 263341618Scy freq = auth->neg_freq; 264341618Scy wpa_printf(MSG_DEBUG, 265341618Scy "DPP: Continue reply wait on channel %u MHz for %u ms", 266341618Scy freq, wait_time); 267341618Scy hapd->dpp_in_response_listen = 1; 268341618Scy 269341618Scy if (freq != (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) { 270341618Scy /* TODO: Listen operation on non-operating channel */ 271341618Scy wpa_printf(MSG_INFO, 272341618Scy "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)", 273341618Scy freq, hapd->iface->freq); 274341618Scy } 275341618Scy 276341618Scy eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000, 277341618Scy hostapd_dpp_reply_wait_timeout, hapd, NULL); 278341618Scy} 279341618Scy 280341618Scy 281341618Scystatic void hostapd_dpp_set_testing_options(struct hostapd_data *hapd, 282341618Scy struct dpp_authentication *auth) 283341618Scy{ 284341618Scy#ifdef CONFIG_TESTING_OPTIONS 285341618Scy if (hapd->dpp_config_obj_override) 286341618Scy auth->config_obj_override = 287341618Scy os_strdup(hapd->dpp_config_obj_override); 288341618Scy if (hapd->dpp_discovery_override) 289341618Scy auth->discovery_override = 290341618Scy os_strdup(hapd->dpp_discovery_override); 291341618Scy if (hapd->dpp_groups_override) 292341618Scy auth->groups_override = os_strdup(hapd->dpp_groups_override); 293341618Scy auth->ignore_netaccesskey_mismatch = 294341618Scy hapd->dpp_ignore_netaccesskey_mismatch; 295341618Scy#endif /* CONFIG_TESTING_OPTIONS */ 296341618Scy} 297341618Scy 298341618Scy 299341618Scystatic void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx) 300341618Scy{ 301341618Scy struct hostapd_data *hapd = eloop_ctx; 302341618Scy 303341618Scy if (!hapd->dpp_auth) 304341618Scy return; 305341618Scy wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout"); 306341618Scy hostapd_dpp_auth_init_next(hapd); 307341618Scy} 308341618Scy 309341618Scy 310341618Scystatic int hostapd_dpp_auth_init_next(struct hostapd_data *hapd) 311341618Scy{ 312341618Scy struct dpp_authentication *auth = hapd->dpp_auth; 313341618Scy const u8 *dst; 314341618Scy unsigned int wait_time, max_wait_time, freq, max_tries, used; 315341618Scy struct os_reltime now, diff; 316341618Scy 317341618Scy if (!auth) 318341618Scy return -1; 319341618Scy 320341618Scy if (auth->freq_idx == 0) 321341618Scy os_get_reltime(&hapd->dpp_init_iter_start); 322341618Scy 323341618Scy if (auth->freq_idx >= auth->num_freq) { 324341618Scy auth->num_freq_iters++; 325341618Scy if (hapd->dpp_init_max_tries) 326341618Scy max_tries = hapd->dpp_init_max_tries; 327341618Scy else 328341618Scy max_tries = 5; 329341618Scy if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) { 330341618Scy wpa_printf(MSG_INFO, 331341618Scy "DPP: No response received from responder - stopping initiation attempt"); 332341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, 333341618Scy DPP_EVENT_AUTH_INIT_FAILED); 334341618Scy eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, 335341618Scy hapd, NULL); 336341618Scy hostapd_drv_send_action_cancel_wait(hapd); 337341618Scy dpp_auth_deinit(hapd->dpp_auth); 338341618Scy hapd->dpp_auth = NULL; 339341618Scy return -1; 340341618Scy } 341341618Scy auth->freq_idx = 0; 342341618Scy eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL); 343341618Scy if (hapd->dpp_init_retry_time) 344341618Scy wait_time = hapd->dpp_init_retry_time; 345341618Scy else 346341618Scy wait_time = 10000; 347341618Scy os_get_reltime(&now); 348341618Scy os_reltime_sub(&now, &hapd->dpp_init_iter_start, &diff); 349341618Scy used = diff.sec * 1000 + diff.usec / 1000; 350341618Scy if (used > wait_time) 351341618Scy wait_time = 0; 352341618Scy else 353341618Scy wait_time -= used; 354341618Scy wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms", 355341618Scy wait_time); 356341618Scy eloop_register_timeout(wait_time / 1000, 357341618Scy (wait_time % 1000) * 1000, 358341618Scy hostapd_dpp_init_timeout, hapd, 359341618Scy NULL); 360341618Scy return 0; 361341618Scy } 362341618Scy freq = auth->freq[auth->freq_idx++]; 363341618Scy auth->curr_freq = freq; 364341618Scy 365341618Scy if (is_zero_ether_addr(auth->peer_bi->mac_addr)) 366341618Scy dst = broadcast; 367341618Scy else 368341618Scy dst = auth->peer_bi->mac_addr; 369341618Scy hapd->dpp_auth_ok_on_ack = 0; 370341618Scy eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); 371341618Scy wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */ 372341618Scy max_wait_time = hapd->dpp_resp_wait_time ? 373341618Scy hapd->dpp_resp_wait_time : 2000; 374341618Scy if (wait_time > max_wait_time) 375341618Scy wait_time = max_wait_time; 376341618Scy wait_time += 10; /* give the driver some extra time to complete */ 377341618Scy eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000, 378341618Scy hostapd_dpp_reply_wait_timeout, hapd, NULL); 379341618Scy wait_time -= 10; 380341618Scy if (auth->neg_freq > 0 && freq != auth->neg_freq) { 381341618Scy wpa_printf(MSG_DEBUG, 382341618Scy "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response", 383341618Scy freq, auth->neg_freq); 384341618Scy } 385341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 386341618Scy " freq=%u type=%d", 387341618Scy MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ); 388341618Scy auth->auth_req_ack = 0; 389341618Scy os_get_reltime(&hapd->dpp_last_init); 390341618Scy return hostapd_drv_send_action(hapd, freq, wait_time, 391341618Scy dst, 392341618Scy wpabuf_head(hapd->dpp_auth->req_msg), 393341618Scy wpabuf_len(hapd->dpp_auth->req_msg)); 394341618Scy} 395341618Scy 396341618Scy 397341618Scyint hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd) 398341618Scy{ 399341618Scy const char *pos; 400341618Scy struct dpp_bootstrap_info *peer_bi, *own_bi = NULL; 401341618Scy u8 allowed_roles = DPP_CAPAB_CONFIGURATOR; 402341618Scy unsigned int neg_freq = 0; 403341618Scy 404341618Scy pos = os_strstr(cmd, " peer="); 405341618Scy if (!pos) 406341618Scy return -1; 407341618Scy pos += 6; 408346981Scy peer_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos)); 409341618Scy if (!peer_bi) { 410341618Scy wpa_printf(MSG_INFO, 411341618Scy "DPP: Could not find bootstrapping info for the identified peer"); 412341618Scy return -1; 413341618Scy } 414341618Scy 415341618Scy pos = os_strstr(cmd, " own="); 416341618Scy if (pos) { 417341618Scy pos += 5; 418346981Scy own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, 419346981Scy atoi(pos)); 420341618Scy if (!own_bi) { 421341618Scy wpa_printf(MSG_INFO, 422341618Scy "DPP: Could not find bootstrapping info for the identified local entry"); 423341618Scy return -1; 424341618Scy } 425341618Scy 426341618Scy if (peer_bi->curve != own_bi->curve) { 427341618Scy wpa_printf(MSG_INFO, 428341618Scy "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)", 429341618Scy peer_bi->curve->name, own_bi->curve->name); 430341618Scy return -1; 431341618Scy } 432341618Scy } 433341618Scy 434341618Scy pos = os_strstr(cmd, " role="); 435341618Scy if (pos) { 436341618Scy pos += 6; 437341618Scy if (os_strncmp(pos, "configurator", 12) == 0) 438341618Scy allowed_roles = DPP_CAPAB_CONFIGURATOR; 439341618Scy else if (os_strncmp(pos, "enrollee", 8) == 0) 440341618Scy allowed_roles = DPP_CAPAB_ENROLLEE; 441341618Scy else if (os_strncmp(pos, "either", 6) == 0) 442341618Scy allowed_roles = DPP_CAPAB_CONFIGURATOR | 443341618Scy DPP_CAPAB_ENROLLEE; 444341618Scy else 445341618Scy goto fail; 446341618Scy } 447341618Scy 448341618Scy pos = os_strstr(cmd, " neg_freq="); 449341618Scy if (pos) 450341618Scy neg_freq = atoi(pos + 10); 451341618Scy 452341618Scy if (hapd->dpp_auth) { 453341618Scy eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL); 454341618Scy eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, 455341618Scy hapd, NULL); 456341618Scy eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, 457341618Scy NULL); 458341618Scy hostapd_drv_send_action_cancel_wait(hapd); 459341618Scy dpp_auth_deinit(hapd->dpp_auth); 460341618Scy } 461341618Scy 462341618Scy hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi, 463341618Scy allowed_roles, neg_freq, 464341618Scy hapd->iface->hw_features, 465341618Scy hapd->iface->num_hw_features); 466341618Scy if (!hapd->dpp_auth) 467341618Scy goto fail; 468341618Scy hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth); 469346981Scy if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx, 470346981Scy hapd->dpp_auth, cmd) < 0) { 471341618Scy dpp_auth_deinit(hapd->dpp_auth); 472341618Scy hapd->dpp_auth = NULL; 473341618Scy goto fail; 474341618Scy } 475341618Scy 476341618Scy hapd->dpp_auth->neg_freq = neg_freq; 477341618Scy 478341618Scy if (!is_zero_ether_addr(peer_bi->mac_addr)) 479341618Scy os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr, 480341618Scy ETH_ALEN); 481341618Scy 482341618Scy return hostapd_dpp_auth_init_next(hapd); 483341618Scyfail: 484341618Scy return -1; 485341618Scy} 486341618Scy 487341618Scy 488341618Scyint hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd) 489341618Scy{ 490341618Scy int freq; 491341618Scy 492341618Scy freq = atoi(cmd); 493341618Scy if (freq <= 0) 494341618Scy return -1; 495341618Scy 496341618Scy if (os_strstr(cmd, " role=configurator")) 497341618Scy hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR; 498341618Scy else if (os_strstr(cmd, " role=enrollee")) 499341618Scy hapd->dpp_allowed_roles = DPP_CAPAB_ENROLLEE; 500341618Scy else 501341618Scy hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | 502341618Scy DPP_CAPAB_ENROLLEE; 503341618Scy hapd->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL; 504341618Scy 505341618Scy if (freq != hapd->iface->freq && hapd->iface->freq > 0) { 506341618Scy /* TODO: Listen operation on non-operating channel */ 507341618Scy wpa_printf(MSG_INFO, 508341618Scy "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)", 509341618Scy freq, hapd->iface->freq); 510341618Scy return -1; 511341618Scy } 512341618Scy 513341618Scy return 0; 514341618Scy} 515341618Scy 516341618Scy 517341618Scyvoid hostapd_dpp_listen_stop(struct hostapd_data *hapd) 518341618Scy{ 519341618Scy /* TODO: Stop listen operation on non-operating channel */ 520341618Scy} 521341618Scy 522341618Scy 523341618Scystatic void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src, 524341618Scy const u8 *hdr, const u8 *buf, size_t len, 525341618Scy unsigned int freq) 526341618Scy{ 527341618Scy const u8 *r_bootstrap, *i_bootstrap; 528341618Scy u16 r_bootstrap_len, i_bootstrap_len; 529346981Scy struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL; 530341618Scy 531346981Scy if (!hapd->iface->interfaces->dpp) 532346981Scy return; 533346981Scy 534341618Scy wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR, 535341618Scy MAC2STR(src)); 536341618Scy 537341618Scy r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, 538341618Scy &r_bootstrap_len); 539341618Scy if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { 540341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL 541341618Scy "Missing or invalid required Responder Bootstrapping Key Hash attribute"); 542341618Scy return; 543341618Scy } 544341618Scy wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", 545341618Scy r_bootstrap, r_bootstrap_len); 546341618Scy 547341618Scy i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH, 548341618Scy &i_bootstrap_len); 549341618Scy if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) { 550341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL 551341618Scy "Missing or invalid required Initiator Bootstrapping Key Hash attribute"); 552341618Scy return; 553341618Scy } 554341618Scy wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash", 555341618Scy i_bootstrap, i_bootstrap_len); 556341618Scy 557341618Scy /* Try to find own and peer bootstrapping key matches based on the 558341618Scy * received hash values */ 559346981Scy dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap, 560346981Scy r_bootstrap, &own_bi, &peer_bi); 561351611Scy#ifdef CONFIG_DPP2 562341618Scy if (!own_bi) { 563351611Scy if (dpp_relay_rx_action(hapd->iface->interfaces->dpp, 564351611Scy src, hdr, buf, len, freq, i_bootstrap, 565351611Scy r_bootstrap) == 0) 566351611Scy return; 567351611Scy } 568351611Scy#endif /* CONFIG_DPP2 */ 569351611Scy if (!own_bi) { 570341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL 571341618Scy "No matching own bootstrapping key found - ignore message"); 572341618Scy return; 573341618Scy } 574341618Scy 575341618Scy if (hapd->dpp_auth) { 576341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL 577341618Scy "Already in DPP authentication exchange - ignore new one"); 578341618Scy return; 579341618Scy } 580341618Scy 581341618Scy hapd->dpp_auth_ok_on_ack = 0; 582341618Scy hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles, 583341618Scy hapd->dpp_qr_mutual, 584341618Scy peer_bi, own_bi, freq, hdr, buf, len); 585341618Scy if (!hapd->dpp_auth) { 586341618Scy wpa_printf(MSG_DEBUG, "DPP: No response generated"); 587341618Scy return; 588341618Scy } 589341618Scy hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth); 590346981Scy if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx, 591346981Scy hapd->dpp_auth, 592346981Scy hapd->dpp_configurator_params) < 0) { 593341618Scy dpp_auth_deinit(hapd->dpp_auth); 594341618Scy hapd->dpp_auth = NULL; 595341618Scy return; 596341618Scy } 597341618Scy os_memcpy(hapd->dpp_auth->peer_mac_addr, src, ETH_ALEN); 598341618Scy 599341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 600341618Scy " freq=%u type=%d", 601341618Scy MAC2STR(src), hapd->dpp_auth->curr_freq, 602341618Scy DPP_PA_AUTHENTICATION_RESP); 603341618Scy hostapd_drv_send_action(hapd, hapd->dpp_auth->curr_freq, 0, 604341618Scy src, wpabuf_head(hapd->dpp_auth->resp_msg), 605341618Scy wpabuf_len(hapd->dpp_auth->resp_msg)); 606341618Scy} 607341618Scy 608341618Scy 609341618Scystatic void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd, 610341618Scy struct dpp_authentication *auth) 611341618Scy{ 612341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED); 613341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s", 614341618Scy dpp_akm_str(auth->akm)); 615341618Scy if (auth->ssid_len) 616341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s", 617341618Scy wpa_ssid_txt(auth->ssid, auth->ssid_len)); 618341618Scy if (auth->connector) { 619341618Scy /* TODO: Save the Connector and consider using a command 620341618Scy * to fetch the value instead of sending an event with 621341618Scy * it. The Connector could end up being larger than what 622341618Scy * most clients are ready to receive as an event 623341618Scy * message. */ 624341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s", 625341618Scy auth->connector); 626341618Scy } else if (auth->passphrase[0]) { 627341618Scy char hex[64 * 2 + 1]; 628341618Scy 629341618Scy wpa_snprintf_hex(hex, sizeof(hex), 630341618Scy (const u8 *) auth->passphrase, 631341618Scy os_strlen(auth->passphrase)); 632341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s", 633341618Scy hex); 634341618Scy } else if (auth->psk_set) { 635341618Scy char hex[PMK_LEN * 2 + 1]; 636341618Scy 637341618Scy wpa_snprintf_hex(hex, sizeof(hex), auth->psk, PMK_LEN); 638341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s", 639341618Scy hex); 640341618Scy } 641341618Scy if (auth->c_sign_key) { 642341618Scy char *hex; 643341618Scy size_t hexlen; 644341618Scy 645341618Scy hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1; 646341618Scy hex = os_malloc(hexlen); 647341618Scy if (hex) { 648341618Scy wpa_snprintf_hex(hex, hexlen, 649341618Scy wpabuf_head(auth->c_sign_key), 650341618Scy wpabuf_len(auth->c_sign_key)); 651341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, 652341618Scy DPP_EVENT_C_SIGN_KEY "%s", hex); 653341618Scy os_free(hex); 654341618Scy } 655341618Scy } 656341618Scy if (auth->net_access_key) { 657341618Scy char *hex; 658341618Scy size_t hexlen; 659341618Scy 660341618Scy hexlen = 2 * wpabuf_len(auth->net_access_key) + 1; 661341618Scy hex = os_malloc(hexlen); 662341618Scy if (hex) { 663341618Scy wpa_snprintf_hex(hex, hexlen, 664341618Scy wpabuf_head(auth->net_access_key), 665341618Scy wpabuf_len(auth->net_access_key)); 666341618Scy if (auth->net_access_key_expiry) 667341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, 668341618Scy DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex, 669341618Scy (unsigned long) 670341618Scy auth->net_access_key_expiry); 671341618Scy else 672341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, 673341618Scy DPP_EVENT_NET_ACCESS_KEY "%s", hex); 674341618Scy os_free(hex); 675341618Scy } 676341618Scy } 677341618Scy} 678341618Scy 679341618Scy 680341618Scystatic void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, 681341618Scy enum gas_query_ap_result result, 682341618Scy const struct wpabuf *adv_proto, 683341618Scy const struct wpabuf *resp, u16 status_code) 684341618Scy{ 685341618Scy struct hostapd_data *hapd = ctx; 686341618Scy const u8 *pos; 687341618Scy struct dpp_authentication *auth = hapd->dpp_auth; 688346981Scy enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED; 689341618Scy 690341618Scy if (!auth || !auth->auth_success) { 691341618Scy wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); 692341618Scy return; 693341618Scy } 694341618Scy if (!resp || status_code != WLAN_STATUS_SUCCESS) { 695341618Scy wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed"); 696341618Scy goto fail; 697341618Scy } 698341618Scy 699341618Scy wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto", 700341618Scy adv_proto); 701341618Scy wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)", 702341618Scy resp); 703341618Scy 704341618Scy if (wpabuf_len(adv_proto) != 10 || 705341618Scy !(pos = wpabuf_head(adv_proto)) || 706341618Scy pos[0] != WLAN_EID_ADV_PROTO || 707341618Scy pos[1] != 8 || 708341618Scy pos[3] != WLAN_EID_VENDOR_SPECIFIC || 709341618Scy pos[4] != 5 || 710341618Scy WPA_GET_BE24(&pos[5]) != OUI_WFA || 711341618Scy pos[8] != 0x1a || 712341618Scy pos[9] != 1) { 713341618Scy wpa_printf(MSG_DEBUG, 714341618Scy "DPP: Not a DPP Advertisement Protocol ID"); 715341618Scy goto fail; 716341618Scy } 717341618Scy 718341618Scy if (dpp_conf_resp_rx(auth, resp) < 0) { 719341618Scy wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); 720341618Scy goto fail; 721341618Scy } 722341618Scy 723341618Scy hostapd_dpp_handle_config_obj(hapd, auth); 724346981Scy status = DPP_STATUS_OK; 725346981Scy#ifdef CONFIG_TESTING_OPTIONS 726346981Scy if (dpp_test == DPP_TEST_REJECT_CONFIG) { 727346981Scy wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object"); 728346981Scy status = DPP_STATUS_CONFIG_REJECTED; 729346981Scy } 730346981Scy#endif /* CONFIG_TESTING_OPTIONS */ 731346981Scyfail: 732346981Scy if (status != DPP_STATUS_OK) 733346981Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); 734346981Scy#ifdef CONFIG_DPP2 735346981Scy if (auth->peer_version >= 2 && 736346981Scy auth->conf_resp_status == DPP_STATUS_OK) { 737346981Scy struct wpabuf *msg; 738341618Scy 739346981Scy wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result"); 740346981Scy msg = dpp_build_conf_result(auth, status); 741346981Scy if (!msg) 742346981Scy goto fail2; 743346981Scy 744346981Scy wpa_msg(hapd->msg_ctx, MSG_INFO, 745346981Scy DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", 746346981Scy MAC2STR(addr), auth->curr_freq, 747346981Scy DPP_PA_CONFIGURATION_RESULT); 748346981Scy hostapd_drv_send_action(hapd, auth->curr_freq, 0, 749346981Scy addr, wpabuf_head(msg), 750346981Scy wpabuf_len(msg)); 751346981Scy wpabuf_free(msg); 752346981Scy 753346981Scy /* This exchange will be terminated in the TX status handler */ 754346981Scy auth->connect_on_tx_status = 1; 755346981Scy return; 756346981Scy } 757346981Scyfail2: 758346981Scy#endif /* CONFIG_DPP2 */ 759341618Scy dpp_auth_deinit(hapd->dpp_auth); 760341618Scy hapd->dpp_auth = NULL; 761341618Scy} 762341618Scy 763341618Scy 764341618Scystatic void hostapd_dpp_start_gas_client(struct hostapd_data *hapd) 765341618Scy{ 766341618Scy struct dpp_authentication *auth = hapd->dpp_auth; 767346981Scy struct wpabuf *buf; 768341618Scy char json[100]; 769341618Scy int res; 770341618Scy int netrole_ap = 1; 771341618Scy 772341618Scy os_snprintf(json, sizeof(json), 773341618Scy "{\"name\":\"Test\"," 774341618Scy "\"wi-fi_tech\":\"infra\"," 775341618Scy "\"netRole\":\"%s\"}", 776341618Scy netrole_ap ? "ap" : "sta"); 777341618Scy wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json); 778341618Scy 779346981Scy buf = dpp_build_conf_req(auth, json); 780346981Scy if (!buf) { 781341618Scy wpa_printf(MSG_DEBUG, 782341618Scy "DPP: No configuration request data available"); 783341618Scy return; 784341618Scy } 785341618Scy 786341618Scy wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)", 787341618Scy MAC2STR(auth->peer_mac_addr), auth->curr_freq); 788341618Scy 789341618Scy res = gas_query_ap_req(hapd->gas, auth->peer_mac_addr, auth->curr_freq, 790341618Scy buf, hostapd_dpp_gas_resp_cb, hapd); 791341618Scy if (res < 0) { 792341618Scy wpa_msg(hapd->msg_ctx, MSG_DEBUG, 793341618Scy "GAS: Failed to send Query Request"); 794341618Scy wpabuf_free(buf); 795341618Scy } else { 796341618Scy wpa_printf(MSG_DEBUG, 797341618Scy "DPP: GAS query started with dialog token %u", res); 798341618Scy } 799341618Scy} 800341618Scy 801341618Scy 802341618Scystatic void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator) 803341618Scy{ 804341618Scy wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded"); 805341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", 806341618Scy initiator); 807341618Scy#ifdef CONFIG_TESTING_OPTIONS 808341618Scy if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) { 809341618Scy wpa_printf(MSG_INFO, 810341618Scy "DPP: TESTING - stop at Authentication Confirm"); 811341618Scy if (hapd->dpp_auth->configurator) { 812341618Scy /* Prevent GAS response */ 813341618Scy hapd->dpp_auth->auth_success = 0; 814341618Scy } 815341618Scy return; 816341618Scy } 817341618Scy#endif /* CONFIG_TESTING_OPTIONS */ 818341618Scy 819341618Scy if (!hapd->dpp_auth->configurator) 820341618Scy hostapd_dpp_start_gas_client(hapd); 821341618Scy} 822341618Scy 823341618Scy 824341618Scystatic void hostapd_dpp_rx_auth_resp(struct hostapd_data *hapd, const u8 *src, 825341618Scy const u8 *hdr, const u8 *buf, size_t len, 826341618Scy unsigned int freq) 827341618Scy{ 828341618Scy struct dpp_authentication *auth = hapd->dpp_auth; 829341618Scy struct wpabuf *msg; 830341618Scy 831341618Scy wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR, 832341618Scy MAC2STR(src)); 833341618Scy 834341618Scy if (!auth) { 835341618Scy wpa_printf(MSG_DEBUG, 836341618Scy "DPP: No DPP Authentication in progress - drop"); 837341618Scy return; 838341618Scy } 839341618Scy 840341618Scy if (!is_zero_ether_addr(auth->peer_mac_addr) && 841341618Scy os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { 842341618Scy wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " 843341618Scy MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); 844341618Scy return; 845341618Scy } 846341618Scy 847341618Scy eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); 848341618Scy 849341618Scy if (auth->curr_freq != freq && auth->neg_freq == freq) { 850341618Scy wpa_printf(MSG_DEBUG, 851341618Scy "DPP: Responder accepted request for different negotiation channel"); 852341618Scy auth->curr_freq = freq; 853341618Scy } 854341618Scy 855341618Scy eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL); 856341618Scy msg = dpp_auth_resp_rx(auth, hdr, buf, len); 857341618Scy if (!msg) { 858341618Scy if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) { 859341618Scy wpa_printf(MSG_DEBUG, "DPP: Wait for full response"); 860341618Scy return; 861341618Scy } 862341618Scy wpa_printf(MSG_DEBUG, "DPP: No confirm generated"); 863341618Scy return; 864341618Scy } 865341618Scy os_memcpy(auth->peer_mac_addr, src, ETH_ALEN); 866341618Scy 867341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 868341618Scy " freq=%u type=%d", MAC2STR(src), auth->curr_freq, 869341618Scy DPP_PA_AUTHENTICATION_CONF); 870341618Scy hostapd_drv_send_action(hapd, auth->curr_freq, 0, src, 871341618Scy wpabuf_head(msg), wpabuf_len(msg)); 872341618Scy wpabuf_free(msg); 873341618Scy hapd->dpp_auth_ok_on_ack = 1; 874341618Scy} 875341618Scy 876341618Scy 877341618Scystatic void hostapd_dpp_rx_auth_conf(struct hostapd_data *hapd, const u8 *src, 878341618Scy const u8 *hdr, const u8 *buf, size_t len) 879341618Scy{ 880341618Scy struct dpp_authentication *auth = hapd->dpp_auth; 881341618Scy 882341618Scy wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR, 883341618Scy MAC2STR(src)); 884341618Scy 885341618Scy if (!auth) { 886341618Scy wpa_printf(MSG_DEBUG, 887341618Scy "DPP: No DPP Authentication in progress - drop"); 888341618Scy return; 889341618Scy } 890341618Scy 891341618Scy if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { 892341618Scy wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " 893341618Scy MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); 894341618Scy return; 895341618Scy } 896341618Scy 897341618Scy if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) { 898341618Scy wpa_printf(MSG_DEBUG, "DPP: Authentication failed"); 899341618Scy return; 900341618Scy } 901341618Scy 902341618Scy hostapd_dpp_auth_success(hapd, 0); 903341618Scy} 904341618Scy 905341618Scy 906346981Scy#ifdef CONFIG_DPP2 907346981Scy 908346981Scystatic void hostapd_dpp_config_result_wait_timeout(void *eloop_ctx, 909346981Scy void *timeout_ctx) 910346981Scy{ 911346981Scy struct hostapd_data *hapd = eloop_ctx; 912346981Scy struct dpp_authentication *auth = hapd->dpp_auth; 913346981Scy 914346981Scy if (!auth || !auth->waiting_conf_result) 915346981Scy return; 916346981Scy 917346981Scy wpa_printf(MSG_DEBUG, 918346981Scy "DPP: Timeout while waiting for Configuration Result"); 919346981Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); 920346981Scy dpp_auth_deinit(auth); 921346981Scy hapd->dpp_auth = NULL; 922346981Scy} 923346981Scy 924346981Scy 925346981Scystatic void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src, 926346981Scy const u8 *hdr, const u8 *buf, size_t len) 927346981Scy{ 928346981Scy struct dpp_authentication *auth = hapd->dpp_auth; 929346981Scy enum dpp_status_error status; 930346981Scy 931346981Scy wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR, 932346981Scy MAC2STR(src)); 933346981Scy 934346981Scy if (!auth || !auth->waiting_conf_result) { 935346981Scy wpa_printf(MSG_DEBUG, 936346981Scy "DPP: No DPP Configuration waiting for result - drop"); 937346981Scy return; 938346981Scy } 939346981Scy 940346981Scy if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { 941346981Scy wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " 942346981Scy MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); 943346981Scy return; 944346981Scy } 945346981Scy 946346981Scy status = dpp_conf_result_rx(auth, hdr, buf, len); 947346981Scy 948346981Scy hostapd_drv_send_action_cancel_wait(hapd); 949346981Scy hostapd_dpp_listen_stop(hapd); 950346981Scy if (status == DPP_STATUS_OK) 951346981Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT); 952346981Scy else 953346981Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); 954346981Scy dpp_auth_deinit(auth); 955346981Scy hapd->dpp_auth = NULL; 956346981Scy eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd, 957346981Scy NULL); 958346981Scy} 959346981Scy 960346981Scy#endif /* CONFIG_DPP2 */ 961346981Scy 962346981Scy 963341618Scystatic void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd, 964341618Scy const u8 *src, unsigned int freq, 965341618Scy u8 trans_id, 966341618Scy enum dpp_status_error status) 967341618Scy{ 968341618Scy struct wpabuf *msg; 969341618Scy 970341618Scy msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP, 971341618Scy 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector)); 972341618Scy if (!msg) 973341618Scy return; 974341618Scy 975341618Scy#ifdef CONFIG_TESTING_OPTIONS 976341618Scy if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_RESP) { 977341618Scy wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID"); 978341618Scy goto skip_trans_id; 979341618Scy } 980341618Scy if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_RESP) { 981341618Scy wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID"); 982341618Scy trans_id ^= 0x01; 983341618Scy } 984341618Scy#endif /* CONFIG_TESTING_OPTIONS */ 985341618Scy 986341618Scy /* Transaction ID */ 987341618Scy wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); 988341618Scy wpabuf_put_le16(msg, 1); 989341618Scy wpabuf_put_u8(msg, trans_id); 990341618Scy 991341618Scy#ifdef CONFIG_TESTING_OPTIONS 992341618Scyskip_trans_id: 993341618Scy if (dpp_test == DPP_TEST_NO_STATUS_PEER_DISC_RESP) { 994341618Scy wpa_printf(MSG_INFO, "DPP: TESTING - no Status"); 995341618Scy goto skip_status; 996341618Scy } 997341618Scy if (dpp_test == DPP_TEST_INVALID_STATUS_PEER_DISC_RESP) { 998341618Scy wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status"); 999341618Scy status = 254; 1000341618Scy } 1001341618Scy#endif /* CONFIG_TESTING_OPTIONS */ 1002341618Scy 1003341618Scy /* DPP Status */ 1004341618Scy wpabuf_put_le16(msg, DPP_ATTR_STATUS); 1005341618Scy wpabuf_put_le16(msg, 1); 1006341618Scy wpabuf_put_u8(msg, status); 1007341618Scy 1008341618Scy#ifdef CONFIG_TESTING_OPTIONS 1009341618Scyskip_status: 1010341618Scy if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_RESP) { 1011341618Scy wpa_printf(MSG_INFO, "DPP: TESTING - no Connector"); 1012341618Scy goto skip_connector; 1013341618Scy } 1014341618Scy if (status == DPP_STATUS_OK && 1015341618Scy dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_RESP) { 1016341618Scy char *connector; 1017341618Scy 1018341618Scy wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector"); 1019341618Scy connector = dpp_corrupt_connector_signature( 1020341618Scy hapd->conf->dpp_connector); 1021341618Scy if (!connector) { 1022341618Scy wpabuf_free(msg); 1023341618Scy return; 1024341618Scy } 1025341618Scy wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); 1026341618Scy wpabuf_put_le16(msg, os_strlen(connector)); 1027341618Scy wpabuf_put_str(msg, connector); 1028341618Scy os_free(connector); 1029341618Scy goto skip_connector; 1030341618Scy } 1031341618Scy#endif /* CONFIG_TESTING_OPTIONS */ 1032341618Scy 1033341618Scy /* DPP Connector */ 1034341618Scy if (status == DPP_STATUS_OK) { 1035341618Scy wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); 1036341618Scy wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector)); 1037341618Scy wpabuf_put_str(msg, hapd->conf->dpp_connector); 1038341618Scy } 1039341618Scy 1040341618Scy#ifdef CONFIG_TESTING_OPTIONS 1041341618Scyskip_connector: 1042341618Scy#endif /* CONFIG_TESTING_OPTIONS */ 1043341618Scy 1044341618Scy wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR 1045341618Scy " status=%d", MAC2STR(src), status); 1046341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 1047341618Scy " freq=%u type=%d status=%d", MAC2STR(src), freq, 1048341618Scy DPP_PA_PEER_DISCOVERY_RESP, status); 1049341618Scy hostapd_drv_send_action(hapd, freq, 0, src, 1050341618Scy wpabuf_head(msg), wpabuf_len(msg)); 1051341618Scy wpabuf_free(msg); 1052341618Scy} 1053341618Scy 1054341618Scy 1055341618Scystatic void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, 1056341618Scy const u8 *src, 1057341618Scy const u8 *buf, size_t len, 1058341618Scy unsigned int freq) 1059341618Scy{ 1060341618Scy const u8 *connector, *trans_id; 1061341618Scy u16 connector_len, trans_id_len; 1062341618Scy struct os_time now; 1063341618Scy struct dpp_introduction intro; 1064341618Scy os_time_t expire; 1065341618Scy int expiration; 1066341618Scy enum dpp_status_error res; 1067341618Scy 1068341618Scy wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR, 1069341618Scy MAC2STR(src)); 1070341618Scy if (!hapd->wpa_auth || 1071341618Scy !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) || 1072341618Scy !(hapd->conf->wpa & WPA_PROTO_RSN)) { 1073341618Scy wpa_printf(MSG_DEBUG, "DPP: DPP AKM not in use"); 1074341618Scy return; 1075341618Scy } 1076341618Scy 1077341618Scy if (!hapd->conf->dpp_connector || !hapd->conf->dpp_netaccesskey || 1078341618Scy !hapd->conf->dpp_csign) { 1079341618Scy wpa_printf(MSG_DEBUG, "DPP: No own Connector/keys set"); 1080341618Scy return; 1081341618Scy } 1082341618Scy 1083341618Scy os_get_time(&now); 1084341618Scy 1085341618Scy if (hapd->conf->dpp_netaccesskey_expiry && 1086341618Scy (os_time_t) hapd->conf->dpp_netaccesskey_expiry < now.sec) { 1087341618Scy wpa_printf(MSG_INFO, "DPP: Own netAccessKey expired"); 1088341618Scy return; 1089341618Scy } 1090341618Scy 1091341618Scy trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID, 1092341618Scy &trans_id_len); 1093341618Scy if (!trans_id || trans_id_len != 1) { 1094341618Scy wpa_printf(MSG_DEBUG, 1095341618Scy "DPP: Peer did not include Transaction ID"); 1096341618Scy return; 1097341618Scy } 1098341618Scy 1099341618Scy connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len); 1100341618Scy if (!connector) { 1101341618Scy wpa_printf(MSG_DEBUG, 1102341618Scy "DPP: Peer did not include its Connector"); 1103341618Scy return; 1104341618Scy } 1105341618Scy 1106341618Scy res = dpp_peer_intro(&intro, hapd->conf->dpp_connector, 1107341618Scy wpabuf_head(hapd->conf->dpp_netaccesskey), 1108341618Scy wpabuf_len(hapd->conf->dpp_netaccesskey), 1109341618Scy wpabuf_head(hapd->conf->dpp_csign), 1110341618Scy wpabuf_len(hapd->conf->dpp_csign), 1111341618Scy connector, connector_len, &expire); 1112341618Scy if (res == 255) { 1113341618Scy wpa_printf(MSG_INFO, 1114341618Scy "DPP: Network Introduction protocol resulted in internal failure (peer " 1115341618Scy MACSTR ")", MAC2STR(src)); 1116341618Scy return; 1117341618Scy } 1118341618Scy if (res != DPP_STATUS_OK) { 1119341618Scy wpa_printf(MSG_INFO, 1120341618Scy "DPP: Network Introduction protocol resulted in failure (peer " 1121341618Scy MACSTR " status %d)", MAC2STR(src), res); 1122341618Scy hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0], 1123341618Scy res); 1124341618Scy return; 1125341618Scy } 1126341618Scy 1127341618Scy if (!expire || (os_time_t) hapd->conf->dpp_netaccesskey_expiry < expire) 1128341618Scy expire = hapd->conf->dpp_netaccesskey_expiry; 1129341618Scy if (expire) 1130341618Scy expiration = expire - now.sec; 1131341618Scy else 1132341618Scy expiration = 0; 1133341618Scy 1134341618Scy if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len, 1135341618Scy intro.pmkid, expiration, 1136341618Scy WPA_KEY_MGMT_DPP) < 0) { 1137341618Scy wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry"); 1138341618Scy return; 1139341618Scy } 1140341618Scy 1141341618Scy hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0], 1142341618Scy DPP_STATUS_OK); 1143341618Scy} 1144341618Scy 1145341618Scy 1146341618Scystatic void 1147341618Scyhostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src, 1148341618Scy const u8 *buf, size_t len, 1149341618Scy unsigned int freq) 1150341618Scy{ 1151341618Scy struct wpabuf *msg; 1152341618Scy 1153341618Scy wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR, 1154341618Scy MAC2STR(src)); 1155341618Scy 1156341618Scy /* TODO: Support multiple PKEX codes by iterating over all the enabled 1157341618Scy * values here */ 1158341618Scy 1159341618Scy if (!hapd->dpp_pkex_code || !hapd->dpp_pkex_bi) { 1160341618Scy wpa_printf(MSG_DEBUG, 1161341618Scy "DPP: No PKEX code configured - ignore request"); 1162341618Scy return; 1163341618Scy } 1164341618Scy 1165341618Scy if (hapd->dpp_pkex) { 1166341618Scy /* TODO: Support parallel operations */ 1167341618Scy wpa_printf(MSG_DEBUG, 1168341618Scy "DPP: Already in PKEX session - ignore new request"); 1169341618Scy return; 1170341618Scy } 1171341618Scy 1172341618Scy hapd->dpp_pkex = dpp_pkex_rx_exchange_req(hapd->msg_ctx, 1173341618Scy hapd->dpp_pkex_bi, 1174341618Scy hapd->own_addr, src, 1175341618Scy hapd->dpp_pkex_identifier, 1176341618Scy hapd->dpp_pkex_code, 1177341618Scy buf, len); 1178341618Scy if (!hapd->dpp_pkex) { 1179341618Scy wpa_printf(MSG_DEBUG, 1180341618Scy "DPP: Failed to process the request - ignore it"); 1181341618Scy return; 1182341618Scy } 1183341618Scy 1184341618Scy msg = hapd->dpp_pkex->exchange_resp; 1185341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 1186341618Scy " freq=%u type=%d", MAC2STR(src), freq, 1187341618Scy DPP_PA_PKEX_EXCHANGE_RESP); 1188341618Scy hostapd_drv_send_action(hapd, freq, 0, src, 1189341618Scy wpabuf_head(msg), wpabuf_len(msg)); 1190341618Scy if (hapd->dpp_pkex->failed) { 1191341618Scy wpa_printf(MSG_DEBUG, 1192341618Scy "DPP: Terminate PKEX exchange due to an earlier error"); 1193341618Scy if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t) 1194341618Scy hapd->dpp_pkex->own_bi->pkex_t = hapd->dpp_pkex->t; 1195341618Scy dpp_pkex_free(hapd->dpp_pkex); 1196341618Scy hapd->dpp_pkex = NULL; 1197341618Scy } 1198341618Scy} 1199341618Scy 1200341618Scy 1201341618Scystatic void 1202341618Scyhostapd_dpp_rx_pkex_exchange_resp(struct hostapd_data *hapd, const u8 *src, 1203341618Scy const u8 *buf, size_t len, unsigned int freq) 1204341618Scy{ 1205341618Scy struct wpabuf *msg; 1206341618Scy 1207341618Scy wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response from " MACSTR, 1208341618Scy MAC2STR(src)); 1209341618Scy 1210341618Scy /* TODO: Support multiple PKEX codes by iterating over all the enabled 1211341618Scy * values here */ 1212341618Scy 1213341618Scy if (!hapd->dpp_pkex || !hapd->dpp_pkex->initiator || 1214341618Scy hapd->dpp_pkex->exchange_done) { 1215341618Scy wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); 1216341618Scy return; 1217341618Scy } 1218341618Scy 1219341618Scy msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, src, buf, len); 1220341618Scy if (!msg) { 1221341618Scy wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); 1222341618Scy return; 1223341618Scy } 1224341618Scy 1225341618Scy wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR, 1226341618Scy MAC2STR(src)); 1227341618Scy 1228341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 1229341618Scy " freq=%u type=%d", MAC2STR(src), freq, 1230341618Scy DPP_PA_PKEX_COMMIT_REVEAL_REQ); 1231341618Scy hostapd_drv_send_action(hapd, freq, 0, src, 1232341618Scy wpabuf_head(msg), wpabuf_len(msg)); 1233341618Scy wpabuf_free(msg); 1234341618Scy} 1235341618Scy 1236341618Scy 1237341618Scystatic void 1238341618Scyhostapd_dpp_rx_pkex_commit_reveal_req(struct hostapd_data *hapd, const u8 *src, 1239341618Scy const u8 *hdr, const u8 *buf, size_t len, 1240341618Scy unsigned int freq) 1241341618Scy{ 1242341618Scy struct wpabuf *msg; 1243341618Scy struct dpp_pkex *pkex = hapd->dpp_pkex; 1244341618Scy struct dpp_bootstrap_info *bi; 1245341618Scy 1246341618Scy wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR, 1247341618Scy MAC2STR(src)); 1248341618Scy 1249341618Scy if (!pkex || pkex->initiator || !pkex->exchange_done) { 1250341618Scy wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); 1251341618Scy return; 1252341618Scy } 1253341618Scy 1254341618Scy msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len); 1255341618Scy if (!msg) { 1256341618Scy wpa_printf(MSG_DEBUG, "DPP: Failed to process the request"); 1257341618Scy if (hapd->dpp_pkex->failed) { 1258341618Scy wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange"); 1259341618Scy if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t) 1260341618Scy hapd->dpp_pkex->own_bi->pkex_t = 1261341618Scy hapd->dpp_pkex->t; 1262341618Scy dpp_pkex_free(hapd->dpp_pkex); 1263341618Scy hapd->dpp_pkex = NULL; 1264341618Scy } 1265341618Scy return; 1266341618Scy } 1267341618Scy 1268341618Scy wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to " 1269341618Scy MACSTR, MAC2STR(src)); 1270341618Scy 1271341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 1272341618Scy " freq=%u type=%d", MAC2STR(src), freq, 1273341618Scy DPP_PA_PKEX_COMMIT_REVEAL_RESP); 1274341618Scy hostapd_drv_send_action(hapd, freq, 0, src, 1275341618Scy wpabuf_head(msg), wpabuf_len(msg)); 1276341618Scy wpabuf_free(msg); 1277341618Scy 1278346981Scy bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq); 1279341618Scy if (!bi) 1280341618Scy return; 1281341618Scy hapd->dpp_pkex = NULL; 1282341618Scy} 1283341618Scy 1284341618Scy 1285341618Scystatic void 1286341618Scyhostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src, 1287341618Scy const u8 *hdr, const u8 *buf, size_t len, 1288341618Scy unsigned int freq) 1289341618Scy{ 1290341618Scy int res; 1291346981Scy struct dpp_bootstrap_info *bi; 1292341618Scy struct dpp_pkex *pkex = hapd->dpp_pkex; 1293341618Scy char cmd[500]; 1294341618Scy 1295341618Scy wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response from " MACSTR, 1296341618Scy MAC2STR(src)); 1297341618Scy 1298341618Scy if (!pkex || !pkex->initiator || !pkex->exchange_done) { 1299341618Scy wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); 1300341618Scy return; 1301341618Scy } 1302341618Scy 1303341618Scy res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len); 1304341618Scy if (res < 0) { 1305341618Scy wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); 1306341618Scy return; 1307341618Scy } 1308341618Scy 1309346981Scy bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq); 1310341618Scy if (!bi) 1311341618Scy return; 1312341618Scy hapd->dpp_pkex = NULL; 1313341618Scy 1314341618Scy os_snprintf(cmd, sizeof(cmd), " peer=%u %s", 1315341618Scy bi->id, 1316341618Scy hapd->dpp_pkex_auth_cmd ? hapd->dpp_pkex_auth_cmd : ""); 1317341618Scy wpa_printf(MSG_DEBUG, 1318341618Scy "DPP: Start authentication after PKEX with parameters: %s", 1319341618Scy cmd); 1320341618Scy if (hostapd_dpp_auth_init(hapd, cmd) < 0) { 1321341618Scy wpa_printf(MSG_DEBUG, 1322341618Scy "DPP: Authentication initialization failed"); 1323341618Scy return; 1324341618Scy } 1325341618Scy} 1326341618Scy 1327341618Scy 1328341618Scyvoid hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, 1329341618Scy const u8 *buf, size_t len, unsigned int freq) 1330341618Scy{ 1331341618Scy u8 crypto_suite; 1332341618Scy enum dpp_public_action_frame_type type; 1333341618Scy const u8 *hdr; 1334341618Scy unsigned int pkex_t; 1335341618Scy 1336341618Scy if (len < DPP_HDR_LEN) 1337341618Scy return; 1338341618Scy if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE) 1339341618Scy return; 1340341618Scy hdr = buf; 1341341618Scy buf += 4; 1342341618Scy len -= 4; 1343341618Scy crypto_suite = *buf++; 1344341618Scy type = *buf++; 1345341618Scy len -= 2; 1346341618Scy 1347341618Scy wpa_printf(MSG_DEBUG, 1348341618Scy "DPP: Received DPP Public Action frame crypto suite %u type %d from " 1349341618Scy MACSTR " freq=%u", 1350341618Scy crypto_suite, type, MAC2STR(src), freq); 1351341618Scy if (crypto_suite != 1) { 1352341618Scy wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u", 1353341618Scy crypto_suite); 1354341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR 1355341618Scy " freq=%u type=%d ignore=unsupported-crypto-suite", 1356341618Scy MAC2STR(src), freq, type); 1357341618Scy return; 1358341618Scy } 1359341618Scy wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len); 1360341618Scy if (dpp_check_attrs(buf, len) < 0) { 1361341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR 1362341618Scy " freq=%u type=%d ignore=invalid-attributes", 1363341618Scy MAC2STR(src), freq, type); 1364341618Scy return; 1365341618Scy } 1366341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR 1367341618Scy " freq=%u type=%d", MAC2STR(src), freq, type); 1368341618Scy 1369351611Scy#ifdef CONFIG_DPP2 1370351611Scy if (dpp_relay_rx_action(hapd->iface->interfaces->dpp, 1371351611Scy src, hdr, buf, len, freq, NULL, NULL) == 0) 1372351611Scy return; 1373351611Scy#endif /* CONFIG_DPP2 */ 1374351611Scy 1375341618Scy switch (type) { 1376341618Scy case DPP_PA_AUTHENTICATION_REQ: 1377341618Scy hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq); 1378341618Scy break; 1379341618Scy case DPP_PA_AUTHENTICATION_RESP: 1380341618Scy hostapd_dpp_rx_auth_resp(hapd, src, hdr, buf, len, freq); 1381341618Scy break; 1382341618Scy case DPP_PA_AUTHENTICATION_CONF: 1383341618Scy hostapd_dpp_rx_auth_conf(hapd, src, hdr, buf, len); 1384341618Scy break; 1385341618Scy case DPP_PA_PEER_DISCOVERY_REQ: 1386341618Scy hostapd_dpp_rx_peer_disc_req(hapd, src, buf, len, freq); 1387341618Scy break; 1388341618Scy case DPP_PA_PKEX_EXCHANGE_REQ: 1389341618Scy hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq); 1390341618Scy break; 1391341618Scy case DPP_PA_PKEX_EXCHANGE_RESP: 1392341618Scy hostapd_dpp_rx_pkex_exchange_resp(hapd, src, buf, len, freq); 1393341618Scy break; 1394341618Scy case DPP_PA_PKEX_COMMIT_REVEAL_REQ: 1395341618Scy hostapd_dpp_rx_pkex_commit_reveal_req(hapd, src, hdr, buf, len, 1396341618Scy freq); 1397341618Scy break; 1398341618Scy case DPP_PA_PKEX_COMMIT_REVEAL_RESP: 1399341618Scy hostapd_dpp_rx_pkex_commit_reveal_resp(hapd, src, hdr, buf, len, 1400341618Scy freq); 1401341618Scy break; 1402346981Scy#ifdef CONFIG_DPP2 1403346981Scy case DPP_PA_CONFIGURATION_RESULT: 1404346981Scy hostapd_dpp_rx_conf_result(hapd, src, hdr, buf, len); 1405346981Scy break; 1406346981Scy#endif /* CONFIG_DPP2 */ 1407341618Scy default: 1408341618Scy wpa_printf(MSG_DEBUG, 1409341618Scy "DPP: Ignored unsupported frame subtype %d", type); 1410341618Scy break; 1411341618Scy } 1412341618Scy 1413341618Scy if (hapd->dpp_pkex) 1414341618Scy pkex_t = hapd->dpp_pkex->t; 1415341618Scy else if (hapd->dpp_pkex_bi) 1416341618Scy pkex_t = hapd->dpp_pkex_bi->pkex_t; 1417341618Scy else 1418341618Scy pkex_t = 0; 1419341618Scy if (pkex_t >= PKEX_COUNTER_T_LIMIT) { 1420341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0"); 1421341618Scy hostapd_dpp_pkex_remove(hapd, "*"); 1422341618Scy } 1423341618Scy} 1424341618Scy 1425341618Scy 1426341618Scystruct wpabuf * 1427341618Scyhostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa, 1428351611Scy const u8 *query, size_t query_len, 1429351611Scy const u8 *data, size_t data_len) 1430341618Scy{ 1431341618Scy struct dpp_authentication *auth = hapd->dpp_auth; 1432341618Scy struct wpabuf *resp; 1433341618Scy 1434341618Scy wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa)); 1435341618Scy if (!auth || !auth->auth_success || 1436341618Scy os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) { 1437351611Scy#ifdef CONFIG_DPP2 1438351611Scy if (dpp_relay_rx_gas_req(hapd->iface->interfaces->dpp, sa, data, 1439351611Scy data_len) == 0) { 1440351611Scy /* Response will be forwarded once received over TCP */ 1441351611Scy return NULL; 1442351611Scy } 1443351611Scy#endif /* CONFIG_DPP2 */ 1444341618Scy wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); 1445341618Scy return NULL; 1446341618Scy } 1447341618Scy wpa_hexdump(MSG_DEBUG, 1448341618Scy "DPP: Received Configuration Request (GAS Query Request)", 1449341618Scy query, query_len); 1450341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR, 1451341618Scy MAC2STR(sa)); 1452341618Scy resp = dpp_conf_req_rx(auth, query, query_len); 1453341618Scy if (!resp) 1454341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); 1455341618Scy return resp; 1456341618Scy} 1457341618Scy 1458341618Scy 1459341618Scyvoid hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok) 1460341618Scy{ 1461346981Scy struct dpp_authentication *auth = hapd->dpp_auth; 1462346981Scy 1463346981Scy if (!auth) 1464341618Scy return; 1465341618Scy 1466346981Scy wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)", 1467346981Scy ok); 1468341618Scy eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); 1469341618Scy eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); 1470346981Scy#ifdef CONFIG_DPP2 1471346981Scy if (ok && auth->peer_version >= 2 && 1472346981Scy auth->conf_resp_status == DPP_STATUS_OK) { 1473346981Scy wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result"); 1474346981Scy auth->waiting_conf_result = 1; 1475346981Scy eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, 1476346981Scy hapd, NULL); 1477346981Scy eloop_register_timeout(2, 0, 1478346981Scy hostapd_dpp_config_result_wait_timeout, 1479346981Scy hapd, NULL); 1480346981Scy return; 1481346981Scy } 1482346981Scy#endif /* CONFIG_DPP2 */ 1483341618Scy hostapd_drv_send_action_cancel_wait(hapd); 1484341618Scy 1485341618Scy if (ok) 1486341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT); 1487341618Scy else 1488341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); 1489341618Scy dpp_auth_deinit(hapd->dpp_auth); 1490341618Scy hapd->dpp_auth = NULL; 1491341618Scy} 1492341618Scy 1493341618Scy 1494341618Scyint hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd) 1495341618Scy{ 1496341618Scy struct dpp_authentication *auth; 1497341618Scy int ret = -1; 1498341618Scy char *curve = NULL; 1499341618Scy 1500341618Scy auth = os_zalloc(sizeof(*auth)); 1501341618Scy if (!auth) 1502341618Scy return -1; 1503341618Scy 1504341618Scy curve = get_param(cmd, " curve="); 1505341618Scy hostapd_dpp_set_testing_options(hapd, auth); 1506346981Scy if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx, 1507346981Scy auth, cmd) == 0 && 1508341618Scy dpp_configurator_own_config(auth, curve, 1) == 0) { 1509341618Scy hostapd_dpp_handle_config_obj(hapd, auth); 1510341618Scy ret = 0; 1511341618Scy } 1512341618Scy 1513341618Scy dpp_auth_deinit(auth); 1514341618Scy os_free(curve); 1515341618Scy 1516341618Scy return ret; 1517341618Scy} 1518341618Scy 1519341618Scy 1520341618Scyint hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd) 1521341618Scy{ 1522341618Scy struct dpp_bootstrap_info *own_bi; 1523341618Scy const char *pos, *end; 1524341618Scy 1525341618Scy pos = os_strstr(cmd, " own="); 1526341618Scy if (!pos) 1527341618Scy return -1; 1528341618Scy pos += 5; 1529346981Scy own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos)); 1530341618Scy if (!own_bi) { 1531341618Scy wpa_printf(MSG_DEBUG, 1532341618Scy "DPP: Identified bootstrap info not found"); 1533341618Scy return -1; 1534341618Scy } 1535341618Scy if (own_bi->type != DPP_BOOTSTRAP_PKEX) { 1536341618Scy wpa_printf(MSG_DEBUG, 1537341618Scy "DPP: Identified bootstrap info not for PKEX"); 1538341618Scy return -1; 1539341618Scy } 1540341618Scy hapd->dpp_pkex_bi = own_bi; 1541341618Scy own_bi->pkex_t = 0; /* clear pending errors on new code */ 1542341618Scy 1543341618Scy os_free(hapd->dpp_pkex_identifier); 1544341618Scy hapd->dpp_pkex_identifier = NULL; 1545341618Scy pos = os_strstr(cmd, " identifier="); 1546341618Scy if (pos) { 1547341618Scy pos += 12; 1548341618Scy end = os_strchr(pos, ' '); 1549341618Scy if (!end) 1550341618Scy return -1; 1551341618Scy hapd->dpp_pkex_identifier = os_malloc(end - pos + 1); 1552341618Scy if (!hapd->dpp_pkex_identifier) 1553341618Scy return -1; 1554341618Scy os_memcpy(hapd->dpp_pkex_identifier, pos, end - pos); 1555341618Scy hapd->dpp_pkex_identifier[end - pos] = '\0'; 1556341618Scy } 1557341618Scy 1558341618Scy pos = os_strstr(cmd, " code="); 1559341618Scy if (!pos) 1560341618Scy return -1; 1561341618Scy os_free(hapd->dpp_pkex_code); 1562341618Scy hapd->dpp_pkex_code = os_strdup(pos + 6); 1563341618Scy if (!hapd->dpp_pkex_code) 1564341618Scy return -1; 1565341618Scy 1566341618Scy if (os_strstr(cmd, " init=1")) { 1567341618Scy struct wpabuf *msg; 1568341618Scy 1569341618Scy wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX"); 1570341618Scy dpp_pkex_free(hapd->dpp_pkex); 1571341618Scy hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi, 1572341618Scy hapd->own_addr, 1573341618Scy hapd->dpp_pkex_identifier, 1574341618Scy hapd->dpp_pkex_code); 1575341618Scy if (!hapd->dpp_pkex) 1576341618Scy return -1; 1577341618Scy 1578341618Scy msg = hapd->dpp_pkex->exchange_req; 1579341618Scy /* TODO: Which channel to use? */ 1580341618Scy wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 1581341618Scy " freq=%u type=%d", MAC2STR(broadcast), 2437, 1582341618Scy DPP_PA_PKEX_EXCHANGE_REQ); 1583341618Scy hostapd_drv_send_action(hapd, 2437, 0, broadcast, 1584341618Scy wpabuf_head(msg), wpabuf_len(msg)); 1585341618Scy } 1586341618Scy 1587341618Scy /* TODO: Support multiple PKEX info entries */ 1588341618Scy 1589341618Scy os_free(hapd->dpp_pkex_auth_cmd); 1590341618Scy hapd->dpp_pkex_auth_cmd = os_strdup(cmd); 1591341618Scy 1592341618Scy return 1; 1593341618Scy} 1594341618Scy 1595341618Scy 1596341618Scyint hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id) 1597341618Scy{ 1598341618Scy unsigned int id_val; 1599341618Scy 1600341618Scy if (os_strcmp(id, "*") == 0) { 1601341618Scy id_val = 0; 1602341618Scy } else { 1603341618Scy id_val = atoi(id); 1604341618Scy if (id_val == 0) 1605341618Scy return -1; 1606341618Scy } 1607341618Scy 1608341618Scy if ((id_val != 0 && id_val != 1) || !hapd->dpp_pkex_code) 1609341618Scy return -1; 1610341618Scy 1611341618Scy /* TODO: Support multiple PKEX entries */ 1612341618Scy os_free(hapd->dpp_pkex_code); 1613341618Scy hapd->dpp_pkex_code = NULL; 1614341618Scy os_free(hapd->dpp_pkex_identifier); 1615341618Scy hapd->dpp_pkex_identifier = NULL; 1616341618Scy os_free(hapd->dpp_pkex_auth_cmd); 1617341618Scy hapd->dpp_pkex_auth_cmd = NULL; 1618341618Scy hapd->dpp_pkex_bi = NULL; 1619341618Scy /* TODO: Remove dpp_pkex only if it is for the identified PKEX code */ 1620341618Scy dpp_pkex_free(hapd->dpp_pkex); 1621341618Scy hapd->dpp_pkex = NULL; 1622341618Scy return 0; 1623341618Scy} 1624341618Scy 1625341618Scy 1626341618Scyvoid hostapd_dpp_stop(struct hostapd_data *hapd) 1627341618Scy{ 1628341618Scy dpp_auth_deinit(hapd->dpp_auth); 1629341618Scy hapd->dpp_auth = NULL; 1630341618Scy dpp_pkex_free(hapd->dpp_pkex); 1631341618Scy hapd->dpp_pkex = NULL; 1632341618Scy} 1633341618Scy 1634341618Scy 1635351611Scy#ifdef CONFIG_DPP2 1636351611Scy 1637351611Scystatic void hostapd_dpp_relay_tx(void *ctx, const u8 *addr, unsigned int freq, 1638351611Scy const u8 *msg, size_t len) 1639351611Scy{ 1640351611Scy struct hostapd_data *hapd = ctx; 1641351611Scy u8 *buf; 1642351611Scy 1643351611Scy wpa_printf(MSG_DEBUG, "DPP: Send action frame dst=" MACSTR " freq=%u", 1644351611Scy MAC2STR(addr), freq); 1645351611Scy buf = os_malloc(2 + len); 1646351611Scy if (!buf) 1647351611Scy return; 1648351611Scy buf[0] = WLAN_ACTION_PUBLIC; 1649351611Scy buf[1] = WLAN_PA_VENDOR_SPECIFIC; 1650351611Scy os_memcpy(buf + 2, msg, len); 1651351611Scy hostapd_drv_send_action(hapd, freq, 0, addr, buf, 2 + len); 1652351611Scy os_free(buf); 1653351611Scy} 1654351611Scy 1655351611Scy 1656351611Scystatic void hostapd_dpp_relay_gas_resp_tx(void *ctx, const u8 *addr, 1657351611Scy u8 dialog_token, int prot, 1658351611Scy struct wpabuf *buf) 1659351611Scy{ 1660351611Scy struct hostapd_data *hapd = ctx; 1661351611Scy 1662351611Scy gas_serv_req_dpp_processing(hapd, addr, dialog_token, prot, buf); 1663351611Scy} 1664351611Scy 1665351611Scy#endif /* CONFIG_DPP2 */ 1666351611Scy 1667351611Scy 1668351611Scystatic int hostapd_dpp_add_controllers(struct hostapd_data *hapd) 1669351611Scy{ 1670351611Scy#ifdef CONFIG_DPP2 1671351611Scy struct dpp_controller_conf *ctrl; 1672351611Scy struct dpp_relay_config config; 1673351611Scy 1674351611Scy os_memset(&config, 0, sizeof(config)); 1675351611Scy config.cb_ctx = hapd; 1676351611Scy config.tx = hostapd_dpp_relay_tx; 1677351611Scy config.gas_resp_tx = hostapd_dpp_relay_gas_resp_tx; 1678351611Scy for (ctrl = hapd->conf->dpp_controller; ctrl; ctrl = ctrl->next) { 1679351611Scy config.ipaddr = &ctrl->ipaddr; 1680351611Scy config.pkhash = ctrl->pkhash; 1681351611Scy if (dpp_relay_add_controller(hapd->iface->interfaces->dpp, 1682351611Scy &config) < 0) 1683351611Scy return -1; 1684351611Scy } 1685351611Scy#endif /* CONFIG_DPP2 */ 1686351611Scy 1687351611Scy return 0; 1688351611Scy} 1689351611Scy 1690351611Scy 1691341618Scyint hostapd_dpp_init(struct hostapd_data *hapd) 1692341618Scy{ 1693341618Scy hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE; 1694341618Scy hapd->dpp_init_done = 1; 1695351611Scy return hostapd_dpp_add_controllers(hapd); 1696341618Scy} 1697341618Scy 1698341618Scy 1699341618Scyvoid hostapd_dpp_deinit(struct hostapd_data *hapd) 1700341618Scy{ 1701341618Scy#ifdef CONFIG_TESTING_OPTIONS 1702341618Scy os_free(hapd->dpp_config_obj_override); 1703341618Scy hapd->dpp_config_obj_override = NULL; 1704341618Scy os_free(hapd->dpp_discovery_override); 1705341618Scy hapd->dpp_discovery_override = NULL; 1706341618Scy os_free(hapd->dpp_groups_override); 1707341618Scy hapd->dpp_groups_override = NULL; 1708341618Scy hapd->dpp_ignore_netaccesskey_mismatch = 0; 1709341618Scy#endif /* CONFIG_TESTING_OPTIONS */ 1710341618Scy if (!hapd->dpp_init_done) 1711341618Scy return; 1712341618Scy eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); 1713341618Scy eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL); 1714341618Scy eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); 1715346981Scy#ifdef CONFIG_DPP2 1716346981Scy eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd, 1717346981Scy NULL); 1718346981Scy#endif /* CONFIG_DPP2 */ 1719341618Scy dpp_auth_deinit(hapd->dpp_auth); 1720341618Scy hapd->dpp_auth = NULL; 1721341618Scy hostapd_dpp_pkex_remove(hapd, "*"); 1722341618Scy hapd->dpp_pkex = NULL; 1723341618Scy os_free(hapd->dpp_configurator_params); 1724341618Scy hapd->dpp_configurator_params = NULL; 1725341618Scy} 1726