WPS: Add support for dynamic AP PIN management

A new hostapd_cli command, wps_ap_pin, can now be used to manage
AP PIN at runtime. This can be used to generate a random AP PIN and
to only enable the AP PIN for short period (e.g., based on user
action on the AP device). Use of random AP PIN that is only enabled
for short duration is highly recommended to avoid security issues
with a static AP PIN.
This commit is contained in:
Jouni Malinen 2010-08-24 16:35:37 +03:00
parent 944814106e
commit 5a1cc30f1a
9 changed files with 210 additions and 5 deletions

View file

@ -195,6 +195,33 @@ which will generate a new WPA PSK in the same way as the PIN method
described above.
When an external Registrar is used, the AP can act as an Enrollee and
use its AP PIN. A static AP PIN (e.g., one one a label in the AP
device) can be configured in hostapd.conf (ap_pin parameter). A more
secure option is to use hostapd_cli wps_ap_pin command to enable the
AP PIN only based on user action (and even better security by using a
random AP PIN for each session, i.e., by using "wps_ap_pin random"
command with a timeout value). Following commands are available for
managing the dynamic AP PIN operations:
hostapd_cli wps_ap_pin disable
- disable AP PIN (i.e., do not allow external Registrars to use it to
learn the current AP settings or to reconfigure the AP)
hostapd_cli wps_ap_pin random [timeout]
- generate a random AP PIN and enable it
- if the optional timeout parameter is given, the AP PIN will be enabled
for the specified number of seconds
hostapd_cli wps_ap_pin get
- fetch the current AP PIN
hostapd_cli wps_ap_pin set <PIN> [timeout]
- set the AP PIN and enable it
- if the optional timeout parameter is given, the AP PIN will be enabled
for the specified number of seconds
Credential generation and configuration changes
-----------------------------------------------

View file

@ -313,6 +313,59 @@ static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
return hostapd_wps_start_oob(hapd, txt, path, method, name);
}
#endif /* CONFIG_WPS_OOB */
static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
char *buf, size_t buflen)
{
int timeout = 300;
char *pos;
const char *pin_txt;
pos = os_strchr(txt, ' ');
if (pos)
*pos++ = '\0';
if (os_strcmp(txt, "disable") == 0) {
hostapd_wps_ap_pin_disable(hapd);
return os_snprintf(buf, buflen, "OK\n");
}
if (os_strcmp(txt, "random") == 0) {
if (pos)
timeout = atoi(pos);
pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
if (pin_txt == NULL)
return -1;
return os_snprintf(buf, buflen, "%s", pin_txt);
}
if (os_strcmp(txt, "get") == 0) {
pin_txt = hostapd_wps_ap_pin_get(hapd);
if (pin_txt == NULL)
return -1;
return os_snprintf(buf, buflen, "%s", pin_txt);
}
if (os_strcmp(txt, "set") == 0) {
char *pin;
if (pos == NULL)
return -1;
pin = pos;
pos = os_strchr(pos, ' ');
if (pos) {
*pos++ = '\0';
timeout = atoi(pos);
}
if (os_strlen(pin) > buflen)
return -1;
if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
return -1;
return os_snprintf(buf, buflen, "%s", pin);
}
return -1;
}
#endif /* CONFIG_WPS */
@ -426,6 +479,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
reply_len = -1;
#endif /* CONFIG_WPS_OOB */
} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
reply, reply_size);
#endif /* CONFIG_WPS */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);

View file

@ -916,9 +916,13 @@ own_ip_addr=127.0.0.1
# nfc_interface push_button keypad
#config_methods=label display push_button keypad
# Access point PIN for initial configuration and adding Registrars
# Static access point PIN for initial configuration and adding Registrars
# If not set, hostapd will not allow external WPS Registrars to control the
# access point.
# access point. The AP PIN can also be set at runtime with hostapd_cli
# wps_ap_pin command. Use of temporary (enabled by user action) and random
# AP PIN is much more secure than configuring a static AP PIN here. As such,
# use of the ap_pin parameter is not recommended if the AP device has means for
# displaying a random PIN.
#ap_pin=12345670
# Skip building of automatic WPS credential

View file

