wpa_supplicant: Add GTK RSC relaxation workaround
authorMax Stepanov <Max.Stepanov@intel.com>
Wed, 14 Oct 2015 09:26:33 +0000 (12:26 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 1 Nov 2015 19:00:22 +0000 (21:00 +0200)
Some APs may send RSC octets in EAPOL-Key message 3 of 4-Way Handshake
or in EAPOL-Key message 1 of Group Key Handshake in the opposite byte
order (or by some other corrupted way). Thus, after a successful
EAPOL-Key exchange the TSC values of received multicast packets, such as
DHCP, don't match the RSC one and as a result these packets are dropped
on replay attack TSC verification. An example of such AP is Sapido
RB-1732.

Work around this by setting RSC octets to 0 on GTK installation if the
AP RSC value is identified as a potentially having the byte order issue.
This may open a short window during which older (but valid)
group-addressed frames could be replayed. However, the local receive
counter will be updated on the first received group-addressed frame and
the workaround is enabled only if the common invalid cases are detected,
so this workaround is acceptable as not decreasing security
significantly. The wpa_rsc_relaxation global configuration property
allows the GTK RSC workaround to be disabled if it's not needed.

Signed-off-by: Max Stepanov <Max.Stepanov@intel.com>
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
src/rsn_supp/wpa_i.h
wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.c
wpa_supplicant/wpas_glue.c

index 505c7a1..0b5fe51 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * WPA Supplicant - WPA state machine and EAPOL-Key processing
  * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright(c) 2015 Intel Deutschland GmbH
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -23,6 +24,9 @@
 #include "peerkey.h"
 
 
+static const u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+
 /**
  * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -611,7 +615,6 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
        int keylen, rsclen;
        enum wpa_alg alg;
        const u8 *key_rsc;
-       u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
        if (!sm->tk_to_set) {
                wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
@@ -768,12 +771,43 @@ static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm,
 }
 
 
+static int wpa_supplicant_rsc_relaxation(const struct wpa_sm *sm,
+                                        const u8 *rsc)
+{
+       int rsclen;
+
+       if (!sm->wpa_rsc_relaxation)
+               return 0;
+
+       rsclen = wpa_cipher_rsc_len(sm->group_cipher);
+
+       /*
+        * Try to detect RSC (endian) corruption issue where the AP sends
+        * the RSC bytes in EAPOL-Key message in the wrong order, both if
+        * it's actually a 6-byte field (as it should be) and if it treats
+        * it as an 8-byte field.
+        * An AP model known to have this bug is the Sapido RB-1632.
+        */
+       if (rsclen == 6 && ((rsc[5] && !rsc[0]) || rsc[6] || rsc[7])) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "RSC %02x%02x%02x%02x%02x%02x%02x%02x is likely bogus, using 0",
+                       rsc[0], rsc[1], rsc[2], rsc[3],
+                       rsc[4], rsc[5], rsc[6], rsc[7]);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+
 static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
                                       const struct wpa_eapol_key *key,
                                       const u8 *gtk, size_t gtk_len,
                                       int key_info)
 {
        struct wpa_gtk_data gd;
+       const u8 *key_rsc;
 
        /*
         * IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x
@@ -799,11 +833,15 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
        os_memcpy(gd.gtk, gtk, gtk_len);
        gd.gtk_len = gtk_len;
 
+       key_rsc = key->key_rsc;
+       if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc))
+               key_rsc = null_rsc;
+
        if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED &&
            (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
                                               gtk_len, gtk_len,
                                               &gd.key_rsc_len, &gd.alg) ||
-            wpa_supplicant_install_gtk(sm, &gd, key->key_rsc))) {
+            wpa_supplicant_install_gtk(sm, &gd, key_rsc))) {
                wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
                        "RSN: Failed to install GTK");
                os_memset(&gd, 0, sizeof(gd));
@@ -1464,6 +1502,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
        u16 key_info;
        int rekey, ret;
        struct wpa_gtk_data gd;
+       const u8 *key_rsc;
 
        if (!sm->msg_3_of_4_ok) {
                wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -1494,7 +1533,11 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
        if (ret)
                goto failed;
 
-       if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) ||
+       key_rsc = key->key_rsc;
+       if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc))
+               key_rsc = null_rsc;
+
+       if (wpa_supplicant_install_gtk(sm, &gd, key_rsc) ||
            wpa_supplicant_send_2_of_2(sm, key, ver, key_info) < 0)
                goto failed;
        os_memset(&gd, 0, sizeof(gd));
@@ -2450,6 +2493,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
                        sm->ssid_len = 0;
                sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
                sm->p2p = config->p2p;
+               sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
        } else {
                sm->network_ctx = NULL;
                sm->peerkey_enabled = 0;
@@ -2460,6 +2504,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
                sm->ssid_len = 0;
                sm->wpa_ptk_rekey = 0;
                sm->p2p = 0;
+               sm->wpa_rsc_relaxation = 0;
        }
 }
 
index e163b70..9bfe0e2 100644 (file)
@@ -104,6 +104,7 @@ struct rsn_supp_config {
        size_t ssid_len;
        int wpa_ptk_rekey;
        int p2p;
+       int wpa_rsc_relaxation;
 };
 
 #ifndef CONFIG_NO_WPA
index 4368caa..14b7799 100644 (file)
@@ -61,6 +61,7 @@ struct wpa_sm {
        size_t ssid_len;
        int wpa_ptk_rekey;
        int p2p;
+       int wpa_rsc_relaxation;
 
        u8 own_addr[ETH_ALEN];
        const char *ifname;
index 03b91a2..db5de5f 100644 (file)
@@ -3540,6 +3540,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
        config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
        config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
        config->cert_in_cb = DEFAULT_CERT_IN_CB;
+       config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
 
        if (ctrl_interface)
                config->ctrl_interface = os_strdup(ctrl_interface);
@@ -4246,6 +4247,7 @@ static const struct global_parse_data global_fields[] = {
        { INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 },
        { INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 },
 #endif /* CONFIG_FST */
+       { INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 },
 };
 
 #undef FUNC
