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