aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2012-06-27 15:56:41 (GMT)
committerJouni Malinen <j@w1.fi>2012-06-27 18:22:12 (GMT)
commit3f2c8ba6d39d5c5184a8fdd121998dd0d7629f1f (patch)
treee63a9ec4c9a7a18b0de561fb48befbc5975e67a1
parent6b5a0c9466e42847d19d812a6f2854c099d78d27 (diff)
downloadhostap-3f2c8ba6d39d5c5184a8fdd121998dd0d7629f1f.zip
hostap-3f2c8ba6d39d5c5184a8fdd121998dd0d7629f1f.tar.gz
hostap-3f2c8ba6d39d5c5184a8fdd121998dd0d7629f1f.tar.bz2
WPS: Add new mechanism for NFC config method using password token
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>
-rw-r--r--src/wps/wps.h3
-rw-r--r--src/wps/wps_common.c24
-rw-r--r--wpa_supplicant/config.c40
-rw-r--r--wpa_supplicant/config.h20
-rw-r--r--wpa_supplicant/config_file.c25
-rw-r--r--wpa_supplicant/ctrl_iface.c52
-rw-r--r--wpa_supplicant/wpa_cli.c48
-rw-r--r--wpa_supplicant/wps_supplicant.c87
-rw-r--r--wpa_supplicant/wps_supplicant.h2
9 files changed, 299 insertions, 2 deletions
diff --git a/src/wps/wps.h b/src/wps/wps.h
index b49bb91..48ba76f 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -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);
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index c7c0c29..63857e0 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -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;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 80f87f4..a68b31e 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -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]))
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index fd6aeb3..46c4da2 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -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;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 6d31ec1..8badc7b 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -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 */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index ec8c8a1..2ef42ac 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -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))
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index cff7df8..ba311df 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -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,
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 78e1166..cd16e21 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -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 */
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index a5472a0..6ce0e7b 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -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 */