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;

View 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

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

View 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 */

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