[PATCH 4/4] wpa_supplicant: Add GTK RSC relaxation workaround

Ilan Peer ilan.peer
Wed Oct 14 02:26:33 PDT 2015


From: Max Stepanov <Max.Stepanov at intel.com>

Some APs may send RSC octets in EAP message 3 of 4-Way Handshake or in
EAP message 1 of Group Key Handshake in the opposite order. Thus, after a
successful EAP authentication 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.

Workaournd 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.
The wpa_rsc_relaxation global configuration property allows to disable
the GTK RSC workaround if it's not needed.

Signed-off-by: Max Stepanov <Max.Stepanov at intel.com>
---
 src/rsn_supp/wpa.c           | 55 +++++++++++++++++++++++++++++++++++++++++---
 src/rsn_supp/wpa.h           |  1 +
 wpa_supplicant/config.c      |  3 +++
 wpa_supplicant/config.h      | 12 ++++++++++
 wpa_supplicant/config_file.c |  4 ++++
 wpa_supplicant/wpas_glue.c   |  9 ++++++++
 6 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index f1f65c6..39e4850 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -1,6 +1,7 @@
 /*
  * WPA Supplicant - WPA state machine and EAPOL-Key processing
  * Copyright (c) 2003-2015, Jouni Malinen <j at 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.
@@ -22,6 +23,7 @@
 #include "wpa_ie.h"
 #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
@@ -604,7 +606,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,
@@ -761,12 +762,51 @@ static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm,
 }
 
 
+static int wpa_supplicant_get_wpa_rsc_relaxation(const struct wpa_sm *sm)
+{
+	if (sm->ctx->get_wpa_rsc_relaxation)
+		return sm->ctx->get_wpa_rsc_relaxation(sm->ctx->ctx);
+	return 0;
+}
+
+
+static int wpa_supplicant_rsc_relaxation(const struct wpa_sm *sm,
+					 const u8 *rsc)
+{
+	int rsclen;
+
+	if (wpa_supplicant_get_wpa_rsc_relaxation(sm))
+		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 %.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x 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
@@ -792,11 +832,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));
@@ -1461,6 +1505,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,
@@ -1491,7 +1536,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))
 		goto failed;
 	os_memset(&gd, 0, sizeof(gd));
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index e163b70..2ba100d 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -77,6 +77,7 @@ struct wpa_sm_ctx {
 				  const u8 *kck, size_t kck_len,
 				  const u8 *replay_ctr);
 	int (*key_mgmt_set_pmk)(void *ctx, const u8 *pmk, size_t pmk_len);
+	int (*get_wpa_rsc_relaxation)(void *ctx);
 };
 
 
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index b1adab7..d20fc01 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -3546,6 +3546,8 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
 	if (driver_param)
 		config->driver_param = os_strdup(driver_param);
 
+	config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
+
 	return config;
 }
 
@@ -4246,6 +4248,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
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 68d64fa..6901a33 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -40,6 +40,8 @@
 #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"
 #include "common/ieee802_11_defs.h"
@@ -1252,6 +1254,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;
 };
 
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index fb438ea..cbc79a8 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -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=%u\n",
+			config->wpa_rsc_relaxation);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 29c22ba..39207ed 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -1030,6 +1030,14 @@ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
 }
 
 
+static int wpa_supplicant_wpa_rsc_relaxation(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	return wpa_s->conf->wpa_rsc_relaxation;
+}
+
+
 int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
 {
 #ifndef CONFIG_NO_WPA
@@ -1076,6 +1084,7 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_TDLS */
 	ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
 	ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk;
+	ctx->get_wpa_rsc_relaxation = wpa_supplicant_wpa_rsc_relaxation;
 
 	wpa_s->wpa = wpa_sm_init(ctx);
 	if (wpa_s->wpa == NULL) {
-- 
1.9.1




More information about the Hostap mailing list