Added an optional mitigation mechanism for certain attacks against TKIP by

delaying Michael MIC error reports by a random amount of time between 0 and
60 seconds if multiple Michael MIC failures are detected with the same PTK
(i.e., the Authenticator does not rekey PTK on first failure report). This
is disabled by default and can be enabled with a build option
CONFIG_DELAYED_MIC_ERROR_REPORT=y in .config.

This may help in making a chopchop attack take much longer time by forcing
the attacker to wait 60 seconds before knowing whether a modified frame
resulted in a MIC failure.
This commit is contained in:
Jouni Malinen 2008-11-08 04:43:12 +02:00 committed by Jouni Malinen
parent 6982784e20
commit 46690a3b9b
6 changed files with 94 additions and 4 deletions

View file

@ -8,6 +8,10 @@ ChangeLog for wpa_supplicant
* added a new network configuration option, wpa_ptk_rekey, that can be
used to enforce frequent PTK rekeying, e.g., to mitigate some attacks
against TKIP deficiencies
* added an optional mitigation mechanism for certain attacks against
TKIP by delaying Michael MIC error reports by a random amount of time
between 0 and 60 seconds; this can be enabled with a build option
CONFIG_DELAYED_MIC_ERROR_REPORT=y in .config
* fixed EAP-AKA to use RES Length field in AT_RES as length in bits,
not bytes

View file

@ -951,6 +951,10 @@ ifdef CONFIG_DEBUG_FILE
CFLAGS += -DCONFIG_DEBUG_FILE
endif
ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
CFLAGS += -DCONFIG_DELAYED_MIC_ERROR_REPORT
endif
OBJS += ../src/drivers/scan_helpers.o
OBJS_wpa_rm := ctrl_iface.o mlme.o ctrl_iface_unix.o

View file

@ -364,3 +364,7 @@ CONFIG_PEERKEY=y
# Enable privilege separation (see README 'Privilege separation' for details)
#CONFIG_PRIVSEP=y
# Enable mitigation against certain attacks against TKIP by delaying Michael
# MIC error reports by a random amount of time between 0 and 60 seconds
#CONFIG_DELAYED_MIC_ERROR_REPORT=y

View file

@ -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++;
}

View file

@ -334,6 +334,10 @@ struct wpa_supplicant {
struct wpa_client_mlme mlme;
int use_client_mlme;
int driver_4way_handshake;
int pending_mic_error_report;
int pending_mic_error_pairwise;
int mic_errors_seen; /* Michael MIC errors with the current PTK */
};

View file

@ -427,11 +427,16 @@ static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid)
}
static int wpa_supplicant_set_key(void *wpa_s, wpa_alg alg,
static int wpa_supplicant_set_key(void *_wpa_s, wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len)
{
struct wpa_supplicant *wpa_s = _wpa_s;
if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) {
/* Clear the MIC error counter when setting a new PTK. */
wpa_s->mic_errors_seen = 0;
}
return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
key, key_len);
}