Update to version 2.8 from upstream

Drop obsoleted patches
This commit is contained in:
John W. Linville 2019-05-15 15:49:56 -04:00
parent 3dada5d43b
commit dc7f38e87e
17 changed files with 8 additions and 2028 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
/hostapd-2.7.tar.gz
/hostapd-2.8.tar.gz

View File

@ -1,93 +0,0 @@
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 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 <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 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

View File

@ -1,218 +0,0 @@
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 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 <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 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

View File

@ -1,60 +0,0 @@
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 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 <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 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

View File

@ -1,324 +0,0 @@
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 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 <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 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

View File

@ -1,241 +0,0 @@
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 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 <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 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

View File

@ -1,144 +0,0 @@
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 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 <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 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

View File

@ -1,118 +0,0 @@
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 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 <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 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

View File

@ -1,105 +0,0 @@
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 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 <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 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

View File

@ -1,136 +0,0 @@
From cff138b0747fa39765cbc641b66cfa5d7f1735d1 Mon Sep 17 00:00:00 2001
From: Jouni Malinen <jouni@codeaurora.org>
Date: Sat, 2 Mar 2019 16:05:56 +0200
Subject: [PATCH 09/14] SAE: Use constant time operations in
sae_test_pwd_seed_ffc()
Try to avoid showing externally visible timing or memory access
differences regardless of whether the derived pwd-value is smaller than
the group prime.
This is related to CVE-2019-9494.
Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
---
src/common/sae.c | 75 ++++++++++++++++++++++++++++++++++----------------------
1 file changed, 46 insertions(+), 29 deletions(-)
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

View File

@ -1,57 +0,0 @@
From ac8fa9ef198640086cf2ce7c94673be2b6a018a0 Mon Sep 17 00:00:00 2001
From: Jouni Malinen <jouni@codeaurora.org>
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 <jouni@codeaurora.org>
---
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

View File

@ -1,58 +0,0 @@
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 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 <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 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

View File

@ -1,45 +0,0 @@
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 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 <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 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

View File

@ -1,58 +0,0 @@
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 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 <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 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

View File

@ -1,331 +0,0 @@
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 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 <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 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

View File

@ -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 <linville@redhat.com> - 2.8-1
- Update to version 2.8 from upstream
- Drop obsoleted patches
* Fri Apr 12 2019 John W. Linville <linville@redhat.com> - 2.7-2
- Bump N-V-R for rebuild

View File

@ -1 +1 @@
SHA512 (hostapd-2.7.tar.gz) = 1c9a210dfffb951fb667be19aa44ad8c66dccd2aed26cdab939185923550e3c1998a678ebe6975e560e1b3385bff2098f1b2cb773452ba66fb35246fdd3eb2c1
SHA512 (hostapd-2.8.tar.gz) = 5a352517470912bcb87755a592238eac2d814a7089d4ba1ecb7969f172dbb746a4e9a6c0d47c0d7c4a6a86b04b14ac39147d729fdf3163371c1067490a4897aa