@ -94,6 +94,7 @@ static const char *commands_help =
#ifdef CONFIG_WPS_OOB
" wps_oob <type> <path> <method> use WPS with out-of-band (UFD)\n"
#endif /* CONFIG_WPS_OOB */
" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
#endif /* CONFIG_WPS */
" help show this usage help\n"
" interface [ifname] show interfaces/select interface\n"
@ -405,6 +406,27 @@ static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
return wpa_ctrl_command(ctrl, cmd);
}
#endif /* CONFIG_WPS_OOB */
static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[64];
if (argc < 1) {
printf("Invalid 'wps_ap_pin' command - at least one argument "
"is required.\n");
return -1;
}
if (argc > 2)
snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
argv[0], argv[1], argv[2]);
else if (argc > 1)
snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
argv[0], argv[1]);
else
snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
#endif /* CONFIG_WPS */
@ -567,6 +589,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
#ifdef CONFIG_WPS_OOB
{ "wps_oob", hostapd_cli_cmd_wps_oob },
#endif /* CONFIG_WPS_OOB */
{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
#endif /* CONFIG_WPS */
{ "help", hostapd_cli_cmd_help },
{ "interface", hostapd_cli_cmd_interface },

View file

@ -1,6 +1,6 @@
/*
* hostapd / WPS integration
* Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -42,6 +42,7 @@ static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
const u8 *ie, size_t ie_len);
static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
@ -432,7 +433,6 @@ static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
hapd->wps->ap_setup_locked = 0;
wps_registrar_update_ie(hapd->wps->registrar);
}
@ -683,6 +683,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
void hostapd_deinit_wps(struct hostapd_data *hapd)
{
eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
if (hapd->wps == NULL)
return;
#ifdef CONFIG_WPS_UPNP
@ -942,3 +943,72 @@ int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
return 0;
return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen);
}
static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
{
struct hostapd_data *hapd = eloop_data;
wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
hostapd_wps_ap_pin_disable(hapd);
}
static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout)
{
wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
hapd->ap_pin_failures = 0;
hapd->conf->ap_setup_locked = 0;
if (hapd->wps->ap_setup_locked) {
wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
hapd->wps->ap_setup_locked = 0;
wps_registrar_update_ie(hapd->wps->registrar);
}
eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
if (timeout > 0)
eloop_register_timeout(timeout, 0,
hostapd_wps_ap_pin_timeout, hapd, NULL);
}
void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd)
{
wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
os_free(hapd->conf->ap_pin);
hapd->conf->ap_pin = NULL;
upnp_wps_set_ap_pin(hapd->wps_upnp, NULL);
eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
}
const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
{
unsigned int pin;
char pin_txt[9];
pin = wps_generate_pin();
os_snprintf(pin_txt, sizeof(pin_txt), "%u", pin);
os_free(hapd->conf->ap_pin);
hapd->conf->ap_pin = os_strdup(pin_txt);
upnp_wps_set_ap_pin(hapd->wps_upnp, pin_txt);
hostapd_wps_ap_pin_enable(hapd, timeout);
return hapd->conf->ap_pin;
}
const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd)
{
return hapd->conf->ap_pin;
}
int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
int timeout)
{
os_free(hapd->conf->ap_pin);
hapd->conf->ap_pin = os_strdup(pin);
if (hapd->conf->ap_pin == NULL)
return -1;
upnp_wps_set_ap_pin(hapd->wps_upnp, hapd->conf->ap_pin);
hostapd_wps_ap_pin_enable(hapd, timeout);
return 0;
}

View file

@ -1,6 +1,6 @@
/*
* hostapd / WPS integration
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
* Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -28,6 +28,11 @@ int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
char *path, char *method, char *name);
int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
char *buf, size_t buflen);
void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd);
const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout);
const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd);
int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
int timeout);
#else /* CONFIG_WPS */

View file

@ -94,6 +94,8 @@ extern "C" {
#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS "
#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED "
#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED "
#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED "
#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "

View file

@ -1074,3 +1074,20 @@ int upnp_wps_subscribers(struct upnp_wps_device_sm *sm)
{
return !dl_list_empty(&sm->subscriptions);
}
int upnp_wps_set_ap_pin(struct upnp_wps_device_sm *sm, const char *ap_pin)
{
if (sm == NULL)
return 0;
os_free(sm->ctx->ap_pin);
if (ap_pin) {
sm->ctx->ap_pin = os_strdup(ap_pin);
if (sm->ctx->ap_pin == NULL)
return -1;
} else
sm->ctx->ap_pin = NULL;
return 0;
}

View file

@ -46,5 +46,6 @@ int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm,
enum upnp_wps_wlanevent_type ev_type,
const struct wpabuf *msg);
int upnp_wps_subscribers(struct upnp_wps_device_sm *sm);
int upnp_wps_set_ap_pin(struct upnp_wps_device_sm *sm, const char *ap_pin);
#endif /* WPS_UPNP_H */