]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WPS: Add support for NCF password token from AP
authorJouni Malinen <j@w1.fi>
Thu, 28 Jun 2012 16:43:29 +0000 (19:43 +0300)
committerJouni Malinen <j@w1.fi>
Thu, 28 Jun 2012 16:43:29 +0000 (19:43 +0300)
The new hostapd ctrl_iface command WPS_NFC_TOKEN can now be used to
manage AP-as-Enrollee operations with NFC password token. WPS/NDEF
parameters to this command can be used to generate a new NFC password
token. enable/disable parameters can be used to enable/disable use of
NFC password token (instead of AP PIN) for external Registrars.

A preconfigured NFS password token can be used by providing its
parameters with new hostapd.conf fields wps_nfc_dev_pw_id,
wps_nfc_dh_pubkey, wps_nfc_dh_privkey, and wps_nfc_dev_pw. This use
will also depend on WPS_NFC_TOKEN enable/disable commands, i.e., the
configured NFS password token is disabled by default.

Signed-hostap: Jouni Malinen <j@w1.fi>

hostapd/config_file.c
hostapd/ctrl_iface.c
hostapd/hostapd_cli.c
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/wps_hostapd.c
src/ap/wps_hostapd.h
src/wps/wps.c
src/wps/wps.h
src/wps/wps_attr_build.c

index b00ed8fcfbd9885d1bb93cb97cfa8e22b3772c5b..7b15e576b3669fd5a7fbdd1a377129f893ed90d1 100644 (file)
@@ -1325,6 +1325,31 @@ fail:
 #endif /* CONFIG_INTERWORKING */
 
 
+#ifdef CONFIG_WPS_NFC
+static struct wpabuf * hostapd_parse_bin(const char *buf)
+{
+       size_t len;
+       struct wpabuf *ret;
+
+       len = os_strlen(buf);
+       if (len & 0x01)
+               return NULL;
+       len /= 2;
+
+       ret = wpabuf_alloc(len);
+       if (ret == NULL)
+               return NULL;
+
+       if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
+               wpabuf_free(ret);
+               return NULL;
+       }
+
+       return ret;
+}
+#endif /* CONFIG_WPS_NFC */
+
+
 static int hostapd_config_fill(struct hostapd_config *conf,
                               struct hostapd_bss_config *bss,
                               char *buf, char *pos, int line)
@@ -2224,6 +2249,25 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        bss->upc = os_strdup(pos);
                } else if (os_strcmp(buf, "pbc_in_m1") == 0) {
                        bss->pbc_in_m1 = atoi(pos);
+#ifdef CONFIG_WPS_NFC
+               } else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
+                       bss->wps_nfc_dev_pw_id = atoi(pos);
+                       if (bss->wps_nfc_dev_pw_id < 0x10 ||
+                           bss->wps_nfc_dev_pw_id > 0xffff) {
+                               wpa_printf(MSG_ERROR, "Line %d: Invalid "
+                                          "wps_nfc_dev_pw_id value", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
+                       wpabuf_free(bss->wps_nfc_dh_pubkey);
+                       bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
+               } else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
+                       wpabuf_free(bss->wps_nfc_dh_privkey);
+                       bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
+               } else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
+                       wpabuf_free(bss->wps_nfc_dev_pw);
+                       bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
+#endif /* CONFIG_WPS_NFC */
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P_MANAGER
                } else if (os_strcmp(buf, "manage_p2p") == 0) {
@@ -2398,7 +2442,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
        struct hostapd_config *conf;
        struct hostapd_bss_config *bss;
        FILE *f;
-       char buf[256], *pos;
+       char buf[512], *pos;
        int line = 0;
        int errors = 0;
        size_t i;
index 0fa176411118b5acced4cd3d326ed9e324a6b6ad..7587e0328ea3dfa72865ef9461be19a77c13896d 100644 (file)
@@ -330,6 +330,52 @@ static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
 
        return res;
 }
+
+
+static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
+                                               char *reply, size_t max_len,
+                                               int ndef)
+{
+       struct wpabuf *buf;
+       int res;
+
+       buf = hostapd_wps_nfc_token_gen(hapd, ndef);
+       if (buf == NULL)
+               return -1;
+
+       res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+                                        wpabuf_len(buf));
+       reply[res++] = '\n';
+       reply[res] = '\0';
+
+       wpabuf_free(buf);
+
+       return res;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
+                                           char *cmd, char *reply,
+                                           size_t max_len)
+{
+       if (os_strcmp(cmd, "WPS") == 0)
+               return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
+                                                           max_len, 0);
+
+       if (os_strcmp(cmd, "NDEF") == 0)
+               return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
+                                                           max_len, 1);
+
+       if (os_strcmp(cmd, "enable") == 0)
+               return hostapd_wps_nfc_token_enable(hapd);
+
+       if (os_strcmp(cmd, "disable") == 0) {
+               hostapd_wps_nfc_token_disable(hapd);
+               return 0;
+       }
+
+       return -1;
+}
 #endif /* CONFIG_WPS_NFC */
 
 
