]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
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 c41d2e8511a8d8351681e191702dfe6ed3668d3b..1f7d8d65a5c3031c213a66016d8d3779048051f5 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 badda34da4d70169fa5c88395810d2254f1db725..277894c1381259f79e210ed7c0e859c30c637232 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 38435cd10b6c343c5b4ac557f3f1759edd85bd1c..2653654eb4557cc3cd59d5ffa1cee02df37704d6 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 45b5ac3a32ee9891134a919944f256cb846892ee..27dfd55ff85583b2a1ae3c2cca3db0f74d27df10 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 9afae2a9817e03c13d3b1fcb36594e3db5f2093b..a8fb6d22bcb0d302daf531715a9a0157cf1ba558 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 d5e31ebb0d3d77ad53dc9ba1735afeeeb07e4800..e1e2cd66e79b3eed69fb61cffec1a6b42a8bbb83 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);
 }