diff options
author | Stefan Lippers-Hollmann <s.l-h@gmx.de> | 2019-04-11 02:53:10 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2019-04-11 11:26:01 +0200 |
commit | af606d077f3cc175a39bfffc84cc615e0d3bf336 (patch) | |
tree | c2b4c01ce108fa218bafc3c49d23e66414339621 /package/network/services/hostapd/patches/061-0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch | |
parent | d1739c6c9a3618bafc04388b0c0209951125897a (diff) | |
download | upstream-af606d077f3cc175a39bfffc84cc615e0d3bf336.tar.gz upstream-af606d077f3cc175a39bfffc84cc615e0d3bf336.tar.bz2 upstream-af606d077f3cc175a39bfffc84cc615e0d3bf336.zip |
hostapd: fix CVE-2019-9494
SAE side-channel attacks
Published: April 10, 2019
Identifiers:
- VU#871675
- CVE-2019-9494 (cache attack against SAE)
Latest version available from: https://w1.fi/security/2019-1/
Vulnerability
Number of potential side channel attacks were discovered in the SAE
implementations used by both hostapd (AP) and wpa_supplicant
(infrastructure BSS station/mesh station). SAE (Simultaneous
Authentication of Equals) is also known as WPA3-Personal. The discovered
side channel attacks may be able to leak information about the used
password based on observable timing differences and cache access
patterns. This might result in full password recovery when combined with
an offline dictionary attack and if the password is not strong enough to
protect against dictionary attacks.
Cache attack
A novel cache-based attack against SAE handshake was discovered. This
attack targets SAE with ECC groups. ECC group 19 being the mandatory
group to support and the most likely used group for SAE today, so this
attack applies to the most common SAE use case. Even though the PWE
derivation iteration in SAE has protections against timing attacks, this
new cache-based attack enables an attacker to determine which code
branch is taken in the iteration if the attacker is able to run
unprivileged code on the victim machine (e.g., an app installed on a
smart phone or potentially a JavaScript code on a web site loaded by a
web browser). This depends on the used CPU not providing sufficient
protection to prevent unprivileged applications from observing memory
access patterns through the shared cache (which is the most likely case
with today's designs).
The attacker can use information about the selected branch to learn
information about the password and combine this information from number
of handshake instances with an offline dictionary attack. With
sufficient number of handshakes and sufficiently weak password, this
might result in full discovery of the used password.
This attack requires the attacker to be able to run a program on the
target device. This is not commonly the case on access points, so the
most likely target for this would be a client device using SAE in an
infrastructure BSS or mesh BSS.
The commits listed in the end of this advisory change the SAE
implementation shared by hostapd and wpa_supplicant to perform the PWE
derivation loop using operations that use constant time and memory
access pattern to minimize the externally observable differences from
operations that depend on the password even for the case where the
attacker might be able to run unprivileged code on the same device.
Timing attack
The timing attack applies to the MODP groups 22, 23, and 24 where the
PWE generation algorithm defined for SAE can have sufficient timing
differences for an attacker to be able to determine how many rounds were
needed to find the PWE based on the used password and MAC
addresses. When the attack is repeated with multiple times, the attacker
may be able to gather enough information about the password to be able
to recover it fully using an offline dictionary attack if the password
is not strong enough to protect against dictionary attacks. This attack
could be performed by an attacker in radio range of an access point or a
station enabling the specific MODP groups.
This timing attack requires the applicable MODP groups to be enabled
explicitly in hostapd/wpa_supplicant configuration (sae_groups
parameter). All versions of hostapd/wpa_supplicant have disabled these
groups by default.
While this security advisory lists couple of commits introducing
additional protection for MODP groups in SAE, it should be noted that
the groups 22, 23, and 24 are not considered strong enough to meet the
current expectation for a secure system. As such, their use is
discouraged even if the additional protection mechanisms in the
implementation are included.
Vulnerable versions/configurations
All wpa_supplicant and hostapd versions with SAE support (CONFIG_SAE=y
in the build configuration and SAE being enabled in the runtime
configuration).
Acknowledgments
Thanks to Mathy Vanhoef (New York University Abu Dhabi) and Eyal Ronen
(Tel Aviv University) for discovering the issues and for discussions on
how to address them.
Possible mitigation steps
- Merge the following commits to wpa_supplicant/hostapd and rebuild:
OpenSSL: Use constant time operations for private bignums
Add helper functions for constant time operations
OpenSSL: Use constant time selection for crypto_bignum_legendre()
SAE: Minimize timing differences in PWE derivation
SAE: Avoid branches in is_quadratic_residue_blind()
SAE: Mask timing of MODP groups 22, 23, 24
SAE: Use const_time selection for PWE in FFC
SAE: Use constant time operations in sae_test_pwd_seed_ffc()
These patches are available from https://w1.fi/security/2019-1/
- Update to wpa_supplicant/hostapd v2.8 or newer, once available
- In addition to either of the above alternatives, disable MODP groups
1, 2, 5, 22, 23, and 24 by removing them from hostapd/wpa_supplicant
sae_groups runtime configuration parameter, if they were explicitly
enabled since those groups are not considered strong enough to meet
current security expectations. The groups 22, 23, and 24 are related
to the discovered side channel (timing) attack. The other groups in
the list are consider too weak to provide sufficient security. Note
that all these groups have been disabled by default in all
hostapd/wpa_supplicant versions and these would be used only if
explicitly enabled in the configuration.
- Use strong passwords to prevent dictionary attacks
Signed-off-by: Stefan Lippers-Hollmann <s.l-h@gmx.de>
[bump PKG_RELEASE]
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'package/network/services/hostapd/patches/061-0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch')
-rw-r--r-- | package/network/services/hostapd/patches/061-0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/package/network/services/hostapd/patches/061-0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch b/package/network/services/hostapd/patches/061-0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch new file mode 100644 index 0000000000..150cbeb8ac --- /dev/null +++ b/package/network/services/hostapd/patches/061-0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch @@ -0,0 +1,133 @@ +From cff138b0747fa39765cbc641b66cfa5d7f1735d1 Mon Sep 17 00:00:00 2001 +From: Jouni Malinen <jouni@codeaurora.org> +Date: Sat, 2 Mar 2019 16:05:56 +0200 +Subject: [PATCH 09/14] SAE: Use constant time operations in + sae_test_pwd_seed_ffc() + +Try to avoid showing externally visible timing or memory access +differences regardless of whether the derived pwd-value is smaller than +the group prime. + +This is related to CVE-2019-9494. + +Signed-off-by: Jouni Malinen <jouni@codeaurora.org> +--- + src/common/sae.c | 75 ++++++++++++++++++++++++++++++++++---------------------- + 1 file changed, 46 insertions(+), 29 deletions(-) + +--- a/src/common/sae.c ++++ b/src/common/sae.c +@@ -311,14 +311,17 @@ static int sae_test_pwd_seed_ecc(struct + } + + ++/* Returns -1 on fatal failure, 0 if PWE cannot be derived from the provided ++ * pwd-seed, or 1 if a valid PWE was derived from pwd-seed. */ + static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed, + struct crypto_bignum *pwe) + { + u8 pwd_value[SAE_MAX_PRIME_LEN]; + size_t bits = sae->tmp->prime_len * 8; + u8 exp[1]; +- struct crypto_bignum *a, *b; +- int res; ++ struct crypto_bignum *a, *b = NULL; ++ int res, is_val; ++ u8 pwd_value_valid; + + wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN); + +@@ -330,16 +333,29 @@ static int sae_test_pwd_seed_ffc(struct + wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value, + sae->tmp->prime_len); + +- if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0) +- { +- wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p"); +- return 0; +- } ++ /* Check whether pwd-value < p */ ++ res = const_time_memcmp(pwd_value, sae->tmp->dh->prime, ++ sae->tmp->prime_len); ++ /* pwd-value >= p is invalid, so res is < 0 for the valid cases and ++ * the negative sign can be used to fill the mask for constant time ++ * selection */ ++ pwd_value_valid = const_time_fill_msb(res); ++ ++ /* If pwd-value >= p, force pwd-value to be < p and perform the ++ * calculations anyway to hide timing difference. The derived PWE will ++ * be ignored in that case. */ ++ pwd_value[0] = const_time_select_u8(pwd_value_valid, pwd_value[0], 0); + + /* PWE = pwd-value^((p-1)/r) modulo p */ + ++ res = -1; + a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len); ++ if (!a) ++ goto fail; + ++ /* This is an optimization based on the used group that does not depend ++ * on the password in any way, so it is fine to use separate branches ++ * for this step without constant time operations. */ + if (sae->tmp->dh->safe_prime) { + /* + * r = (p-1)/2 for the group used here, so this becomes: +@@ -353,33 +369,34 @@ static int sae_test_pwd_seed_ffc(struct + b = crypto_bignum_init_set(exp, sizeof(exp)); + if (b == NULL || + crypto_bignum_sub(sae->tmp->prime, b, b) < 0 || +- crypto_bignum_div(b, sae->tmp->order, b) < 0) { +- crypto_bignum_deinit(b, 0); +- b = NULL; +- } ++ crypto_bignum_div(b, sae->tmp->order, b) < 0) ++ goto fail; + } + +- if (a == NULL || b == NULL) +- res = -1; +- else +- res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe); +- +- crypto_bignum_deinit(a, 0); +- crypto_bignum_deinit(b, 0); +- +- if (res < 0) { +- wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE"); +- return -1; +- } +- +- /* if (PWE > 1) --> found */ +- if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) { +- wpa_printf(MSG_DEBUG, "SAE: PWE <= 1"); +- return 0; +- } ++ if (!b) ++ goto fail; + +- wpa_printf(MSG_DEBUG, "SAE: PWE found"); +- return 1; ++ res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe); ++ if (res < 0) ++ goto fail; ++ ++ /* There were no fatal errors in calculations, so determine the return ++ * value using constant time operations. We get here for number of ++ * invalid cases which are cleared here after having performed all the ++ * computation. PWE is valid if pwd-value was less than prime and ++ * PWE > 1. Start with pwd-value check first and then use constant time ++ * operations to clear res to 0 if PWE is 0 or 1. ++ */ ++ res = const_time_select_u8(pwd_value_valid, 1, 0); ++ is_val = crypto_bignum_is_zero(pwe); ++ res = const_time_select_u8(const_time_is_zero(is_val), res, 0); ++ is_val = crypto_bignum_is_one(pwe); ++ res = const_time_select_u8(const_time_is_zero(is_val), res, 0); ++ ++fail: ++ crypto_bignum_deinit(a, 1); ++ crypto_bignum_deinit(b, 1); ++ return res; + } + + |