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>
This commit is contained in:
Max Stepanov 2015-10-14 12:26:33 +03:00 committed by Jouni Malinen
parent ea6030c77f
commit 73ed03f333
7 changed files with 68 additions and 3 deletions

View 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;
}
}

View 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

View 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;