From 033ad6ffaabe9fb3c580d343c7141d2047ffe0d5 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 2 Feb 2022 16:52:01 +0200 Subject: [PATCH] DPP: Allow Configurator parameters to be provided during config exchange This provides an alternative mechanism for upper layer components to control configuration parameters to be used by the local Configurator. Instead of the previously used design where the Configurator parameters had to be provided before initiating the DPP Authentication exchange, the new alternative approach allows the DPP Authentication exchange to be started before any Configurator parameters have been determined and wpa_supplicant will then request the parameters once the DPP Configuration Request has been received from the Enrollee. This allows the Config Request information to be used at upper layers to determine how the Enrollee should be configured. For example for an Initiator: CTRL: DPP_QR_CODE CTRL: DPP_AUTH_INIT peer=1 conf=query <3>DPP-CONF-NEEDED peer=1 src=02:00:00:00:00:00 net_role=sta name="Test" opclass=81,82,83,84,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130 mud_url=N/A (upper layer processing; potentially including user interaction) CTRL: DPP_CONF_SET peer=1 conf=sta-sae ssid=736165 pass=70617373776f7264 <3>DPP-CONF-SENT For example for a Responder: CTRL: SET dpp_configurator_params conf=query CTRL: DPP_LISTEN 2412 role=configurator <3>DPP-CONF-NEEDED peer=2 src=02:00:00:00:01:00 net_role=sta name="Test" opclass=81,82,83,84,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130 mud_url=N/A (upper layer processing; potentially including user interaction) CTRL: DPP_CONF_SET peer=2 conf=sta-sae ssid=736165 pass=70617373776f7264 <3>DPP-CONF-SENT For example for an Initiator that can act both as a Configurator and an Enrollee in a case where the Initiator becomes the Enrollee: CTRL: DPP_AUTH_INIT peer=1 role=either conf=query <3>DPP-CONF-RECEIVED Signed-off-by: Jouni Malinen --- src/common/dpp.c | 57 +++++++--- src/common/dpp.h | 4 +- src/common/dpp_tcp.c | 46 ++++++++ src/common/wpa_ctrl.h | 1 + wpa_supplicant/ctrl_iface.c | 3 + wpa_supplicant/dpp_supplicant.c | 183 +++++++++++++++++++++++++++----- wpa_supplicant/dpp_supplicant.h | 2 + 7 files changed, 250 insertions(+), 46 deletions(-) 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 */