@@ -835,6 +881,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
        } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
                reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
                        hapd, buf + 21, reply, reply_size);
+       } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
+               reply_len = hostapd_ctrl_iface_wps_nfc_token(
+                       hapd, buf + 14, reply, reply_size);
 #endif /* CONFIG_WPS_NFC */
 #endif /* CONFIG_WPS */
        } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
index ed52187fabf311a44fe98d7a37ec880f1d45c28c..0c33d5bc6864c6489f39840e06ece02d9b0f113e 100644 (file)
@@ -77,6 +77,7 @@ static const char *commands_help =
 #ifdef CONFIG_WPS_NFC
 "   wps_nfc_tag_read <hexdump>  report read NFC tag with WPS data\n"
 "   wps_nfc_config_token <WPS/NDEF>  build NFC configuration token\n"
+"   wps_nfc_token <WPS/NDEF/enable/disable>  manager NFC password token\n"
 #endif /* CONFIG_WPS_NFC */
 "   wps_ap_pin <cmd> [params..]  enable/disable AP PIN\n"
 "   wps_config <SSID> <auth> <encr> <key>  configure AP\n"
@@ -484,6 +485,27 @@ static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
        }
        return wpa_ctrl_command(ctrl, cmd);
 }
+
+
+static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
+                                        int argc, char *argv[])
+{
+       char cmd[64];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid 'wps_nfc_token' command - one argument is "
+                      "required.\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long WPS_NFC_TOKEN command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
 #endif /* CONFIG_WPS_NFC */
 
 
@@ -787,6 +809,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
 #ifdef CONFIG_WPS_NFC
        { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
        { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
+       { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
 #endif /* CONFIG_WPS_NFC */
        { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
        { "wps_config", hostapd_cli_cmd_wps_config },
index d8f55a217ec1b950f2c7776e78cb72cc7605dfc0..2c633d9f5affdae47e6ace985f416ffc513fc469 100644 (file)
@@ -491,6 +491,9 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        os_free(conf->model_description);
        os_free(conf->model_url);
        os_free(conf->upc);
+       wpabuf_free(conf->wps_nfc_dh_pubkey);
+       wpabuf_free(conf->wps_nfc_dh_privkey);
+       wpabuf_free(conf->wps_nfc_dev_pw);
 #endif /* CONFIG_WPS */
 
        os_free(conf->roaming_consortium);
index 1f35f72fe68de53d46bfe2b955bf20670ba8deeb..73b200c5ef5b2a0397ffce39300f52b1e7a11935 100644 (file)
@@ -344,6 +344,10 @@ struct hostapd_bss_config {
        char *model_url;
        char *upc;
        struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+       int wps_nfc_dev_pw_id;
+       struct wpabuf *wps_nfc_dh_pubkey;
+       struct wpabuf *wps_nfc_dh_privkey;
+       struct wpabuf *wps_nfc_dev_pw;
 #endif /* CONFIG_WPS */
        int pbc_in_m1;
 
index b95b6170dbe05346a5925a19fe3755b2f388e441..0b1fa301d766badcf83c6e6a1016ac410b86765d 100644 (file)
@@ -12,6 +12,8 @@
 #include "utils/eloop.h"
 #include "utils/uuid.h"
 #include "crypto/dh_groups.h"
+#include "crypto/dh_group5.h"
+#include "crypto/random.h"
 #include "common/wpa_ctrl.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
@@ -992,6 +994,20 @@ int hostapd_init_wps_complete(struct hostapd_data *hapd)
 }
 
 
+static void hostapd_wps_nfc_clear(struct wps_context *wps)
+{
+#ifdef CONFIG_WPS_NFC
+       wps->ap_nfc_dev_pw_id = 0;
+       wpabuf_free(wps->ap_nfc_dh_pubkey);
+       wps->ap_nfc_dh_pubkey = NULL;
+       wpabuf_free(wps->ap_nfc_dh_privkey);
+       wps->ap_nfc_dh_privkey = NULL;
+       wpabuf_free(wps->ap_nfc_dev_pw);
+       wps->ap_nfc_dev_pw = NULL;
+#endif /* CONFIG_WPS_NFC */
+}
+
+
 void hostapd_deinit_wps(struct hostapd_data *hapd)
 {
        eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
@@ -1009,6 +1025,7 @@ void hostapd_deinit_wps(struct hostapd_data *hapd)
        wpabuf_free(hapd->wps->oob_conf.pubkey_hash);
        wpabuf_free(hapd->wps->oob_conf.dev_password);
        wps_free_pending_msgs(hapd->wps->upnp_msgs);
+       hostapd_wps_nfc_clear(hapd->wps);
        os_free(hapd->wps);
        hapd->wps = NULL;
        hostapd_wps_clear_ies(hapd);
@@ -1606,4 +1623,86 @@ struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
        return ret;
 }
 
+
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
+{
+       struct wpabuf *priv = NULL, *pub = NULL, *pw;
+       void *dh_ctx;
+       struct wpabuf *ret;
+
+       pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN);
+       if (pw == NULL)
+               return NULL;
+
+       if (random_get_bytes(wpabuf_put(pw, WPS_OOB_DEVICE_PASSWORD_LEN),
+                            WPS_OOB_DEVICE_PASSWORD_LEN)) {
+               wpabuf_free(pw);
+               return NULL;
+       }
+
+       dh_ctx = dh5_init(&priv, &pub);
+       if (dh_ctx == NULL) {
+               wpabuf_free(pw);
+               return NULL;
+       }
+       dh5_free(dh_ctx);
+
+       hapd->conf->wps_nfc_dev_pw_id = 0x10 + os_random() % 0xfff0;
+       wpabuf_free(hapd->conf->wps_nfc_dh_pubkey);
+       hapd->conf->wps_nfc_dh_pubkey = pub;
+       wpabuf_free(hapd->conf->wps_nfc_dh_privkey);
+       hapd->conf->wps_nfc_dh_privkey = priv;
+       wpabuf_free(hapd->conf->wps_nfc_dev_pw);
+       hapd->conf->wps_nfc_dev_pw = pw;
+
+       ret = wps_build_nfc_pw_token(hapd->conf->wps_nfc_dev_pw_id,
+                                    hapd->conf->wps_nfc_dh_pubkey,
+                                    hapd->conf->wps_nfc_dev_pw);
+       if (ndef && ret) {
+               struct wpabuf *tmp;
+               tmp = ndef_build_wifi(ret);
+               wpabuf_free(ret);
+               if (tmp == NULL)
+                       return NULL;
+               ret = tmp;
+       }
+
+       return ret;
+}
+
+
+int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
+{
+       struct wps_context *wps = hapd->wps;
+
+       if (wps == NULL)
+               return -1;
+
+       if (!hapd->conf->wps_nfc_dh_pubkey ||
+           !hapd->conf->wps_nfc_dh_privkey ||
+           !hapd->conf->wps_nfc_dev_pw ||
+           !hapd->conf->wps_nfc_dev_pw_id)
+               return -1;
+
+       hostapd_wps_nfc_clear(wps);
+       wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
+       wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
+       wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
+       wps->ap_nfc_dev_pw = wpabuf_dup(hapd->conf->wps_nfc_dev_pw);
+
+       if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey ||
+           !wps->ap_nfc_dev_pw) {
+               hostapd_wps_nfc_clear(wps);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd)
+{
+       hostapd_wps_nfc_clear(hapd->wps);
+}
+
 #endif /* CONFIG_WPS_NFC */
index 8256c0651e0bf4345dd255e12b87f2c7acf69225..f968e151fe1f8daafa928e2da7195b472f07458c 100644 (file)
@@ -37,6 +37,9 @@ int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
                             const struct wpabuf *data);
 struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
                                             int ndef);
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef);
+int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd);
+void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd);
 
 #else /* CONFIG_WPS */
 
