]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WPS: Add new mechanism for NFC config method using password token
authorJouni Malinen <j@w1.fi>
Wed, 27 Jun 2012 15:56:41 +0000 (18:56 +0300)
committerJouni Malinen <j@w1.fi>
Wed, 27 Jun 2012 18:22:12 +0000 (21:22 +0300)
Instead of requiring low-level access to an NFC device and synchronous
operations, the new WPS_NFC_TOKEN and WPS_NFC ctrl_iface commands can be
used to build a NFC password token and initiate WPS protocol run using
that token (or pre-configured values) as separate commands. The
WPS_NFC_TOKEN output can be written to a NFC tag using an external
program, i.e., wpa_supplicant does not need to have low-level code for
NFC operations for this.

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

src/wps/wps.h
src/wps/wps_common.c
wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.c
wpa_supplicant/ctrl_iface.c
wpa_supplicant/wpa_cli.c
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h

index b49bb9128efc849d9e8c6d226ec828ac230dc50d..48ba76f470e98b1c90c2b2722dffe5cc58491b61 100644 (file)
@@ -832,6 +832,9 @@ char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
                            size_t buf_len);
 void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid);
 u16 wps_config_methods_str2bin(const char *str);
+struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
+                                      const struct wpabuf *pubkey,
+                                      const struct wpabuf *dev_pw);
 
 /* ndef.c */
 struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
index c7c0c297d09bdc703522257bb8285c5f1eb2e56b..63857e0afce8c4d03768cf2514a91008aa4f6ef7 100644 (file)
@@ -335,6 +335,30 @@ static struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
 }
 
 
+struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
+                                      const struct wpabuf *pubkey,
+                                      const struct wpabuf *dev_pw)
+{
+       struct wpabuf *data;
+
+       data = wpabuf_alloc(200);
+       if (data == NULL)
+               return NULL;
+
+       if (wps_build_version(data) ||
+           wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
+                                wpabuf_head(dev_pw), wpabuf_len(dev_pw)) ||
+           wps_build_wfa_ext(data, 0, NULL, 0)) {
+               wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
+                          "token");
+               wpabuf_free(data);
+               return NULL;
+       }
+
+       return data;
+}
+
+
 static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps)
 {
        struct wpabuf *data;
index 80f87f47460f5f8a9023ab69b36a95f7dd6ec6ce..a68b31e7bffe89a08265ba6fab370011f6fbcc1f 100644 (file)
@@ -1860,6 +1860,9 @@ void wpa_config_free(struct wpa_config *config)
        os_free(config->pssid);
        os_free(config->p2p_pref_chan);
        os_free(config->autoscan);
+       wpabuf_free(config->wps_nfc_dh_pubkey);
+       wpabuf_free(config->wps_nfc_dh_privkey);
+       wpabuf_free(config->wps_nfc_dev_pw);
        os_free(config);
 }
 
@@ -2607,6 +2610,35 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
 }
 
 
+static int wpa_global_config_parse_bin(const struct global_parse_data *data,
+                                      struct wpa_config *config, int line,
+                                      const char *pos)
+{
+       size_t len;
+       struct wpabuf **dst, *tmp;
+
+       len = os_strlen(pos);
+       if (len & 0x01)
+               return -1;
+
+       tmp = wpabuf_alloc(len / 2);
+       if (tmp == NULL)
+               return -1;
+
+       if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) {
+               wpabuf_free(tmp);
+               return -1;
+       }
+
+       dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
+       wpabuf_free(*dst);
+       *dst = tmp;
+       wpa_printf(MSG_DEBUG, "%s", data->name);
+
+       return 0;
+}
+
+
 static int wpa_config_process_country(const struct global_parse_data *data,
                                      struct wpa_config *config, int line,
                                      const char *pos)
