aboutsummaryrefslogtreecommitdiffstats
path: root/src/rsn_supp
diff options
context:
space:
mode:
authorMax Stepanov <Max.Stepanov@intel.com>2015-10-14 09:26:33 (GMT)
committerJouni Malinen <j@w1.fi>2015-11-01 19:00:22 (GMT)
commit73ed03f33323414ba02e50c15149bcb1c37d57e8 (patch)
tree861aaa8f5bbddd46b1bd588a6cf21bc2de64f984 /src/rsn_supp
parentea6030c77f119056868e9b8df06f3200943c61ef (diff)
downloadhostap-73ed03f33323414ba02e50c15149bcb1c37d57e8.zip
hostap-73ed03f33323414ba02e50c15149bcb1c37d57e8.tar.gz
hostap-73ed03f33323414ba02e50c15149bcb1c37d57e8.tar.bz2
wpa_supplicant: Add GTK RSC relaxation workaround
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>
Diffstat (limited to 'src/rsn_supp')
-rw-r--r--src/rsn_supp/wpa.c51
-rw-r--r--src/rsn_supp/wpa.h1
-rw-r--r--src/rsn_supp/wpa_i.h1
3 files changed, 50 insertions, 3 deletions
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 505c7a1..0b5fe51 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@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;
}
}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index e163b70..9bfe0e2 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -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
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 4368caa..14b7799 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -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;