WPS: Add support for setting timeout for PIN

hostapd_cli wps_pin command can now have an optional timeout
parameter that sets the PIN lifetime in seconds. This can be used
to reduce the likelihood of someone else using the PIN should an
active PIN be left in the Registrar.
This commit is contained in:
Jouni Malinen 2009-05-26 17:44:44 +03:00 committed by Jouni Malinen
parent b63303b864
commit 077a781f7a
9 changed files with 84 additions and 19 deletions

View File

@ -165,10 +165,17 @@ Example command to add a PIN (12345670) for an Enrollee:
hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c 12345670 hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c 12345670
If the UUID-E is not available (e.g., Enrollee waits for the Registrar If the UUID-E is not available (e.g., Enrollee waits for the Registrar
to be selected before connecting), wildcard UUID may be used to allow the PIN to be used once with any UUID: to be selected before connecting), wildcard UUID may be used to allow
the PIN to be used once with any UUID:
hostapd_cli wps_pin any 12345670 hostapd_cli wps_pin any 12345670
To reduce likelihood of PIN being used with other devices or of
forgetting an active PIN available for potential attackers, expiration
time can be set for the new PIN:
hostapd_cli wps_pin any 12345670 300
After this, the Enrollee can connect to the AP again and complete WPS After this, the Enrollee can connect to the AP again and complete WPS
negotiation. At that point, a new, random WPA PSK is generated for the negotiation. At that point, a new, random WPA PSK is generated for the

View File

@ -256,10 +256,21 @@ static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt) static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
{ {
char *pin = os_strchr(txt, ' '); char *pin = os_strchr(txt, ' ');
char *timeout_txt;
int timeout;
if (pin == NULL) if (pin == NULL)
return -1; return -1;
*pin++ = '\0'; *pin++ = '\0';
return hostapd_wps_add_pin(hapd, txt, pin);
timeout_txt = os_strchr(pin, ' ');
if (timeout_txt) {
*timeout_txt++ = '\0';
timeout = atoi(timeout_txt);
} else
timeout = 0;
return hostapd_wps_add_pin(hapd, txt, pin, timeout);
} }

View File

@ -87,7 +87,7 @@ static const char *commands_help =
" sa_query <addr> send SA Query to a station\n" " sa_query <addr> send SA Query to a station\n"
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS #ifdef CONFIG_WPS
" wps_pin <uuid> <pin> add WPS Enrollee PIN (Device Password)\n" " wps_pin <uuid> <pin> [timeout] add WPS Enrollee PIN (Device Password)\n"
" wps_pbc indicate button pushed to initiate PBC\n" " wps_pbc indicate button pushed to initiate PBC\n"
#ifdef CONFIG_WPS_OOB #ifdef CONFIG_WPS_OOB
" wps_oob <type> <path> <method> use WPS with out-of-band (UFD)\n" " wps_oob <type> <path> <method> use WPS with out-of-band (UFD)\n"
@ -263,12 +263,16 @@ static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[]) char *argv[])
{ {
char buf[64]; char buf[64];
if (argc != 2) { if (argc < 2) {
printf("Invalid 'wps_pin' command - exactly two arguments, " printf("Invalid 'wps_pin' command - at least two arguments, "
"UUID and PIN, are required.\n"); "UUID and PIN, are required.\n");
return -1; return -1;
} }
snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]); if (argc > 2)
snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
argv[0], argv[1], argv[2]);
else
snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
return wpa_ctrl_command(ctrl, buf); return wpa_ctrl_command(ctrl, buf);
} }

View File

@ -704,7 +704,7 @@ void hostapd_deinit_wps(struct hostapd_data *hapd)
int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid, int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
const char *pin) const char *pin, int timeout)
{ {
u8 u[UUID_LEN]; u8 u[UUID_LEN];
int any = 0; int any = 0;
@ -716,7 +716,8 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
else if (uuid_str2bin(uuid, u)) else if (uuid_str2bin(uuid, u))
return -1; return -1;
return wps_registrar_add_pin(hapd->wps->registrar, any ? NULL : u, return wps_registrar_add_pin(hapd->wps->registrar, any ? NULL : u,
(const u8 *) pin, os_strlen(pin)); (const u8 *) pin, os_strlen(pin),
timeout);
} }
@ -766,7 +767,8 @@ int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E || if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) && wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
hostapd_wps_add_pin(hapd, "any", hostapd_wps_add_pin(hapd, "any",
wpabuf_head(wps->oob_conf.dev_password)) < 0) wpabuf_head(wps->oob_conf.dev_password), 0) <
0)
goto error; goto error;
return 0; return 0;

View File

@ -21,7 +21,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
struct hostapd_bss_config *conf); struct hostapd_bss_config *conf);
void hostapd_deinit_wps(struct hostapd_data *hapd); void hostapd_deinit_wps(struct hostapd_data *hapd);
int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid, int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
const char *pin); const char *pin, int timeout);
int hostapd_wps_button_pushed(struct hostapd_data *hapd); int hostapd_wps_button_pushed(struct hostapd_data *hapd);
int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type, int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
char *path, char *method, char *name); char *path, char *method, char *name);

View File

@ -144,7 +144,7 @@ static void * eap_wsc_init(struct eap_sm *sm)
if (registrar && cfg.pin) { if (registrar && cfg.pin) {
wps_registrar_add_pin(data->wps_ctx->registrar, NULL, wps_registrar_add_pin(data->wps_ctx->registrar, NULL,
cfg.pin, cfg.pin_len); cfg.pin, cfg.pin_len, 0);
} }
return data; return data;

