WPS: Do not disable AP PIN permanently, only slow down attacks
authorJouni Malinen <j@w1.fi>
Tue, 24 Aug 2010 12:24:05 +0000 (15:24 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 24 Aug 2010 12:24:05 +0000 (15:24 +0300)
As a compromise between usability and security, do not disable
AP PIN permanently based on failed PIN validations. Instead, go to
AP Setup Locked state for increasing amount of time between each
failure to slow down brute force attacks against the AP PIN.

This avoids problems with some external Registrars that may try
to use the same PIN multiple times without user input. Now, the
user will still be able to fix the PIN and try again later while
a real attack is delayed enough to make it impractical.

src/ap/hostapd.h
src/ap/wps_hostapd.c
src/common/wpa_ctrl.h

index 5bf4040..d0d67c8 100644 (file)
@@ -167,6 +167,7 @@ struct hostapd_data {
 #ifdef CONFIG_WPS
        unsigned int ap_pin_failures;
        struct upnp_wps_device_sm *wps_upnp;
+       unsigned int ap_pin_lockout_time;
 #endif /* CONFIG_WPS */
 
        struct hostapd_probereq_cb *probereq_cb;
index c63b7fc..d0e7e0a 100644 (file)
@@ -421,20 +421,36 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
 }
 
 
+static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
+{
+       struct hostapd_data *hapd = eloop_data;
+
+       if (hapd->conf->ap_setup_locked)
+               return;
+
+       wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN");
+       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);
+
+}
+
+
 static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
                                  struct wps_event_pwd_auth_fail *data)
 {
-       FILE *f;
-
        if (!data->enrollee || hapd->conf->ap_pin == NULL)
                return;
 
        /*
         * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup
-        * if this happens multiple times.
+        * for some time if this happens multiple times to slow down brute
+        * force attacks.
         */
        hapd->ap_pin_failures++;
-       if (hapd->ap_pin_failures < 4)
+       wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u",
+                  hapd->ap_pin_failures);
+       if (hapd->ap_pin_failures < 3)
                return;
 
        wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
@@ -442,23 +458,22 @@ static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
 
        wps_registrar_update_ie(hapd->wps->registrar);
 
-       if (hapd->conf->wps_cred_processing == 1)
-               return;
-
-       f = fopen(hapd->iface->config_fname, "a");
-       if (f == NULL) {
-               wpa_printf(MSG_WARNING, "WPS: Could not append to the current "
-                          "configuration file");
-               return;
+       if (!hapd->conf->ap_setup_locked) {
+               if (hapd->ap_pin_lockout_time == 0)
+                       hapd->ap_pin_lockout_time = 60;
+               else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 &&
+                        (hapd->ap_pin_failures % 3) == 0)
+                       hapd->ap_pin_lockout_time *= 2;
+
+               wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds",
+                          hapd->ap_pin_lockout_time);
+               eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
+               eloop_register_timeout(hapd->ap_pin_lockout_time, 0,
+                                      hostapd_wps_reenable_ap_pin, hapd,
+                                      NULL);
        }
 
-       fprintf(f, "# WPS AP Setup Locked based on possible attack\n");
-       fprintf(f, "ap_setup_locked=1\n");
-       fclose(f);
-
-       /* TODO: dualband AP may need to update multiple configuration files */
-
-       wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
+       /* TODO: dualband AP may need to update other interfaces */
 }
 
 
@@ -667,6 +682,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);
        if (hapd->wps == NULL)
                return;
 #ifdef CONFIG_WPS_UPNP
index ac88e8f..0c4a965 100644 (file)
@@ -93,6 +93,7 @@ extern "C" {
 #define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
 #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 AP_STA_CONNECTED "AP-STA-CONNECTED "
 #define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "