diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 24709eeb2..9f9d7e3a3 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -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 diff --git a/hostapd/hostapd.h b/hostapd/hostapd.h index db822cc64..b9b345b42 100644 --- a/hostapd/hostapd.h +++ b/hostapd/hostapd.h @@ -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 */ }; diff --git a/hostapd/wps_hostapd.c b/hostapd/wps_hostapd.c index 077e40017..2d9654456 100644 --- a/hostapd/wps_hostapd.c +++ b/hostapd/wps_hostapd.c @@ -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)); diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index f7cad572e..1bfc0d645 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -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 */ diff --git a/src/wps/wps.h b/src/wps/wps.h index 7524acbf1..e18adab24 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -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); diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c index 050f04305..48af3032e 100644 --- a/src/wps/wps_common.c +++ b/src/wps/wps_common.c @@ -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); +} diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c index dda8fc6ac..d02f1c0da 100644 --- a/src/wps/wps_enrollee.c +++ b/src/wps/wps_enrollee.c @@ -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; } diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h index da7f7699d..7221af377 100644 --- a/src/wps/wps_i.h +++ b/src/wps/wps_i.h @@ -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); diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 7ddd6494b..8ef982bd4 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -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); +} diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 2dd22f2e2..9b7360176 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -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; } }