]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WPS: Make it possible to use PSKs loaded from the PSK file
authorTomasz Jankowski <tomasz.jankowski@plume.com>
Mon, 10 Feb 2020 11:49:33 +0000 (12:49 +0100)
committerJouni Malinen <j@w1.fi>
Sat, 15 Feb 2020 15:28:00 +0000 (17:28 +0200)
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 <tomasz.jankowski@plume.com>
hostapd/hostapd.wpa_psk
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/wps_hostapd.c
src/wps/wps.h
src/wps/wps_registrar.c

index 166e59e9c64ff5d7b4d53ab08a09a3ec56994e9a..2ce5ff2346df9a851b73203a79638b14c4b62206 100644 (file)
@@ -7,9 +7,15 @@
 # keyid=<keyid_string>
 # An optional VLAN ID can be specified by prefixing the line with
 # vlanid=<VLAN ID>.
+# 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
index 12aae6c73fb05ce9408d10fc9743ca1985f481e5..d4d098b38c84b4715ae99154dbfeadb93230c4b8 100644 (file)
@@ -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;
        }
index 017e60aa425b13bc7f613cd5b4d02b0b564966ce..f321017e88cf5736faf456577eaa61454f346448 100644 (file)
@@ -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];
index 3ea2228a90f7ae093d1d70c340c6c1403d1b4d28..35e5772af6cb1652821b54deafa2853cbd7e9ae5 100644 (file)
@@ -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;
index f42045e9387dae8e120918c1189375bd04677931..3b56da74dcb5ff1e44ecd9768cd248814ed94068 100644 (file)
@@ -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
         */
index c07d42bdd3749fc56c91b684828dfdcca6570ba8..fb6c71d7eed015069bceee09600a8ba87c78be57 100644 (file)
@@ -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;