SAE: Verify that own/peer commit-scalar and COMMIT-ELEMENT are different

This check explicitly for reflection attack and stops authentication
immediately if that is detected instead of continuing to the following
4-way handshake that would fail due to the attacker not knowing the key
from the SAE exchange.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2015-06-23 22:30:15 +03:00
parent 4e7e68890a
commit 6a58444d27
4 changed files with 47 additions and 3 deletions

View file

@ -769,6 +769,12 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
((const u8 *) mgmt) + len - ((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token, mgmt->u.auth.variable, &token,
&token_len, hapd->conf->sae_groups); &token_len, hapd->conf->sae_groups);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
MAC2STR(sta->addr));
return;
}
if (token && check_sae_token(hapd, sta->addr, token, token_len) if (token && check_sae_token(hapd, sta->addr, token, token_len)
< 0) { < 0) {
wpa_printf(MSG_DEBUG, "SAE: Drop commit message with " wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "

View file

@ -915,7 +915,34 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
return res; return res;
/* commit-element */ /* commit-element */
return sae_parse_commit_element(sae, pos, end); res = sae_parse_commit_element(sae, pos, end);
if (res != WLAN_STATUS_SUCCESS)
return res;
/*
* Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
* the values we sent which would be evidence of a reflection attack.
*/
if (!sae->tmp->own_commit_scalar ||
crypto_bignum_cmp(sae->tmp->own_commit_scalar,
sae->peer_commit_scalar) != 0 ||
(sae->tmp->dh &&
(!sae->tmp->own_commit_element_ffc ||
crypto_bignum_cmp(sae->tmp->own_commit_element_ffc,
sae->tmp->peer_commit_element_ffc) != 0)) ||
(sae->tmp->ec &&
(!sae->tmp->own_commit_element_ecc ||
crypto_ec_point_cmp(sae->tmp->ec,
sae->tmp->own_commit_element_ecc,
sae->tmp->peer_commit_element_ecc) != 0)))
return WLAN_STATUS_SUCCESS; /* scalars/elements are different */
/*
* This is a reflection attack - return special value to trigger caller
* to silently discard the frame instead of replying with a specific
* status code.
*/
return SAE_SILENTLY_DISCARD;
} }

View file

@ -18,6 +18,9 @@
#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN) #define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN)
#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN) #define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN)
/* Special value returned by sae_parse_commit() */
#define SAE_SILENTLY_DISCARD 65535
struct sae_temporary_data { struct sae_temporary_data {
u8 kck[SAE_KCK_LEN]; u8 kck[SAE_KCK_LEN];
struct crypto_bignum *own_commit_scalar; struct crypto_bignum *own_commit_scalar;

View file

@ -698,6 +698,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
return -1; return -1;
if (auth_transaction == 1) { if (auth_transaction == 1) {
u16 res;
groups = wpa_s->conf->sae_groups; groups = wpa_s->conf->sae_groups;
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit"); wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
@ -708,8 +710,14 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
return -1; return -1;
if (groups && groups[0] <= 0) if (groups && groups[0] <= 0)
groups = NULL; groups = NULL;
if (sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL, res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
groups) != WLAN_STATUS_SUCCESS) groups);
if (res == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message due to reflection attack");
return 0;
}
if (res != WLAN_STATUS_SUCCESS)
return -1; return -1;
if (sae_process_commit(&wpa_s->sme.sae) < 0) { if (sae_process_commit(&wpa_s->sme.sae) < 0) {