[PATCH] WPS: Make it possible to use PSKs loaded from PSK file

Tomasz Jankowski <[email protected]>
Newsgroups gmane.linux.drivers.hostap
Message-ID <CAOO=4Oh+aaSZnckboUgpj-uaykxNPh5BOJJkxorD60DafpSq+w@mail.gmail.com>
From: Tomasz Jankowski <[email protected]>

By default, when conf file defines wpa_psk_file, hostapd will generate a random
PSK for each device connecting using WPS and append that PSK to wpa_psk_file.

This patch changes that behavior by adding new step. WPS will first try to
use 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
appropriate PSK code fallbacks to generating new PSK.

Signed-off-by: Tomasz Jankowski <[email protected]>
---
 hostapd/hostapd.wpa_psk |  4 ++++
 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 | 20 ++++++++++++++++++++
 6 files changed, 77 insertions(+)

diff --git a/hostapd/hostapd.wpa_psk b/hostapd/hostapd.wpa_psk
index 166e59e9c..9a63d93f7 100644
--- a/hostapd/hostapd.wpa_psk
+++ b/hostapd/hostapd.wpa_psk
@@ -7,9 +7,13 @@
 # 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)
 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 27c4b48e4..290d5fa39 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 {
@@ -404,6 +407,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..ea60ae76c 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -268,6 +268,44 @@ static void hostapd_wps_enrollee_seen_cb(void
*ctx, const u8 *addr,
      config_methods, dev_password_id, request_type, dev_name);
 }

+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;
+ u8 any_mac_addr[ETH_ALEN];
+
+ os_memset(any_mac_addr, 0, ETH_ALEN);
+
+ for (wpa_psk = hapd->conf->ssid.wpa_psk; wpa_psk->next;
+ wpa_psk = wpa_psk->next)
+ {
+ if (wpa_psk->wps == 0)
+ continue;
+
+ if (!any_psk && os_memcmp(any_mac_addr, wpa_psk->addr, ETH_ALEN) == 0)
+ 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;
+ }
+ }
+
+ if (dev_psk)
+ *psk = dev_psk;
+ else if (any_psk)
+ *psk = any_psk;
+ else {
+ *psk = NULL;
+ wpa_printf(MSG_DEBUG,
+ "WPS: Failed to find appropriate PSK in wpa_psk_file");
+ }
+
+ return *psk ? 1 : 0;
+}

 static void wps_reload_config(void *eloop_data, void *user_ctx)
 {
@@ -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 da81d1adc..91b35b6f2 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -159,6 +159,9 @@ 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;
@@ -681,6 +684,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) {
@@ -1289,6 +1293,14 @@ static void wps_cb_set_sel_reg(struct wps_registrar *reg)
     methods);
 }

+static int wps_cp_lookup_pskfile(struct wps_registrar *reg, const u8 *mac_addr,
+                const u8** psk)
+{
+ if (reg->lookup_pskfile_cb == NULL)
+ return 0;
+
+ return reg->lookup_pskfile_cb(reg->cb_ctx, mac_addr, psk);
+}

 static int wps_set_ie(struct wps_registrar *reg)
 {
@@ -1644,6 +1656,7 @@ 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;

  if (wps->wps->registrar->skip_cred_build)
  goto skip_cred_build;
@@ -1759,6 +1772,13 @@ 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)) {
+ char hex[65];
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Use PSK from wpa_psk_file",
+ pskfile_psk, 32);
+ wpa_snprintf_hex(hex, sizeof(hex), pskfile_psk, 32);
+ os_memcpy(wps->cred.key, hex, 32 * 2);
+ wps->cred.key_len = 32 * 2;
  } else if (!wps->wps->registrar->force_per_enrollee_psk &&
    wps->use_psk_key && wps->wps->psk_set) {
  char hex[65];
--
2.25.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.