From e00f780e2bdd98d1b7c96876716d8084808e635d Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 24 Mar 2019 22:17:49 +0200 Subject: [PATCH] DPP2: hostapd as TCP Relay The new hostapd configuration parameter dpp_controller can now be used with the following subparameter values: ipaddr= pkhash=. This adds a new Controller into the configuration (i.e., more than one can be configured) and all incoming DPP exchanges that match the specified Controller public key hash are relayed to the particular Controller. Signed-off-by: Jouni Malinen --- hostapd/config_file.c | 35 ++++++++++++++++++ src/ap/ap_config.c | 17 +++++++++ src/ap/ap_config.h | 10 ++++++ src/ap/dpp_hostapd.c | 83 +++++++++++++++++++++++++++++++++++++++++-- src/ap/dpp_hostapd.h | 3 +- src/ap/gas_serv.c | 9 ++--- src/ap/gas_serv.h | 4 +++ 7 files changed, 154 insertions(+), 7 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 42f3b40ef..3f61cb625 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2376,6 +2376,36 @@ fail: #endif /* CONFIG_SAE */ +#ifdef CONFIG_DPP2 +static int hostapd_dpp_controller_parse(struct hostapd_bss_config *bss, + const char *pos) +{ + struct dpp_controller_conf *conf; + char *val; + + conf = os_zalloc(sizeof(*conf)); + if (!conf) + return -1; + val = get_param(pos, "ipaddr="); + if (!val || hostapd_parse_ip_addr(val, &conf->ipaddr)) + goto fail; + os_free(val); + val = get_param(pos, "pkhash="); + if (!val || os_strlen(val) != 2 * SHA256_MAC_LEN || + hexstr2bin(val, conf->pkhash, SHA256_MAC_LEN) < 0) + goto fail; + os_free(val); + conf->next = bss->dpp_controller; + bss->dpp_controller = conf; + return 0; +fail: + os_free(val); + os_free(conf); + return -1; +} +#endif /* CONFIG_DPP2 */ + + static int hostapd_config_fill(struct hostapd_config *conf, struct hostapd_bss_config *bss, const char *buf, char *pos, int line) @@ -4298,6 +4328,11 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "dpp_csign") == 0) { if (parse_wpabuf_hex(line, buf, &bss->dpp_csign, pos)) return 1; +#ifdef CONFIG_DPP2 + } else if (os_strcmp(buf, "dpp_controller") == 0) { + if (hostapd_dpp_controller_parse(bss, pos)) + return 1; +#endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP */ #ifdef CONFIG_OWE } else if (os_strcmp(buf, "owe_transition_bssid") == 0) { diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index e640e9984..07b818eb3 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -559,6 +559,20 @@ static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf) } +#ifdef CONFIG_DPP2 +static void hostapd_dpp_controller_conf_free(struct dpp_controller_conf *conf) +{ + struct dpp_controller_conf *prev; + + while (conf) { + prev = conf; + conf = conf->next; + os_free(prev); + } +} +#endif /* CONFIG_DPP2 */ + + void hostapd_config_free_bss(struct hostapd_bss_config *conf) { if (conf == NULL) @@ -740,6 +754,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->dpp_connector); wpabuf_free(conf->dpp_netaccesskey); wpabuf_free(conf->dpp_csign); +#ifdef CONFIG_DPP2 + hostapd_dpp_controller_conf_free(conf->dpp_controller); +#endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP */ hostapd_config_free_sae_passwords(conf); diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 509677a45..19eda67e1 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -15,6 +15,7 @@ #include "common/wpa_common.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" +#include "crypto/sha256.h" #include "wps/wps.h" #include "fst/fst.h" #include "vlan.h" @@ -252,6 +253,12 @@ struct sae_password_entry { int vlan_id; }; +struct dpp_controller_conf { + struct dpp_controller_conf *next; + u8 pkhash[SHA256_MAC_LEN]; + struct hostapd_ip_addr ipaddr; +}; + /** * struct hostapd_bss_config - Per-BSS configuration */ @@ -692,6 +699,9 @@ struct hostapd_bss_config { struct wpabuf *dpp_netaccesskey; unsigned int dpp_netaccesskey_expiry; struct wpabuf *dpp_csign; +#ifdef CONFIG_DPP2 + struct dpp_controller_conf *dpp_controller; +#endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP */ #ifdef CONFIG_OWE diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index 75edbc909..697c3bad3 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -16,6 +16,7 @@ #include "hostapd.h" #include "ap_drv_ops.h" #include "gas_query_ap.h" +#include "gas_serv.h" #include "wpa_auth.h" #include "dpp_hostapd.h" @@ -557,6 +558,14 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src, * received hash values */ dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap, r_bootstrap, &own_bi, &peer_bi); +#ifdef CONFIG_DPP2 + if (!own_bi) { + if (dpp_relay_rx_action(hapd->iface->interfaces->dpp, + src, hdr, buf, len, freq, i_bootstrap, + r_bootstrap) == 0) + return; + } +#endif /* CONFIG_DPP2 */ if (!own_bi) { wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "No matching own bootstrapping key found - ignore message"); @@ -1357,6 +1366,12 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR " freq=%u type=%d", MAC2STR(src), freq, type); +#ifdef CONFIG_DPP2 + if (dpp_relay_rx_action(hapd->iface->interfaces->dpp, + src, hdr, buf, len, freq, NULL, NULL) == 0) + return; +#endif /* CONFIG_DPP2 */ + switch (type) { case DPP_PA_AUTHENTICATION_REQ: hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq); @@ -1410,7 +1425,8 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, struct wpabuf * hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa, - const u8 *query, size_t query_len) + const u8 *query, size_t query_len, + const u8 *data, size_t data_len) { struct dpp_authentication *auth = hapd->dpp_auth; struct wpabuf *resp; @@ -1418,6 +1434,13 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa, wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa)); if (!auth || !auth->auth_success || os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) { +#ifdef CONFIG_DPP2 + if (dpp_relay_rx_gas_req(hapd->iface->interfaces->dpp, sa, data, + data_len) == 0) { + /* Response will be forwarded once received over TCP */ + return NULL; + } +#endif /* CONFIG_DPP2 */ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); return NULL; } @@ -1609,11 +1632,67 @@ void hostapd_dpp_stop(struct hostapd_data *hapd) } +#ifdef CONFIG_DPP2 + +static void hostapd_dpp_relay_tx(void *ctx, const u8 *addr, unsigned int freq, + const u8 *msg, size_t len) +{ + struct hostapd_data *hapd = ctx; + u8 *buf; + + wpa_printf(MSG_DEBUG, "DPP: Send action frame dst=" MACSTR " freq=%u", + MAC2STR(addr), freq); + buf = os_malloc(2 + len); + if (!buf) + return; + buf[0] = WLAN_ACTION_PUBLIC; + buf[1] = WLAN_PA_VENDOR_SPECIFIC; + os_memcpy(buf + 2, msg, len); + hostapd_drv_send_action(hapd, freq, 0, addr, buf, 2 + len); + os_free(buf); +} + + +static void hostapd_dpp_relay_gas_resp_tx(void *ctx, const u8 *addr, + u8 dialog_token, int prot, + struct wpabuf *buf) +{ + struct hostapd_data *hapd = ctx; + + gas_serv_req_dpp_processing(hapd, addr, dialog_token, prot, buf); +} + +#endif /* CONFIG_DPP2 */ + + +static int hostapd_dpp_add_controllers(struct hostapd_data *hapd) +{ +#ifdef CONFIG_DPP2 + struct dpp_controller_conf *ctrl; + struct dpp_relay_config config; + + os_memset(&config, 0, sizeof(config)); + config.cb_ctx = hapd; + config.tx = hostapd_dpp_relay_tx; + config.gas_resp_tx = hostapd_dpp_relay_gas_resp_tx; + for (ctrl = hapd->conf->dpp_controller; ctrl; ctrl = ctrl->next) { + config.ipaddr = &ctrl->ipaddr; + config.pkhash = ctrl->pkhash; + if (dpp_relay_add_controller(hapd->iface->interfaces->dpp, + &config) < 0) + return -1; + } +#endif /* CONFIG_DPP2 */ + + return 0; +} + + int hostapd_dpp_init(struct hostapd_data *hapd) { hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE; hapd->dpp_init_done = 1; - return 0; + return hostapd_dpp_add_controllers(hapd); } diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h index 449ca16d1..c1ec5d70e 100644 --- a/src/ap/dpp_hostapd.h +++ b/src/ap/dpp_hostapd.h @@ -19,7 +19,8 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst, const u8 *data, size_t data_len, int ok); struct wpabuf * hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa, - const u8 *query, size_t query_len); + const u8 *query, size_t query_len, + const u8 *data, size_t data_len); void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok); int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd); int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id); diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c index a7df81032..9567e202a 100644 --- a/src/ap/gas_serv.c +++ b/src/ap/gas_serv.c @@ -1522,9 +1522,9 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd, #ifdef CONFIG_DPP -static void gas_serv_req_dpp_processing(struct hostapd_data *hapd, - const u8 *sa, u8 dialog_token, - int prot, struct wpabuf *buf) +void gas_serv_req_dpp_processing(struct hostapd_data *hapd, + const u8 *sa, u8 dialog_token, + int prot, struct wpabuf *buf) { struct wpabuf *tx_buf; @@ -1681,7 +1681,8 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd, if (dpp) { struct wpabuf *msg; - msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen); + msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen, + data, len); if (!msg) return; gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg); diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h index 2cf181729..1528af4af 100644 --- a/src/ap/gas_serv.h +++ b/src/ap/gas_serv.h @@ -88,4 +88,8 @@ void gas_serv_dialog_clear(struct gas_dialog_info *dialog); int gas_serv_init(struct hostapd_data *hapd); void gas_serv_deinit(struct hostapd_data *hapd); +void gas_serv_req_dpp_processing(struct hostapd_data *hapd, + const u8 *sa, u8 dialog_token, + int prot, struct wpabuf *buf); + #endif /* GAS_SERV_H */