From dc7f38e87eff1d00dc542239950df2c90c2ff00f Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 15 May 2019 15:49:56 -0400 Subject: [PATCH] Update to version 2.8 from upstream Drop obsoleted patches --- .gitignore | 2 +- ...tant-time-operations-for-private-big.patch | 93 ----- ...nctions-for-constant-time-operations.patch | 218 ------------ ...tant-time-selection-for-crypto_bignu.patch | 60 ---- ...tant-time-and-memory-access-for-find.patch | 324 ----------------- ...timing-differences-in-PWE-derivation.patch | 241 ------------- ...anches-in-is_quadratic_residue_blind.patch | 144 -------- ...-Mask-timing-of-MODP-groups-22-23-24.patch | 118 ------- ...-const_time-selection-for-PWE-in-FFC.patch | 105 ------ ...-time-operations-in-sae_test_pwd_see.patch | 136 ------- ...rm-message-validation-in-error-cases.patch | 57 --- ...r-Verify-received-scalar-and-element.patch | 58 --- ...pwd-server-Detect-reflection-attacks.patch | 45 --- ...t-Verify-received-scalar-and-element.patch | 58 --- ...k-element-x-y-coordinates-explicitly.patch | 331 ------------------ hostapd.spec | 44 +-- sources | 2 +- 17 files changed, 8 insertions(+), 2028 deletions(-) delete mode 100644 0001-OpenSSL-Use-constant-time-operations-for-private-big.patch delete mode 100644 0002-Add-helper-functions-for-constant-time-operations.patch delete mode 100644 0003-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch delete mode 100644 0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch delete mode 100644 0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch delete mode 100644 0006-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch delete mode 100644 0007-SAE-Mask-timing-of-MODP-groups-22-23-24.patch delete mode 100644 0008-SAE-Use-const_time-selection-for-PWE-in-FFC.patch delete mode 100644 0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch delete mode 100644 0010-SAE-Fix-confirm-message-validation-in-error-cases.patch delete mode 100644 0011-EAP-pwd-server-Verify-received-scalar-and-element.patch delete mode 100644 0012-EAP-pwd-server-Detect-reflection-attacks.patch delete mode 100644 0013-EAP-pwd-client-Verify-received-scalar-and-element.patch delete mode 100644 0014-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch diff --git a/.gitignore b/.gitignore index 82d10a9..16015c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -/hostapd-2.7.tar.gz +/hostapd-2.8.tar.gz diff --git a/0001-OpenSSL-Use-constant-time-operations-for-private-big.patch b/0001-OpenSSL-Use-constant-time-operations-for-private-big.patch deleted file mode 100644 index f5dfca4..0000000 --- a/0001-OpenSSL-Use-constant-time-operations-for-private-big.patch +++ /dev/null @@ -1,93 +0,0 @@ -From d42c477cc794163a3757956bbffca5cea000923c Mon Sep 17 00:00:00 2001 -From: Jouni Malinen -Date: Tue, 26 Feb 2019 11:43:03 +0200 -Subject: [PATCH 01/14] 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 ---- - 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 9c2ba58..ac53cc8 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.7.4 - diff --git a/0002-Add-helper-functions-for-constant-time-operations.patch b/0002-Add-helper-functions-for-constant-time-operations.patch deleted file mode 100644 index d4c3ccb..0000000 --- a/0002-Add-helper-functions-for-constant-time-operations.patch +++ /dev/null @@ -1,218 +0,0 @@ -From 6e34f618d37ddbb5854c42e2ad4fca83492fa7b7 Mon Sep 17 00:00:00 2001 -From: Jouni Malinen -Date: Wed, 27 Feb 2019 18:38:30 +0200 -Subject: [PATCH 02/14] 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 ---- - 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 0000000..ab8f611 ---- /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.7.4 - diff --git a/0003-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch b/0003-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch deleted file mode 100644 index 7b54dd0..0000000 --- a/0003-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch +++ /dev/null @@ -1,60 +0,0 @@ -From c93461c1d98f52681717a088776ab32fd97872b0 Mon Sep 17 00:00:00 2001 -From: Jouni Malinen -Date: Fri, 8 Mar 2019 00:24:12 +0200 -Subject: [PATCH 03/14] 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 ---- - 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 ac53cc8..0f52101 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.7.4 - diff --git a/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch b/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch deleted file mode 100644 index a48952b..0000000 --- a/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch +++ /dev/null @@ -1,324 +0,0 @@ -From aaf65feac67c3993935634eefe5bc76b9fce03aa Mon Sep 17 00:00:00 2001 -From: Jouni Malinen -Date: Tue, 26 Feb 2019 11:59:45 +0200 -Subject: [PATCH 04/14] 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 ---- - 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 02fe01e..e49aaf8 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.7.4 - diff --git a/0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch b/0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch deleted file mode 100644 index 5f48f07..0000000 --- a/0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch +++ /dev/null @@ -1,241 +0,0 @@ -From 6513db3e96c43c2e36805cf5ead349765d18eaf7 Mon Sep 17 00:00:00 2001 -From: Jouni Malinen -Date: Tue, 26 Feb 2019 13:05:09 +0200 -Subject: [PATCH 05/14] 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 ---- - 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 8129a7c..d55323b 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.7.4 - diff --git a/0006-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch b/0006-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch deleted file mode 100644 index 8c72126..0000000 --- a/0006-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch +++ /dev/null @@ -1,144 +0,0 @@ -From 362704dda04507e7ebb8035122e83d9f0ae7c320 Mon Sep 17 00:00:00 2001 -From: Jouni Malinen -Date: Tue, 26 Feb 2019 19:34:38 +0200 -Subject: [PATCH 06/14] 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 ---- - 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 d55323b..5df9b95 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.7.4 - diff --git a/0007-SAE-Mask-timing-of-MODP-groups-22-23-24.patch b/0007-SAE-Mask-timing-of-MODP-groups-22-23-24.patch deleted file mode 100644 index a966db7..0000000 --- a/0007-SAE-Mask-timing-of-MODP-groups-22-23-24.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 90839597cc4016b33f00055b12d59174c62770a3 Mon Sep 17 00:00:00 2001 -From: Jouni Malinen -Date: Sat, 2 Mar 2019 12:24:09 +0200 -Subject: [PATCH 07/14] 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 ---- - 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 5df9b95..75b1b4a 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.7.4 - diff --git a/0008-SAE-Use-const_time-selection-for-PWE-in-FFC.patch b/0008-SAE-Use-const_time-selection-for-PWE-in-FFC.patch deleted file mode 100644 index 3a77f9e..0000000 --- a/0008-SAE-Use-const_time-selection-for-PWE-in-FFC.patch +++ /dev/null @@ -1,105 +0,0 @@ -From f8f20717f87eff1f025f48ed585c7684debacf72 Mon Sep 17 00:00:00 2001 -From: Jouni Malinen -Date: Sat, 2 Mar 2019 12:45:33 +0200 -Subject: [PATCH 08/14] 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 ---- - 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 75b1b4a..fa9a145 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.7.4 - diff --git a/0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch b/0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch deleted file mode 100644 index cc6498b..0000000 --- a/0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch +++ /dev/null @@ -1,136 +0,0 @@ -From cff138b0747fa39765cbc641b66cfa5d7f1735d1 Mon Sep 17 00:00:00 2001 -From: Jouni Malinen -Date: Sat, 2 Mar 2019 16:05:56 +0200 -Subject: [PATCH 09/14] SAE: Use constant time operations in - sae_test_pwd_seed_ffc() - -Try to avoid showing externally visible timing or memory access -differences regardless of whether the derived pwd-value is smaller than -the group prime. - -This is related to CVE-2019-9494. - -Signed-off-by: Jouni Malinen ---- - 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 fa9a145..eaf825d 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.7.4 - diff --git a/0010-SAE-Fix-confirm-message-validation-in-error-cases.patch b/0010-SAE-Fix-confirm-message-validation-in-error-cases.patch deleted file mode 100644 index 6f0659c..0000000 --- a/0010-SAE-Fix-confirm-message-validation-in-error-cases.patch +++ /dev/null @@ -1,57 +0,0 @@ -From ac8fa9ef198640086cf2ce7c94673be2b6a018a0 Mon Sep 17 00:00:00 2001 -From: Jouni Malinen -Date: Tue, 5 Mar 2019 23:43:25 +0200 -Subject: [PATCH 10/14] SAE: Fix confirm message validation in error cases - -Explicitly verify that own and peer commit scalar/element are available -when trying to check SAE confirm message. It could have been possible to -hit a NULL pointer dereference if the peer element could not have been -parsed. (CVE-2019-9496) - -Signed-off-by: Jouni Malinen ---- - src/common/sae.c | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - -diff --git a/src/common/sae.c b/src/common/sae.c -index eaf825d..5a50294 100644 ---- a/src/common/sae.c -+++ b/src/common/sae.c -@@ -1487,23 +1487,31 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) - - wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data)); - -- if (sae->tmp == NULL) { -+ if (!sae->tmp || !sae->peer_commit_scalar || -+ !sae->tmp->own_commit_scalar) { - wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available"); - return -1; - } - -- if (sae->tmp->ec) -+ if (sae->tmp->ec) { -+ if (!sae->tmp->peer_commit_element_ecc || -+ !sae->tmp->own_commit_element_ecc) -+ return -1; - sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ecc, - sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ecc, - verifier); -- else -+ } else { -+ if (!sae->tmp->peer_commit_element_ffc || -+ !sae->tmp->own_commit_element_ffc) -+ return -1; - sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar, - sae->tmp->peer_commit_element_ffc, - sae->tmp->own_commit_scalar, - sae->tmp->own_commit_element_ffc, - verifier); -+ } - - if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) { - wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch"); --- -2.7.4 - diff --git a/0011-EAP-pwd-server-Verify-received-scalar-and-element.patch b/0011-EAP-pwd-server-Verify-received-scalar-and-element.patch deleted file mode 100644 index 5a3dba0..0000000 --- a/0011-EAP-pwd-server-Verify-received-scalar-and-element.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 70ff850e89fbc8bc7da515321b4d15b5eef70581 Mon Sep 17 00:00:00 2001 -From: Mathy Vanhoef -Date: Sun, 31 Mar 2019 17:13:06 +0200 -Subject: [PATCH 11/14] 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 ---- - 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 d0fa54a..74979da 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.7.4 - diff --git a/0012-EAP-pwd-server-Detect-reflection-attacks.patch b/0012-EAP-pwd-server-Detect-reflection-attacks.patch deleted file mode 100644 index 8121d66..0000000 --- a/0012-EAP-pwd-server-Detect-reflection-attacks.patch +++ /dev/null @@ -1,45 +0,0 @@ -From d63edfa90243e9a7de6ae5c275032f2cc79fef95 Mon Sep 17 00:00:00 2001 -From: Mathy Vanhoef -Date: Sun, 31 Mar 2019 17:26:01 +0200 -Subject: [PATCH 12/14] 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 ---- - 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 74979da..16057e9 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.7.4 - diff --git a/0013-EAP-pwd-client-Verify-received-scalar-and-element.patch b/0013-EAP-pwd-client-Verify-received-scalar-and-element.patch deleted file mode 100644 index ee780a7..0000000 --- a/0013-EAP-pwd-client-Verify-received-scalar-and-element.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 8ad8585f91823ddcc3728155e288e0f9f872e31a Mon Sep 17 00:00:00 2001 -From: Mathy Vanhoef -Date: Sun, 31 Mar 2019 17:43:44 +0200 -Subject: [PATCH 13/14] 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 ---- - 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 761c16a..5a05e54 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.7.4 - diff --git a/0014-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch b/0014-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch deleted file mode 100644 index 4fe35e0..0000000 --- a/0014-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch +++ /dev/null @@ -1,331 +0,0 @@ -From 16d4f1069118aa19bfce013493e1ac5783f92f1d Mon Sep 17 00:00:00 2001 -From: Jouni Malinen -Date: Fri, 5 Apr 2019 02:12:50 +0300 -Subject: [PATCH 14/14] 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 ---- - 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 e49aaf8..c28b56d 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 6b07cf8..2387e59 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 5a05e54..f37b974 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 16057e9..f6c75cf 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.7.4 - diff --git a/hostapd.spec b/hostapd.spec index 92b4585..5d10fd6 100644 --- a/hostapd.spec +++ b/hostapd.spec @@ -1,8 +1,8 @@ %global _hardened_build 1 Name: hostapd -Version: 2.7 -Release: 2%{?dist} +Version: 2.8 +Release: 1%{?dist} Summary: IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator License: BSD URL: http://w1.fi/hostapd @@ -13,28 +13,6 @@ Source2: %{name}.conf Source3: %{name}.sysconfig Source4: %{name}.init -# https://w1.fi/security/2019-1/sae-side-channel-attacks.txt -Patch1: https://w1.fi/security/2019-1/0001-OpenSSL-Use-constant-time-operations-for-private-big.patch -Patch2: https://w1.fi/security/2019-1/0002-Add-helper-functions-for-constant-time-operations.patch -Patch3: https://w1.fi/security/2019-1/0003-OpenSSL-Use-constant-time-selection-for-crypto_bignu.patch -Patch4: https://w1.fi/security/2019-1/0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch -Patch5: https://w1.fi/security/2019-1/0006-SAE-Avoid-branches-in-is_quadratic_residue_blind.patch -Patch6: https://w1.fi/security/2019-1/0007-SAE-Mask-timing-of-MODP-groups-22-23-24.patch -Patch7: https://w1.fi/security/2019-1/0008-SAE-Use-const_time-selection-for-PWE-in-FFC.patch -Patch8: https://w1.fi/security/2019-1/0009-SAE-Use-constant-time-operations-in-sae_test_pwd_see.patch - -# https://w1.fi/security/2019-2/eap-pwd-side-channel-attack.txt -Patch9: https://w1.fi/security/2019-2/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch - -# https://w1.fi/security/2019-3/sae-confirm-missing-state-validation.txt -Patch10: https://w1.fi/security/2019-3/0010-SAE-Fix-confirm-message-validation-in-error-cases.patch - -# https://w1.fi/security/2019-4/eap-pwd-missing-commit-validation.txt -Patch11: https://w1.fi/security/2019-4/0011-EAP-pwd-server-Verify-received-scalar-and-element.patch -Patch12: https://w1.fi/security/2019-4/0012-EAP-pwd-server-Detect-reflection-attacks.patch -Patch13: https://w1.fi/security/2019-4/0013-EAP-pwd-client-Verify-received-scalar-and-element.patch -Patch14: https://w1.fi/security/2019-4/0014-EAP-pwd-Check-element-x-y-coordinates-explicitly.patch - BuildRequires: libnl3-devel BuildRequires: openssl-devel BuildRequires: perl-generators @@ -79,20 +57,6 @@ Logwatch scripts for hostapd. %prep %setup -q -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 -%patch12 -p1 -%patch13 -p1 -%patch14 -p1 %build cd hostapd @@ -212,6 +176,10 @@ fi %{_sysconfdir}/logwatch/scripts/services/%{name} %changelog +* Wed May 15 2019 John W. Linville - 2.8-1 +- Update to version 2.8 from upstream +- Drop obsoleted patches + * Fri Apr 12 2019 John W. Linville - 2.7-2 - Bump N-V-R for rebuild diff --git a/sources b/sources index 5333a08..1349c6c 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (hostapd-2.7.tar.gz) = 1c9a210dfffb951fb667be19aa44ad8c66dccd2aed26cdab939185923550e3c1998a678ebe6975e560e1b3385bff2098f1b2cb773452ba66fb35246fdd3eb2c1 +SHA512 (hostapd-2.8.tar.gz) = 5a352517470912bcb87755a592238eac2d814a7089d4ba1ecb7969f172dbb746a4e9a6c0d47c0d7c4a6a86b04b14ac39147d729fdf3163371c1067490a4897aa