diff --git a/hostapd/Android.mk b/hostapd/Android.mk index c581f5d89..f33163057 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -539,6 +539,7 @@ L_CFLAGS += -DCONFIG_DPP OBJS += src/common/dpp.c OBJS += src/common/dpp_crypto.c OBJS += src/common/dpp_pkex.c +OBJS += src/common/dpp_reconfig.c OBJS += src/ap/dpp_hostapd.c OBJS += src/ap/gas_query_ap.c NEED_AES_SIV=y diff --git a/hostapd/Makefile b/hostapd/Makefile index c20a1a822..ded784f03 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -570,6 +570,7 @@ CFLAGS += -DCONFIG_DPP OBJS += ../src/common/dpp.o OBJS += ../src/common/dpp_crypto.o OBJS += ../src/common/dpp_pkex.o +OBJS += ../src/common/dpp_reconfig.o OBJS += ../src/ap/dpp_hostapd.o OBJS += ../src/ap/gas_query_ap.o NEED_AES_SIV=y diff --git a/src/common/dpp.h b/src/common/dpp.h index e81526fc8..988c6fc2c 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -626,5 +626,10 @@ struct dpp_global * dpp_global_init(struct dpp_global_config *config); void dpp_global_clear(struct dpp_global *dpp); void dpp_global_deinit(struct dpp_global *dpp); +/* dpp_reconfig.c */ + +struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key, + size_t csign_key_len); + #endif /* CONFIG_DPP */ #endif /* DPP_H */ diff --git a/src/common/dpp_reconfig.c b/src/common/dpp_reconfig.c new file mode 100644 index 000000000..597963f3c --- /dev/null +++ b/src/common/dpp_reconfig.c @@ -0,0 +1,76 @@ +/* + * DPP reconfiguration + * Copyright (c) 2020, The Linux Foundation + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "crypto/crypto.h" +#include "dpp.h" +#include "dpp_i.h" + + +#ifdef CONFIG_DPP2 + +static void dpp_build_attr_csign_key_hash(struct wpabuf *msg, const u8 *hash) +{ + if (hash) { + wpa_printf(MSG_DEBUG, "DPP: Configurator C-sign key Hash"); + wpabuf_put_le16(msg, DPP_ATTR_C_SIGN_KEY_HASH); + wpabuf_put_le16(msg, SHA256_MAC_LEN); + wpabuf_put_data(msg, hash, SHA256_MAC_LEN); + } +} + + +struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key, + size_t csign_key_len) +{ + struct wpabuf *msg; + EVP_PKEY *csign = NULL; + const unsigned char *p; + struct wpabuf *uncomp; + u8 hash[SHA256_MAC_LEN]; + const u8 *addr[1]; + size_t len[1]; + int res; + + wpa_printf(MSG_DEBUG, "DPP: Build Reconfig Announcement frame"); + + p = csign_key; + csign = d2i_PUBKEY(NULL, &p, csign_key_len); + if (!csign) { + wpa_printf(MSG_ERROR, + "DPP: Failed to parse local C-sign-key information"); + return NULL; + } + + uncomp = dpp_get_pubkey_point(csign, 1); + EVP_PKEY_free(csign); + if (!uncomp) + return NULL; + addr[0] = wpabuf_head(uncomp); + len[0] = wpabuf_len(uncomp); + wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed C-sign key", addr[0], len[0]); + res = sha256_vector(1, addr, len, hash); + wpabuf_free(uncomp); + if (res < 0) + return NULL; + wpa_hexdump(MSG_DEBUG, "DPP: kid = SHA256(uncompressed C-sign key)", + hash, SHA256_MAC_LEN); + + msg = dpp_alloc_msg(DPP_PA_RECONFIG_ANNOUNCEMENT, 4 + SHA256_MAC_LEN); + if (!msg) + return NULL; + + /* Configurator C-sign key Hash */ + dpp_build_attr_csign_key_hash(msg, hash); + wpa_hexdump_buf(MSG_DEBUG, + "DPP: Reconfig Announcement frame attributes", msg); + return msg; +} +#endif /* CONFIG_DPP2 */ diff --git a/tests/fuzzing/dpp-uri/Makefile b/tests/fuzzing/dpp-uri/Makefile index e5788a833..6125e4b36 100644 --- a/tests/fuzzing/dpp-uri/Makefile +++ b/tests/fuzzing/dpp-uri/Makefile @@ -23,6 +23,7 @@ OBJS += $(SRC)/tls/asn1.o OBJS += $(SRC)/common/dpp.o OBJS += $(SRC)/common/dpp_crypto.o OBJS += $(SRC)/common/dpp_pkex.o +OBJS += $(SRC)/common/dpp_reconfig.o dpp-uri: dpp-uri.o $(OBJS) $(LIBS) $(LDO) $(LDFLAGS) -o $@ $^ -lcrypto diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index a589b2774..0b091d756 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -249,6 +249,7 @@ L_CFLAGS += -DCONFIG_DPP OBJS += src/common/dpp.c OBJS += src/common/dpp_crypto.c OBJS += src/common/dpp_pkex.c +OBJS += src/common/dpp_reconfig.c OBJS += dpp_supplicant.c NEED_AES_SIV=y NEED_HMAC_SHA256_KDF=y diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 441a7db1a..d2bdbc47c 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -281,6 +281,7 @@ CFLAGS += -DCONFIG_DPP OBJS += ../src/common/dpp.o OBJS += ../src/common/dpp_crypto.o OBJS += ../src/common/dpp_pkex.o +OBJS += ../src/common/dpp_reconfig.o OBJS += dpp_supplicant.o NEED_AES_SIV=y NEED_HMAC_SHA256_KDF=y diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 6e673fe36..5c99735c8 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -11013,6 +11013,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = -1; } else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) { wpas_dpp_chirp_stop(wpa_s); + } else if (os_strncmp(buf, "DPP_RECONFIG ", 13) == 0) { + struct wpa_ssid *ssid; + + ssid = wpa_config_get_network(wpa_s->conf, atoi(buf + 13)); + if (!ssid || wpas_dpp_reconfig(wpa_s, ssid) < 0) + reply_len = -1; #endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP */ } else { diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 837ddbe04..f74f1d695 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -2878,15 +2878,24 @@ static void wpas_dpp_chirp_tx_status(struct wpa_supplicant *wpa_s, static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s) { + struct wpabuf *msg; + int type; + + msg = wpa_s->dpp_presence_announcement; + type = DPP_PA_PRESENCE_ANNOUNCEMENT; + if (!msg) { + msg = wpa_s->dpp_reconfig_announcement; + if (!msg) + return; + type = DPP_PA_RECONFIG_ANNOUNCEMENT; + } wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", wpa_s->dpp_chirp_freq); wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", - MAC2STR(broadcast), wpa_s->dpp_chirp_freq, - DPP_PA_PRESENCE_ANNOUNCEMENT); + MAC2STR(broadcast), wpa_s->dpp_chirp_freq, type); if (offchannel_send_action( wpa_s, wpa_s->dpp_chirp_freq, broadcast, wpa_s->own_addr, broadcast, - wpabuf_head(wpa_s->dpp_presence_announcement), - wpabuf_len(wpa_s->dpp_presence_announcement), + wpabuf_head(msg), wpabuf_len(msg), 2000, wpas_dpp_chirp_tx_status, 0) < 0) wpas_dpp_chirp_stop(wpa_s); } @@ -2901,7 +2910,7 @@ static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s, int c; struct wpa_bss *bss; - if (!bi) + if (!bi && !wpa_s->dpp_reconfig_announcement) return; wpa_s->dpp_chirp_scan_done = 1; @@ -2910,8 +2919,11 @@ static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s, wpa_s->dpp_chirp_freqs = NULL; /* Channels from own bootstrapping info */ - for (i = 0; i < bi->num_freq; i++) - int_array_add_unique(&wpa_s->dpp_chirp_freqs, bi->freq[i]); + if (bi) { + for (i = 0; i < bi->num_freq; i++) + int_array_add_unique(&wpa_s->dpp_chirp_freqs, + bi->freq[i]); + } /* Preferred chirping channels */ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437); @@ -3085,13 +3097,16 @@ int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd) void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s) { - if (wpa_s->dpp_presence_announcement) { + if (wpa_s->dpp_presence_announcement || + wpa_s->dpp_reconfig_announcement) { offchannel_send_action_done(wpa_s); wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CHIRP_STOPPED); } wpa_s->dpp_chirp_bi = NULL; wpabuf_free(wpa_s->dpp_presence_announcement); wpa_s->dpp_presence_announcement = NULL; + wpabuf_free(wpa_s->dpp_reconfig_announcement); + wpa_s->dpp_reconfig_announcement = NULL; if (wpa_s->dpp_chirp_listen) wpas_dpp_listen_stop(wpa_s); wpa_s->dpp_chirp_listen = 0; @@ -3106,4 +3121,29 @@ void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s) } } + +int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) +{ + if (!ssid->dpp_connector || !ssid->dpp_netaccesskey || + !ssid->dpp_csign) + return -1; + + wpas_dpp_chirp_stop(wpa_s); + wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE; + wpa_s->dpp_qr_mutual = 0; + wpa_s->dpp_reconfig_announcement = + dpp_build_reconfig_announcement(ssid->dpp_csign, + ssid->dpp_csign_len); + if (!wpa_s->dpp_reconfig_announcement) + return -1; + wpa_s->dpp_reconfig_ssid = ssid; + wpa_s->dpp_reconfig_ssid_id = ssid->id; + wpa_s->dpp_chirp_iter = 1; + wpa_s->dpp_chirp_round = 0; + wpa_s->dpp_chirp_scan_done = 0; + wpa_s->dpp_chirp_listen = 0; + + return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL); +} + #endif /* CONFIG_DPP2 */ diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h index 6d70874c4..2dc86e09e 100644 --- a/wpa_supplicant/dpp_supplicant.h +++ b/wpa_supplicant/dpp_supplicant.h @@ -39,5 +39,6 @@ void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s, enum dpp_status_error result); 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, struct wpa_ssid *ssid); #endif /* DPP_SUPPLICANT_H */ diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 2ed8e2f85..734ba0797 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1277,6 +1277,7 @@ struct wpa_supplicant { #ifdef CONFIG_DPP2 struct dpp_pfs *dpp_pfs; int dpp_pfs_fallback; + struct wpabuf *dpp_reconfig_announcement; struct wpabuf *dpp_presence_announcement; struct dpp_bootstrap_info *dpp_chirp_bi; int dpp_chirp_freq; @@ -1285,6 +1286,8 @@ struct wpa_supplicant { int dpp_chirp_round; int dpp_chirp_scan_done; int dpp_chirp_listen; + struct wpa_ssid *dpp_reconfig_ssid; + int dpp_reconfig_ssid_id; #endif /* CONFIG_DPP2 */ #ifdef CONFIG_TESTING_OPTIONS char *dpp_config_obj_override;