]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WPS: Lock AP Setup on multiple AP PIN validation failures
authorJouni Malinen <j@w1.fi>
Fri, 23 Jan 2009 19:57:43 +0000 (21:57 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 23 Jan 2009 19:57:43 +0000 (21:57 +0200)
If a Registrar tries to configure the AP, but fails to validate the
device password (AP PIN), lock the AP setup after four failures. This
protects the AP PIN against brute force guessing attacks.

hostapd/hostapd.conf
hostapd/hostapd.h
hostapd/wps_hostapd.c
src/common/wpa_ctrl.h
src/wps/wps.h
src/wps/wps_common.c
src/wps/wps_enrollee.c
src/wps/wps_i.h
src/wps/wps_registrar.c
wpa_supplicant/wps_supplicant.c

index 24709eeb2ce7d604fea074e270876038be509df9..9f9d7e3a3e3ee4a345477f435df69cd5fe40bd2b 100644 (file)
@@ -956,6 +956,11 @@ own_ip_addr=127.0.0.1
 #      to external program(s)
 # Note: With wps_cred_processing=1, skip_cred_build should be set to 1 and
 # extra_cred be used to provide the Credential data for Enrollees.
+#
+# wps_cred_processing=1 will disabled automatic updates of hostapd.conf file
+# both for Credential processing and for marking AP Setup Locked based on
+# validation failures of AP PIN. An external program is responsible on updating
+# the configuration appropriately in this case.
 #wps_cred_processing=0
 
 # AP Settings Attributes for M7
index db822cc64a3715656f38da35de6b6c9e07ba4389..b9b345b427e8acdcc63d72b3a4a22381290a6671 100644 (file)
@@ -95,6 +95,7 @@ struct hostapd_data {
        size_t wps_beacon_ie_len;
        u8 *wps_probe_resp_ie;
        size_t wps_probe_resp_ie_len;
+       unsigned int ap_pin_failures;
 #endif /* CONFIG_WPS */
 };
 
index 077e40017f306ae63bd534c0aed5b4d49db5812c..2d96544561b7051f9cd723965a327d984a856ad9 100644 (file)
@@ -376,6 +376,57 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
 }
 
 
+static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
+                                 struct wps_event_pwd_auth_fail *data)
+{
+       FILE *f;
+
+       if (!data->enrollee)
+               return;
+
+       /*
+        * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup
+        * if this happens multiple times.
+        */
+       hapd->ap_pin_failures++;
+       if (hapd->ap_pin_failures < 4)
+               return;
+
+       wpa_msg(hapd, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
+       hapd->wps->ap_setup_locked = 1;
+
+       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;
+       }
+
+       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");
+}
+
+
+static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
+                                union wps_event_data *data)
+{
+       struct hostapd_data *hapd = ctx;
+
+       if (event == WPS_EV_PWD_AUTH_FAIL)
+               hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
+}
+
+
 static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
 {
        os_free(hapd->wps_beacon_ie);
@@ -406,6 +457,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
                return -1;
 
        wps->cred_cb = hostapd_wps_cred_cb;
+       wps->event_cb = hostapd_wps_event_cb;
        wps->cb_ctx = hapd;
 
        os_memset(&cfg, 0, sizeof(cfg));
index f7cad572e20353cebb86f59956247bf64b9e2d6f..1bfc0d6453468c897f107ec8c47f415556ddcc5d 100644 (file)
@@ -73,6 +73,7 @@ extern "C" {
 #define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
 #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 "
 
 
 /* wpa_supplicant/hostapd control interface access */
index 7524acbf1ef3a5fd828c4cce96b008aa47f3a35a..e18adab24f1cac9a93a652bffef75f42a07874dc 100644 (file)
@@ -278,7 +278,12 @@ enum wps_event {
        /**
         * WPS_EV_SUCCESS - Registration succeeded
         */
-       WPS_EV_SUCCESS
+       WPS_EV_SUCCESS,
+
+       /**
+        * WPS_EV_PWD_AUTH_FAIL - Password authentication failed
+        */
+       WPS_EV_PWD_AUTH_FAIL
 };
 
 /**
@@ -312,6 +317,11 @@ union wps_event_data {
        struct wps_event_fail {
                int msg;
        } fail;
+
+       struct wps_event_pwd_auth_fail {
+               int enrollee;
+               int part;
+       } pwd_auth_fail;
 };
 
 /**
@@ -444,6 +454,7 @@ int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
 int wps_registrar_button_pushed(struct wps_registrar *reg);
 void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
                                const struct wpabuf *wps_data);
+int wps_registrar_update_ie(struct wps_registrar *reg);
 
 unsigned int wps_pin_checksum(unsigned int pin);
 unsigned int wps_pin_valid(unsigned int pin);
index 050f04305533c0e9f5da132698a1c6df2c964ffe..48af3032e77e2d263917e3bb5725fbe6266b8e23 100644 (file)
@@ -321,3 +321,17 @@ void wps_success_event(struct wps_context *wps)
 
        wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL);
 }
+
+
+void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)
+{
+       union wps_event_data data;
+
+       if (wps->event_cb == NULL)
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       data.pwd_auth_fail.enrollee = enrollee;
+       data.pwd_auth_fail.part = part;
+       wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data);
+}
index dda8fc6ac2ad8f148711283e4c04b54d2b191849..d02f1c0dadff61fe8d475eaf475a3e19eaedb28b 100644 (file)
@@ -580,6 +580,7 @@ static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1)
                wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does "
                           "not match with the pre-committed value");
                wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+               wps_pwd_auth_fail_event(wps->wps, 1, 1);
                return -1;
        }
 
@@ -619,6 +620,7 @@ static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
                wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does "
                           "not match with the pre-committed value");
                wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+               wps_pwd_auth_fail_event(wps->wps, 1, 2);
                return -1;
        }
 
index da7f7699d117afbbdbcfa0e52b830d794eaa3640..7221af377fe84d0a35a4a874c2012ed976667cd7 100644 (file)
@@ -187,6 +187,7 @@ struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
                                          size_t encr_len);
 void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg);
 void wps_success_event(struct wps_context *wps);
+void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part);
 
 /* wps_attr_parse.c */
 int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
index 7ddd6494bdb4a376190aa4cecd02d1531f4bf612..8ef982bd483b77511773ef41428507d075718cdb 100644 (file)
@@ -1477,6 +1477,7 @@ static int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1)
                wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does "
                           "not match with the pre-committed value");
                wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+               wps_pwd_auth_fail_event(wps->wps, 0, 1);
                return -1;
        }
 
@@ -1517,6 +1518,7 @@ static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2)
                           "not match with the pre-committed value");
                wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e);
                wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+               wps_pwd_auth_fail_event(wps->wps, 0, 2);
                return -1;
        }
 
@@ -2219,3 +2221,9 @@ enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
                return WPS_FAILURE;
        }
 }
+
+
+int wps_registrar_update_ie(struct wps_registrar *reg)
+{
+       return wps_set_ie(reg);
+}
index 2dd22f2e24598fc119543584985122d5574dc8cc..9b73601762597eb9a978cc2500e5385e4ead8931 100644 (file)
@@ -275,6 +275,8 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
        case WPS_EV_SUCCESS:
                wpa_supplicant_wps_event_success(wpa_s);
                break;
+       case WPS_EV_PWD_AUTH_FAIL:
+               break;
        }
 }