index 3ee0797..2dd1475 100644 (file)
@@ -39,6 +39,7 @@
 #define DEFAULT_KEY_MGMT_OFFLOAD 1
 #define DEFAULT_CERT_IN_CB 1
 #define DEFAULT_P2P_GO_CTWINDOW 0
+#define DEFAULT_WPA_RSC_RELAXATION 1
 
 #include "config_ssid.h"
 #include "wps/wps.h"
@@ -1252,6 +1253,16 @@ struct wpa_config {
         * interface.
         */
        int fst_llt;
+
+        /**
+         * wpa_rsc_relaxation - RSC relaxation on GTK installation
+         *
+         * Values:
+         * 0 - use the EAPOL-Key RSC value on GTK installation
+         * 1 - use the null RSC if a bogus RSC value is detected in message 3
+         * of 4-Way Handshake or message 1 of Group Key Handshake.
+         */
+        int wpa_rsc_relaxation;
 };
 
 
index fb438ea..215388c 100644 (file)
@@ -1299,6 +1299,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
 
        if (config->wps_priority)
                fprintf(f, "wps_priority=%d\n", config->wps_priority);
+
+       if (config->wpa_rsc_relaxation != DEFAULT_WPA_RSC_RELAXATION)
+               fprintf(f, "wpa_rsc_relaxation=%d\n",
+                       config->wpa_rsc_relaxation);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
index 29c22ba..aaadb95 100644 (file)
@@ -1124,6 +1124,7 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
                        }
                }
 #endif /* CONFIG_P2P */
+               conf.wpa_rsc_relaxation = wpa_s->conf->wpa_rsc_relaxation;
        }
        wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
 }