Added an optional mitigation mechanism for certain attacks against TKIP by
authorJouni Malinen <jouni.malinen@atheros.com>
Sat, 8 Nov 2008 02:43:12 +0000 (04:43 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 8 Nov 2008 02:43:12 +0000 (04:43 +0200)
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.

wpa_supplicant/ChangeLog
wpa_supplicant/Makefile
wpa_supplicant/defconfig
wpa_supplicant/events.c
wpa_supplicant/wpa_supplicant_i.h
wpa_supplicant/wpas_glue.c

index c41d2e8..1f7d8d6 100644 (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
 
index badda34..277894c 100644 (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
index 38435cd..2653654 100644 (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
index 45b5ac3..27dfd55 100644 (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++;
 }
 
 
index 9afae2a..a8fb6d2 100644 (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 */
 };
 
 
index d5e31eb..e1e2cd6 100644 (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);
 }