aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeonardo Arena <rnalrd@alpinelinux.org>2019-08-16 08:13:51 +0000
committerLeonardo Arena <rnalrd@alpinelinux.org>2019-08-16 08:14:34 +0000
commitb7d037c2a9b8f72b1230453919246b1637028ada (patch)
tree62037a9265890748738badb82eaccbb9f32ad656
parent4eb3f0ba36d173d0d72b335c97203d6744d3fac3 (diff)
downloadaports-b7d037c2a9b8f72b1230453919246b1637028ada.tar.bz2
aports-b7d037c2a9b8f72b1230453919246b1637028ada.tar.xz
main/hostapd: security fixes (CVE-2019-13377)
Align patches with wpa_supplicant Ref #10731
-rw-r--r--main/hostapd/0001-OpenSSL-Use-constant-time-operations-for-private-big.patch92
-rw-r--r--main/hostapd/0002-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch60
-rw-r--r--main/hostapd/0003-SAE-Minimize-timing-differences-in-PWE-derivation.patch241
-rw-r--r--main/hostapd/0004-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch144
-rw-r--r--main/hostapd/0005-SAE-Mask-timing-of-MODP-groups-22-23-24.patch118
-rw-r--r--main/hostapd/0006-SAE-Use-const_time-selection-for-PWE-in-FFC.patch105
-rw-r--r--main/hostapd/0007-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch135
-rw-r--r--main/hostapd/0008-Add-helper-functions-for-constant-time-operations.patch218
-rw-r--r--main/hostapd/0009-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch324
-rw-r--r--main/hostapd/0010-EAP-pwd-server-Detect-reflection-attacks.patch45
-rw-r--r--main/hostapd/0011-EAP-pwd-client-Verify-received-scalar-and-element.patch58
-rw-r--r--main/hostapd/0012-EAP-pwd-server-Verify-received-scalar-and-element.patch58
-rw-r--r--main/hostapd/0013-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch331
-rw-r--r--main/hostapd/0014-EAP-pwd-server-Fix-reassembly-buffer-handling.patch (renamed from main/hostapd/0001-EAP-pwd-server-Fix-reassembly-buffer-handling.patch)0
-rw-r--r--main/hostapd/0015-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch (renamed from main/hostapd/0003-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch)0
-rw-r--r--main/hostapd/0016-SAE-Use-const_time_memcmp-for-pwd_value-prime-compar.patch31
-rw-r--r--main/hostapd/0017-EAP-pwd-Enforce-1-rand-mask-r-and-rand-mask-mod-r-1.patch121
-rw-r--r--main/hostapd/0018-EAP-pwd-Remove-unused-checks-for-cofactor-1-cases.patch257
-rw-r--r--main/hostapd/0019-EAP-pwd-Use-const_time_memcmp-for-pwd_value-prime-co.patch70
-rw-r--r--main/hostapd/0020-OpenSSL-Use-BN_bn2binpad-or-BN_bn2bin_padded-if-avai.patch66
-rw-r--r--main/hostapd/0021-SAE-Run-through-prf-result-processing-even-if-it-pri.patch59
-rw-r--r--main/hostapd/0022-EAP-pwd-Run-through-prf-result-processing-even-if-it.patch57
-rw-r--r--main/hostapd/0023-EAP-pwd-Disallow-ECC-groups-with-a-prime-under-256-b.patch45
-rw-r--r--main/hostapd/0024-SAE-Reject-unsuitable-groups-based-on-REVmd-changes.patch59
-rw-r--r--main/hostapd/0025-dragonfly-Disable-use-of-groups-using-Brainpool-curv.patch51
-rw-r--r--main/hostapd/APKBUILD58
26 files changed, 2798 insertions, 5 deletions
diff --git a/main/hostapd/0001-OpenSSL-Use-constant-time-operations-for-private-big.patch b/main/hostapd/0001-OpenSSL-Use-constant-time-operations-for-private-big.patch
new file mode 100644
index 0000000000..516c3b633a
--- /dev/null
+++ b/main/hostapd/0001-OpenSSL-Use-constant-time-operations-for-private-big.patch
@@ -0,0 +1,92 @@
+From d42c477cc794163a3757956bbffca5cea000923c Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Tue, 26 Feb 2019 11:43:03 +0200
+Subject: [PATCH] OpenSSL: Use constant time operations for private bignums
+
+This helps in reducing measurable timing differences in operations
+involving private information. BoringSSL has removed BN_FLG_CONSTTIME
+and expects specific constant time functions to be called instead, so a
+bit different approach is needed depending on which library is used.
+
+The main operation that needs protection against side channel attacks is
+BN_mod_exp() that depends on private keys (the public key validation
+step in crypto_dh_derive_secret() is an exception that can use the
+faster version since it does not depend on private keys).
+
+crypto_bignum_div() is currently used only in SAE FFC case with not
+safe-prime groups and only with values that do not depend on private
+keys, so it is not critical to protect it.
+
+crypto_bignum_inverse() is currently used only in SAE FFC PWE
+derivation. The additional protection here is targeting only OpenSSL.
+BoringSSL may need conversion to using BN_mod_inverse_blinded().
+
+This is related to CVE-2019-9494 and CVE-2019-9495.
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+---
+ src/crypto/crypto_openssl.c | 20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
+index 9c2ba58d5..ac53cc81a 100644
+--- a/src/crypto/crypto_openssl.c
++++ b/src/crypto/crypto_openssl.c
+@@ -607,7 +607,8 @@ int crypto_mod_exp(const u8 *base, size_t base_len,
+ bn_result == NULL)
+ goto error;
+
+- if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1)
++ if (BN_mod_exp_mont_consttime(bn_result, bn_base, bn_exp, bn_modulus,
++ ctx, NULL) != 1)
+ goto error;
+
+ *result_len = BN_bn2bin(bn_result, result);
+@@ -1360,8 +1361,9 @@ int crypto_bignum_exptmod(const struct crypto_bignum *a,
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -1;
+- res = BN_mod_exp((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
+- (const BIGNUM *) c, bnctx);
++ res = BN_mod_exp_mont_consttime((BIGNUM *) d, (const BIGNUM *) a,
++ (const BIGNUM *) b, (const BIGNUM *) c,
++ bnctx, NULL);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+@@ -1380,6 +1382,11 @@ int crypto_bignum_inverse(const struct crypto_bignum *a,
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -1;
++#ifdef OPENSSL_IS_BORINGSSL
++ /* TODO: use BN_mod_inverse_blinded() ? */
++#else /* OPENSSL_IS_BORINGSSL */
++ BN_set_flags((BIGNUM *) a, BN_FLG_CONSTTIME);
++#endif /* OPENSSL_IS_BORINGSSL */
+ res = BN_mod_inverse((BIGNUM *) c, (const BIGNUM *) a,
+ (const BIGNUM *) b, bnctx);
+ BN_CTX_free(bnctx);
+@@ -1413,6 +1420,9 @@ int crypto_bignum_div(const struct crypto_bignum *a,
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -1;
++#ifndef OPENSSL_IS_BORINGSSL
++ BN_set_flags((BIGNUM *) a, BN_FLG_CONSTTIME);
++#endif /* OPENSSL_IS_BORINGSSL */
+ res = BN_div((BIGNUM *) c, NULL, (const BIGNUM *) a,
+ (const BIGNUM *) b, bnctx);
+ BN_CTX_free(bnctx);
+@@ -1504,8 +1514,8 @@ int crypto_bignum_legendre(const struct crypto_bignum *a,
+ /* exp = (p-1) / 2 */
+ !BN_sub(exp, (const BIGNUM *) p, BN_value_one()) ||
+ !BN_rshift1(exp, exp) ||
+- !BN_mod_exp(tmp, (const BIGNUM *) a, exp, (const BIGNUM *) p,
+- bnctx))
++ !BN_mod_exp_mont_consttime(tmp, (const BIGNUM *) a, exp,
++ (const BIGNUM *) p, bnctx, NULL))
+ goto fail;
+
+ if (BN_is_word(tmp, 1))
+--
+2.21.0
+
diff --git a/main/hostapd/0002-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch b/main/hostapd/0002-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch
new file mode 100644
index 0000000000..8e635c1371
--- /dev/null
+++ b/main/hostapd/0002-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch
@@ -0,0 +1,60 @@
+From c93461c1d98f52681717a088776ab32fd97872b0 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Fri, 8 Mar 2019 00:24:12 +0200
+Subject: [PATCH] OpenSSL: Use constant time selection for
+ crypto_bignum_legendre()
+
+Get rid of the branches that depend on the result of the Legendre
+operation. This is needed to avoid leaking information about different
+temporary results in blinding mechanisms.
+
+This is related to CVE-2019-9494 and CVE-2019-9495.
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+---
+ src/crypto/crypto_openssl.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
+index ac53cc81a..0f52101ea 100644
+--- a/src/crypto/crypto_openssl.c
++++ b/src/crypto/crypto_openssl.c
+@@ -24,6 +24,7 @@
+ #endif /* CONFIG_ECC */
+
+ #include "common.h"
++#include "utils/const_time.h"
+ #include "wpabuf.h"
+ #include "dh_group5.h"
+ #include "sha1.h"
+@@ -1500,6 +1501,7 @@ int crypto_bignum_legendre(const struct crypto_bignum *a,
+ BN_CTX *bnctx;
+ BIGNUM *exp = NULL, *tmp = NULL;
+ int res = -2;
++ unsigned int mask;
+
+ if (TEST_FAIL())
+ return -2;
+@@ -1518,12 +1520,13 @@ int crypto_bignum_legendre(const struct crypto_bignum *a,
+ (const BIGNUM *) p, bnctx, NULL))
+ goto fail;
+
+- if (BN_is_word(tmp, 1))
+- res = 1;
+- else if (BN_is_zero(tmp))
+- res = 0;
+- else
+- res = -1;
++ /* Return 1 if tmp == 1, 0 if tmp == 0, or -1 otherwise. Need to use
++ * constant time selection to avoid branches here. */
++ res = -1;
++ mask = const_time_eq(BN_is_word(tmp, 1), 1);
++ res = const_time_select_int(mask, 1, res);
++ mask = const_time_eq(BN_is_zero(tmp), 1);
++ res = const_time_select_int(mask, 0, res);
+
+ fail:
+ BN_clear_free(tmp);
+--
+2.21.0
+
diff --git a/main/hostapd/0003-SAE-Minimize-timing-differences-in-PWE-derivation.patch b/main/hostapd/0003-SAE-Minimize-timing-differences-in-PWE-derivation.patch
new file mode 100644
index 0000000000..10b89d6b02
--- /dev/null
+++ b/main/hostapd/0003-SAE-Minimize-timing-differences-in-PWE-derivation.patch
@@ -0,0 +1,241 @@
+From 6513db3e96c43c2e36805cf5ead349765d18eaf7 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Tue, 26 Feb 2019 13:05:09 +0200
+Subject: [PATCH] SAE: Minimize timing differences in PWE derivation
+
+The QR test result can provide information about the password to an
+attacker, so try to minimize differences in how the
+sae_test_pwd_seed_ecc() result is used. (CVE-2019-9494)
+
+Use heap memory for the dummy password to allow the same password length
+to be used even with long passwords.
+
+Use constant time selection functions to track the real vs. dummy
+variables so that the exact same operations can be performed for both QR
+test results.
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+---
+ src/common/sae.c | 106 +++++++++++++++++++++++++----------------------
+ 1 file changed, 57 insertions(+), 49 deletions(-)
+
+diff --git a/src/common/sae.c b/src/common/sae.c
+index 8129a7c15..d55323bcd 100644
+--- a/src/common/sae.c
++++ b/src/common/sae.c
+@@ -9,6 +9,7 @@
+ #include "includes.h"
+
+ #include "common.h"
++#include "utils/const_time.h"
+ #include "crypto/crypto.h"
+ #include "crypto/sha256.h"
+ #include "crypto/random.h"
+@@ -292,15 +293,12 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
+ const u8 *prime,
+ const struct crypto_bignum *qr,
+ const struct crypto_bignum *qnr,
+- struct crypto_bignum **ret_x_cand)
++ u8 *pwd_value)
+ {
+- u8 pwd_value[SAE_MAX_ECC_PRIME_LEN];
+ struct crypto_bignum *y_sqr, *x_cand;
+ int res;
+ size_t bits;
+
+- *ret_x_cand = NULL;
+-
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
+
+ /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
+@@ -309,7 +307,7 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
+ prime, sae->tmp->prime_len, pwd_value, bits) < 0)
+ return -1;
+ if (bits % 8)
+- buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
++ buf_shift_right(pwd_value, sae->tmp->prime_len, 8 - bits % 8);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
+ pwd_value, sae->tmp->prime_len);
+
+@@ -320,20 +318,13 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
+ if (!x_cand)
+ return -1;
+ y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand);
+- if (!y_sqr) {
+- crypto_bignum_deinit(x_cand, 1);
++ crypto_bignum_deinit(x_cand, 1);
++ if (!y_sqr)
+ return -1;
+- }
+
+ res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
+ crypto_bignum_deinit(y_sqr, 1);
+- if (res <= 0) {
+- crypto_bignum_deinit(x_cand, 1);
+- return res;
+- }
+-
+- *ret_x_cand = x_cand;
+- return 1;
++ return res;
+ }
+
+
+@@ -454,25 +445,30 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
+ const u8 *addr[3];
+ size_t len[3];
+ size_t num_elem;
+- u8 dummy_password[32];
+- size_t dummy_password_len;
++ u8 *dummy_password, *tmp_password;
+ int pwd_seed_odd = 0;
+ u8 prime[SAE_MAX_ECC_PRIME_LEN];
+ size_t prime_len;
+- struct crypto_bignum *x = NULL, *qr, *qnr;
++ struct crypto_bignum *x = NULL, *qr = NULL, *qnr = NULL;
++ u8 x_bin[SAE_MAX_ECC_PRIME_LEN];
++ u8 x_cand_bin[SAE_MAX_ECC_PRIME_LEN];
+ size_t bits;
+- int res;
++ int res = -1;
++ u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
++ * mask */
+
+- dummy_password_len = password_len;
+- if (dummy_password_len > sizeof(dummy_password))
+- dummy_password_len = sizeof(dummy_password);
+- if (random_get_bytes(dummy_password, dummy_password_len) < 0)
+- return -1;
++ os_memset(x_bin, 0, sizeof(x_bin));
++
++ dummy_password = os_malloc(password_len);
++ tmp_password = os_malloc(password_len);
++ if (!dummy_password || !tmp_password ||
++ random_get_bytes(dummy_password, password_len) < 0)
++ goto fail;
+
+ prime_len = sae->tmp->prime_len;
+ if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
+ prime_len) < 0)
+- return -1;
++ goto fail;
+ bits = crypto_ec_prime_len_bits(sae->tmp->ec);
+
+ /*
+@@ -481,7 +477,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
+ */
+ if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
+ &qr, &qnr) < 0)
+- return -1;
++ goto fail;
+
+ wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+ password, password_len);
+@@ -497,7 +493,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
+ */
+ sae_pwd_seed_key(addr1, addr2, addrs);
+
+- addr[0] = password;
++ addr[0] = tmp_password;
+ len[0] = password_len;
+ num_elem = 1;
+ if (identifier) {
+@@ -514,9 +510,8 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
+ * attacks that attempt to determine the number of iterations required
+ * in the loop.
+ */
+- for (counter = 1; counter <= k || !x; counter++) {
++ for (counter = 1; counter <= k || !found; counter++) {
+ u8 pwd_seed[SHA256_MAC_LEN];
+- struct crypto_bignum *x_cand;
+
+ if (counter > 200) {
+ /* This should not happen in practice */
+@@ -524,36 +519,45 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
+ break;
+ }
+
+- wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
++ wpa_printf(MSG_DEBUG, "SAE: counter = %03u", counter);
++ const_time_select_bin(found, dummy_password, password,
++ password_len, tmp_password);
+ if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
+ addr, len, pwd_seed) < 0)
+ break;
+
+ res = sae_test_pwd_seed_ecc(sae, pwd_seed,
+- prime, qr, qnr, &x_cand);
++ prime, qr, qnr, x_cand_bin);
++ const_time_select_bin(found, x_bin, x_cand_bin, prime_len,
++ x_bin);
++ pwd_seed_odd = const_time_select_u8(
++ found, pwd_seed_odd,
++ pwd_seed[SHA256_MAC_LEN - 1] & 0x01);
++ os_memset(pwd_seed, 0, sizeof(pwd_seed));
+ if (res < 0)
+ goto fail;
+- if (res > 0 && !x) {
+- wpa_printf(MSG_DEBUG,
+- "SAE: Selected pwd-seed with counter %u",
+- counter);
+- x = x_cand;
+- pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
+- os_memset(pwd_seed, 0, sizeof(pwd_seed));
++ /* Need to minimize differences in handling res == 0 and 1 here
++ * to avoid differences in timing and instruction cache access,
++ * so use const_time_select_*() to make local copies of the
++ * values based on whether this loop iteration was the one that
++ * found the pwd-seed/x. */
++
++ /* found is 0 or 0xff here and res is 0 or 1. Bitwise OR of them
++ * (with res converted to 0/0xff) handles this in constant time.
++ */
++ found |= res * 0xff;
++ wpa_printf(MSG_DEBUG, "SAE: pwd-seed result %d found=0x%02x",
++ res, found);
++ }
+
+- /*
+- * Use a dummy password for the following rounds, if
+- * any.
+- */
+- addr[0] = dummy_password;
+- len[0] = dummy_password_len;
+- } else if (res > 0) {
+- crypto_bignum_deinit(x_cand, 1);
+- }
++ if (!found) {
++ wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
++ res = -1;
++ goto fail;
+ }
+
++ x = crypto_bignum_init_set(x_bin, prime_len);
+ if (!x) {
+- wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
+ res = -1;
+ goto fail;
+ }
+@@ -566,7 +570,6 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
+ res = crypto_ec_point_solve_y_coord(sae->tmp->ec,
+ sae->tmp->pwe_ecc, x,
+ pwd_seed_odd);
+- crypto_bignum_deinit(x, 1);
+ if (res < 0) {
+ /*
+ * This should not happen since we already checked that there
+@@ -578,6 +581,11 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
+ fail:
+ crypto_bignum_deinit(qr, 0);
+ crypto_bignum_deinit(qnr, 0);
++ os_free(dummy_password);
++ bin_clear_free(tmp_password, password_len);
++ crypto_bignum_deinit(x, 1);
++ os_memset(x_bin, 0, sizeof(x_bin));
++ os_memset(x_cand_bin, 0, sizeof(x_cand_bin));
+
+ return res;
+ }
+--
+2.21.0
+
diff --git a/main/hostapd/0004-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch b/main/hostapd/0004-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch
new file mode 100644
index 0000000000..aad9b1d4a4
--- /dev/null
+++ b/main/hostapd/0004-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch
@@ -0,0 +1,144 @@
+From 362704dda04507e7ebb8035122e83d9f0ae7c320 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Tue, 26 Feb 2019 19:34:38 +0200
+Subject: [PATCH] SAE: Avoid branches in is_quadratic_residue_blind()
+
+Make the non-failure path in the function proceed without branches based
+on r_odd and in constant time to minimize risk of observable differences
+in timing or cache use. (CVE-2019-9494)
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+---
+ src/common/sae.c | 64 ++++++++++++++++++++++++++++--------------------
+ 1 file changed, 37 insertions(+), 27 deletions(-)
+
+diff --git a/src/common/sae.c b/src/common/sae.c
+index d55323bcd..5df9b95aa 100644
+--- a/src/common/sae.c
++++ b/src/common/sae.c
+@@ -232,12 +232,14 @@ get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits,
+
+ static int is_quadratic_residue_blind(struct sae_data *sae,
+ const u8 *prime, size_t bits,
+- const struct crypto_bignum *qr,
+- const struct crypto_bignum *qnr,
++ const u8 *qr, const u8 *qnr,
+ const struct crypto_bignum *y_sqr)
+ {
+- struct crypto_bignum *r, *num;
++ struct crypto_bignum *r, *num, *qr_or_qnr = NULL;
+ int r_odd, check, res = -1;
++ u8 qr_or_qnr_bin[SAE_MAX_ECC_PRIME_LEN];
++ size_t prime_len = sae->tmp->prime_len;
++ unsigned int mask;
+
+ /*
+ * Use the blinding technique to mask y_sqr while determining
+@@ -248,7 +250,7 @@ static int is_quadratic_residue_blind(struct sae_data *sae,
+ * r = a random number between 1 and p-1, inclusive
+ * num = (v * r * r) modulo p
+ */
+- r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd);
++ r = get_rand_1_to_p_1(prime, prime_len, bits, &r_odd);
+ if (!r)
+ return -1;
+
+@@ -258,41 +260,45 @@ static int is_quadratic_residue_blind(struct sae_data *sae,
+ crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0)
+ goto fail;
+
+- if (r_odd) {
+- /*
+- * num = (num * qr) module p
+- * LGR(num, p) = 1 ==> quadratic residue
+- */
+- if (crypto_bignum_mulmod(num, qr, sae->tmp->prime, num) < 0)
+- goto fail;
+- check = 1;
+- } else {
+- /*
+- * num = (num * qnr) module p
+- * LGR(num, p) = -1 ==> quadratic residue
+- */
+- if (crypto_bignum_mulmod(num, qnr, sae->tmp->prime, num) < 0)
+- goto fail;
+- check = -1;
+- }
++ /*
++ * Need to minimize differences in handling different cases, so try to
++ * avoid branches and timing differences.
++ *
++ * If r_odd:
++ * num = (num * qr) module p
++ * LGR(num, p) = 1 ==> quadratic residue
++ * else:
++ * num = (num * qnr) module p
++ * LGR(num, p) = -1 ==> quadratic residue
++ */
++ mask = const_time_is_zero(r_odd);
++ const_time_select_bin(mask, qnr, qr, prime_len, qr_or_qnr_bin);
++ qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, prime_len);
++ if (!qr_or_qnr ||
++ crypto_bignum_mulmod(num, qr_or_qnr, sae->tmp->prime, num) < 0)
++ goto fail;
++ /* r_odd is 0 or 1; branchless version of check = r_odd ? 1 : -1, */
++ check = const_time_select_int(mask, -1, 1);
+
+ res = crypto_bignum_legendre(num, sae->tmp->prime);
+ if (res == -2) {
+ res = -1;
+ goto fail;
+ }
+- res = res == check;
++ /* branchless version of res = res == check
++ * (res is -1, 0, or 1; check is -1 or 1) */
++ mask = const_time_eq(res, check);
++ res = const_time_select_int(mask, 1, 0);
+ fail:
+ crypto_bignum_deinit(num, 1);
+ crypto_bignum_deinit(r, 1);
++ crypto_bignum_deinit(qr_or_qnr, 1);
+ return res;
+ }
+
+
+ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
+- const u8 *prime,
+- const struct crypto_bignum *qr,
+- const struct crypto_bignum *qnr,
++ const u8 *prime, const u8 *qr, const u8 *qnr,
+ u8 *pwd_value)
+ {
+ struct crypto_bignum *y_sqr, *x_cand;
+@@ -452,6 +458,8 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
+ struct crypto_bignum *x = NULL, *qr = NULL, *qnr = NULL;
+ u8 x_bin[SAE_MAX_ECC_PRIME_LEN];
+ u8 x_cand_bin[SAE_MAX_ECC_PRIME_LEN];
++ u8 qr_bin[SAE_MAX_ECC_PRIME_LEN];
++ u8 qnr_bin[SAE_MAX_ECC_PRIME_LEN];
+ size_t bits;
+ int res = -1;
+ u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
+@@ -476,7 +484,9 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
+ * (qnr) modulo p for blinding purposes during the loop.
+ */
+ if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
+- &qr, &qnr) < 0)
++ &qr, &qnr) < 0 ||
++ crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin), prime_len) < 0 ||
++ crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin), prime_len) < 0)
+ goto fail;
+
+ wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+@@ -527,7 +537,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
+ break;
+
+ res = sae_test_pwd_seed_ecc(sae, pwd_seed,
+- prime, qr, qnr, x_cand_bin);
++ prime, qr_bin, qnr_bin, x_cand_bin);
+ const_time_select_bin(found, x_bin, x_cand_bin, prime_len,
+ x_bin);
+ pwd_seed_odd = const_time_select_u8(
+--
+2.21.0
+
diff --git a/main/hostapd/0005-SAE-Mask-timing-of-MODP-groups-22-23-24.patch b/main/hostapd/0005-SAE-Mask-timing-of-MODP-groups-22-23-24.patch
new file mode 100644
index 0000000000..11dc244f5f
--- /dev/null
+++ b/main/hostapd/0005-SAE-Mask-timing-of-MODP-groups-22-23-24.patch
@@ -0,0 +1,118 @@
+From 90839597cc4016b33f00055b12d59174c62770a3 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Sat, 2 Mar 2019 12:24:09 +0200
+Subject: [PATCH] SAE: Mask timing of MODP groups 22, 23, 24
+
+These groups have significant probability of coming up with pwd-value
+that is equal or greater than the prime and as such, need for going
+through the PWE derivation loop multiple times. This can result in
+sufficient timing different to allow an external observer to determine
+how many rounds are needed and that can leak information about the used
+password.
+
+Force at least 40 loop rounds for these MODP groups similarly to the ECC
+group design to mask timing. This behavior is not described in IEEE Std
+802.11-2016 for SAE, but it does not result in different values (i.e.,
+only different timing), so such implementation specific countermeasures
+can be done without breaking interoperability with other implementation.
+
+Note: These MODP groups 22, 23, and 24 are not considered sufficiently
+strong to be used with SAE (or more or less anything else). As such,
+they should never be enabled in runtime configuration for any production
+use cases. These changes to introduce additional protection to mask
+timing is only for completeness of implementation and not an indication
+that these groups should be used.
+
+This is related to CVE-2019-9494.
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+---
+ src/common/sae.c | 38 ++++++++++++++++++++++++++++----------
+ 1 file changed, 28 insertions(+), 10 deletions(-)
+
+diff --git a/src/common/sae.c b/src/common/sae.c
+index 5df9b95aa..75b1b4a83 100644
+--- a/src/common/sae.c
++++ b/src/common/sae.c
+@@ -601,22 +601,27 @@ fail:
+ }
+
+
++static int sae_modp_group_require_masking(int group)
++{
++ /* Groups for which pwd-value is likely to be >= p frequently */
++ return group == 22 || group == 23 || group == 24;
++}
++
++
+ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
+ const u8 *addr2, const u8 *password,
+ size_t password_len, const char *identifier)
+ {
+- u8 counter;
++ u8 counter, k;
+ u8 addrs[2 * ETH_ALEN];
+ const u8 *addr[3];
+ size_t len[3];
+ size_t num_elem;
+ int found = 0;
++ struct crypto_bignum *pwe = NULL;
+
+- if (sae->tmp->pwe_ffc == NULL) {
+- sae->tmp->pwe_ffc = crypto_bignum_init();
+- if (sae->tmp->pwe_ffc == NULL)
+- return -1;
+- }
++ crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
++ sae->tmp->pwe_ffc = NULL;
+
+ wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+ password, password_len);
+@@ -640,7 +645,9 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
+ len[num_elem] = sizeof(counter);
+ num_elem++;
+
+- for (counter = 1; !found; counter++) {
++ k = sae_modp_group_require_masking(sae->group) ? 40 : 1;
++
++ for (counter = 1; counter <= k || !found; counter++) {
+ u8 pwd_seed[SHA256_MAC_LEN];
+ int res;
+
+@@ -650,19 +657,30 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
+ break;
+ }
+
+- wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
++ wpa_printf(MSG_DEBUG, "SAE: counter = %02u", counter);
+ if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
+ addr, len, pwd_seed) < 0)
+ break;
+- res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc);
++ if (!pwe) {
++ pwe = crypto_bignum_init();
++ if (!pwe)
++ break;
++ }
++ res = sae_test_pwd_seed_ffc(sae, pwd_seed, pwe);
+ if (res < 0)
+ break;
+ if (res > 0) {
+- wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
+ found = 1;
++ if (!sae->tmp->pwe_ffc) {
++ wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
++ sae->tmp->pwe_ffc = pwe;
++ pwe = NULL;
++ }
+ }
+ }
+
++ crypto_bignum_deinit(pwe, 1);
++
+ return found ? 0 : -1;
+ }
+
+--
+2.21.0
+
diff --git a/main/hostapd/0006-SAE-Use-const_time-selection-for-PWE-in-FFC.patch b/main/hostapd/0006-SAE-Use-const_time-selection-for-PWE-in-FFC.patch
new file mode 100644
index 0000000000..f336d5b74a
--- /dev/null
+++ b/main/hostapd/0006-SAE-Use-const_time-selection-for-PWE-in-FFC.patch
@@ -0,0 +1,105 @@
+From f8f20717f87eff1f025f48ed585c7684debacf72 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Sat, 2 Mar 2019 12:45:33 +0200
+Subject: [PATCH] SAE: Use const_time selection for PWE in FFC
+
+This is an initial step towards making the FFC case use strictly
+constant time operations similarly to the ECC case.
+sae_test_pwd_seed_ffc() does not yet have constant time behavior,
+though.
+
+This is related to CVE-2019-9494.
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+---
+ src/common/sae.c | 53 ++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 35 insertions(+), 18 deletions(-)
+
+diff --git a/src/common/sae.c b/src/common/sae.c
+index 75b1b4a83..fa9a145e3 100644
+--- a/src/common/sae.c
++++ b/src/common/sae.c
+@@ -612,17 +612,28 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
+ const u8 *addr2, const u8 *password,
+ size_t password_len, const char *identifier)
+ {
+- u8 counter, k;
++ u8 counter, k, sel_counter = 0;
+ u8 addrs[2 * ETH_ALEN];
+ const u8 *addr[3];
+ size_t len[3];
+ size_t num_elem;
+- int found = 0;
+- struct crypto_bignum *pwe = NULL;
++ u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
++ * mask */
++ u8 mask;
++ struct crypto_bignum *pwe;
++ size_t prime_len = sae->tmp->prime_len * 8;
++ u8 *pwe_buf;
+
+ crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
+ sae->tmp->pwe_ffc = NULL;
+
++ /* Allocate a buffer to maintain selected and candidate PWE for constant
++ * time selection. */
++ pwe_buf = os_zalloc(prime_len * 2);
++ pwe = crypto_bignum_init();
++ if (!pwe_buf || !pwe)
++ goto fail;
++
+ wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+ password, password_len);
+
+@@ -661,27 +672,33 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
+ if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
+ addr, len, pwd_seed) < 0)
+ break;
+- if (!pwe) {
+- pwe = crypto_bignum_init();
+- if (!pwe)
+- break;
+- }
+ res = sae_test_pwd_seed_ffc(sae, pwd_seed, pwe);
++ /* res is -1 for fatal failure, 0 if a valid PWE was not found,
++ * or 1 if a valid PWE was found. */
+ if (res < 0)
+ break;
+- if (res > 0) {
+- found = 1;
+- if (!sae->tmp->pwe_ffc) {
+- wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
+- sae->tmp->pwe_ffc = pwe;
+- pwe = NULL;
+- }
+- }
++ /* Store the candidate PWE into the second half of pwe_buf and
++ * the selected PWE in the beginning of pwe_buf using constant
++ * time selection. */
++ if (crypto_bignum_to_bin(pwe, pwe_buf + prime_len, prime_len,
++ prime_len) < 0)
++ break;
++ const_time_select_bin(found, pwe_buf, pwe_buf + prime_len,
++ prime_len, pwe_buf);
++ sel_counter = const_time_select_u8(found, sel_counter, counter);
++ mask = const_time_eq_u8(res, 1);
++ found = const_time_select_u8(found, found, mask);
+ }
+
+- crypto_bignum_deinit(pwe, 1);
++ if (!found)
++ goto fail;
+
+- return found ? 0 : -1;
++ wpa_printf(MSG_DEBUG, "SAE: Use PWE from counter = %02u", sel_counter);
++ sae->tmp->pwe_ffc = crypto_bignum_init_set(pwe_buf, prime_len);
++fail:
++ crypto_bignum_deinit(pwe, 1);
++ bin_clear_free(pwe_buf, prime_len * 2);
++ return sae->tmp->pwe_ffc ? 0 : -1;
+ }
+
+
+--
+2.21.0
+
diff --git a/main/hostapd/0007-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch b/main/hostapd/0007-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch
new file mode 100644
index 0000000000..bf22916b7d
--- /dev/null
+++ b/main/hostapd/0007-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch
@@ -0,0 +1,135 @@
+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] 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(-)
+
+diff --git a/src/common/sae.c b/src/common/sae.c
+index fa9a145e3..eaf825d19 100644
+--- a/src/common/sae.c
++++ b/src/common/sae.c
+@@ -334,14 +334,17 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
+ }
+
+
++/* 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);
+
+@@ -353,16 +356,29 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
+ 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:
+@@ -376,33 +392,34 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
+ 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 (!b)
++ goto fail;
+
+- if (res < 0) {
+- wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE");
+- return -1;
+- }
++ res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
++ if (res < 0)
++ goto fail;
+
+- /* if (PWE > 1) --> found */
+- if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) {
+- wpa_printf(MSG_DEBUG, "SAE: PWE <= 1");
+- return 0;
+- }
++ /* 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);
+
+- wpa_printf(MSG_DEBUG, "SAE: PWE found");
+- return 1;
++fail:
++ crypto_bignum_deinit(a, 1);
++ crypto_bignum_deinit(b, 1);
++ return res;
+ }
+
+
+--
+2.21.0
+
diff --git a/main/hostapd/0008-Add-helper-functions-for-constant-time-operations.patch b/main/hostapd/0008-Add-helper-functions-for-constant-time-operations.patch
new file mode 100644
index 0000000000..e0b8550c8f
--- /dev/null
+++ b/main/hostapd/0008-Add-helper-functions-for-constant-time-operations.patch
@@ -0,0 +1,218 @@
+From 6e34f618d37ddbb5854c42e2ad4fca83492fa7b7 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Wed, 27 Feb 2019 18:38:30 +0200
+Subject: [PATCH] Add helper functions for constant time operations
+
+These functions can be used to help implement constant time operations
+for various cryptographic operations that must minimize externally
+observable differences in processing (both in timing and also in
+internal cache use, etc.).
+
+This is related to CVE-2019-9494 and CVE-2019-9495.
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+---
+ src/utils/const_time.h | 191 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 191 insertions(+)
+ create mode 100644 src/utils/const_time.h
+
+diff --git a/src/utils/const_time.h b/src/utils/const_time.h
+new file mode 100644
+index 000000000..ab8f611ef
+--- /dev/null
++++ b/src/utils/const_time.h
+@@ -0,0 +1,191 @@
++/*
++ * Helper functions for constant time operations
++ * Copyright (c) 2019, The Linux Foundation
++ *
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
++ *
++ * These helper functions can be used to implement logic that needs to minimize
++ * externally visible differences in execution path by avoiding use of branches,
++ * avoiding early termination or other time differences, and forcing same memory
++ * access pattern regardless of values.
++ */
++
++#ifndef CONST_TIME_H
++#define CONST_TIME_H
++
++
++#if defined(__clang__)
++#define NO_UBSAN_UINT_OVERFLOW \
++ __attribute__((no_sanitize("unsigned-integer-overflow")))
++#else
++#define NO_UBSAN_UINT_OVERFLOW
++#endif
++
++
++/**
++ * const_time_fill_msb - Fill all bits with MSB value
++ * @val: Input value
++ * Returns: Value with all the bits set to the MSB of the input val
++ */
++static inline unsigned int const_time_fill_msb(unsigned int val)
++{
++ /* Move the MSB to LSB and multiple by -1 to fill in all bits. */
++ return (val >> (sizeof(val) * 8 - 1)) * ~0U;
++}
++
++
++/* Returns: -1 if val is zero; 0 if val is not zero */
++static inline unsigned int const_time_is_zero(unsigned int val)
++ NO_UBSAN_UINT_OVERFLOW
++{
++ /* Set MSB to 1 for 0 and fill rest of bits with the MSB value */
++ return const_time_fill_msb(~val & (val - 1));
++}
++
++
++/* Returns: -1 if a == b; 0 if a != b */
++static inline unsigned int const_time_eq(unsigned int a, unsigned int b)
++{
++ return const_time_is_zero(a ^ b);
++}
++
++
++/* Returns: -1 if a == b; 0 if a != b */
++static inline u8 const_time_eq_u8(unsigned int a, unsigned int b)
++{
++ return (u8) const_time_eq(a, b);
++}
++
++
++/**
++ * const_time_eq_bin - Constant time memory comparison
++ * @a: First buffer to compare
++ * @b: Second buffer to compare
++ * @len: Number of octets to compare
++ * Returns: -1 if buffers are equal, 0 if not
++ *
++ * This function is meant for comparing passwords or hash values where
++ * difference in execution time or memory access pattern could provide external
++ * observer information about the location of the difference in the memory
++ * buffers. The return value does not behave like memcmp(), i.e.,
++ * const_time_eq_bin() cannot be used to sort items into a defined order. Unlike
++ * memcmp(), the execution time of const_time_eq_bin() does not depend on the
++ * contents of the compared memory buffers, but only on the total compared
++ * length.
++ */
++static inline unsigned int const_time_eq_bin(const void *a, const void *b,
++ size_t len)
++{
++ const u8 *aa = a;
++ const u8 *bb = b;
++ size_t i;
++ u8 res = 0;
++
++ for (i = 0; i < len; i++)
++ res |= aa[i] ^ bb[i];
++
++ return const_time_is_zero(res);
++}
++
++
++/**
++ * const_time_select - Constant time unsigned int selection
++ * @mask: 0 (false) or -1 (true) to identify which value to select
++ * @true_val: Value to select for the true case
++ * @false_val: Value to select for the false case
++ * Returns: true_val if mask == -1, false_val if mask == 0
++ */
++static inline unsigned int const_time_select(unsigned int mask,
++ unsigned int true_val,
++ unsigned int false_val)
++{
++ return (mask & true_val) | (~mask & false_val);
++}
++
++
++/**
++ * const_time_select_int - Constant time int selection
++ * @mask: 0 (false) or -1 (true) to identify which value to select
++ * @true_val: Value to select for the true case
++ * @false_val: Value to select for the false case
++ * Returns: true_val if mask == -1, false_val if mask == 0
++ */
++static inline int const_time_select_int(unsigned int mask, int true_val,
++ int false_val)
++{
++ return (int) const_time_select(mask, (unsigned int) true_val,
++ (unsigned int) false_val);
++}
++
++
++/**
++ * const_time_select_u8 - Constant time u8 selection
++ * @mask: 0 (false) or -1 (true) to identify which value to select
++ * @true_val: Value to select for the true case
++ * @false_val: Value to select for the false case
++ * Returns: true_val if mask == -1, false_val if mask == 0
++ */
++static inline u8 const_time_select_u8(u8 mask, u8 true_val, u8 false_val)
++{
++ return (u8) const_time_select(mask, true_val, false_val);
++}
++
++
++/**
++ * const_time_select_s8 - Constant time s8 selection
++ * @mask: 0 (false) or -1 (true) to identify which value to select
++ * @true_val: Value to select for the true case
++ * @false_val: Value to select for the false case
++ * Returns: true_val if mask == -1, false_val if mask == 0
++ */
++static inline s8 const_time_select_s8(u8 mask, s8 true_val, s8 false_val)
++{
++ return (s8) const_time_select(mask, (unsigned int) true_val,
++ (unsigned int) false_val);
++}
++
++
++/**
++ * const_time_select_bin - Constant time binary buffer selection copy
++ * @mask: 0 (false) or -1 (true) to identify which value to copy
++ * @true_val: Buffer to copy for the true case
++ * @false_val: Buffer to copy for the false case
++ * @len: Number of octets to copy
++ * @dst: Destination buffer for the copy
++ *
++ * This function copies the specified buffer into the destination buffer using
++ * operations with identical memory access pattern regardless of which buffer
++ * is being copied.
++ */
++static inline void const_time_select_bin(u8 mask, const u8 *true_val,
++ const u8 *false_val, size_t len,
++ u8 *dst)
++{
++ size_t i;
++
++ for (i = 0; i < len; i++)
++ dst[i] = const_time_select_u8(mask, true_val[i], false_val[i]);
++}
++
++
++static inline int const_time_memcmp(const void *a, const void *b, size_t len)
++{
++ const u8 *aa = a;
++ const u8 *bb = b;
++ int diff, res = 0;
++ unsigned int mask;
++
++ if (len == 0)
++ return 0;
++ do {
++ len--;
++ diff = (int) aa[len] - (int) bb[len];
++ mask = const_time_is_zero((unsigned int) diff);
++ res = const_time_select_int(mask, res, diff);
++ } while (len);
++
++ return res;
++}
++
++#endif /* CONST_TIME_H */
+--
+2.21.0
+
diff --git a/main/hostapd/0009-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch b/main/hostapd/0009-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch
new file mode 100644
index 0000000000..f363f1563c
--- /dev/null
+++ b/main/hostapd/0009-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch
@@ -0,0 +1,324 @@
+From aaf65feac67c3993935634eefe5bc76b9fce03aa Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Tue, 26 Feb 2019 11:59:45 +0200
+Subject: [PATCH] EAP-pwd: Use constant time and memory access for finding the
+ PWE
+
+This algorithm could leak information to external observers in form of
+timing differences or memory access patterns (cache use). While the
+previous implementation had protection against the most visible timing
+differences (looping 40 rounds and masking the legendre operation), it
+did not protect against memory access patterns between the two possible
+code paths in the masking operations. That might be sufficient to allow
+an unprivileged process running on the same device to be able to
+determine which path is being executed through a cache attack and based
+on that, determine information about the used password.
+
+Convert the PWE finding loop to use constant time functions and
+identical memory access path without different branches for the QR/QNR
+cases to minimize possible side-channel information similarly to the
+changes done for SAE authentication. (CVE-2019-9495)
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+---
+ src/eap_common/eap_pwd_common.c | 187 +++++++++++++++++---------------
+ 1 file changed, 99 insertions(+), 88 deletions(-)
+
+diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
+index 02fe01e9f..e49aaf8c7 100644
+--- a/src/eap_common/eap_pwd_common.c
++++ b/src/eap_common/eap_pwd_common.c
+@@ -8,11 +8,15 @@
+
+ #include "includes.h"
+ #include "common.h"
++#include "utils/const_time.h"
+ #include "crypto/sha256.h"
+ #include "crypto/crypto.h"
+ #include "eap_defs.h"
+ #include "eap_pwd_common.h"
+
++#define MAX_ECC_PRIME_LEN 66
++
++
+ /* The random function H(x) = HMAC-SHA256(0^32, x) */
+ struct crypto_hash * eap_pwd_h_init(void)
+ {
+@@ -102,6 +106,15 @@ EAP_PWD_group * get_eap_pwd_group(u16 num)
+ }
+
+
++static void buf_shift_right(u8 *buf, size_t len, size_t bits)
++{
++ size_t i;
++ for (i = len - 1; i > 0; i--)
++ buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
++ buf[0] >>= bits;
++}
++
++
+ /*
+ * compute a "random" secret point on an elliptic curve based
+ * on the password and identities.
+@@ -113,17 +126,27 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ const u8 *token)
+ {
+ struct crypto_bignum *qr = NULL, *qnr = NULL, *one = NULL;
++ struct crypto_bignum *qr_or_qnr = NULL;
++ u8 qr_bin[MAX_ECC_PRIME_LEN];
++ u8 qnr_bin[MAX_ECC_PRIME_LEN];
++ u8 qr_or_qnr_bin[MAX_ECC_PRIME_LEN];
++ u8 x_bin[MAX_ECC_PRIME_LEN];
+ struct crypto_bignum *tmp1 = NULL, *tmp2 = NULL, *pm1 = NULL;
+ struct crypto_hash *hash;
+ unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
+- int is_odd, ret = 0, check, found = 0;
+- size_t primebytelen, primebitlen;
+- struct crypto_bignum *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
++ int ret = 0, check, res;
++ u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
++ * mask */
++ size_t primebytelen = 0, primebitlen;
++ struct crypto_bignum *x_candidate = NULL, *cofactor = NULL;
+ const struct crypto_bignum *prime;
++ u8 mask, found_ctr = 0, is_odd = 0;
+
+ if (grp->pwe)
+ return -1;
+
++ os_memset(x_bin, 0, sizeof(x_bin));
++
+ prime = crypto_ec_get_prime(grp->group);
+ cofactor = crypto_bignum_init();
+ grp->pwe = crypto_ec_point_init(grp->group);
+@@ -152,8 +175,6 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+
+ /* get a random quadratic residue and nonresidue */
+ while (!qr || !qnr) {
+- int res;
+-
+ if (crypto_bignum_rand(tmp1, prime) < 0)
+ goto fail;
+ res = crypto_bignum_legendre(tmp1, prime);
+@@ -167,6 +188,11 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ if (!tmp1)
+ goto fail;
+ }
++ if (crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin),
++ primebytelen) < 0 ||
++ crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin),
++ primebytelen) < 0)
++ goto fail;
+
+ os_memset(prfbuf, 0, primebytelen);
+ ctr = 0;
+@@ -194,17 +220,16 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ eap_pwd_h_update(hash, &ctr, sizeof(ctr));
+ eap_pwd_h_final(hash, pwe_digest);
+
+- crypto_bignum_deinit(rnd, 1);
+- rnd = crypto_bignum_init_set(pwe_digest, SHA256_MAC_LEN);
+- if (!rnd) {
+- wpa_printf(MSG_INFO, "EAP-pwd: unable to create rnd");
+- goto fail;
+- }
++ is_odd = const_time_select_u8(
++ found, is_odd, pwe_digest[SHA256_MAC_LEN - 1] & 0x01);
+ if (eap_pwd_kdf(pwe_digest, SHA256_MAC_LEN,
+ (u8 *) "EAP-pwd Hunting And Pecking",
+ os_strlen("EAP-pwd Hunting And Pecking"),
+ prfbuf, primebitlen) < 0)
+ goto fail;
++ if (primebitlen % 8)
++ buf_shift_right(prfbuf, primebytelen,
++ 8 - primebitlen % 8);
+
+ crypto_bignum_deinit(x_candidate, 1);
+ x_candidate = crypto_bignum_init_set(prfbuf, primebytelen);
+@@ -214,24 +239,13 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ goto fail;
+ }
+
+- /*
+- * eap_pwd_kdf() returns a string of bits 0..primebitlen but
+- * BN_bin2bn will treat that string of bits as a big endian
+- * number. If the primebitlen is not an even multiple of 8
+- * then excessive bits-- those _after_ primebitlen-- so now
+- * we have to shift right the amount we masked off.
+- */
+- if ((primebitlen % 8) &&
+- crypto_bignum_rshift(x_candidate,
+- (8 - (primebitlen % 8)),
+- x_candidate) < 0)
+- goto fail;
+-
+ if (crypto_bignum_cmp(x_candidate, prime) >= 0)
+ continue;
+
+- wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate",
+- prfbuf, primebytelen);
++ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: x_candidate",
++ prfbuf, primebytelen);
++ const_time_select_bin(found, x_bin, prfbuf, primebytelen,
++ x_bin);
+
+ /*
+ * compute y^2 using the equation of the curve
+@@ -261,13 +275,15 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ * Flip a coin, multiply by the random quadratic residue or the
+ * random quadratic nonresidue and record heads or tails.
+ */
+- if (crypto_bignum_is_odd(tmp1)) {
+- crypto_bignum_mulmod(tmp2, qr, prime, tmp2);
+- check = 1;
+- } else {
+- crypto_bignum_mulmod(tmp2, qnr, prime, tmp2);
+- check = -1;
+- }
++ mask = const_time_eq_u8(crypto_bignum_is_odd(tmp1), 1);
++ check = const_time_select_s8(mask, 1, -1);
++ const_time_select_bin(mask, qr_bin, qnr_bin, primebytelen,
++ qr_or_qnr_bin);
++ crypto_bignum_deinit(qr_or_qnr, 1);
++ qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, primebytelen);
++ if (!qr_or_qnr ||
++ crypto_bignum_mulmod(tmp2, qr_or_qnr, prime, tmp2) < 0)
++ goto fail;
+
+ /*
+ * Now it's safe to do legendre, if check is 1 then it's
+@@ -275,59 +291,12 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ * change result), if check is -1 then it's the opposite test
+ * (multiplying a qr by qnr would make a qnr).
+ */
+- if (crypto_bignum_legendre(tmp2, prime) == check) {
+- if (found == 1)
+- continue;
+-
+- /* need to unambiguously identify the solution */
+- is_odd = crypto_bignum_is_odd(rnd);
+-
+- /*
+- * We know x_candidate is a quadratic residue so set
+- * it here.
+- */
+- if (crypto_ec_point_solve_y_coord(grp->group, grp->pwe,
+- x_candidate,
+- is_odd) != 0) {
+- wpa_printf(MSG_INFO,
+- "EAP-pwd: Could not solve for y");
+- continue;
+- }
+-
+- /*
+- * If there's a solution to the equation then the point
+- * must be on the curve so why check again explicitly?
+- * OpenSSL code says this is required by X9.62. We're
+- * not X9.62 but it can't hurt just to be sure.
+- */
+- if (!crypto_ec_point_is_on_curve(grp->group,
+- grp->pwe)) {
+- wpa_printf(MSG_INFO,
+- "EAP-pwd: point is not on curve");
+- continue;
+- }
+-
+- if (!crypto_bignum_is_one(cofactor)) {
+- /* make sure the point is not in a small
+- * sub-group */
+- if (crypto_ec_point_mul(grp->group, grp->pwe,
+- cofactor,
+- grp->pwe) != 0) {
+- wpa_printf(MSG_INFO,
+- "EAP-pwd: cannot multiply generator by order");
+- continue;
+- }
+- if (crypto_ec_point_is_at_infinity(grp->group,
+- grp->pwe)) {
+- wpa_printf(MSG_INFO,
+- "EAP-pwd: point is at infinity");
+- continue;
+- }
+- }
+- wpa_printf(MSG_DEBUG,
+- "EAP-pwd: found a PWE in %d tries", ctr);
+- found = 1;
+- }
++ res = crypto_bignum_legendre(tmp2, prime);
++ if (res == -2)
++ goto fail;
++ mask = const_time_eq(res, check);
++ found_ctr = const_time_select_u8(found, found_ctr, ctr);
++ found |= mask;
+ }
+ if (found == 0) {
+ wpa_printf(MSG_INFO,
+@@ -335,6 +304,44 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ num);
+ goto fail;
+ }
++
++ /*
++ * We know x_candidate is a quadratic residue so set it here.
++ */
++ crypto_bignum_deinit(x_candidate, 1);
++ x_candidate = crypto_bignum_init_set(x_bin, primebytelen);
++ if (!x_candidate ||
++ crypto_ec_point_solve_y_coord(grp->group, grp->pwe, x_candidate,
++ is_odd) != 0) {
++ wpa_printf(MSG_INFO, "EAP-pwd: Could not solve for y");
++ goto fail;
++ }
++
++ /*
++ * If there's a solution to the equation then the point must be on the
++ * curve so why check again explicitly? OpenSSL code says this is
++ * required by X9.62. We're not X9.62 but it can't hurt just to be sure.
++ */
++ if (!crypto_ec_point_is_on_curve(grp->group, grp->pwe)) {
++ wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve");
++ goto fail;
++ }
++
++ if (!crypto_bignum_is_one(cofactor)) {
++ /* make sure the point is not in a small sub-group */
++ if (crypto_ec_point_mul(grp->group, grp->pwe, cofactor,
++ grp->pwe) != 0) {
++ wpa_printf(MSG_INFO,
++ "EAP-pwd: cannot multiply generator by order");
++ goto fail;
++ }
++ if (crypto_ec_point_is_at_infinity(grp->group, grp->pwe)) {
++ wpa_printf(MSG_INFO, "EAP-pwd: point is at infinity");
++ goto fail;
++ }
++ }
++ wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %02d tries", found_ctr);
++
+ if (0) {
+ fail:
+ crypto_ec_point_deinit(grp->pwe, 1);
+@@ -344,14 +351,18 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ /* cleanliness and order.... */
+ crypto_bignum_deinit(cofactor, 1);
+ crypto_bignum_deinit(x_candidate, 1);
+- crypto_bignum_deinit(rnd, 1);
+ crypto_bignum_deinit(pm1, 0);
+ crypto_bignum_deinit(tmp1, 1);
+ crypto_bignum_deinit(tmp2, 1);
+ crypto_bignum_deinit(qr, 1);
+ crypto_bignum_deinit(qnr, 1);
++ crypto_bignum_deinit(qr_or_qnr, 1);
+ crypto_bignum_deinit(one, 0);
+- os_free(prfbuf);
++ bin_clear_free(prfbuf, primebytelen);
++ os_memset(qr_bin, 0, sizeof(qr_bin));
++ os_memset(qnr_bin, 0, sizeof(qnr_bin));
++ os_memset(qr_or_qnr_bin, 0, sizeof(qr_or_qnr_bin));
++ os_memset(pwe_digest, 0, sizeof(pwe_digest));
+
+ return ret;
+ }
+--
+2.21.0
+
diff --git a/main/hostapd/0010-EAP-pwd-server-Detect-reflection-attacks.patch b/main/hostapd/0010-EAP-pwd-server-Detect-reflection-attacks.patch
new file mode 100644
index 0000000000..9bc1447965
--- /dev/null
+++ b/main/hostapd/0010-EAP-pwd-server-Detect-reflection-attacks.patch
@@ -0,0 +1,45 @@
+From d63edfa90243e9a7de6ae5c275032f2cc79fef95 Mon Sep 17 00:00:00 2001
+From: Mathy Vanhoef <mathy.vanhoef@nyu.edu>
+Date: Sun, 31 Mar 2019 17:26:01 +0200
+Subject: [PATCH] EAP-pwd server: Detect reflection attacks
+
+When processing an EAP-pwd Commit frame, verify that the peer's scalar
+and elliptic curve element differ from the one sent by the server. This
+prevents reflection attacks where the adversary reflects the scalar and
+element sent by the server. (CVE-2019-9497)
+
+The vulnerability allows an adversary to complete the EAP-pwd handshake
+as any user. However, the adversary does not learn the negotiated
+session key, meaning the subsequent 4-way handshake would fail. As a
+result, this cannot be abused to bypass authentication unless EAP-pwd is
+used in non-WLAN cases without any following key exchange that would
+require the attacker to learn the MSK.
+
+Signed-off-by: Mathy Vanhoef <mathy.vanhoef@nyu.edu>
+---
+ src/eap_server/eap_server_pwd.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
+index 74979da6e..16057e94f 100644
+--- a/src/eap_server/eap_server_pwd.c
++++ b/src/eap_server/eap_server_pwd.c
+@@ -753,6 +753,15 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+ }
+ }
+
++ /* detect reflection attacks */
++ if (crypto_bignum_cmp(data->my_scalar, data->peer_scalar) == 0 ||
++ crypto_ec_point_cmp(data->grp->group, data->my_element,
++ data->peer_element) == 0) {
++ wpa_printf(MSG_INFO,
++ "EAP-PWD (server): detected reflection attack!");
++ goto fin;
++ }
++
+ /* compute the shared key, k */
+ if ((crypto_ec_point_mul(data->grp->group, data->grp->pwe,
+ data->peer_scalar, K) < 0) ||
+--
+2.21.0
+
diff --git a/main/hostapd/0011-EAP-pwd-client-Verify-received-scalar-and-element.patch b/main/hostapd/0011-EAP-pwd-client-Verify-received-scalar-and-element.patch
new file mode 100644
index 0000000000..83efc5cc1e
--- /dev/null
+++ b/main/hostapd/0011-EAP-pwd-client-Verify-received-scalar-and-element.patch
@@ -0,0 +1,58 @@
+From 8ad8585f91823ddcc3728155e288e0f9f872e31a Mon Sep 17 00:00:00 2001
+From: Mathy Vanhoef <mathy.vanhoef@nyu.edu>
+Date: Sun, 31 Mar 2019 17:43:44 +0200
+Subject: [PATCH] EAP-pwd client: Verify received scalar and element
+
+When processing an EAP-pwd Commit frame, the server's scalar and element
+(elliptic curve point) were not validated. This allowed an adversary to
+bypass authentication, and act as a rogue Access Point (AP) if the
+crypto implementation did not verify the validity of the EC point.
+
+Fix this vulnerability by assuring the received scalar lies within the
+valid range, and by checking that the received element is not the point
+at infinity and lies on the elliptic curve being used. (CVE-2019-9499)
+
+The vulnerability is only exploitable if OpenSSL version 1.0.2 or lower
+is used, or if LibreSSL or wolfssl is used. Newer versions of OpenSSL
+(and also BoringSSL) implicitly validate the elliptic curve point in
+EC_POINT_set_affine_coordinates_GFp(), preventing the attack.
+
+Signed-off-by: Mathy Vanhoef <mathy.vanhoef@nyu.edu>
+---
+ src/eap_peer/eap_pwd.c | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
+index 761c16af9..5a05e5432 100644
+--- a/src/eap_peer/eap_pwd.c
++++ b/src/eap_peer/eap_pwd.c
+@@ -594,6 +594,26 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+ goto fin;
+ }
+
++ /* verify received scalar */
++ if (crypto_bignum_is_zero(data->server_scalar) ||
++ crypto_bignum_is_one(data->server_scalar) ||
++ crypto_bignum_cmp(data->server_scalar,
++ crypto_ec_get_order(data->grp->group)) >= 0) {
++ wpa_printf(MSG_INFO,
++ "EAP-PWD (peer): received scalar is invalid");
++ goto fin;
++ }
++
++ /* verify received element */
++ if (!crypto_ec_point_is_on_curve(data->grp->group,
++ data->server_element) ||
++ crypto_ec_point_is_at_infinity(data->grp->group,
++ data->server_element)) {
++ wpa_printf(MSG_INFO,
++ "EAP-PWD (peer): received element is invalid");
++ goto fin;
++ }
++
+ /* check to ensure server's element is not in a small sub-group */
+ if (!crypto_bignum_is_one(cofactor)) {
+ if (crypto_ec_point_mul(data->grp->group, data->server_element,
+--
+2.21.0
+
diff --git a/main/hostapd/0012-EAP-pwd-server-Verify-received-scalar-and-element.patch b/main/hostapd/0012-EAP-pwd-server-Verify-received-scalar-and-element.patch
new file mode 100644
index 0000000000..d11f0009be
--- /dev/null
+++ b/main/hostapd/0012-EAP-pwd-server-Verify-received-scalar-and-element.patch
@@ -0,0 +1,58 @@
+From 70ff850e89fbc8bc7da515321b4d15b5eef70581 Mon Sep 17 00:00:00 2001
+From: Mathy Vanhoef <mathy.vanhoef@nyu.edu>
+Date: Sun, 31 Mar 2019 17:13:06 +0200
+Subject: [PATCH] EAP-pwd server: Verify received scalar and element
+
+When processing an EAP-pwd Commit frame, the peer's scalar and element
+(elliptic curve point) were not validated. This allowed an adversary to
+bypass authentication, and impersonate any user if the crypto
+implementation did not verify the validity of the EC point.
+
+Fix this vulnerability by assuring the received scalar lies within the
+valid range, and by checking that the received element is not the point
+at infinity and lies on the elliptic curve being used. (CVE-2019-9498)
+
+The vulnerability is only exploitable if OpenSSL version 1.0.2 or lower
+is used, or if LibreSSL or wolfssl is used. Newer versions of OpenSSL
+(and also BoringSSL) implicitly validate the elliptic curve point in
+EC_POINT_set_affine_coordinates_GFp(), preventing the attack.
+
+Signed-off-by: Mathy Vanhoef <mathy.vanhoef@nyu.edu>
+---
+ src/eap_server/eap_server_pwd.c | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
+index d0fa54a3a..74979da6e 100644
+--- a/src/eap_server/eap_server_pwd.c
++++ b/src/eap_server/eap_server_pwd.c
+@@ -718,6 +718,26 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+ goto fin;
+ }
+
++ /* verify received scalar */
++ if (crypto_bignum_is_zero(data->peer_scalar) ||
++ crypto_bignum_is_one(data->peer_scalar) ||
++ crypto_bignum_cmp(data->peer_scalar,
++ crypto_ec_get_order(data->grp->group)) >= 0) {
++ wpa_printf(MSG_INFO,
++ "EAP-PWD (server): received scalar is invalid");
++ goto fin;
++ }
++
++ /* verify received element */
++ if (!crypto_ec_point_is_on_curve(data->grp->group,
++ data->peer_element) ||
++ crypto_ec_point_is_at_infinity(data->grp->group,
++ data->peer_element)) {
++ wpa_printf(MSG_INFO,
++ "EAP-PWD (server): received element is invalid");
++ goto fin;
++ }
++
+ /* check to ensure peer's element is not in a small sub-group */
+ if (!crypto_bignum_is_one(cofactor)) {
+ if (crypto_ec_point_mul(data->grp->group, data->peer_element,
+--
+2.21.0
+
diff --git a/main/hostapd/0013-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch b/main/hostapd/0013-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch
new file mode 100644
index 0000000000..daea13e21a
--- /dev/null
+++ b/main/hostapd/0013-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch
@@ -0,0 +1,331 @@
+From 16d4f1069118aa19bfce013493e1ac5783f92f1d Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Fri, 5 Apr 2019 02:12:50 +0300
+Subject: [PATCH] EAP-pwd: Check element x,y coordinates explicitly
+
+This adds an explicit check for 0 < x,y < prime based on RFC 5931,
+2.8.5.2.2 requirement. The earlier checks might have covered this
+implicitly, but it is safer to avoid any dependency on implicit checks
+and specific crypto library behavior. (CVE-2019-9498 and CVE-2019-9499)
+
+Furthermore, this moves the EAP-pwd element and scalar parsing and
+validation steps into shared helper functions so that there is no need
+to maintain two separate copies of this common functionality between the
+server and peer implementations.
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+---
+ src/eap_common/eap_pwd_common.c | 106 ++++++++++++++++++++++++++++++++
+ src/eap_common/eap_pwd_common.h | 3 +
+ src/eap_peer/eap_pwd.c | 45 ++------------
+ src/eap_server/eap_server_pwd.c | 45 ++------------
+ 4 files changed, 117 insertions(+), 82 deletions(-)
+
+diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
+index e49aaf8c7..c28b56d62 100644
+--- a/src/eap_common/eap_pwd_common.c
++++ b/src/eap_common/eap_pwd_common.c
+@@ -428,3 +428,109 @@ int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k,
+
+ return 1;
+ }
++
++
++static int eap_pwd_element_coord_ok(const struct crypto_bignum *prime,
++ const u8 *buf, size_t len)
++{
++ struct crypto_bignum *val;
++ int ok = 1;
++
++ val = crypto_bignum_init_set(buf, len);
++ if (!val || crypto_bignum_is_zero(val) ||
++ crypto_bignum_cmp(val, prime) >= 0)
++ ok = 0;
++ crypto_bignum_deinit(val, 0);
++ return ok;
++}
++
++
++struct crypto_ec_point * eap_pwd_get_element(EAP_PWD_group *group,
++ const u8 *buf)
++{
++ struct crypto_ec_point *element;
++ const struct crypto_bignum *prime;
++ size_t prime_len;
++ struct crypto_bignum *cofactor = NULL;
++
++ prime = crypto_ec_get_prime(group->group);
++ prime_len = crypto_ec_prime_len(group->group);
++
++ /* RFC 5931, 2.8.5.2.2: 0 < x,y < p */
++ if (!eap_pwd_element_coord_ok(prime, buf, prime_len) ||
++ !eap_pwd_element_coord_ok(prime, buf + prime_len, prime_len)) {
++ wpa_printf(MSG_INFO, "EAP-pwd: Invalid coordinate in element");
++ return NULL;
++ }
++
++ element = crypto_ec_point_from_bin(group->group, buf);
++ if (!element) {
++ wpa_printf(MSG_INFO, "EAP-pwd: EC point from element failed");
++ return NULL;
++ }
++
++ /* RFC 5931, 2.8.5.2.2: on curve and not the point at infinity */
++ if (!crypto_ec_point_is_on_curve(group->group, element) ||
++ crypto_ec_point_is_at_infinity(group->group, element)) {
++ wpa_printf(MSG_INFO, "EAP-pwd: Invalid element");
++ goto fail;
++ }
++
++ cofactor = crypto_bignum_init();
++ if (!cofactor || crypto_ec_cofactor(group->group, cofactor) < 0) {
++ wpa_printf(MSG_INFO,
++ "EAP-pwd: Unable to get cofactor for curve");
++ goto fail;
++ }
++
++ if (!crypto_bignum_is_one(cofactor)) {
++ struct crypto_ec_point *point;
++ int ok = 1;
++
++ /* check to ensure peer's element is not in a small sub-group */
++ point = crypto_ec_point_init(group->group);
++ if (!point ||
++ crypto_ec_point_mul(group->group, element,
++ cofactor, point) != 0 ||
++ crypto_ec_point_is_at_infinity(group->group, point))
++ ok = 0;
++ crypto_ec_point_deinit(point, 0);
++
++ if (!ok) {
++ wpa_printf(MSG_INFO,
++ "EAP-pwd: Small sub-group check on peer element failed");
++ goto fail;
++ }
++ }
++
++out:
++ crypto_bignum_deinit(cofactor, 0);
++ return element;
++fail:
++ crypto_ec_point_deinit(element, 0);
++ element = NULL;
++ goto out;
++}
++
++
++struct crypto_bignum * eap_pwd_get_scalar(EAP_PWD_group *group, const u8 *buf)
++{
++ struct crypto_bignum *scalar;
++ const struct crypto_bignum *order;
++ size_t order_len;
++
++ order = crypto_ec_get_order(group->group);
++ order_len = crypto_ec_order_len(group->group);
++
++ /* RFC 5931, 2.8.5.2: 1 < scalar < r */
++ scalar = crypto_bignum_init_set(buf, order_len);
++ if (!scalar || crypto_bignum_is_zero(scalar) ||
++ crypto_bignum_is_one(scalar) ||
++ crypto_bignum_cmp(scalar, order) >= 0) {
++ wpa_printf(MSG_INFO, "EAP-pwd: received scalar is invalid");
++ crypto_bignum_deinit(scalar, 0);
++ scalar = NULL;
++ }
++
++ return scalar;
++}
+diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h
+index 6b07cf8f7..2387e59a2 100644
+--- a/src/eap_common/eap_pwd_common.h
++++ b/src/eap_common/eap_pwd_common.h
+@@ -67,5 +67,8 @@ int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k,
+ struct crypto_hash * eap_pwd_h_init(void);
+ void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len);
+ void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest);
++struct crypto_ec_point * eap_pwd_get_element(EAP_PWD_group *group,
++ const u8 *buf);
++struct crypto_bignum * eap_pwd_get_scalar(EAP_PWD_group *group, const u8 *buf);
+
+ #endif /* EAP_PWD_COMMON_H */
+diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
+index 5a05e5432..f37b974eb 100644
+--- a/src/eap_peer/eap_pwd.c
++++ b/src/eap_peer/eap_pwd.c
+@@ -308,7 +308,7 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+ const struct wpabuf *reqData,
+ const u8 *payload, size_t payload_len)
+ {
+- struct crypto_ec_point *K = NULL, *point = NULL;
++ struct crypto_ec_point *K = NULL;
+ struct crypto_bignum *mask = NULL, *cofactor = NULL;
+ const u8 *ptr = payload;
+ u8 *scalar = NULL, *element = NULL;
+@@ -572,63 +572,27 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+ /* process the request */
+ data->k = crypto_bignum_init();
+ K = crypto_ec_point_init(data->grp->group);
+- point = crypto_ec_point_init(data->grp->group);
+- if (!data->k || !K || !point) {
++ if (!data->k || !K) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation "
+ "fail");
+ goto fin;
+ }
+
+ /* element, x then y, followed by scalar */
+- data->server_element = crypto_ec_point_from_bin(data->grp->group, ptr);
++ data->server_element = eap_pwd_get_element(data->grp, ptr);
+ if (!data->server_element) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element "
+ "fail");
+ goto fin;
+ }
+ ptr += prime_len * 2;
+- data->server_scalar = crypto_bignum_init_set(ptr, order_len);
++ data->server_scalar = eap_pwd_get_scalar(data->grp, ptr);
+ if (!data->server_scalar) {
+ wpa_printf(MSG_INFO,
+ "EAP-PWD (peer): setting peer scalar fail");
+ goto fin;
+ }
+
+- /* verify received scalar */
+- if (crypto_bignum_is_zero(data->server_scalar) ||
+- crypto_bignum_is_one(data->server_scalar) ||
+- crypto_bignum_cmp(data->server_scalar,
+- crypto_ec_get_order(data->grp->group)) >= 0) {
+- wpa_printf(MSG_INFO,
+- "EAP-PWD (peer): received scalar is invalid");
+- goto fin;
+- }
+-
+- /* verify received element */
+- if (!crypto_ec_point_is_on_curve(data->grp->group,
+- data->server_element) ||
+- crypto_ec_point_is_at_infinity(data->grp->group,
+- data->server_element)) {
+- wpa_printf(MSG_INFO,
+- "EAP-PWD (peer): received element is invalid");
+- goto fin;
+- }
+-
+- /* check to ensure server's element is not in a small sub-group */
+- if (!crypto_bignum_is_one(cofactor)) {
+- if (crypto_ec_point_mul(data->grp->group, data->server_element,
+- cofactor, point) < 0) {
+- wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
+- "server element by order!\n");
+- goto fin;
+- }
+- if (crypto_ec_point_is_at_infinity(data->grp->group, point)) {
+- wpa_printf(MSG_INFO, "EAP-PWD (peer): server element "
+- "is at infinity!\n");
+- goto fin;
+- }
+- }
+-
+ /* compute the shared key, k */
+ if (crypto_ec_point_mul(data->grp->group, data->grp->pwe,
+ data->server_scalar, K) < 0 ||
+@@ -702,7 +666,6 @@ fin:
+ crypto_bignum_deinit(mask, 1);
+ crypto_bignum_deinit(cofactor, 1);
+ crypto_ec_point_deinit(K, 1);
+- crypto_ec_point_deinit(point, 1);
+ if (data->outbuf == NULL)
+ eap_pwd_state(data, FAILURE);
+ else
+diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
+index 16057e94f..f6c75cf80 100644
+--- a/src/eap_server/eap_server_pwd.c
++++ b/src/eap_server/eap_server_pwd.c
+@@ -669,7 +669,7 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+ {
+ const u8 *ptr;
+ struct crypto_bignum *cofactor = NULL;
+- struct crypto_ec_point *K = NULL, *point = NULL;
++ struct crypto_ec_point *K = NULL;
+ int res = 0;
+ size_t prime_len, order_len;
+
+@@ -688,9 +688,8 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+
+ data->k = crypto_bignum_init();
+ cofactor = crypto_bignum_init();
+- point = crypto_ec_point_init(data->grp->group);
+ K = crypto_ec_point_init(data->grp->group);
+- if (!data->k || !cofactor || !point || !K) {
++ if (!data->k || !cofactor || !K) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
+ "fail");
+ goto fin;
+@@ -704,55 +703,20 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+
+ /* element, x then y, followed by scalar */
+ ptr = payload;
+- data->peer_element = crypto_ec_point_from_bin(data->grp->group, ptr);
++ data->peer_element = eap_pwd_get_element(data->grp, ptr);
+ if (!data->peer_element) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
+ "fail");
+ goto fin;
+ }
+ ptr += prime_len * 2;
+- data->peer_scalar = crypto_bignum_init_set(ptr, order_len);
++ data->peer_scalar = eap_pwd_get_scalar(data->grp, ptr);
+ if (!data->peer_scalar) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
+ "fail");
+ goto fin;
+ }
+
+- /* verify received scalar */
+- if (crypto_bignum_is_zero(data->peer_scalar) ||
+- crypto_bignum_is_one(data->peer_scalar) ||
+- crypto_bignum_cmp(data->peer_scalar,
+- crypto_ec_get_order(data->grp->group)) >= 0) {
+- wpa_printf(MSG_INFO,
+- "EAP-PWD (server): received scalar is invalid");
+- goto fin;
+- }
+-
+- /* verify received element */
+- if (!crypto_ec_point_is_on_curve(data->grp->group,
+- data->peer_element) ||
+- crypto_ec_point_is_at_infinity(data->grp->group,
+- data->peer_element)) {
+- wpa_printf(MSG_INFO,
+- "EAP-PWD (server): received element is invalid");
+- goto fin;
+- }
+-
+- /* check to ensure peer's element is not in a small sub-group */
+- if (!crypto_bignum_is_one(cofactor)) {
+- if (crypto_ec_point_mul(data->grp->group, data->peer_element,
+- cofactor, point) != 0) {
+- wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
+- "multiply peer element by order");
+- goto fin;
+- }
+- if (crypto_ec_point_is_at_infinity(data->grp->group, point)) {
+- wpa_printf(MSG_INFO, "EAP-PWD (server): peer element "
+- "is at infinity!\n");
+- goto fin;
+- }
+- }
+-
+ /* detect reflection attacks */
+ if (crypto_bignum_cmp(data->my_scalar, data->peer_scalar) == 0 ||
+ crypto_ec_point_cmp(data->grp->group, data->my_element,
+@@ -804,7 +768,6 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+
+ fin:
+ crypto_ec_point_deinit(K, 1);
+- crypto_ec_point_deinit(point, 1);
+ crypto_bignum_deinit(cofactor, 1);
+
+ if (res)
+--
+2.21.0
+
diff --git a/main/hostapd/0001-EAP-pwd-server-Fix-reassembly-buffer-handling.patch b/main/hostapd/0014-EAP-pwd-server-Fix-reassembly-buffer-handling.patch
index 620d67da02..620d67da02 100644
--- a/main/hostapd/0001-EAP-pwd-server-Fix-reassembly-buffer-handling.patch
+++ b/main/hostapd/0014-EAP-pwd-server-Fix-reassembly-buffer-handling.patch
diff --git a/main/hostapd/0003-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch b/main/hostapd/0015-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch
index 1a23e0fa90..1a23e0fa90 100644
--- a/main/hostapd/0003-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch
+++ b/main/hostapd/0015-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch
diff --git a/main/hostapd/0016-SAE-Use-const_time_memcmp-for-pwd_value-prime-compar.patch b/main/hostapd/0016-SAE-Use-const_time_memcmp-for-pwd_value-prime-compar.patch
new file mode 100644
index 0000000000..073f1e3ce1
--- /dev/null
+++ b/main/hostapd/0016-SAE-Use-const_time_memcmp-for-pwd_value-prime-compar.patch
@@ -0,0 +1,31 @@
+From e43f08991f00820c1f711ca254021d5f83b5cd7d Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Thu, 25 Apr 2019 18:52:34 +0300
+Subject: [PATCH 1/6] SAE: Use const_time_memcmp() for pwd_value >= prime
+ comparison
+
+This reduces timing and memory access pattern differences for an
+operation that could depend on the used password.
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+(cherry picked from commit 8e14b030e558d23f65d761895c07089404e61cf1)
+---
+ src/common/sae.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/common/sae.c b/src/common/sae.c
+index 5a50294a6..0d56e5505 100644
+--- a/src/common/sae.c
++++ b/src/common/sae.c
+@@ -317,7 +317,7 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
+ pwd_value, sae->tmp->prime_len);
+
+- if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
++ if (const_time_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
+ return 0;
+
+ x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
+--
+2.20.1
+
diff --git a/main/hostapd/0017-EAP-pwd-Enforce-1-rand-mask-r-and-rand-mask-mod-r-1.patch b/main/hostapd/0017-EAP-pwd-Enforce-1-rand-mask-r-and-rand-mask-mod-r-1.patch
new file mode 100644
index 0000000000..2cd0aa5a27
--- /dev/null
+++ b/main/hostapd/0017-EAP-pwd-Enforce-1-rand-mask-r-and-rand-mask-mod-r-1.patch
@@ -0,0 +1,121 @@
+From 4396f74a36e16e32a51238d84bf6225b89c8b25c Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Fri, 5 Apr 2019 12:37:21 +0300
+Subject: [PATCH] EAP-pwd: Enforce 1 < rand,mask < r and rand+mask mod r > 1
+
+RFC 5931 has these conditions as MUST requirements, so better follow
+them explicitly even if the rand,mask == 0 or rand+mask == 0 or 1 cases
+are very unlikely to occur in practice while generating random values
+locally.
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+---
+ src/eap_common/eap_pwd_common.c | 28 ++++++++++++++++++++++++++++
+ src/eap_common/eap_pwd_common.h | 3 +++
+ src/eap_peer/eap_pwd.c | 14 ++------------
+ src/eap_server/eap_server_pwd.c | 13 ++-----------
+ 4 files changed, 35 insertions(+), 23 deletions(-)
+
+diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
+index c28b56d62..4288b5299 100644
+--- a/src/eap_common/eap_pwd_common.c
++++ b/src/eap_common/eap_pwd_common.c
+@@ -534,3 +534,31 @@ struct crypto_bignum * eap_pwd_get_scalar(EAP_PWD_group *group, const u8 *buf)
+
+ return scalar;
+ }
++
++
++int eap_pwd_get_rand_mask(EAP_PWD_group *group, struct crypto_bignum *_rand,
++ struct crypto_bignum *_mask,
++ struct crypto_bignum *scalar)
++{
++ const struct crypto_bignum *order;
++ int count;
++
++ order = crypto_ec_get_order(group->group);
++
++ /* Select two random values rand,mask such that 1 < rand,mask < r and
++ * rand + mask mod r > 1. */
++ for (count = 0; count < 100; count++) {
++ if (crypto_bignum_rand(_rand, order) == 0 &&
++ !crypto_bignum_is_zero(_rand) &&
++ crypto_bignum_rand(_mask, order) == 0 &&
++ !crypto_bignum_is_zero(_mask) &&
++ crypto_bignum_add(_rand, _mask, scalar) == 0 &&
++ crypto_bignum_mod(scalar, order, scalar) == 0 &&
++ !crypto_bignum_is_zero(scalar) &&
++ !crypto_bignum_is_one(scalar))
++ return 0;
++ }
++
++ wpa_printf(MSG_INFO, "EAP-pwd: unable to get randomness");
++ return -1;
++}
+diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h
+index 2387e59a2..c48acee20 100644
+--- a/src/eap_common/eap_pwd_common.h
++++ b/src/eap_common/eap_pwd_common.h
+@@ -70,5 +70,8 @@ void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest);
+ struct crypto_ec_point * eap_pwd_get_element(EAP_PWD_group *group,
+ const u8 *buf);
+ struct crypto_bignum * eap_pwd_get_scalar(EAP_PWD_group *group, const u8 *buf);
++int eap_pwd_get_rand_mask(EAP_PWD_group *group, struct crypto_bignum *_rand,
++ struct crypto_bignum *_mask,
++ struct crypto_bignum *scalar);
+
+ #endif /* EAP_PWD_COMMON_H */
+diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
+index f37b974eb..5f6c00218 100644
+--- a/src/eap_peer/eap_pwd.c
++++ b/src/eap_peer/eap_pwd.c
+@@ -542,19 +542,9 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+ goto fin;
+ }
+
+- if (crypto_bignum_rand(data->private_value,
+- crypto_ec_get_order(data->grp->group)) < 0 ||
+- crypto_bignum_rand(mask,
+- crypto_ec_get_order(data->grp->group)) < 0 ||
+- crypto_bignum_add(data->private_value, mask,
+- data->my_scalar) < 0 ||
+- crypto_bignum_mod(data->my_scalar,
+- crypto_ec_get_order(data->grp->group),
+- data->my_scalar) < 0) {
+- wpa_printf(MSG_INFO,
+- "EAP-pwd (peer): unable to get randomness");
++ if (eap_pwd_get_rand_mask(data->grp, data->private_value, mask,
++ data->my_scalar) < 0)
+ goto fin;
+- }
+
+ if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask,
+ data->my_element) < 0) {
+diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
+index f6c75cf80..cf6affdaf 100644
+--- a/src/eap_server/eap_server_pwd.c
++++ b/src/eap_server/eap_server_pwd.c
+@@ -261,18 +261,9 @@ static void eap_pwd_build_commit_req(struct eap_sm *sm,
+ goto fin;
+ }
+
+- if (crypto_bignum_rand(data->private_value,
+- crypto_ec_get_order(data->grp->group)) < 0 ||
+- crypto_bignum_rand(mask,
+- crypto_ec_get_order(data->grp->group)) < 0 ||
+- crypto_bignum_add(data->private_value, mask, data->my_scalar) < 0 ||
+- crypto_bignum_mod(data->my_scalar,
+- crypto_ec_get_order(data->grp->group),
+- data->my_scalar) < 0) {
+- wpa_printf(MSG_INFO,
+- "EAP-pwd (server): unable to get randomness");
++ if (eap_pwd_get_rand_mask(data->grp, data->private_value, mask,
++ data->my_scalar) < 0)
+ goto fin;
+- }
+
+ if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask,
+ data->my_element) < 0) {
+--
+2.22.0
+
diff --git a/main/hostapd/0018-EAP-pwd-Remove-unused-checks-for-cofactor-1-cases.patch b/main/hostapd/0018-EAP-pwd-Remove-unused-checks-for-cofactor-1-cases.patch
new file mode 100644
index 0000000000..9ffa00c1d0
--- /dev/null
+++ b/main/hostapd/0018-EAP-pwd-Remove-unused-checks-for-cofactor-1-cases.patch
@@ -0,0 +1,257 @@
+From 8b093db2c3f489a74b67f687becf750d24fcf626 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <j@w1.fi>
+Date: Sat, 13 Apr 2019 17:30:22 +0300
+Subject: [PATCH] EAP-pwd: Remove unused checks for cofactor > 1 cases
+
+None of the ECC groups supported in the implementation had a cofactor
+greater than 1, so these checks are unreachable and for all cases, the
+cofactor is known to be 1. Furthermore, RFC 5931 explicitly disallow use
+of ECC groups with cofactor larger than 1, so this checks cannot be
+needed for any curve that is compliant with the RFC.
+
+Remove the unneeded group cofactor checks to simplify the
+implementation.
+
+Signed-off-by: Jouni Malinen <j@w1.fi>
+---
+ src/eap_common/eap_pwd_common.c | 53 ++-------------------------------
+ src/eap_peer/eap_pwd.c | 23 ++------------
+ src/eap_server/eap_server_pwd.c | 23 ++------------
+ 3 files changed, 7 insertions(+), 92 deletions(-)
+
+diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
+index 00f85a390..884150e6c 100644
+--- a/src/eap_common/eap_pwd_common.c
++++ b/src/eap_common/eap_pwd_common.c
+@@ -151,7 +151,7 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
+ * mask */
+ size_t primebytelen = 0, primebitlen;
+- struct crypto_bignum *x_candidate = NULL, *cofactor = NULL;
++ struct crypto_bignum *x_candidate = NULL;
+ const struct crypto_bignum *prime;
+ u8 mask, found_ctr = 0, is_odd = 0;
+
+@@ -161,21 +161,15 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ os_memset(x_bin, 0, sizeof(x_bin));
+
+ prime = crypto_ec_get_prime(grp->group);
+- cofactor = crypto_bignum_init();
+ grp->pwe = crypto_ec_point_init(grp->group);
+ tmp1 = crypto_bignum_init();
+ pm1 = crypto_bignum_init();
+ one = crypto_bignum_init_set((const u8 *) "\x01", 1);
+- if (!cofactor || !grp->pwe || !tmp1 || !pm1 || !one) {
++ if (!grp->pwe || !tmp1 || !pm1 || !one) {
+ wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums");
+ goto fail;
+ }
+
+- if (crypto_ec_cofactor(grp->group, cofactor) < 0) {
+- wpa_printf(MSG_INFO, "EAP-pwd: unable to get cofactor for "
+- "curve");
+- goto fail;
+- }
+ primebitlen = crypto_ec_prime_len_bits(grp->group);
+ primebytelen = crypto_ec_prime_len(grp->group);
+ if ((prfbuf = os_malloc(primebytelen)) == NULL) {
+@@ -340,19 +334,6 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ goto fail;
+ }
+
+- if (!crypto_bignum_is_one(cofactor)) {
+- /* make sure the point is not in a small sub-group */
+- if (crypto_ec_point_mul(grp->group, grp->pwe, cofactor,
+- grp->pwe) != 0) {
+- wpa_printf(MSG_INFO,
+- "EAP-pwd: cannot multiply generator by order");
+- goto fail;
+- }
+- if (crypto_ec_point_is_at_infinity(grp->group, grp->pwe)) {
+- wpa_printf(MSG_INFO, "EAP-pwd: point is at infinity");
+- goto fail;
+- }
+- }
+ wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %02d tries", found_ctr);
+
+ if (0) {
+@@ -362,7 +343,6 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ ret = 1;
+ }
+ /* cleanliness and order.... */
+- crypto_bignum_deinit(cofactor, 1);
+ crypto_bignum_deinit(x_candidate, 1);
+ crypto_bignum_deinit(pm1, 0);
+ crypto_bignum_deinit(tmp1, 1);
+@@ -464,7 +444,6 @@ struct crypto_ec_point * eap_pwd_get_element(EAP_PWD_group *group,
+ struct crypto_ec_point *element;
+ const struct crypto_bignum *prime;
+ size_t prime_len;
+- struct crypto_bignum *cofactor = NULL;
+
+ prime = crypto_ec_get_prime(group->group);
+ prime_len = crypto_ec_prime_len(group->group);
+@@ -489,35 +468,7 @@ struct crypto_ec_point * eap_pwd_get_element(EAP_PWD_group *group,
+ goto fail;
+ }
+
+- cofactor = crypto_bignum_init();
+- if (!cofactor || crypto_ec_cofactor(group->group, cofactor) < 0) {
+- wpa_printf(MSG_INFO,
+- "EAP-pwd: Unable to get cofactor for curve");
+- goto fail;
+- }
+-
+- if (!crypto_bignum_is_one(cofactor)) {
+- struct crypto_ec_point *point;
+- int ok = 1;
+-
+- /* check to ensure peer's element is not in a small sub-group */
+- point = crypto_ec_point_init(group->group);
+- if (!point ||
+- crypto_ec_point_mul(group->group, element,
+- cofactor, point) != 0 ||
+- crypto_ec_point_is_at_infinity(group->group, point))
+- ok = 0;
+- crypto_ec_point_deinit(point, 0);
+-
+- if (!ok) {
+- wpa_printf(MSG_INFO,
+- "EAP-pwd: Small sub-group check on peer element failed");
+- goto fail;
+- }
+- }
+-
+ out:
+- crypto_bignum_deinit(cofactor, 0);
+ return element;
+ fail:
+ crypto_ec_point_deinit(element, 0);
+diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
+index 4be4fcf35..46894a52f 100644
+--- a/src/eap_peer/eap_pwd.c
++++ b/src/eap_peer/eap_pwd.c
+@@ -309,7 +309,7 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+ const u8 *payload, size_t payload_len)
+ {
+ struct crypto_ec_point *K = NULL;
+- struct crypto_bignum *mask = NULL, *cofactor = NULL;
++ struct crypto_bignum *mask = NULL;
+ const u8 *ptr = payload;
+ u8 *scalar, *element;
+ size_t prime_len, order_len;
+@@ -527,21 +527,14 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+
+ data->private_value = crypto_bignum_init();
+ data->my_element = crypto_ec_point_init(data->grp->group);
+- cofactor = crypto_bignum_init();
+ data->my_scalar = crypto_bignum_init();
+ mask = crypto_bignum_init();
+- if (!data->private_value || !data->my_element || !cofactor ||
++ if (!data->private_value || !data->my_element ||
+ !data->my_scalar || !mask) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail");
+ goto fin;
+ }
+
+- if (crypto_ec_cofactor(data->grp->group, cofactor) < 0) {
+- wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor "
+- "for curve");
+- goto fin;
+- }
+-
+ if (eap_pwd_get_rand_mask(data->grp, data->private_value, mask,
+ data->my_scalar) < 0)
+ goto fin;
+@@ -595,17 +588,8 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+ goto fin;
+ }
+
+- /* ensure that the shared key isn't in a small sub-group */
+- if (!crypto_bignum_is_one(cofactor)) {
+- if (crypto_ec_point_mul(data->grp->group, K, cofactor, K) < 0) {
+- wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
+- "shared key point by order");
+- goto fin;
+- }
+- }
+-
+ /*
+- * This check is strictly speaking just for the case above where
++ * This check is strictly speaking just for the case where
+ * co-factor > 1 but it was suggested that even though this is probably
+ * never going to happen it is a simple and safe check "just to be
+ * sure" so let's be safe.
+@@ -644,7 +628,6 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+
+ fin:
+ crypto_bignum_deinit(mask, 1);
+- crypto_bignum_deinit(cofactor, 1);
+ crypto_ec_point_deinit(K, 1);
+ if (data->outbuf == NULL)
+ eap_pwd_state(data, FAILURE);
+diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
+index 9799c8197..81ecd773f 100644
+--- a/src/eap_server/eap_server_pwd.c
++++ b/src/eap_server/eap_server_pwd.c
+@@ -648,7 +648,6 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+ const u8 *payload, size_t payload_len)
+ {
+ const u8 *ptr;
+- struct crypto_bignum *cofactor = NULL;
+ struct crypto_ec_point *K = NULL;
+ int res = 0;
+ size_t prime_len, order_len;
+@@ -667,20 +666,13 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+ }
+
+ data->k = crypto_bignum_init();
+- cofactor = crypto_bignum_init();
+ K = crypto_ec_point_init(data->grp->group);
+- if (!data->k || !cofactor || !K) {
++ if (!data->k || !K) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
+ "fail");
+ goto fin;
+ }
+
+- if (crypto_ec_cofactor(data->grp->group, cofactor) < 0) {
+- wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get "
+- "cofactor for curve");
+- goto fin;
+- }
+-
+ /* element, x then y, followed by scalar */
+ ptr = payload;
+ data->peer_element = eap_pwd_get_element(data->grp, ptr);
+@@ -718,18 +710,8 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+ goto fin;
+ }
+
+- /* ensure that the shared key isn't in a small sub-group */
+- if (!crypto_bignum_is_one(cofactor)) {
+- if (crypto_ec_point_mul(data->grp->group, K, cofactor,
+- K) != 0) {
+- wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
+- "multiply shared key point by order!\n");
+- goto fin;
+- }
+- }
+-
+ /*
+- * This check is strictly speaking just for the case above where
++ * This check is strictly speaking just for the case where
+ * co-factor > 1 but it was suggested that even though this is probably
+ * never going to happen it is a simple and safe check "just to be
+ * sure" so let's be safe.
+@@ -748,7 +730,6 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+
+ fin:
+ crypto_ec_point_deinit(K, 1);
+- crypto_bignum_deinit(cofactor, 1);
+
+ if (res)
+ eap_pwd_state(data, PWD_Confirm_Req);
+--
+2.22.0
+
diff --git a/main/hostapd/0019-EAP-pwd-Use-const_time_memcmp-for-pwd_value-prime-co.patch b/main/hostapd/0019-EAP-pwd-Use-const_time_memcmp-for-pwd_value-prime-co.patch
new file mode 100644
index 0000000000..e27cd827e8
--- /dev/null
+++ b/main/hostapd/0019-EAP-pwd-Use-const_time_memcmp-for-pwd_value-prime-co.patch
@@ -0,0 +1,70 @@
+From 20d7bd83c43fb24c4cf84d3045254d3ee1957166 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Thu, 25 Apr 2019 19:07:05 +0300
+Subject: [PATCH 2/6] EAP-pwd: Use const_time_memcmp() for pwd_value >= prime
+ comparison
+
+This reduces timing and memory access pattern differences for an
+operation that could depend on the used password.
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+(cherry picked from commit 7958223fdcfe82479e6ed71019a84f6d4cbf799c)
+---
+ src/eap_common/eap_pwd_common.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
+index 884150e6c..6ca2c8bad 100644
+--- a/src/eap_common/eap_pwd_common.c
++++ b/src/eap_common/eap_pwd_common.c
+@@ -144,6 +144,7 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ u8 qnr_bin[MAX_ECC_PRIME_LEN];
+ u8 qr_or_qnr_bin[MAX_ECC_PRIME_LEN];
+ u8 x_bin[MAX_ECC_PRIME_LEN];
++ u8 prime_bin[MAX_ECC_PRIME_LEN];
+ struct crypto_bignum *tmp1 = NULL, *tmp2 = NULL, *pm1 = NULL;
+ struct crypto_hash *hash;
+ unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
+@@ -161,6 +162,11 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ os_memset(x_bin, 0, sizeof(x_bin));
+
+ prime = crypto_ec_get_prime(grp->group);
++ primebitlen = crypto_ec_prime_len_bits(grp->group);
++ primebytelen = crypto_ec_prime_len(grp->group);
++ if (crypto_bignum_to_bin(prime, prime_bin, sizeof(prime_bin),
++ primebytelen) < 0)
++ return -1;
+ grp->pwe = crypto_ec_point_init(grp->group);
+ tmp1 = crypto_bignum_init();
+ pm1 = crypto_bignum_init();
+@@ -170,8 +176,6 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ goto fail;
+ }
+
+- primebitlen = crypto_ec_prime_len_bits(grp->group);
+- primebytelen = crypto_ec_prime_len(grp->group);
+ if ((prfbuf = os_malloc(primebytelen)) == NULL) {
+ wpa_printf(MSG_INFO, "EAP-pwd: unable to malloc space for prf "
+ "buffer");
+@@ -237,6 +241,8 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ if (primebitlen % 8)
+ buf_shift_right(prfbuf, primebytelen,
+ 8 - primebitlen % 8);
++ if (const_time_memcmp(prfbuf, prime_bin, primebytelen) >= 0)
++ continue;
+
+ crypto_bignum_deinit(x_candidate, 1);
+ x_candidate = crypto_bignum_init_set(prfbuf, primebytelen);
+@@ -246,9 +252,6 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ goto fail;
+ }
+
+- if (crypto_bignum_cmp(x_candidate, prime) >= 0)
+- continue;
+-
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: x_candidate",
+ prfbuf, primebytelen);
+ const_time_select_bin(found, x_bin, prfbuf, primebytelen,
+--
+2.20.1
+
diff --git a/main/hostapd/0020-OpenSSL-Use-BN_bn2binpad-or-BN_bn2bin_padded-if-avai.patch b/main/hostapd/0020-OpenSSL-Use-BN_bn2binpad-or-BN_bn2bin_padded-if-avai.patch
new file mode 100644
index 0000000000..16feeaabb4
--- /dev/null
+++ b/main/hostapd/0020-OpenSSL-Use-BN_bn2binpad-or-BN_bn2bin_padded-if-avai.patch
@@ -0,0 +1,66 @@
+From ee34d8cfbd0fbf7ba7429531d4bee1c43b074d8b Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Thu, 25 Apr 2019 19:23:05 +0300
+Subject: [PATCH 3/6] OpenSSL: Use BN_bn2binpad() or BN_bn2bin_padded() if
+ available
+
+This converts crypto_bignum_to_bin() to use the OpenSSL/BoringSSL
+functions BN_bn2binpad()/BN_bn2bin_padded(), when available, to avoid
+differences in runtime and memory access patterns depending on the
+leading bytes of the BIGNUM value.
+
+OpenSSL 1.0.2 and LibreSSL do not include such functions, so those cases
+are still using the previous implementation where the BN_num_bytes()
+call may result in different memory access pattern.
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+(cherry picked from commit 1e237903f5b5d3117342daf006c5878cdb45e3d3)
+---
+ src/crypto/crypto_openssl.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
+index 1b0c1ec96..23ae5462d 100644
+--- a/src/crypto/crypto_openssl.c
++++ b/src/crypto/crypto_openssl.c
+@@ -1295,7 +1295,13 @@ void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
+ int crypto_bignum_to_bin(const struct crypto_bignum *a,
+ u8 *buf, size_t buflen, size_t padlen)
+ {
++#ifdef OPENSSL_IS_BORINGSSL
++#else /* OPENSSL_IS_BORINGSSL */
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
++#else
+ int num_bytes, offset;
++#endif
++#endif /* OPENSSL_IS_BORINGSSL */
+
+ if (TEST_FAIL())
+ return -1;
+@@ -1303,6 +1309,14 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
+ if (padlen > buflen)
+ return -1;
+
++#ifdef OPENSSL_IS_BORINGSSL
++ if (BN_bn2bin_padded(buf, padlen, (const BIGNUM *) a) == 0)
++ return -1;
++ return padlen;
++#else /* OPENSSL_IS_BORINGSSL */
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
++ return BN_bn2binpad((const BIGNUM *) a, buf, padlen);
++#else
+ num_bytes = BN_num_bytes((const BIGNUM *) a);
+ if ((size_t) num_bytes > buflen)
+ return -1;
+@@ -1315,6 +1329,8 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
+ BN_bn2bin((const BIGNUM *) a, buf + offset);
+
+ return num_bytes + offset;
++#endif
++#endif /* OPENSSL_IS_BORINGSSL */
+ }
+
+
+--
+2.20.1
+
diff --git a/main/hostapd/0021-SAE-Run-through-prf-result-processing-even-if-it-pri.patch b/main/hostapd/0021-SAE-Run-through-prf-result-processing-even-if-it-pri.patch
new file mode 100644
index 0000000000..0a2f398527
--- /dev/null
+++ b/main/hostapd/0021-SAE-Run-through-prf-result-processing-even-if-it-pri.patch
@@ -0,0 +1,59 @@
+From a25b48118d75f3c2d7cb1b2c3b4cffb13091a34c Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <j@w1.fi>
+Date: Mon, 24 Jun 2019 23:01:06 +0300
+Subject: [PATCH 4/6] SAE: Run through prf result processing even if it >=
+ prime
+
+This reduces differences in timing and memory access within the
+hunting-and-pecking loop for ECC groups that have a prime that is not
+close to a power of two (e.g., Brainpool curves).
+
+Signed-off-by: Jouni Malinen <j@w1.fi>
+(cherry picked from commit 147bf7b88a9c231322b5b574263071ca6dbb0503)
+---
+ src/common/sae.c | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/src/common/sae.c b/src/common/sae.c
+index 0d56e5505..759e48e22 100644
+--- a/src/common/sae.c
++++ b/src/common/sae.c
+@@ -304,6 +304,8 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
+ struct crypto_bignum *y_sqr, *x_cand;
+ int res;
+ size_t bits;
++ int cmp_prime;
++ unsigned int in_range;
+
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
+
+@@ -317,8 +319,13 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
+ pwd_value, sae->tmp->prime_len);
+
+- if (const_time_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
+- return 0;
++ cmp_prime = const_time_memcmp(pwd_value, prime, sae->tmp->prime_len);
++ /* Create a const_time mask for selection based on prf result
++ * being smaller than prime. */
++ in_range = const_time_fill_msb((unsigned int) cmp_prime);
++ /* The algorithm description would skip the next steps if
++ * cmp_prime >= 0 (reutnr 0 here), but go through them regardless to
++ * minimize externally observable differences in behavior. */
+
+ x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
+ if (!x_cand)
+@@ -330,7 +337,9 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
+
+ res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
+ crypto_bignum_deinit(y_sqr, 1);
+- return res;
++ if (res < 0)
++ return res;
++ return const_time_select_int(in_range, res, 0);
+ }
+
+
+--
+2.20.1
+
diff --git a/main/hostapd/0022-EAP-pwd-Run-through-prf-result-processing-even-if-it.patch b/main/hostapd/0022-EAP-pwd-Run-through-prf-result-processing-even-if-it.patch
new file mode 100644
index 0000000000..d5ebe59aec
--- /dev/null
+++ b/main/hostapd/0022-EAP-pwd-Run-through-prf-result-processing-even-if-it.patch
@@ -0,0 +1,57 @@
+From 00a6cc73da61b03c146b6c341d0d1e572bcef432 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <j@w1.fi>
+Date: Mon, 24 Jun 2019 23:02:51 +0300
+Subject: [PATCH 5/6] EAP-pwd: Run through prf result processing even if it >=
+ prime
+
+This reduces differences in timing and memory access within the
+hunting-and-pecking loop for ECC groups that have a prime that is not
+close to a power of two (e.g., Brainpool curves).
+
+Signed-off-by: Jouni Malinen <j@w1.fi>
+(cherry picked from commit cd803299ca485eb857e37c88f973fccfbb8600e5)
+---
+ src/eap_common/eap_pwd_common.c | 13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
+index 6ca2c8bad..fec251472 100644
+--- a/src/eap_common/eap_pwd_common.c
++++ b/src/eap_common/eap_pwd_common.c
+@@ -155,6 +155,8 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ struct crypto_bignum *x_candidate = NULL;
+ const struct crypto_bignum *prime;
+ u8 mask, found_ctr = 0, is_odd = 0;
++ int cmp_prime;
++ unsigned int in_range;
+
+ if (grp->pwe)
+ return -1;
+@@ -241,8 +243,13 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ if (primebitlen % 8)
+ buf_shift_right(prfbuf, primebytelen,
+ 8 - primebitlen % 8);
+- if (const_time_memcmp(prfbuf, prime_bin, primebytelen) >= 0)
+- continue;
++ cmp_prime = const_time_memcmp(prfbuf, prime_bin, primebytelen);
++ /* Create a const_time mask for selection based on prf result
++ * being smaller than prime. */
++ in_range = const_time_fill_msb((unsigned int) cmp_prime);
++ /* The algorithm description would skip the next steps if
++ * cmp_prime >= 0, but go through them regardless to minimize
++ * externally observable differences in behavior. */
+
+ crypto_bignum_deinit(x_candidate, 1);
+ x_candidate = crypto_bignum_init_set(prfbuf, primebytelen);
+@@ -306,7 +313,7 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
+ goto fail;
+ mask = const_time_eq(res, check);
+ found_ctr = const_time_select_u8(found, found_ctr, ctr);
+- found |= mask;
++ found |= mask & in_range;
+ }
+ if (found == 0) {
+ wpa_printf(MSG_INFO,
+--
+2.20.1
+
diff --git a/main/hostapd/0023-EAP-pwd-Disallow-ECC-groups-with-a-prime-under-256-b.patch b/main/hostapd/0023-EAP-pwd-Disallow-ECC-groups-with-a-prime-under-256-b.patch
new file mode 100644
index 0000000000..0ffff7ea9d
--- /dev/null
+++ b/main/hostapd/0023-EAP-pwd-Disallow-ECC-groups-with-a-prime-under-256-b.patch
@@ -0,0 +1,45 @@
+From 92e1b96c26a84e503847bdd22ebadf697c4031ad Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <j@w1.fi>
+Date: Sat, 13 Apr 2019 17:20:57 +0300
+Subject: [PATCH] EAP-pwd: Disallow ECC groups with a prime under 256 bits
+
+Based on the SAE implementation guidance update to not allow ECC groups
+with a prime that is under 256 bits, reject groups 25, 26, and 27 in
+EAP-pwd.
+
+Signed-off-by: Jouni Malinen <j@w1.fi>
+---
+ src/eap_common/eap_pwd_common.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
+index 4288b5299..00f85a390 100644
+--- a/src/eap_common/eap_pwd_common.c
++++ b/src/eap_common/eap_pwd_common.c
+@@ -85,10 +85,23 @@ static int eap_pwd_kdf(const u8 *key, size_t keylen, const u8 *label,
+ }
+
+
++static int eap_pwd_suitable_group(u16 num)
++{
++ /* Do not allow ECC groups with prime under 256 bits based on guidance
++ * for the similar design in SAE. */
++ return num == 19 || num == 20 || num == 21 ||
++ num == 28 || num == 29 || num == 30;
++}
++
++
+ EAP_PWD_group * get_eap_pwd_group(u16 num)
+ {
+ EAP_PWD_group *grp;
+
++ if (!eap_pwd_suitable_group(num)) {
++ wpa_printf(MSG_INFO, "EAP-pwd: unsuitable group %u", num);
++ return NULL;
++ }
+ grp = os_zalloc(sizeof(EAP_PWD_group));
+ if (!grp)
+ return NULL;
+--
+2.22.0
+
diff --git a/main/hostapd/0024-SAE-Reject-unsuitable-groups-based-on-REVmd-changes.patch b/main/hostapd/0024-SAE-Reject-unsuitable-groups-based-on-REVmd-changes.patch
new file mode 100644
index 0000000000..a7e6d37fb1
--- /dev/null
+++ b/main/hostapd/0024-SAE-Reject-unsuitable-groups-based-on-REVmd-changes.patch
@@ -0,0 +1,59 @@
+From db54db11aec763b6fc74715c36e0f9de0d65e206 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@codeaurora.org>
+Date: Mon, 8 Apr 2019 18:01:07 +0300
+Subject: [PATCH] SAE: Reject unsuitable groups based on REVmd changes
+
+The rules defining which DH groups are suitable for SAE use were
+accepted into IEEE 802.11 REVmd based on this document:
+https://mentor.ieee.org/802.11/dcn/19/11-19-0387-02-000m-addressing-some-sae-comments.docx
+
+Enforce those rules in production builds of wpa_supplicant and hostapd.
+CONFIG_TESTING_OPTIONS=y builds can still be used to select any o the
+implemented groups to maintain testing coverage.
+
+Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
+---
+ src/common/sae.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/src/common/sae.c b/src/common/sae.c
+index 981e788dc..8129a7c15 100644
+--- a/src/common/sae.c
++++ b/src/common/sae.c
+@@ -17,10 +17,33 @@
+ #include "sae.h"
+
+
++static int sae_suitable_group(int group)
++{
++#ifdef CONFIG_TESTING_OPTIONS
++ /* Allow all groups for testing purposes in non-production builds. */
++ return 1;
++#else /* CONFIG_TESTING_OPTIONS */
++ /* Enforce REVmd rules on which SAE groups are suitable for production
++ * purposes: FFC groups whose prime is >= 3072 bits and ECC groups
++ * defined over a prime field whose prime is >= 256 bits. Furthermore,
++ * ECC groups defined over a characteristic 2 finite field and ECC
++ * groups with a co-factor greater than 1 are not suitable. */
++ return group == 19 || group == 20 || group == 21 ||
++ group == 28 || group == 29 || group == 30 ||
++ group == 15 || group == 16 || group == 17 || group == 18;
++#endif /* CONFIG_TESTING_OPTIONS */
++}
++
++
+ int sae_set_group(struct sae_data *sae, int group)
+ {
+ struct sae_temporary_data *tmp;
+
++ if (!sae_suitable_group(group)) {
++ wpa_printf(MSG_DEBUG, "SAE: Reject unsuitable group %d", group);
++ return -1;
++ }
++
+ sae_clear_data(sae);
+ tmp = sae->tmp = os_zalloc(sizeof(*tmp));
+ if (tmp == NULL)
+--
+2.22.0
+
diff --git a/main/hostapd/0025-dragonfly-Disable-use-of-groups-using-Brainpool-curv.patch b/main/hostapd/0025-dragonfly-Disable-use-of-groups-using-Brainpool-curv.patch
new file mode 100644
index 0000000000..8dce92fffc
--- /dev/null
+++ b/main/hostapd/0025-dragonfly-Disable-use-of-groups-using-Brainpool-curv.patch
@@ -0,0 +1,51 @@
+From 558518ed63202e5358116ab7e0afd5e85490f2ef Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <j@w1.fi>
+Date: Sat, 27 Jul 2019 23:19:17 +0300
+Subject: [PATCH 6/6] dragonfly: Disable use of groups using Brainpool curves
+
+Disable groups that use Brainpool curves for now since they leak more
+timing information due to the prime not being close to a power of two.
+This removes use of groups 28, 29, and 30 from SAE and EAP-pwd.
+
+Signed-off-by: Jouni Malinen <j@w1.fi>
+(cherry picked from commit 876c5eaa6dae1a87a17603fc489a44c29eedc2e3)
+---
+ src/common/sae.c | 6 ++++--
+ src/eap_common/eap_pwd_common.c | 3 +--
+ 2 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/src/common/sae.c b/src/common/sae.c
+index 759e48e22..2dbc251a4 100644
+--- a/src/common/sae.c
++++ b/src/common/sae.c
+@@ -28,9 +28,11 @@ static int sae_suitable_group(int group)
+ * purposes: FFC groups whose prime is >= 3072 bits and ECC groups
+ * defined over a prime field whose prime is >= 256 bits. Furthermore,
+ * ECC groups defined over a characteristic 2 finite field and ECC
+- * groups with a co-factor greater than 1 are not suitable. */
++ * groups with a co-factor greater than 1 are not suitable. Disable
++ * groups that use Brainpool curves as well for now since they leak more
++ * timing information due to the prime not being close to a power of
++ * two. */
+ return group == 19 || group == 20 || group == 21 ||
+- group == 28 || group == 29 || group == 30 ||
+ group == 15 || group == 16 || group == 17 || group == 18;
+ #endif /* CONFIG_TESTING_OPTIONS */
+ }
+diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
+index fec251472..4a5eb2599 100644
+--- a/src/eap_common/eap_pwd_common.c
++++ b/src/eap_common/eap_pwd_common.c
+@@ -89,8 +89,7 @@ static int eap_pwd_suitable_group(u16 num)
+ {
+ /* Do not allow ECC groups with prime under 256 bits based on guidance
+ * for the similar design in SAE. */
+- return num == 19 || num == 20 || num == 21 ||
+- num == 28 || num == 29 || num == 30;
++ return num == 19 || num == 20 || num == 21;
+ }
+
+
+--
+2.20.1
+
diff --git a/main/hostapd/APKBUILD b/main/hostapd/APKBUILD
index 72824e2e38..8a604518ff 100644
--- a/main/hostapd/APKBUILD
+++ b/main/hostapd/APKBUILD
@@ -1,7 +1,7 @@
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
pkgname=hostapd
pkgver=2.7
-pkgrel=3
+pkgrel=4
pkgdesc="daemon for wireless software access points"
url="http://hostap.epitest.fi/hostapd/"
arch="all"
@@ -10,8 +10,31 @@ makedepends="openssl-dev libnl3-dev linux-headers"
subpackages="$pkgname-doc $pkgname-openrc"
patches="CVE-2012-4445.patch
CVE-2019-9496.patch
- 0001-EAP-pwd-server-Fix-reassembly-buffer-handling.patch
- 0003-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch
+ 0001-OpenSSL-Use-constant-time-operations-for-private-big.patch
+ 0002-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch
+ 0003-SAE-Minimize-timing-differences-in-PWE-derivation.patch
+ 0004-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch
+ 0005-SAE-Mask-timing-of-MODP-groups-22-23-24.patch
+ 0006-SAE-Use-const_time-selection-for-PWE-in-FFC.patch
+ 0007-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch
+ 0008-Add-helper-functions-for-constant-time-operations.patch
+ 0009-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch
+ 0010-EAP-pwd-server-Detect-reflection-attacks.patch
+ 0011-EAP-pwd-client-Verify-received-scalar-and-element.patch
+ 0012-EAP-pwd-server-Verify-received-scalar-and-element.patch
+ 0013-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch
+ 0014-EAP-pwd-server-Fix-reassembly-buffer-handling.patch
+ 0015-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch
+ 0016-SAE-Use-const_time_memcmp-for-pwd_value-prime-compar.patch
+ 0017-EAP-pwd-Enforce-1-rand-mask-r-and-rand-mask-mod-r-1.patch
+ 0018-EAP-pwd-Remove-unused-checks-for-cofactor-1-cases.patch
+ 0019-EAP-pwd-Use-const_time_memcmp-for-pwd_value-prime-co.patch
+ 0020-OpenSSL-Use-BN_bn2binpad-or-BN_bn2bin_padded-if-avai.patch
+ 0021-SAE-Run-through-prf-result-processing-even-if-it-pri.patch
+ 0022-EAP-pwd-Run-through-prf-result-processing-even-if-it.patch
+ 0023-EAP-pwd-Disallow-ECC-groups-with-a-prime-under-256-b.patch
+ 0024-SAE-Reject-unsuitable-groups-based-on-REVmd-changes.patch
+ 0025-dragonfly-Disable-use-of-groups-using-Brainpool-curv.patch
"
source="http://hostap.epitest.fi/releases/$pkgname-$pkgver.tar.gz
$patches
@@ -21,6 +44,8 @@ options="!check" #no testsuite
builddir="$srcdir"/$pkgname-$pkgver/hostapd
# secfixes:
+# 2.7-r4:
+# - CVE-2019-13377
# 2.7-r3:
# - CVE-2019-9496
# 2.7-r1:
@@ -99,7 +124,30 @@ package() {
sha512sums="1c9a210dfffb951fb667be19aa44ad8c66dccd2aed26cdab939185923550e3c1998a678ebe6975e560e1b3385bff2098f1b2cb773452ba66fb35246fdd3eb2c1 hostapd-2.7.tar.gz
619acce84516dead1e03e5da71657ea4c4b6f3ca8271574409773aeb316cbddc88095b50320804f457f001f4f3fe83053e660c008d8409f59bb4d3bfe058b601 CVE-2012-4445.patch
90981a52d6cb2e91f67a9bc830d3db02da6fde4bea0cf512b22111da6c8ab151f5dd171a2f2e409d9ff75e388e72c2314dd023a98fdabf16248b11a950bde881 CVE-2019-9496.patch
-7038044885871271ac724790663d5c0a428db83b41a691747be7a618ae893670a98f3ba52a297937249084296b0e9bcfd791edaa3928548efddb259e1a15f46c 0001-EAP-pwd-server-Fix-reassembly-buffer-handling.patch
-99c734fe395b4231aa6a097a08a00e5dab65ea9c37a7c83b1904a37c39307d9e7e95485734b0d483687126f4100c75f8a7b1420f0a2edcbfe07b454a14548822 0003-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch
+92fca9bd4d8a1e63ff6b6bce35ceea385f040e475c97eb32a2d53b97030a5513c1a6df238081b5db06ef79163f3a505d0bed641cfd9125446dc0fc30b418a790 0001-OpenSSL-Use-constant-time-operations-for-private-big.patch
+396aa9df1de947d645e22d0fbfe9c8a139a9eedbaf286b0bbba5c2341d2af0a2aec072d814c84b89c01e338ebc2ad8db02dbd52c72c2699e98fd5dc14106706f 0002-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch
+0dafd95c452472e51317df4cc6ac139a10cbc130d3a3a48ce44a8a96ebfa0197ed924086ef3a2984cd84024b347137bd76fd32e834c7667712ffcb3872d75c0b 0003-SAE-Minimize-timing-differences-in-PWE-derivation.patch
+132da8732d783c0e3a4af2c93f2c3c54f832c5231ef36629a45849f9f1ff045dc791ea0727d165edc76c53f827538ab5e9d6026af384733b3008c45b47d711d8 0004-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch
+c02771f2a904d9fac5c4c1c5b25d715bd18ada5a0aaea899d68348bdcd235af66db5473e364994ddf18cf081c6a8148783700ee9e4287c6de45d242e0ef73c93 0005-SAE-Mask-timing-of-MODP-groups-22-23-24.patch
+ff5621cfe8e11e3f7e3efd941b3e68c6c2714d19f69932428b3efbb166760323a9540e3840bc36f930bfcf990bfc99741d96df2edf503e1813400942629b4186 0006-SAE-Use-const_time-selection-for-PWE-in-FFC.patch
+07e57cd6509279fee021dfe290bad964088c39a181712424145f945ddc0682fa726b9bc6cc11c2fd7efb3f1d5bb7731dfee7e46351991340c715d39f536e7b6b 0007-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch
+24bd9359f2808a62af5eaeefa08a817b578cf2a88e3f77c77f43005e2e5a6526cbd96b5c01d2ddff65fd88e3a551ec771bcfbf49419759dc3bffd6dd999415b1 0008-Add-helper-functions-for-constant-time-operations.patch
+65d89c276b43766bf3e9bd6a4e6829c5ec38b59c4725c0a020ecbb9363f27cba20e82f0cebda55d264a1245b81ca545fdbe3d36eff5b5cee07d559b5e093a67c 0009-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch
+c2ebe127e0d14c56b9e274a6f8f97c5fb763edc9dc7a3cab4cb1748d29a4d514c240e398ab140542e7aa088b8f17936187e263466290a8ec483534b7182b8703 0010-EAP-pwd-server-Detect-reflection-attacks.patch
+509aaef9f32eabbc3b7d257fb85d424db89a383a1708353d52f8c26f3cac602b351615c6775731193ca9403da368052482aa8294927e9d1880f567a08e3056da 0011-EAP-pwd-client-Verify-received-scalar-and-element.patch
+217714f651b489f9bc9dad1485b1ea409b0d9c40aef70a4c343f59261198175e5360e6dff99773a7a7358731e010f6c334a095f4868adc9f914a4c4085fb3092 0012-EAP-pwd-server-Verify-received-scalar-and-element.patch
+39cb011348a4723b52405bd6cd85f78da1a80e077b61ef0c489e5a0a03e21e30de38378554f1a81092b65cd923d1c3c430821812037a7607f582038d3ba26687 0013-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch
+7038044885871271ac724790663d5c0a428db83b41a691747be7a618ae893670a98f3ba52a297937249084296b0e9bcfd791edaa3928548efddb259e1a15f46c 0014-EAP-pwd-server-Fix-reassembly-buffer-handling.patch
+99c734fe395b4231aa6a097a08a00e5dab65ea9c37a7c83b1904a37c39307d9e7e95485734b0d483687126f4100c75f8a7b1420f0a2edcbfe07b454a14548822 0015-EAP-pwd-peer-Fix-reassembly-buffer-handling.patch
+0dfc8728cfc3a86f7a182a7f71213b94f64880ee4470e2a939c83059df5af7a60d56ec0a8a5f2f717838995f4ef2c6a8fb909324875b0f12a52040239092d115 0016-SAE-Use-const_time_memcmp-for-pwd_value-prime-compar.patch
+abc2a40f9437280b1b0d3355f6485fd3d3b6412011e23b4699eb53eebbb761b7d6af553df5655bf5171dabf010f18bd9923a5589c295766d8b6643645b466146 0017-EAP-pwd-Enforce-1-rand-mask-r-and-rand-mask-mod-r-1.patch
+d9113a9f59cd35de88a2ef57e2f83c10986dddd3fa18652c3ddfe9f9d5db828d5fdd6385f2de9d6e8e11207c4b35fad2fb72d6698e554fc017cd369231115f44 0018-EAP-pwd-Remove-unused-checks-for-cofactor-1-cases.patch
+88b28f73267b5031417e527b4e2eea117e62649862bafbe99b83b77bade56612283279906c8d1a4c997fb8f32fc7a6cf8c88931a64e9520d1bf45fbdb0e6c381 0019-EAP-pwd-Use-const_time_memcmp-for-pwd_value-prime-co.patch
+01389b9d3951bf1148894c0f4b45d22ef8352a8fe1090721d17216506581305726f6a6c0ebff88479e5342330e75fc04db9201d7d65d4cc6b01a5f7258dc26f9 0020-OpenSSL-Use-BN_bn2binpad-or-BN_bn2bin_padded-if-avai.patch
+1fabc83a5e05ce3d09c89e37365d038bd0eec3a76683966ad172eac3c2c884dbc24fc6ca11c27a8f4582e886d0f1cde73bbede4484352b42a3f686d89d088fff 0021-SAE-Run-through-prf-result-processing-even-if-it-pri.patch
+bcae73930c35d441c5615970c305abb3dff293fdec16df50823e57419b22d1aac0e780970619e0c78b4482b7d07962bcf6162706a20e20f7b21a3a10f500eff1 0022-EAP-pwd-Run-through-prf-result-processing-even-if-it.patch
+89ac9ee8b0a3521b135ea5075fcc01ee37b111ba129e75f58e4bb863aad0e782c0e1928c91cab2ab1859a7a52d66987e14018b0552c167c05dbaeed76f1b12dd 0023-EAP-pwd-Disallow-ECC-groups-with-a-prime-under-256-b.patch
+da5f4248a0173cd7d07972b760631a8dc26f258e7b5be059c0d7de26e17f668945a62d2afce01ed1a1e9df6c55f9fd6ee344d4f006f5564b90a25e90e1e7c704 0024-SAE-Reject-unsuitable-groups-based-on-REVmd-changes.patch
+4734a8ab8ba1e91fc9e3d729f34527c14c291df238b02adea5acc04b0361b41d4bffca2fb13a4f464e9f007fa624117af4f50d755cb41a3129b4868da91bdf9a 0025-dragonfly-Disable-use-of-groups-using-Brainpool-curv.patch
b54b7c6aa17e5cb86a9b354a516eb2dbefb544df18471339c61d82776de447011a2ac290bea1e6c8beae4b6cebefafb8174683ea42fb773e9e8fe6c679f33ba3 hostapd.initd
0882263bbd7c0b05bf51f51d66e11a23a0b8ca7da2a3b8a30166d2c5f044c0c134e6bccb1d02c9e81819ca8fb0c0fb55c7121a08fe7233ccaa73ff8ab9a238fe hostapd.confd"