@@ -2821,6 +2853,7 @@ static int wpa_config_process_hessid(
 #define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f)
 #define STR(f) _STR(f), NULL, NULL
 #define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
+#define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL
 
 static const struct global_parse_data global_fields[] = {
 #ifdef CONFIG_CTRL_IFACE
@@ -2884,7 +2917,11 @@ static const struct global_parse_data global_fields[] = {
        { FUNC(hessid), 0 },
        { INT_RANGE(access_network_type, 0, 15), 0 },
        { INT_RANGE(pbc_in_m1, 0, 1), 0 },
-       { STR(autoscan), 0 }
+       { STR(autoscan), 0 },
+       { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 },
+       { BIN(wps_nfc_dh_pubkey), 0 },
+       { BIN(wps_nfc_dh_privkey), 0 },
+       { BIN(wps_nfc_dev_pw), 0 }
 };
 
 #undef FUNC
@@ -2894,6 +2931,7 @@ static const struct global_parse_data global_fields[] = {
 #undef _STR
 #undef STR
 #undef STR_RANGE
+#undef BIN
 #define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
 
 
index fd6aeb381bb64ae5ef5e5ccc1735d77ec4559720..46c4da247d26cc91efa0252ef4e14671c9f2aa31 100644 (file)
@@ -641,6 +641,26 @@ struct wpa_config {
         * <autoscan module name>:<module parameters>
         */
        char *autoscan;
+
+       /**
+        * wps_nfc_dev_pw_id - NFC Device Password ID for password token
+        */
+       int wps_nfc_dev_pw_id;
+
+       /**
+        * wps_nfc_dh_pubkey - NFC DH Public Key for password token
+        */
+       struct wpabuf *wps_nfc_dh_pubkey;
+
+       /**
+        * wps_nfc_dh_pubkey - NFC DH Private Key for password token
+        */
+       struct wpabuf *wps_nfc_dh_privkey;
+
+       /**
+        * wps_nfc_dh_pubkey - NFC Device Password for password token
+        */
+       struct wpabuf *wps_nfc_dev_pw;
 };
 
 
index 6d31ec1e0cb84b71b202de57375fae0b02a96bd6..8badc7b97c9187ca7dfabde5b7203ddb99f059c2 100644 (file)
@@ -320,7 +320,7 @@ static int wpa_config_process_blob(struct wpa_config *config, FILE *f,
 struct wpa_config * wpa_config_read(const char *name)
 {
        FILE *f;
-       char buf[256], *pos;
+       char buf[512], *pos;
        int errors = 0, line = 0;
        struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
        struct wpa_cred *cred, *cred_tail = NULL, *cred_head = NULL;
@@ -698,6 +698,23 @@ static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
 #endif /* CONFIG_NO_CONFIG_BLOBS */
 
 
+static void write_global_bin(FILE *f, const char *field,
+                            const struct wpabuf *val)
+{
+       size_t i;
+       const u8 *pos;
+
+       if (val == NULL)
+               return;
+
+       fprintf(f, "%s=", field);
+       pos = wpabuf_head(val);
+       for (i = 0; i < wpabuf_len(val); i++)
+               fprintf(f, "%02X", *pos++);
+       fprintf(f, "\n");
+}
+
+
 static void wpa_config_write_global(FILE *f, struct wpa_config *config)
 {
 #ifdef CONFIG_CTRL_IFACE
@@ -852,6 +869,12 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
 #endif /* CONFIG_INTERWORKING */
        if (config->pbc_in_m1)
                fprintf(f, "pbc_in_m1=%u\n", config->pbc_in_m1);
+       if (config->wps_nfc_dev_pw_id)
+               fprintf(f, "wps_nfc_dev_pw_id=%d\n",
+                       config->wps_nfc_dev_pw_id);
+       write_global_bin(f, "wps_nfc_dh_pubkey", config->wps_nfc_dh_pubkey);
+       write_global_bin(f, "wps_nfc_dh_privkey", config->wps_nfc_dh_privkey);
+       write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
index ec8c8a1e47be1d23088485d49d72c61554787d2c..2ef42aca2d8848324c850bd0a74ae2a235af65e0 100644 (file)
@@ -619,6 +619,49 @@ static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
 
        return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
 }
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
+                                            char *cmd)
+{
+       u8 bssid[ETH_ALEN], *_bssid = bssid;
+
+       if (cmd == NULL || cmd[0] == '\0')
+               _bssid = NULL;
+       else if (hwaddr_aton(cmd, bssid))
+               return -1;
+
+       return wpas_wps_start_nfc(wpa_s, _bssid);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc_token(
+       struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+       int ndef;
+       struct wpabuf *buf;
+       int res;
+
+       if (os_strcmp(cmd, "WPS") == 0)
+               ndef = 0;
+       else if (os_strcmp(cmd, "NDEF") == 0)
+               ndef = 1;
+       else
+               return -1;
+
+       buf = wpas_wps_nfc_token(wpa_s, 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;
+}
 #endif /* CONFIG_WPS_OOB */
 
 
@@ -4048,6 +4091,15 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
                if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
                        reply_len = -1;
+       } else if (os_strcmp(buf, "WPS_NFC") == 0) {
+               if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
+               if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
+               reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
+                       wpa_s, buf + 14, reply, reply_size);
 #endif /* CONFIG_WPS_OOB */
        } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
                if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
index cff7df8d0a11d97c5cbede012c02943e93fed63b..ba311dff3b5c8c21238c58a63cbf275f35d06a34 100644 (file)
@@ -845,6 +845,48 @@ static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
        }
        return wpa_ctrl_command(ctrl, cmd);
 }
+
+
+static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc >= 1)
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC %s",
+                                 argv[0]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC");
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long WPS_NFC command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid WPS_NFC_TOKEN command: need one argument:\n"
+                      "format: WPS or NDEF\n");
+               return -1;
+       }
+       if (argc >= 1)
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s",
+                                 argv[0]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN");
+       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_OOB */
 
 
@@ -3041,6 +3083,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "wps_oob", wpa_cli_cmd_wps_oob,
          cli_cmd_flag_sensitive,
          "<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
+       { "wps_nfc", wpa_cli_cmd_wps_nfc,
+         cli_cmd_flag_none,
+         "[BSSID] = start Wi-Fi Protected Setup: NFC" },
+       { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token,
+         cli_cmd_flag_none,
+         "<WPS|NDEF> = create password token" },
 #endif /* CONFIG_WPS_OOB */
        { "wps_reg", wpa_cli_cmd_wps_reg,
          cli_cmd_flag_sensitive,
index 78e116695ac681521e78f4dcea31ff1fbd68b73b..cd16e21d723464f5d4aac75d8618e345c57697c2 100644 (file)
@@ -11,6 +11,7 @@
 #include "common.h"
 #include "eloop.h"
 #include "uuid.h"
+#include "crypto/random.h"
 #include "crypto/dh_group5.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
@@ -1760,3 +1761,89 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
                wps->dev.serial_number = wpa_s->conf->serial_number;
        }
 }
+
+
+#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, 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);
+
+       wpa_s->conf->wps_nfc_dev_pw_id = 0x10 + os_random() % 0xfff0;
+       wpabuf_free(wpa_s->conf->wps_nfc_dh_pubkey);
+       wpa_s->conf->wps_nfc_dh_pubkey = pub;
+       wpabuf_free(wpa_s->conf->wps_nfc_dh_privkey);
+       wpa_s->conf->wps_nfc_dh_privkey = priv;
+       wpabuf_free(wpa_s->conf->wps_nfc_dev_pw);
+       wpa_s->conf->wps_nfc_dev_pw = pw;
+
+       ret = wps_build_nfc_pw_token(wpa_s->conf->wps_nfc_dev_pw_id,
+                                    wpa_s->conf->wps_nfc_dh_pubkey,
+                                    wpa_s->conf->wps_nfc_dev_pw);
+       if (ndef) {
+               struct wpabuf *tmp;
+               tmp = ndef_build_wifi(ret);
+               wpabuf_free(ret);
+               if (tmp == NULL)
+                       return NULL;
+               ret = tmp;
+       }
+
+       return ret;
+}
+
+
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+       struct wps_context *wps = wpa_s->wps;
+       char pw[32 * 2 + 1];
+
+       if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
+           wpa_s->conf->wps_nfc_dh_privkey == NULL ||
+           wpa_s->conf->wps_nfc_dev_pw == NULL)
+               return -1;
+
+       dh5_free(wps->dh_ctx);
+       wpabuf_free(wps->dh_pubkey);
+       wpabuf_free(wps->dh_privkey);
+       wps->dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+       wps->dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+       if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
+               wps->dh_ctx = NULL;
+               wpabuf_free(wps->dh_pubkey);
+               wps->dh_pubkey = NULL;
+               wpabuf_free(wps->dh_privkey);
+               wps->dh_privkey = NULL;
+               return -1;
+       }
+       wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
+       if (wps->dh_ctx == NULL)
+               return -1;
+
+       wpa_snprintf_hex_uppercase(pw, sizeof(pw),
+                                  wpabuf_head(wpa_s->conf->wps_nfc_dev_pw),
+                                  wpabuf_len(wpa_s->conf->wps_nfc_dev_pw));
+       return wpas_wps_start_pin(wpa_s, bssid, pw, 0,
+                                 wpa_s->conf->wps_nfc_dev_pw_id);
+}
+
+#endif /* CONFIG_WPS_NFC */
index a5472a0c1d9d255d280db019951bce3166f14f8c..6ce0e7bc6b27fc4a16c1e45199a3d883e2e3ad0a 100644 (file)
@@ -62,6 +62,8 @@ int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
 int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s);
 int wpas_wps_in_progress(struct wpa_supplicant *wpa_s);
 void wpas_wps_update_config(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
 
 #else /* CONFIG_WPS */