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:
parent
ea6030c77f
commit
73ed03f333
7 changed files with 68 additions and 3 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue