|
@@ -862,6 +862,22 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s)
|
|
|
}
|
|
|
|
|
|
|
|
|
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
|
|
|
+static void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx,
|
|
|
+ void *sock_ctx)
|
|
|
+{
|
|
|
+ struct wpa_supplicant *wpa_s = eloop_ctx;
|
|
|
+
|
|
|
+ if (!wpa_s->pending_mic_error_report)
|
|
|
+ return;
|
|
|
+
|
|
|
+ wpa_printf(MSG_DEBUG, "WPA: Sending pending MIC error report");
|
|
|
+ wpa_sm_key_request(wpa_s->wpa, 1, wpa_s->pending_mic_error_pairwise);
|
|
|
+ wpa_s->pending_mic_error_report = 0;
|
|
|
+}
|
|
|
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
|
|
|
+
|
|
|
+
|
|
|
static void
|
|
|
wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
|
|
|
union wpa_event_data *data)
|
|
@@ -871,10 +887,25 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
|
|
|
|
|
|
wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected");
|
|
|
pairwise = (data && data->michael_mic_failure.unicast);
|
|
|
- wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
|
|
|
os_get_time(&t);
|
|
|
- if (wpa_s->last_michael_mic_error &&
|
|
|
- t.sec - wpa_s->last_michael_mic_error <= 60) {
|
|
|
+ if ((wpa_s->last_michael_mic_error &&
|
|
|
+ t.sec - wpa_s->last_michael_mic_error <= 60) ||
|
|
|
+ wpa_s->pending_mic_error_report) {
|
|
|
+ if (wpa_s->pending_mic_error_report) {
|
|
|
+ /*
|
|
|
+ * Send the pending MIC error report immediately since
|
|
|
+ * we are going to start countermeasures and AP better
|
|
|
+ * do the same.
|
|
|
+ */
|
|
|
+ wpa_sm_key_request(wpa_s->wpa, 1,
|
|
|
+ wpa_s->pending_mic_error_pairwise);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Send the new MIC error report immediately since we are going
|
|
|
+ * to start countermeasures and AP better do the same.
|
|
|
+ */
|
|
|
+ wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
|
|
|
+
|
|
|
/* initialize countermeasures */
|
|
|
wpa_s->countermeasures = 1;
|
|
|
wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
|
|
@@ -895,8 +926,46 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
|
|
|
wpa_s, NULL);
|
|
|
/* TODO: mark the AP rejected for 60 second. STA is
|
|
|
* allowed to associate with another AP.. */
|
|
|
+ } else {
|
|
|
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
|
|
|
+ if (wpa_s->mic_errors_seen) {
|
|
|
+ /*
|
|
|
+ * Reduce the effectiveness of Michael MIC error
|
|
|
+ * reports as a means for attacking against TKIP if
|
|
|
+ * more than one MIC failure is noticed with the same
|
|
|
+ * PTK. We delay the transmission of the reports by a
|
|
|
+ * random time between 0 and 60 seconds in order to
|
|
|
+ * force the attacker wait 60 seconds before getting
|
|
|
+ * the information on whether a frame resulted in a MIC
|
|
|
+ * failure.
|
|
|
+ */
|
|
|
+ u8 rval[4];
|
|
|
+ int sec;
|
|
|
+
|
|
|
+ if (os_get_random(rval, sizeof(rval)) < 0)
|
|
|
+ sec = os_random() % 60;
|
|
|
+ else
|
|
|
+ sec = WPA_GET_BE32(rval) % 60;
|
|
|
+ wpa_printf(MSG_DEBUG, "WPA: Delay MIC error report %d "
|
|
|
+ "seconds", sec);
|
|
|
+ wpa_s->pending_mic_error_report = 1;
|
|
|
+ wpa_s->pending_mic_error_pairwise = pairwise;
|
|
|
+ eloop_cancel_timeout(
|
|
|
+ wpa_supplicant_delayed_mic_error_report,
|
|
|
+ wpa_s, NULL);
|
|
|
+ eloop_register_timeout(
|
|
|
+ sec, os_random() % 1000000,
|
|
|
+ wpa_supplicant_delayed_mic_error_report,
|
|
|
+ wpa_s, NULL);
|
|
|
+ } else {
|
|
|
+ wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
|
|
|
+ }
|
|
|
+#else /* CONFIG_DELAYED_MIC_ERROR_REPORT */
|
|
|
+ wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
|
|
|
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
|
|
|
}
|
|
|
wpa_s->last_michael_mic_error = t.sec;
|
|
|
+ wpa_s->mic_errors_seen++;
|
|
|
}
|
|
|
|
|
|
|