From fde8e7946304569292c5d520d76371291cc4f88c Mon Sep 17 00:00:00 2001 From: Tomasz Jankowski Date: Mon, 10 Feb 2020 12:49:33 +0100 Subject: [PATCH] WPS: Make it possible to use PSKs loaded from the PSK file By default, when configuration file set wpa_psk_file, hostapd generated a random PSK for each Enrollee provisioned using WPS and appended that PSK to wpa_psk_file. Changes that behavior by adding a new step. WPS will first try to use a PSK from wpa_psk_file. It will only try PSKs with wps=1 tag. Additionally it'll try to match enrollee's MAC address (if provided). If it fails to find an appropriate PSK, it falls back to generating a new PSK. Signed-off-by: Tomasz Jankowski --- hostapd/hostapd.wpa_psk | 6 ++++++ src/ap/ap_config.c | 5 +++++ src/ap/ap_config.h | 1 + src/ap/wps_hostapd.c | 39 +++++++++++++++++++++++++++++++++++++++ src/wps/wps.h | 8 ++++++++ src/wps/wps_registrar.c | 21 +++++++++++++++++++-- 6 files changed, 78 insertions(+), 2 deletions(-) diff --git a/hostapd/hostapd.wpa_psk b/hostapd/hostapd.wpa_psk index 166e59e9c..2ce5ff234 100644 --- a/hostapd/hostapd.wpa_psk +++ b/hostapd/hostapd.wpa_psk @@ -7,9 +7,15 @@ # keyid= # An optional VLAN ID can be specified by prefixing the line with # vlanid=. +# An optional WPS tag can be added by prefixing the line with +# wps=<0/1> (default: 0). Any matching entry with that tag will be used when +# generating a PSK for a WPS Enrollee instead of generating a new random +# per-Enrollee PSK. 00:00:00:00:00:00 secret passphrase 00:11:22:33:44:55 another passphrase 00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef keyid=example_id 00:11:22:33:44:77 passphrase with keyid vlanid=3 00:00:00:00:00:00 passphrase with vlanid +wps=1 00:00:00:00:00:00 passphrase for WPS +wps=1 11:22:33:44:55:00 dev-specific passphrase for WPS 00:00:00:00:00:00 another passphrase for all STAs diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 12aae6c73..d4d098b38 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -301,6 +301,7 @@ static int hostapd_config_read_wpa_psk(const char *fname, while (fgets(buf, sizeof(buf), f)) { int vlan_id = 0; + int wps = 0; line++; @@ -331,6 +332,8 @@ static int hostapd_config_read_wpa_psk(const char *fname, value = ""; if (!os_strcmp(name, "keyid")) { keyid = value; + } else if (!os_strcmp(name, "wps")) { + wps = atoi(value); } else if (!os_strcmp(name, "vlanid")) { vlan_id = atoi(value); } else { @@ -406,6 +409,8 @@ static int hostapd_config_read_wpa_psk(const char *fname, } } + psk->wps = wps; + psk->next = ssid->wpa_psk; ssid->wpa_psk = psk; } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 017e60aa4..f321017e8 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -152,6 +152,7 @@ struct hostapd_wpa_psk { struct hostapd_wpa_psk *next; int group; char keyid[KEYID_LEN]; + int wps; u8 psk[PMK_LEN]; u8 addr[ETH_ALEN]; u8 p2p_dev_addr[ETH_ALEN]; diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index 3ea2228a9..35e5772af 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -269,6 +269,44 @@ static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr, } +static int hostapd_wps_lookup_pskfile_cb(void *ctx, const u8 *mac_addr, + const u8 **psk) +{ + const struct hostapd_data *hapd = ctx; + const struct hostapd_wpa_psk *wpa_psk; + const u8 *any_psk = NULL; + const u8 *dev_psk = NULL; + + for (wpa_psk = hapd->conf->ssid.wpa_psk; wpa_psk; + wpa_psk = wpa_psk->next) { + if (!wpa_psk->wps) + continue; + + if (!any_psk && is_zero_ether_addr(wpa_psk->addr)) + any_psk = wpa_psk->psk; + + if (mac_addr && !dev_psk && + os_memcmp(mac_addr, wpa_psk->addr, ETH_ALEN) == 0) { + dev_psk = wpa_psk->psk; + break; + } + } + + if (dev_psk) { + *psk = dev_psk; + } else if (any_psk) { + *psk = any_psk; + } else { + *psk = NULL; + wpa_printf(MSG_DEBUG, + "WPS: No appropriate PSK in wpa_psk_file"); + return 0; + } + + return 1; +} + + static void wps_reload_config(void *eloop_data, void *user_ctx) { struct hostapd_iface *iface = eloop_data; @@ -1213,6 +1251,7 @@ int hostapd_init_wps(struct hostapd_data *hapd, cfg.pin_needed_cb = hostapd_wps_pin_needed_cb; cfg.reg_success_cb = hostapd_wps_reg_success_cb; cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb; + cfg.lookup_pskfile_cb = hostapd_wps_lookup_pskfile_cb; cfg.cb_ctx = hapd; cfg.skip_cred_build = conf->skip_cred_build; cfg.extra_cred = conf->extra_cred; diff --git a/src/wps/wps.h b/src/wps/wps.h index f42045e93..3b56da74d 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -344,6 +344,14 @@ struct wps_registrar_config { u16 dev_password_id, u8 request_type, const char *dev_name); + /** + * lookup_pskfile_cb - Callback for searching for PSK in wpa_psk_file + * @ctx: Higher layer context data (cb_ctx) + * @addr: Enrollee's MAC address + * @psk: Pointer to found PSK (output arg) + */ + int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk); + /** * cb_ctx: Higher layer context data for Registrar callbacks */ diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index c07d42bdd..fb6c71d7e 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -160,6 +160,7 @@ struct wps_registrar { const u8 *pri_dev_type, u16 config_methods, u16 dev_password_id, u8 request_type, const char *dev_name); + int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk); void *cb_ctx; struct dl_list pins; @@ -682,6 +683,7 @@ wps_registrar_init(struct wps_context *wps, reg->reg_success_cb = cfg->reg_success_cb; reg->set_sel_reg_cb = cfg->set_sel_reg_cb; reg->enrollee_seen_cb = cfg->enrollee_seen_cb; + reg->lookup_pskfile_cb = cfg->lookup_pskfile_cb; reg->cb_ctx = cfg->cb_ctx; reg->skip_cred_build = cfg->skip_cred_build; if (cfg->extra_cred) { @@ -1291,6 +1293,15 @@ static void wps_cb_set_sel_reg(struct wps_registrar *reg) } +static int wps_cp_lookup_pskfile(struct wps_registrar *reg, const u8 *mac_addr, + const u8 **psk) +{ + if (!reg->lookup_pskfile_cb) + return 0; + return reg->lookup_pskfile_cb(reg->cb_ctx, mac_addr, psk); +} + + static int wps_set_ie(struct wps_registrar *reg) { struct wpabuf *beacon; @@ -1645,6 +1656,8 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) { struct wpabuf *cred; struct wps_registrar *reg = wps->wps->registrar; + const u8 *pskfile_psk; + char hex[65]; if (wps->wps->registrar->skip_cred_build) goto skip_cred_build; @@ -1760,9 +1773,14 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) wps->new_psk, wps->new_psk_len); os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len); wps->cred.key_len = wps->new_psk_len; + } else if (wps_cp_lookup_pskfile(reg, wps->mac_addr_e, &pskfile_psk)) { + wpa_hexdump_key(MSG_DEBUG, "WPS: Use PSK from wpa_psk_file", + pskfile_psk, PMK_LEN); + wpa_snprintf_hex(hex, sizeof(hex), pskfile_psk, PMK_LEN); + os_memcpy(wps->cred.key, hex, PMK_LEN * 2); + wps->cred.key_len = PMK_LEN * 2; } else if (!wps->wps->registrar->force_per_enrollee_psk && wps->use_psk_key && wps->wps->psk_set) { - char hex[65]; wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key"); wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, PMK_LEN); os_memcpy(wps->cred.key, hex, PMK_LEN * 2); @@ -1773,7 +1791,6 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) wps->wps->network_key_len); wps->cred.key_len = wps->wps->network_key_len; } else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) { - char hex[65]; /* Generate a random per-device PSK */ os_free(wps->new_psk); wps->new_psk_len = PMK_LEN;