diff --git a/src/common/dpp.c b/src/common/dpp.c index 038b21467..2f1b7a437 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -1209,6 +1209,13 @@ int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd) wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd); + if (os_strstr(cmd, " conf=query")) { + auth->configurator_set = 0; + auth->use_config_query = true; + ret = 0; + goto fail; + } + pos = os_strstr(cmd, " configurator="); if (!auth->conf && pos) { pos += 14; @@ -1639,6 +1646,25 @@ dpp_build_conf_obj_legacy(struct dpp_authentication *auth, } +static int dpp_get_peer_bi_id(struct dpp_authentication *auth) +{ + struct dpp_bootstrap_info *bi; + + if (auth->peer_bi) + return auth->peer_bi->id; + if (auth->tmp_peer_bi) + return auth->tmp_peer_bi->id; + + bi = os_zalloc(sizeof(*bi)); + if (!bi) + return -1; + bi->id = dpp_next_id(auth->global); + dl_list_add(&auth->global->bootstrap, &bi->list); + auth->tmp_peer_bi = bi; + return bi->id; +} + + static struct wpabuf * dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole, int idx, bool cert_req) @@ -1667,10 +1693,19 @@ dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole, conf = auth->conf2_ap; } if (!conf) { - if (idx == 0) + if (idx == 0) { + if (auth->use_config_query) { + wpa_printf(MSG_DEBUG, + "DPP: No configuration available for Enrollee(%s) - waiting for configuration", + dpp_netrole_str(netrole)); + auth->waiting_config = true; + dpp_get_peer_bi_id(auth); + return NULL; + } wpa_printf(MSG_DEBUG, "DPP: No configuration available for Enrollee(%s) - reject configuration request", dpp_netrole_str(netrole)); + } return NULL; } @@ -1724,6 +1759,8 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, } } + if (!conf && auth->waiting_config) + return NULL; if (conf || env_data) status = DPP_STATUS_OK; else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta && @@ -2069,21 +2106,9 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, goto cont; } - if (auth->peer_bi) { - id = auth->peer_bi->id; - } else if (auth->tmp_peer_bi) { - id = auth->tmp_peer_bi->id; - } else { - struct dpp_bootstrap_info *bi; - - bi = os_zalloc(sizeof(*bi)); - if (!bi) - goto fail; - bi->id = dpp_next_id(auth->global); - dl_list_add(&auth->global->bootstrap, &bi->list); - auth->tmp_peer_bi = bi; - id = bi->id; - } + id = dpp_get_peer_bi_id(auth); + if (id < 0) + goto fail; wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA"); txt = base64_encode_no_lf(wpabuf_head(cert_req), diff --git a/src/common/dpp.h b/src/common/dpp.h index 40e9775e5..daf27f68e 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -352,8 +352,10 @@ struct dpp_authentication { char *trusted_eap_server_name; struct wpabuf *cacert; struct wpabuf *certbag; - void *cert_resp_ctx; + void *config_resp_ctx; void *gas_server_ctx; + bool use_config_query; + bool waiting_config; char *e_name; char *e_mud_url; int *e_band_support; diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c index 14ff2d903..e88c6de60 100644 --- a/src/common/dpp_tcp.c +++ b/src/common/dpp_tcp.c @@ -1328,6 +1328,52 @@ static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg, WLAN_PA_GAS_INITIAL_RESP); } + if (!resp && auth->waiting_config && auth->peer_bi) { + char *buf = NULL, *name = ""; + char band[200], *b_pos, *b_end; + int i, res, *opclass = auth->e_band_support; + char *mud_url = "N/A"; + + wpa_printf(MSG_DEBUG, "DPP: Configuration not yet ready"); + if (auth->e_name) { + size_t e_len = os_strlen(auth->e_name); + + buf = os_malloc(e_len * 4 + 1); + if (buf) { + printf_encode(buf, len * 4 + 1, + (const u8 *) auth->e_name, e_len); + name = buf; + } + } + band[0] = '\0'; + b_pos = band; + b_end = band + sizeof(band); + for (i = 0; opclass && opclass[i]; i++) { + res = os_snprintf(b_pos, b_end - b_pos, "%s%d", + b_pos == band ? "" : ",", opclass[i]); + if (os_snprintf_error(b_end - b_pos, res)) { + *b_pos = '\0'; + break; + } + b_pos += res; + } + if (auth->e_mud_url) { + size_t e_len = os_strlen(auth->e_mud_url); + + if (!has_ctrl_char((const u8 *) auth->e_mud_url, e_len)) + mud_url = auth->e_mud_url; + } + wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_NEEDED + "peer=%d net_role=%s name=\"%s\" opclass=%s mud_url=%s", + auth->peer_bi->id, dpp_netrole_str(auth->e_netrole), + name, band, mud_url); + os_free(buf); + + conn->gas_comeback_in_progress = 1; + return dpp_tcp_send_comeback_delay(conn, + WLAN_PA_GAS_INITIAL_RESP); + } + return dpp_tcp_send_gas_resp(conn, WLAN_PA_GAS_INITIAL_RESP, resp); } diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 2c7ec043d..3d3a62a17 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -212,6 +212,7 @@ extern "C" { #define DPP_EVENT_BAND_SUPPORT "DPP-BAND-SUPPORT " #define DPP_EVENT_CSR "DPP-CSR " #define DPP_EVENT_CHIRP_RX "DPP-CHIRP-RX " +#define DPP_EVENT_CONF_NEEDED "DPP-CONF-NEEDED " /* MESH events */ #define MESH_GROUP_STARTED "MESH-GROUP-STARTED " diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index bcd67fca3..88dd67ab0 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -12334,6 +12334,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) { if (wpas_dpp_pkex_remove(wpa_s, buf + 16) < 0) reply_len = -1; + } else if (os_strncmp(buf, "DPP_CONF_SET ", 13) == 0) { + if (wpas_dpp_conf_set(wpa_s, buf + 12) < 0) + reply_len = -1; #ifdef CONFIG_DPP2 } else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) { if (wpas_dpp_controller_start(wpa_s, buf + 20) < 0) diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 3189b173c..863e45c70 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -3140,6 +3140,22 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, } +static void wpas_dpp_gas_initial_resp_timeout(void *eloop_ctx, + void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct dpp_authentication *auth = wpa_s->dpp_auth; + + if (!auth || !auth->waiting_config || !auth->config_resp_ctx) + return; + + wpa_printf(MSG_DEBUG, + "DPP: No configuration available from upper layers - send initial response with comeback delay"); + gas_server_set_comeback_delay(wpa_s->gas_server, auth->config_resp_ctx, + 500); +} + + static struct wpabuf * wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa, const u8 *query, size_t query_len, int *comeback_delay) @@ -3174,19 +3190,73 @@ wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa, MAC2STR(sa)); resp = dpp_conf_req_rx(auth, query, query_len); + auth->gas_server_ctx = resp_ctx; + #ifdef CONFIG_DPP2 if (!resp && auth->waiting_cert) { wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready"); - auth->cert_resp_ctx = resp_ctx; + auth->config_resp_ctx = resp_ctx; *comeback_delay = 500; return NULL; } #endif /* CONFIG_DPP2 */ + if (!resp && auth->waiting_config && + (auth->peer_bi || auth->tmp_peer_bi)) { + char *buf = NULL, *name = ""; + char band[200], *pos, *end; + int i, res, *opclass = auth->e_band_support; + char *mud_url = "N/A"; + + wpa_printf(MSG_DEBUG, "DPP: Configuration not yet ready"); + auth->config_resp_ctx = resp_ctx; + *comeback_delay = -1; + if (auth->e_name) { + size_t len = os_strlen(auth->e_name); + + buf = os_malloc(len * 4 + 1); + if (buf) { + printf_encode(buf, len * 4 + 1, + (const u8 *) auth->e_name, len); + name = buf; + } + } + band[0] = '\0'; + pos = band; + end = band + sizeof(band); + for (i = 0; opclass && opclass[i]; i++) { + res = os_snprintf(pos, end - pos, "%s%d", + pos == band ? "" : ",", opclass[i]); + if (os_snprintf_error(end - pos, res)) { + *pos = '\0'; + break; + } + pos += res; + } + if (auth->e_mud_url) { + size_t len = os_strlen(auth->e_mud_url); + + if (!has_ctrl_char((const u8 *) auth->e_mud_url, len)) + mud_url = auth->e_mud_url; + } + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_NEEDED "peer=%d src=" + MACSTR " net_role=%s name=\"%s\" opclass=%s mud_url=%s", + auth->peer_bi ? auth->peer_bi->id : + auth->tmp_peer_bi->id, MAC2STR(sa), + dpp_netrole_str(auth->e_netrole), name, band, mud_url); + os_free(buf); + + eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s, + NULL); + eloop_register_timeout(0, 50000, + wpas_dpp_gas_initial_resp_timeout, wpa_s, + NULL); + return NULL; + } + if (!resp) wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); auth->conf_resp = resp; - auth->gas_server_ctx = resp_ctx; return resp; } @@ -3651,6 +3721,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(wpas_dpp_auth_conf_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s, NULL); #ifdef CONFIG_DPP2 eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout, @@ -3676,6 +3747,87 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s) } +static int wpas_dpp_build_conf_resp(struct wpa_supplicant *wpa_s, + struct dpp_authentication *auth, bool tcp) +{ + struct wpabuf *resp; + + resp = dpp_build_conf_resp(auth, auth->e_nonce, auth->curve->nonce_len, + auth->e_netrole, true); + if (!resp) + return -1; + + if (tcp) { + auth->conf_resp_tcp = resp; + return 0; + } + + eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s, NULL); + if (gas_server_set_resp(wpa_s->gas_server, auth->config_resp_ctx, + resp) < 0) { + wpa_printf(MSG_DEBUG, + "DPP: Could not find pending GAS response"); + wpabuf_free(resp); + return -1; + } + auth->conf_resp = resp; + return 0; +} + + +int wpas_dpp_conf_set(struct wpa_supplicant *wpa_s, const char *cmd) +{ + int peer; + const char *pos; + struct dpp_authentication *auth = wpa_s->dpp_auth; + bool tcp = false; + + pos = os_strstr(cmd, " peer="); + if (!pos) + return -1; + peer = atoi(pos + 6); +#ifdef CONFIG_DPP2 + if (!auth || !auth->waiting_config || + (auth->peer_bi && + (unsigned int) peer != auth->peer_bi->id)) { + auth = dpp_controller_get_auth(wpa_s->dpp, peer); + tcp = true; + } +#endif /* CONFIG_DPP2 */ + + if (!auth || !auth->waiting_config) { + wpa_printf(MSG_DEBUG, + "DPP: No authentication exchange waiting for configuration information"); + return -1; + } + + if ((!auth->peer_bi || + (unsigned int) peer != auth->peer_bi->id) && + (!auth->tmp_peer_bi || + (unsigned int) peer != auth->tmp_peer_bi->id)) { + wpa_printf(MSG_DEBUG, "DPP: Peer mismatch"); + return -1; + } + + pos = os_strstr(cmd, " comeback="); + if (pos) { + eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s, + NULL); + gas_server_set_comeback_delay(wpa_s->gas_server, + auth->config_resp_ctx, + atoi(pos + 10)); + return 0; + } + + if (dpp_set_configurator(auth, cmd) < 0) + return -1; + + auth->use_config_query = false; + auth->waiting_config = false; + return wpas_dpp_build_conf_resp(wpa_s, auth, tcp); +} + + #ifdef CONFIG_DPP2 int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd) @@ -4094,33 +4246,6 @@ int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd) } -static int wpas_dpp_build_conf_resp(struct wpa_supplicant *wpa_s, - struct dpp_authentication *auth, bool tcp) -{ - struct wpabuf *resp; - - resp = dpp_build_conf_resp(auth, auth->e_nonce, auth->curve->nonce_len, - auth->e_netrole, true); - if (!resp) - return -1; - - if (tcp) { - auth->conf_resp_tcp = resp; - return 0; - } - - if (gas_server_set_resp(wpa_s->gas_server, auth->cert_resp_ctx, - resp) < 0) { - wpa_printf(MSG_DEBUG, - "DPP: Could not find pending GAS response"); - wpabuf_free(resp); - return -1; - } - auth->conf_resp = resp; - return 0; -} - - int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd) { int peer = -1; diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h index b0d5fcf18..105c81904 100644 --- a/wpa_supplicant/dpp_supplicant.h +++ b/wpa_supplicant/dpp_supplicant.h @@ -2,6 +2,7 @@ * wpa_supplicant - DPP * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2018-2020, The Linux Foundation + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -41,5 +42,6 @@ int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd); void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s); int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd); int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd); +int wpas_dpp_conf_set(struct wpa_supplicant *wpa_s, const char *cmd); #endif /* DPP_SUPPLICANT_H */