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 <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>
This commit is contained in:
Jouni Malinen 2022-02-02 16:52:01 +02:00 committed by Jouni Malinen
parent d4961a7755
commit 033ad6ffaa
7 changed files with 250 additions and 46 deletions

View 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); 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="); pos = os_strstr(cmd, " configurator=");
if (!auth->conf && pos) { if (!auth->conf && pos) {
pos += 14; 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 * static struct wpabuf *
dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole, dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
int idx, bool cert_req) 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; conf = auth->conf2_ap;
} }
if (!conf) { 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, wpa_printf(MSG_DEBUG,
"DPP: No configuration available for Enrollee(%s) - reject configuration request", "DPP: No configuration available for Enrollee(%s) - reject configuration request",
dpp_netrole_str(netrole)); dpp_netrole_str(netrole));
}
return NULL; 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) if (conf || env_data)
status = DPP_STATUS_OK; status = DPP_STATUS_OK;
else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta && 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; goto cont;
} }
if (auth->peer_bi) { id = dpp_get_peer_bi_id(auth);
id = auth->peer_bi->id; if (id < 0)
} else if (auth->tmp_peer_bi) { goto fail;
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;
}
wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA"); wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA");
txt = base64_encode_no_lf(wpabuf_head(cert_req), txt = base64_encode_no_lf(wpabuf_head(cert_req),

View file

@ -352,8 +352,10 @@ struct dpp_authentication {
char *trusted_eap_server_name; char *trusted_eap_server_name;
struct wpabuf *cacert; struct wpabuf *cacert;
struct wpabuf *certbag; struct wpabuf *certbag;
void *cert_resp_ctx; void *config_resp_ctx;
void *gas_server_ctx; void *gas_server_ctx;
bool use_config_query;
bool waiting_config;
char *e_name; char *e_name;
char *e_mud_url; char *e_mud_url;
int *e_band_support; int *e_band_support;

View file

@ -1328,6 +1328,52 @@ static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
WLAN_PA_GAS_INITIAL_RESP); 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); return dpp_tcp_send_gas_resp(conn, WLAN_PA_GAS_INITIAL_RESP, resp);
} }

View file

@ -212,6 +212,7 @@ extern "C" {
#define DPP_EVENT_BAND_SUPPORT "DPP-BAND-SUPPORT " #define DPP_EVENT_BAND_SUPPORT "DPP-BAND-SUPPORT "
#define DPP_EVENT_CSR "DPP-CSR " #define DPP_EVENT_CSR "DPP-CSR "
#define DPP_EVENT_CHIRP_RX "DPP-CHIRP-RX " #define DPP_EVENT_CHIRP_RX "DPP-CHIRP-RX "
#define DPP_EVENT_CONF_NEEDED "DPP-CONF-NEEDED "
/* MESH events */ /* MESH events */
#define MESH_GROUP_STARTED "MESH-GROUP-STARTED " #define MESH_GROUP_STARTED "MESH-GROUP-STARTED "

View 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) { } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
if (wpas_dpp_pkex_remove(wpa_s, buf + 16) < 0) if (wpas_dpp_pkex_remove(wpa_s, buf + 16) < 0)
reply_len = -1; 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 #ifdef CONFIG_DPP2
} else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) { } else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) {
if (wpas_dpp_controller_start(wpa_s, buf + 20) < 0) if (wpas_dpp_controller_start(wpa_s, buf + 20) < 0)

View 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 * static struct wpabuf *
wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa, wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa,
const u8 *query, size_t query_len, int *comeback_delay) 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)); MAC2STR(sa));
resp = dpp_conf_req_rx(auth, query, query_len); resp = dpp_conf_req_rx(auth, query, query_len);
auth->gas_server_ctx = resp_ctx;
#ifdef CONFIG_DPP2 #ifdef CONFIG_DPP2
if (!resp && auth->waiting_cert) { if (!resp && auth->waiting_cert) {
wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready"); wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
auth->cert_resp_ctx = resp_ctx; auth->config_resp_ctx = resp_ctx;
*comeback_delay = 500; *comeback_delay = 500;
return NULL; return NULL;
} }
#endif /* CONFIG_DPP2 */ #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) if (!resp)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
auth->conf_resp = resp; auth->conf_resp = resp;
auth->gas_server_ctx = resp_ctx;
return resp; 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_auth_conf_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_init_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_auth_resp_retry_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s, NULL);
#ifdef CONFIG_DPP2 #ifdef CONFIG_DPP2
eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout, 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 #ifdef CONFIG_DPP2
int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd) 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 wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd)
{ {
int peer = -1; int peer = -1;

View file

@ -2,6 +2,7 @@
* wpa_supplicant - DPP * wpa_supplicant - DPP
* Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2017, Qualcomm Atheros, Inc.
* Copyright (c) 2018-2020, The Linux Foundation * 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. * This software may be distributed under the terms of the BSD license.
* See README for more details. * 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); 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_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_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 */ #endif /* DPP_SUPPLICANT_H */