index 26542a067b6ca1ee288830ebeeda8f1685b8dd92..5453962a5181b2f62e2c97d96030c8cec4233474 100644 (file)
@@ -56,6 +56,23 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                data->dev_password_len = cfg->pin_len;
        }
 
+#ifdef CONFIG_WPS_NFC
+       if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) {
+               data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id;
+               os_free(data->dev_password);
+               data->dev_password =
+                       os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw));
+               if (data->dev_password == NULL) {
+                       os_free(data);
+                       return NULL;
+               }
+               os_memcpy(data->dev_password,
+                         wpabuf_head(cfg->wps->ap_nfc_dev_pw),
+                         wpabuf_len(cfg->wps->ap_nfc_dev_pw));
+               data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw);
+       }
+#endif /* CONFIG_WPS_NFC */
+
        data->pbc = cfg->pbc;
        if (cfg->pbc) {
                /* Use special PIN '00000000' for PBC */
index c5871af1e1c34a440a3d5c423ed3d56747a5fddf..a94a90a00fc37cc00c7bde6c2c12954c3dfa4b92 100644 (file)
@@ -757,6 +757,11 @@ struct wps_context {
 
        /* Pending messages from UPnP PutWLANResponse */
        struct upnp_pending_message *upnp_msgs;
+
+       u16 ap_nfc_dev_pw_id;
+       struct wpabuf *ap_nfc_dh_pubkey;
+       struct wpabuf *ap_nfc_dh_privkey;
+       struct wpabuf *ap_nfc_dev_pw;
 };
 
 struct oob_device_data {
index 77f90ef795c13a0f69caa291bdf3f7bfdff922ac..9be30b9869d5a98e12605ae58790ab7945427f58 100644 (file)
@@ -30,6 +30,14 @@ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
                wps->dh_ctx = wps->wps->dh_ctx;
                wps->wps->dh_ctx = NULL;
                pubkey = wpabuf_dup(wps->wps->dh_pubkey);
+#ifdef CONFIG_WPS_NFC
+       } else if (wps->dev_pw_id >= 0x10 && wps->wps->ap &&
+                  wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) {
+               wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
+               wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey);
+               pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey);
+               wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
+#endif /* CONFIG_WPS_NFC */
        } else {
                wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
                wps->dh_privkey = NULL;