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>
This commit is contained in:
parent
6b5a0c9466
commit
3f2c8ba6d3
9 changed files with 299 additions and 2 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]))
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in a new issue