diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index a5e53cbd8..42f992e50 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -26,6 +26,10 @@ static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx); static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator); static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx); static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd); +#ifdef CONFIG_DPP2 +static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx, + void *timeout_ctx); +#endif /* CONFIG_DPP2 */ static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -237,6 +241,10 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); +#ifdef CONFIG_DPP2 + eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout, + hapd, NULL); +#endif /* CONFIG_DPP2 */ hostapd_drv_send_action_cancel_wait(hapd); dpp_auth_deinit(hapd->dpp_auth); hapd->dpp_auth = NULL; @@ -539,6 +547,10 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd) hapd, NULL); eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); +#ifdef CONFIG_DPP2 + eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout, + hapd, NULL); +#endif /* CONFIG_DPP2 */ hostapd_drv_send_action_cancel_wait(hapd); dpp_auth_deinit(hapd->dpp_auth); } @@ -1198,6 +1210,22 @@ hostapd_dpp_rx_presence_announcement(struct hostapd_data *hapd, const u8 *src, } +static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx, + void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + struct dpp_authentication *auth = hapd->dpp_auth; + + if (!auth) + return; + + wpa_printf(MSG_DEBUG, "DPP: Reconfig Reply wait timeout"); + hostapd_dpp_listen_stop(hapd); + dpp_auth_deinit(auth); + hapd->dpp_auth = NULL; +} + + static void hostapd_dpp_rx_reconfig_announcement(struct hostapd_data *hapd, const u8 *src, const u8 *hdr, const u8 *buf, size_t len, @@ -1206,6 +1234,8 @@ hostapd_dpp_rx_reconfig_announcement(struct hostapd_data *hapd, const u8 *src, const u8 *csign_hash; u16 csign_hash_len; struct dpp_configurator *conf; + struct dpp_authentication *auth; + unsigned int wait_time, max_wait_time; if (hapd->dpp_auth) { wpa_printf(MSG_DEBUG, @@ -1233,7 +1263,41 @@ hostapd_dpp_rx_reconfig_announcement(struct hostapd_data *hapd, const u8 *src, return; } - /* TODO: Initiate Reconfig Authentication */ + auth = dpp_reconfig_init(hapd->iface->interfaces->dpp, hapd->msg_ctx, + conf, freq); + if (!auth) + return; + hostapd_dpp_set_testing_options(hapd, auth); + if (dpp_set_configurator(auth, hapd->dpp_configurator_params) < 0) { + dpp_auth_deinit(auth); + return; + } + + os_memcpy(auth->peer_mac_addr, src, ETH_ALEN); + hapd->dpp_auth = auth; + + hapd->dpp_in_response_listen = 0; + hapd->dpp_auth_ok_on_ack = 0; + wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */ + max_wait_time = hapd->dpp_resp_wait_time ? + hapd->dpp_resp_wait_time : 2000; + if (wait_time > max_wait_time) + wait_time = max_wait_time; + wait_time += 10; /* give the driver some extra time to complete */ + eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000, + hostapd_dpp_reconfig_reply_wait_timeout, + hapd, NULL); + wait_time -= 10; + + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", + MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_REQ); + if (hostapd_drv_send_action(hapd, freq, wait_time, src, + wpabuf_head(auth->reconfig_req_msg), + wpabuf_len(auth->reconfig_req_msg)) < 0) { + dpp_auth_deinit(hapd->dpp_auth); + hapd->dpp_auth = NULL; + } } #endif /* CONFIG_DPP2 */ @@ -1771,6 +1835,8 @@ void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok) eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); #ifdef CONFIG_DPP2 + eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout, + hapd, NULL); if (ok && auth->peer_version >= 2 && auth->conf_resp_status == DPP_STATUS_OK) { wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result"); @@ -2015,6 +2081,8 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd) eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); #ifdef CONFIG_DPP2 + eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout, + hapd, NULL); eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd, diff --git a/src/common/dpp.c b/src/common/dpp.c index b9b5d53aa..c7e4421eb 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -989,10 +989,9 @@ static int dpp_channel_local_list(struct dpp_authentication *auth, } -static int dpp_prepare_channel_list(struct dpp_authentication *auth, - unsigned int neg_freq, - struct hostapd_hw_modes *own_modes, - u16 num_modes) +int dpp_prepare_channel_list(struct dpp_authentication *auth, + unsigned int neg_freq, + struct hostapd_hw_modes *own_modes, u16 num_modes) { int res; char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end; @@ -2339,7 +2338,7 @@ dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr, } #endif /* CONFIG_TESTING_OPTIONS */ - if (!auth->initiator || !auth->peer_bi) { + if (!auth->initiator || !auth->peer_bi || auth->reconfig) { dpp_auth_fail(auth, "Unexpected Authentication Response"); return NULL; } @@ -2741,7 +2740,8 @@ int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr, } #endif /* CONFIG_TESTING_OPTIONS */ - if (auth->initiator || !auth->own_bi || !auth->waiting_auth_conf) { + if (auth->initiator || !auth->own_bi || !auth->waiting_auth_conf || + auth->reconfig) { wpa_printf(MSG_DEBUG, "DPP: initiator=%d own_bi=%d waiting_auth_conf=%d", auth->initiator, !!auth->own_bi, @@ -3195,7 +3195,7 @@ int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd) wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd); pos = os_strstr(cmd, " configurator="); - if (pos) { + if (!auth->conf && pos) { pos += 14; auth->conf = dpp_configurator_get_id(auth->global, atoi(pos)); if (!auth->conf) { @@ -3258,6 +3258,7 @@ void dpp_auth_deinit(struct dpp_authentication *auth) wpabuf_free(auth->req_msg); wpabuf_free(auth->resp_msg); wpabuf_free(auth->conf_req); + wpabuf_free(auth->reconfig_req_msg); for (i = 0; i < auth->num_conf_obj; i++) { struct dpp_config_obj *conf = &auth->conf_obj[i]; @@ -3324,8 +3325,8 @@ dpp_build_conf_start(struct dpp_authentication *auth, } -static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key, - const char *kid, const struct dpp_curve_params *curve) +int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key, + const char *kid, const struct dpp_curve_params *curve) { struct wpabuf *pub; const u8 *pos; @@ -6270,6 +6271,8 @@ void dpp_configurator_free(struct dpp_configurator *conf) return; EVP_PKEY_free(conf->csign); os_free(conf->kid); + os_free(conf->connector); + EVP_PKEY_free(conf->connector_key); os_free(conf); } diff --git a/src/common/dpp.h b/src/common/dpp.h index f560b34ef..7e3952d14 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -235,6 +235,7 @@ struct dpp_authentication { struct dpp_bootstrap_info *tmp_own_bi; u8 waiting_pubkey_hash[SHA256_MAC_LEN]; int response_pending; + int reconfig; enum dpp_status_error auth_resp_status; enum dpp_status_error conf_resp_status; u8 peer_mac_addr[ETH_ALEN]; @@ -247,6 +248,7 @@ struct dpp_authentication { EVP_PKEY *peer_protocol_key; struct wpabuf *req_msg; struct wpabuf *resp_msg; + struct wpabuf *reconfig_req_msg; /* Intersection of possible frequencies for initiating DPP * Authentication exchange */ unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ]; @@ -304,6 +306,7 @@ struct dpp_authentication { int conn_status_requested; int akm_use_selector; int configurator_set; + u8 transaction_id; #ifdef CONFIG_TESTING_OPTIONS char *config_obj_override; char *discovery_override; @@ -320,6 +323,8 @@ struct dpp_configurator { u8 kid_hash[SHA256_MAC_LEN]; char *kid; const struct dpp_curve_params *curve; + char *connector; /* own Connector for reconfiguration */ + EVP_PKEY *connector_key; }; struct dpp_introduction { @@ -633,6 +638,9 @@ void dpp_global_deinit(struct dpp_global *dpp); struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key, size_t csign_key_len); +struct dpp_authentication * +dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx, + struct dpp_configurator *conf, unsigned int freq); #endif /* CONFIG_DPP */ #endif /* DPP_H */ diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h index dd66617fd..300bf5ce9 100644 --- a/src/common/dpp_i.h +++ b/src/common/dpp_i.h @@ -36,6 +36,11 @@ struct wpabuf * dpp_build_conn_status(enum dpp_status_error result, struct json_token * dpp_parse_own_connector(const char *own_connector); int dpp_connector_match_groups(struct json_token *own_root, struct json_token *peer_root, bool reconfig); +int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key, + const char *kid, const struct dpp_curve_params *curve); +int dpp_prepare_channel_list(struct dpp_authentication *auth, + unsigned int neg_freq, + struct hostapd_hw_modes *own_modes, u16 num_modes); /* dpp_crypto.c */ diff --git a/src/common/dpp_reconfig.c b/src/common/dpp_reconfig.c index 597963f3c..5a11b1e8b 100644 --- a/src/common/dpp_reconfig.c +++ b/src/common/dpp_reconfig.c @@ -9,7 +9,9 @@ #include "utils/includes.h" #include "utils/common.h" +#include "utils/json.h" #include "crypto/crypto.h" +#include "crypto/random.h" #include "dpp.h" #include "dpp_i.h" @@ -73,4 +75,136 @@ struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key, "DPP: Reconfig Announcement frame attributes", msg); return msg; } + + +static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth) +{ + struct wpabuf *msg; + size_t attr_len; + + /* Build DPP Reconfig Authentication Request frame attributes */ + attr_len = 4 + 1 + 4 + 1 + 4 + os_strlen(auth->conf->connector) + + 4 + auth->curve->nonce_len; + msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_REQ, attr_len); + if (!msg) + return NULL; + + /* Transaction ID */ + wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); + wpabuf_put_le16(msg, 1); + wpabuf_put_u8(msg, auth->transaction_id); + + /* Protocol Version */ + wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); + wpabuf_put_le16(msg, 1); + wpabuf_put_u8(msg, DPP_VERSION); + + /* DPP Connector */ + wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); + wpabuf_put_le16(msg, os_strlen(auth->conf->connector)); + wpabuf_put_str(msg, auth->conf->connector); + + /* I-nonce */ + wpabuf_put_le16(msg, DPP_ATTR_I_NONCE); + wpabuf_put_le16(msg, auth->curve->nonce_len); + wpabuf_put_data(msg, auth->i_nonce, auth->curve->nonce_len); + + wpa_hexdump_buf(MSG_DEBUG, + "DPP: Reconfig Authentication Request frame attributes", + msg); + + return msg; +} + + +static int dpp_configurator_build_own_connector(struct dpp_configurator *conf) +{ + struct wpabuf *dppcon = NULL; + int ret = -1; + + if (conf->connector) + return 0; /* already generated */ + + wpa_printf(MSG_DEBUG, + "DPP: Sign own Configurator Connector for reconfiguration with curve %s", + conf->curve->name); + conf->connector_key = dpp_gen_keypair(conf->curve); + if (!conf->connector_key) + goto fail; + + /* Connector (JSON dppCon object) */ + dppcon = wpabuf_alloc(1000 + 2 * conf->curve->prime_len * 4 / 3); + if (!dppcon) + goto fail; + json_start_object(dppcon, NULL); + json_start_array(dppcon, "groups"); + json_start_object(dppcon, NULL); + json_add_string(dppcon, "groupId", "*"); + json_value_sep(dppcon); + json_add_string(dppcon, "netRole", "configurator"); + json_end_object(dppcon); + json_end_array(dppcon); + json_value_sep(dppcon); + if (dpp_build_jwk(dppcon, "netAccessKey", conf->connector_key, NULL, + conf->curve) < 0) { + wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK"); + goto fail; + } + json_end_object(dppcon); + wpa_printf(MSG_DEBUG, "DPP: dppCon: %s", + (const char *) wpabuf_head(dppcon)); + + conf->connector = dpp_sign_connector(conf, dppcon); + if (!conf->connector) + goto fail; + wpa_printf(MSG_DEBUG, "DPP: signedConnector: %s", conf->connector); + + ret = 0; +fail: + wpabuf_free(dppcon); + return ret; +} + + +struct dpp_authentication * +dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx, + struct dpp_configurator *conf, unsigned int freq) +{ + struct dpp_authentication *auth; + + auth = dpp_alloc_auth(dpp, msg_ctx); + if (!auth) + return NULL; + + auth->conf = conf; + auth->reconfig = 1; + auth->initiator = 1; + auth->waiting_auth_resp = 1; + auth->allowed_roles = DPP_CAPAB_CONFIGURATOR; + auth->configurator = 1; + auth->curve = conf->curve; + auth->transaction_id = 1; + if (dpp_prepare_channel_list(auth, freq, NULL, 0) < 0) + goto fail; + + if (dpp_configurator_build_own_connector(conf) < 0) + goto fail; + + if (random_get_bytes(auth->i_nonce, auth->curve->nonce_len)) { + wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce"); + goto fail; + } + + auth->reconfig_req_msg = dpp_reconfig_build_req(auth); + if (!auth->reconfig_req_msg) + goto fail; + +out: + return auth; +fail: + dpp_auth_deinit(auth); + auth = NULL; + goto out; +} + #endif /* CONFIG_DPP2 */ diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index a0e47a8b7..4a32d57c6 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -45,6 +45,10 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s, const u8 *src, const u8 *bssid, const u8 *data, size_t data_len, enum offchannel_send_action_result result); +#ifdef CONFIG_DPP2 +static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx, + void *timeout_ctx); +#endif /* CONFIG_DPP2 */ static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -246,6 +250,35 @@ static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s) #ifdef CONFIG_DPP2 +static void wpas_dpp_stop_listen_for_tx(struct wpa_supplicant *wpa_s, + unsigned int freq, + unsigned int wait_time) +{ + struct os_reltime now, res; + unsigned int remaining; + + if (!wpa_s->dpp_listen_freq) + return; + + os_get_reltime(&now); + if (os_reltime_before(&now, &wpa_s->dpp_listen_end)) { + os_reltime_sub(&wpa_s->dpp_listen_end, &now, &res); + remaining = res.sec * 1000 + res.usec / 1000; + } else { + remaining = 0; + } + if (wpa_s->dpp_listen_freq == freq && remaining > wait_time) + return; + + wpa_printf(MSG_DEBUG, + "DPP: Stop listen on %u MHz ending in %u ms to allow immediate TX on %u MHz for %u ms", + wpa_s->dpp_listen_freq, remaining, freq, wait_time); + wpas_dpp_listen_stop(wpa_s); + + /* TODO: Restart listen in some cases after TX? */ +} + + static void wpas_dpp_conn_status_result_timeout(void *eloop_ctx, void *timeout_ctx) { @@ -434,6 +467,10 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s, eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); +#ifdef CONFIG_DPP2 + eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout, + wpa_s, NULL); +#endif /* CONFIG_DPP2 */ offchannel_send_action_done(wpa_s); dpp_auth_deinit(wpa_s->dpp_auth); wpa_s->dpp_auth = NULL; @@ -766,6 +803,10 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); +#ifdef CONFIG_DPP2 + eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout, + wpa_s, NULL); +#endif /* CONFIG_DPP2 */ offchannel_send_action_done(wpa_s); dpp_auth_deinit(wpa_s->dpp_auth); wpa_s->dpp_auth = NULL; @@ -1780,6 +1821,23 @@ wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src, } +static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx, + void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct dpp_authentication *auth = wpa_s->dpp_auth; + + if (!auth) + return; + + wpa_printf(MSG_DEBUG, "DPP: Reconfig Reply wait timeout"); + offchannel_send_action_done(wpa_s); + wpas_dpp_listen_stop(wpa_s); + dpp_auth_deinit(auth); + wpa_s->dpp_auth = NULL; +} + + static void wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant *wpa_s, const u8 *src, const u8 *hdr, const u8 *buf, size_t len, @@ -1788,6 +1846,8 @@ wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant *wpa_s, const u8 *src, const u8 *csign_hash; u16 csign_hash_len; struct dpp_configurator *conf; + struct dpp_authentication *auth; + unsigned int wait_time, max_wait_time; if (!wpa_s->dpp) return; @@ -1817,7 +1877,42 @@ wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant *wpa_s, const u8 *src, return; } - /* TODO: Initiate Reconfig Authentication */ + auth = dpp_reconfig_init(wpa_s->dpp, wpa_s, conf, freq); + if (!auth) + return; + wpas_dpp_set_testing_options(wpa_s, auth); + if (dpp_set_configurator(auth, wpa_s->dpp_configurator_params) < 0) { + dpp_auth_deinit(auth); + return; + } + + os_memcpy(auth->peer_mac_addr, src, ETH_ALEN); + wpa_s->dpp_auth = auth; + + wpa_s->dpp_in_response_listen = 0; + wpa_s->dpp_auth_ok_on_ack = 0; + wait_time = wpa_s->max_remain_on_chan; + max_wait_time = wpa_s->dpp_resp_wait_time ? + wpa_s->dpp_resp_wait_time : 2000; + if (wait_time > max_wait_time) + wait_time = max_wait_time; + wait_time += 10; /* give the driver some extra time to complete */ + eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000, + wpas_dpp_reconfig_reply_wait_timeout, + wpa_s, NULL); + wait_time -= 10; + + wpas_dpp_stop_listen_for_tx(wpa_s, freq, wait_time); + + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_REQ); + if (offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast, + wpabuf_head(auth->reconfig_req_msg), + wpabuf_len(auth->reconfig_req_msg), + wait_time, wpas_dpp_tx_status, 0) < 0) { + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; + } } #endif /* CONFIG_DPP2 */ @@ -2853,6 +2948,8 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout, + wpa_s, NULL); dpp_pfs_free(wpa_s->dpp_pfs); wpa_s->dpp_pfs = NULL; wpas_dpp_chirp_stop(wpa_s);