DPP2: hostapd as TCP Relay
The new hostapd configuration parameter dpp_controller can now be used with the following subparameter values: ipaddr=<IP address> pkhash=<hexdump>. 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 <jouni@codeaurora.org>
This commit is contained in:
parent
88a78bdde4
commit
e00f780e2b
7 changed files with 154 additions and 7 deletions
|
@ -2376,6 +2376,36 @@ fail:
|
||||||
#endif /* CONFIG_SAE */
|
#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,
|
static int hostapd_config_fill(struct hostapd_config *conf,
|
||||||
struct hostapd_bss_config *bss,
|
struct hostapd_bss_config *bss,
|
||||||
const char *buf, char *pos, int line)
|
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) {
|
} else if (os_strcmp(buf, "dpp_csign") == 0) {
|
||||||
if (parse_wpabuf_hex(line, buf, &bss->dpp_csign, pos))
|
if (parse_wpabuf_hex(line, buf, &bss->dpp_csign, pos))
|
||||||
return 1;
|
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 */
|
#endif /* CONFIG_DPP */
|
||||||
#ifdef CONFIG_OWE
|
#ifdef CONFIG_OWE
|
||||||
} else if (os_strcmp(buf, "owe_transition_bssid") == 0) {
|
} else if (os_strcmp(buf, "owe_transition_bssid") == 0) {
|
||||||
|
|
|
@ -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)
|
void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||||
{
|
{
|
||||||
if (conf == NULL)
|
if (conf == NULL)
|
||||||
|
@ -740,6 +754,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||||
os_free(conf->dpp_connector);
|
os_free(conf->dpp_connector);
|
||||||
wpabuf_free(conf->dpp_netaccesskey);
|
wpabuf_free(conf->dpp_netaccesskey);
|
||||||
wpabuf_free(conf->dpp_csign);
|
wpabuf_free(conf->dpp_csign);
|
||||||
|
#ifdef CONFIG_DPP2
|
||||||
|
hostapd_dpp_controller_conf_free(conf->dpp_controller);
|
||||||
|
#endif /* CONFIG_DPP2 */
|
||||||
#endif /* CONFIG_DPP */
|
#endif /* CONFIG_DPP */
|
||||||
|
|
||||||
hostapd_config_free_sae_passwords(conf);
|
hostapd_config_free_sae_passwords(conf);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "common/wpa_common.h"
|
#include "common/wpa_common.h"
|
||||||
#include "common/ieee802_11_defs.h"
|
#include "common/ieee802_11_defs.h"
|
||||||
#include "common/ieee802_11_common.h"
|
#include "common/ieee802_11_common.h"
|
||||||
|
#include "crypto/sha256.h"
|
||||||
#include "wps/wps.h"
|
#include "wps/wps.h"
|
||||||
#include "fst/fst.h"
|
#include "fst/fst.h"
|
||||||
#include "vlan.h"
|
#include "vlan.h"
|
||||||
|
@ -252,6 +253,12 @@ struct sae_password_entry {
|
||||||
int vlan_id;
|
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
|
* struct hostapd_bss_config - Per-BSS configuration
|
||||||
*/
|
*/
|
||||||
|
@ -692,6 +699,9 @@ struct hostapd_bss_config {
|
||||||
struct wpabuf *dpp_netaccesskey;
|
struct wpabuf *dpp_netaccesskey;
|
||||||
unsigned int dpp_netaccesskey_expiry;
|
unsigned int dpp_netaccesskey_expiry;
|
||||||
struct wpabuf *dpp_csign;
|
struct wpabuf *dpp_csign;
|
||||||
|
#ifdef CONFIG_DPP2
|
||||||
|
struct dpp_controller_conf *dpp_controller;
|
||||||
|
#endif /* CONFIG_DPP2 */
|
||||||
#endif /* CONFIG_DPP */
|
#endif /* CONFIG_DPP */
|
||||||
|
|
||||||
#ifdef CONFIG_OWE
|
#ifdef CONFIG_OWE
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "hostapd.h"
|
#include "hostapd.h"
|
||||||
#include "ap_drv_ops.h"
|
#include "ap_drv_ops.h"
|
||||||
#include "gas_query_ap.h"
|
#include "gas_query_ap.h"
|
||||||
|
#include "gas_serv.h"
|
||||||
#include "wpa_auth.h"
|
#include "wpa_auth.h"
|
||||||
#include "dpp_hostapd.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 */
|
* received hash values */
|
||||||
dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap,
|
dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap,
|
||||||
r_bootstrap, &own_bi, &peer_bi);
|
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) {
|
if (!own_bi) {
|
||||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
|
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
|
||||||
"No matching own bootstrapping key found - ignore message");
|
"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
|
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
|
||||||
" freq=%u type=%d", MAC2STR(src), freq, type);
|
" 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) {
|
switch (type) {
|
||||||
case DPP_PA_AUTHENTICATION_REQ:
|
case DPP_PA_AUTHENTICATION_REQ:
|
||||||
hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq);
|
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 *
|
struct wpabuf *
|
||||||
hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
|
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 dpp_authentication *auth = hapd->dpp_auth;
|
||||||
struct wpabuf *resp;
|
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));
|
wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
|
||||||
if (!auth || !auth->auth_success ||
|
if (!auth || !auth->auth_success ||
|
||||||
os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
|
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");
|
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
|
||||||
return NULL;
|
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)
|
int hostapd_dpp_init(struct hostapd_data *hapd)
|
||||||
{
|
{
|
||||||
hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
|
hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
|
||||||
hapd->dpp_init_done = 1;
|
hapd->dpp_init_done = 1;
|
||||||
return 0;
|
return hostapd_dpp_add_controllers(hapd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
const u8 *data, size_t data_len, int ok);
|
||||||
struct wpabuf *
|
struct wpabuf *
|
||||||
hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
|
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);
|
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_add(struct hostapd_data *hapd, const char *cmd);
|
||||||
int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id);
|
int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id);
|
||||||
|
|
|
@ -1522,9 +1522,9 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_DPP
|
#ifdef CONFIG_DPP
|
||||||
static void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
|
void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
|
||||||
const u8 *sa, u8 dialog_token,
|
const u8 *sa, u8 dialog_token,
|
||||||
int prot, struct wpabuf *buf)
|
int prot, struct wpabuf *buf)
|
||||||
{
|
{
|
||||||
struct wpabuf *tx_buf;
|
struct wpabuf *tx_buf;
|
||||||
|
|
||||||
|
@ -1681,7 +1681,8 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||||
if (dpp) {
|
if (dpp) {
|
||||||
struct wpabuf *msg;
|
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)
|
if (!msg)
|
||||||
return;
|
return;
|
||||||
gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
|
gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
|
||||||
|
|
|
@ -88,4 +88,8 @@ void gas_serv_dialog_clear(struct gas_dialog_info *dialog);
|
||||||
int gas_serv_init(struct hostapd_data *hapd);
|
int gas_serv_init(struct hostapd_data *hapd);
|
||||||
void gas_serv_deinit(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 */
|
#endif /* GAS_SERV_H */
|
||||||
|
|
Loading…
Reference in a new issue