From 6a58444d27fdb475ca2fa2f5cea0806b077fc31d Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 23 Jun 2015 22:30:15 +0300 Subject: [PATCH] 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 --- src/ap/ieee802_11.c | 6 ++++++ src/common/sae.c | 29 ++++++++++++++++++++++++++++- src/common/sae.h | 3 +++ wpa_supplicant/sme.c | 12 ++++++++++-- 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 8d2a06637..db20c8679 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -769,6 +769,12 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, ((const u8 *) mgmt) + len - mgmt->u.auth.variable, &token, &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) < 0) { wpa_printf(MSG_DEBUG, "SAE: Drop commit message with " diff --git a/src/common/sae.c b/src/common/sae.c index ae200f3e0..e3b61a63f 100644 --- a/src/common/sae.c +++ b/src/common/sae.c @@ -915,7 +915,34 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, return res; /* 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; } diff --git a/src/common/sae.h b/src/common/sae.h index 3ebf40cf4..c07026cd4 100644 --- a/src/common/sae.h +++ b/src/common/sae.h @@ -18,6 +18,9 @@ #define SAE_COMMIT_MAX_LEN (2 + 3 * 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 { u8 kck[SAE_KCK_LEN]; struct crypto_bignum *own_commit_scalar; diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 234670ae2..a472febbb 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -698,6 +698,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, return -1; if (auth_transaction == 1) { + u16 res; + groups = wpa_s->conf->sae_groups; 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; if (groups && groups[0] <= 0) groups = NULL; - if (sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL, - groups) != WLAN_STATUS_SUCCESS) + res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL, + 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; if (sae_process_commit(&wpa_s->sme.sae) < 0) {