View File

@ -552,7 +552,7 @@ wps_registrar_init(struct wps_context *wps,
const struct wps_registrar_config *cfg); const struct wps_registrar_config *cfg);
void wps_registrar_deinit(struct wps_registrar *reg); void wps_registrar_deinit(struct wps_registrar *reg);
int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid, int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
const u8 *pin, size_t pin_len); const u8 *pin, size_t pin_len, int timeout);
int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid); int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid);
int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid); int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
int wps_registrar_button_pushed(struct wps_registrar *reg); int wps_registrar_button_pushed(struct wps_registrar *reg);

View File

@ -32,7 +32,10 @@ struct wps_uuid_pin {
int wildcard_uuid; int wildcard_uuid;
u8 *pin; u8 *pin;
size_t pin_len; size_t pin_len;
int locked; #define PIN_LOCKED BIT(0)
#define PIN_EXPIRES BIT(1)
int flags;
struct os_time expiration;
}; };
@ -413,10 +416,11 @@ void wps_registrar_deinit(struct wps_registrar *reg)
* @uuid: UUID-E or %NULL for wildcard (any UUID) * @uuid: UUID-E or %NULL for wildcard (any UUID)
* @pin: PIN (Device Password) * @pin: PIN (Device Password)
* @pin_len: Length of pin in octets * @pin_len: Length of pin in octets
* @timeout: Time (in seconds) when the PIN will be invalidated; 0 = no timeout
* Returns: 0 on success, -1 on failure * Returns: 0 on success, -1 on failure
*/ */
int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid, int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
const u8 *pin, size_t pin_len) const u8 *pin, size_t pin_len, int timeout)
{ {
struct wps_uuid_pin *p; struct wps_uuid_pin *p;
@ -435,10 +439,17 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
os_memcpy(p->pin, pin, pin_len); os_memcpy(p->pin, pin, pin_len);
p->pin_len = pin_len; p->pin_len = pin_len;
if (timeout) {
p->flags |= PIN_EXPIRES;
os_get_time(&p->expiration);
p->expiration.sec += timeout;
}
p->next = reg->pins; p->next = reg->pins;
reg->pins = p; reg->pins = p;
wpa_printf(MSG_DEBUG, "WPS: A new PIN configured"); wpa_printf(MSG_DEBUG, "WPS: A new PIN configured (timeout=%d)",
timeout);
wpa_hexdump(MSG_DEBUG, "WPS: UUID", uuid, WPS_UUID_LEN); wpa_hexdump(MSG_DEBUG, "WPS: UUID", uuid, WPS_UUID_LEN);
wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len); wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len);
reg->selected_registrar = 1; reg->selected_registrar = 1;
@ -449,6 +460,34 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
} }
static void wps_registrar_expire_pins(struct wps_registrar *reg)
{
struct wps_uuid_pin *pin, *prev, *del;
struct os_time now;
os_get_time(&now);
prev = NULL;
pin = reg->pins;
while (pin) {
if ((pin->flags & PIN_EXPIRES) &&
os_time_before(&pin->expiration, &now)) {
if (prev == NULL)
reg->pins = pin->next;
else
prev->next = pin->next;
del = pin;
pin = pin->next;
wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID",
del->uuid, WPS_UUID_LEN);
wps_free_pin(del);
continue;
}
prev = pin;
pin = pin->next;
}
}
/** /**
* wps_registrar_invalidate_pin - Invalidate a PIN for a specific UUID-E * wps_registrar_invalidate_pin - Invalidate a PIN for a specific UUID-E
* @reg: Registrar data from wps_registrar_init() * @reg: Registrar data from wps_registrar_init()
@ -485,6 +524,8 @@ static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,
{ {
struct wps_uuid_pin *pin; struct wps_uuid_pin *pin;
wps_registrar_expire_pins(reg);
pin = reg->pins; pin = reg->pins;
while (pin) { while (pin) {
if (!pin->wildcard_uuid && if (!pin->wildcard_uuid &&
@ -516,13 +557,13 @@ static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,
* Lock the PIN to avoid attacks based on concurrent re-use of the PIN * Lock the PIN to avoid attacks based on concurrent re-use of the PIN
* that could otherwise avoid PIN invalidations. * that could otherwise avoid PIN invalidations.
*/ */
if (pin->locked) { if (pin->flags & PIN_LOCKED) {
wpa_printf(MSG_DEBUG, "WPS: Selected PIN locked - do not " wpa_printf(MSG_DEBUG, "WPS: Selected PIN locked - do not "
"allow concurrent re-use"); "allow concurrent re-use");
return NULL; return NULL;
} }
*pin_len = pin->pin_len; *pin_len = pin->pin_len;
pin->locked = 1; pin->flags |= PIN_LOCKED;
return pin->pin; return pin->pin;
} }
@ -549,7 +590,7 @@ int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid)
"wildcard PIN"); "wildcard PIN");
return wps_registrar_invalidate_pin(reg, uuid); return wps_registrar_invalidate_pin(reg, uuid);
} }
pin->locked = 0; pin->flags &= ~PIN_LOCKED;
return 0; return 0;
} }
pin = pin->next; pin = pin->next;

View File

@ -541,7 +541,7 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
pin = buf; pin = buf;
} }
ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], "any", pin); ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], "any", pin, 0);
if (ret) if (ret)
return -1; return -1;
return ret_len; return ret_len;