]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP: Allow Configurator parameters to be provided during config exchange
authorJouni Malinen <quic_jouni@quicinc.com>
Wed, 2 Feb 2022 14:52:01 +0000 (16:52 +0200)
committerJouni Malinen <j@w1.fi>
Wed, 2 Feb 2022 22:35:49 +0000 (00:35 +0200)
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 <URI from Responder/Enrollee>
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 <quic_jouni@quicinc.com>
src/common/dpp.c
src/common/dpp.h
src/common/dpp_tcp.c
src/common/wpa_ctrl.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/dpp_supplicant.c
wpa_supplicant/dpp_supplicant.h

index 038b21467f019a931082eaac8fe98d1e3995aa92..2f1b7a4372ac2c3577d965e80c797fc805785887 100644 (file)
@@ -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),
index 40e9775e5749dd82be2983cec26d542d35a6cadc..daf27f68eb9af2f86f15fc8aac39fb7c8775a837 100644 (file)
@@ -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;
index 14ff2d9030804410c66630c0613771dba13ff680..e88c6de6033bac1c0414c7080b5b4f7ec121754a 100644 (file)
@@ -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);
 }
 
index 2c7ec043d409840f3bd7dcb9d3ed5d11abc3fa0b..3d3a62a17cc66e44e7fb72ee12907eccae12181c 100644 (file)
@@ -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 "
index bcd67fca3e125db186431afc224042faadbd18a9..88dd67ab02f7e3b2028eda598fc77836d6502585 100644 (file)
@@ -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)
index 3189b173c93e0ee173c39c63aaf32f3cf993db1b..863e45c700b4da6ecbb5d293ac71a8648955c242 100644 (file)
@@ -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;
index b0d5fcf188354a91e12c1ed1ec4486f65727e801..105c81904b956a37990c4fe2d82089acd7ddd5ec 100644 (file)
@@ -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 */