[openwrt/openwrt] hostapd: Apply SAE/EAP-pwd side-channel attack update 2

LEDE Commits lede-commits at lists.infradead.org
Sun Feb 13 14:39:11 PST 2022


hauke pushed a commit to openwrt/openwrt.git, branch openwrt-19.07:
https://git.openwrt.org/e7596ce0b08595083a32870cc019de9bb514aaec

commit e7596ce0b08595083a32870cc019de9bb514aaec
Author: Hauke Mehrtens <hauke at hauke-m.de>
AuthorDate: Sat Feb 12 20:37:12 2022 +0100

    hostapd: Apply SAE/EAP-pwd side-channel attack update 2
    
    This fixes some recent security problems in hostapd.
    See here for details: https://w1.fi/security/2022-1
    * CVE-2022-23303
    * CVE-2022-23304
    
    Signed-off-by: Hauke Mehrtens <hauke at hauke-m.de>
---
 package/network/services/hostapd/Makefile          |   2 +-
 ...rypto-Add-more-bignum-EC-helper-functions.patch | 309 +++++++++++++++++++++
 .../082-dragonfly-Add-sqrt-helper-function.patch   |  65 +++++
 ...the-y-coordinate-for-PWE-with-own-impleme.patch |  94 +++++++
 ...ive-the-y-coordinate-for-PWE-with-own-imp.patch | 108 +++++++
 5 files changed, 577 insertions(+), 1 deletion(-)

diff --git a/package/network/services/hostapd/Makefile b/package/network/services/hostapd/Makefile
index 75615efd9b..4b41168cd5 100644
--- a/package/network/services/hostapd/Makefile
+++ b/package/network/services/hostapd/Makefile
@@ -7,7 +7,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=hostapd
-PKG_RELEASE:=7
+PKG_RELEASE:=8
 
 PKG_SOURCE_URL:=http://w1.fi/hostap.git
 PKG_SOURCE_PROTO:=git
diff --git a/package/network/services/hostapd/patches/081-crypto-Add-more-bignum-EC-helper-functions.patch b/package/network/services/hostapd/patches/081-crypto-Add-more-bignum-EC-helper-functions.patch
new file mode 100644
index 0000000000..e83c5e60f2
--- /dev/null
+++ b/package/network/services/hostapd/patches/081-crypto-Add-more-bignum-EC-helper-functions.patch
@@ -0,0 +1,309 @@
+From 208e5687ff2e48622e28d8888ce5444a54353bbd Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni at codeaurora.org>
+Date: Tue, 27 Aug 2019 16:33:15 +0300
+Subject: [PATCH 1/4] crypto: Add more bignum/EC helper functions
+
+These are needed for implementing SAE hash-to-element.
+
+Signed-off-by: Jouni Malinen <jouni at codeaurora.org>
+---
+ src/crypto/crypto.h         | 45 ++++++++++++++++++
+ src/crypto/crypto_openssl.c | 94 +++++++++++++++++++++++++++++++++++++
+ src/crypto/crypto_wolfssl.c | 66 ++++++++++++++++++++++++++
+ 3 files changed, 205 insertions(+)
+
+--- a/src/crypto/crypto.h
++++ b/src/crypto/crypto.h
+@@ -519,6 +519,13 @@ struct crypto_bignum * crypto_bignum_ini
+ struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len);
+ 
+ /**
++ * crypto_bignum_init_set - Allocate memory for bignum and set the value (uint)
++ * @val: Value to set
++ * Returns: Pointer to allocated bignum or %NULL on failure
++ */
++struct crypto_bignum * crypto_bignum_init_uint(unsigned int val);
++
++/**
+  * crypto_bignum_deinit - Free bignum
+  * @n: Bignum from crypto_bignum_init() or crypto_bignum_init_set()
+  * @clear: Whether to clear the value from memory
+@@ -613,6 +620,19 @@ int crypto_bignum_div(const struct crypt
+ 		      struct crypto_bignum *c);
+ 
+ /**
++ * crypto_bignum_addmod - d = a + b (mod c)
++ * @a: Bignum
++ * @b: Bignum
++ * @c: Bignum
++ * @d: Bignum; used to store the result of (a + b) % c
++ * Returns: 0 on success, -1 on failure
++ */
++int crypto_bignum_addmod(const struct crypto_bignum *a,
++			 const struct crypto_bignum *b,
++			 const struct crypto_bignum *c,
++			 struct crypto_bignum *d);
++
++/**
+  * crypto_bignum_mulmod - d = a * b (mod c)
+  * @a: Bignum
+  * @b: Bignum
+@@ -626,6 +646,28 @@ int crypto_bignum_mulmod(const struct cr
+ 			 struct crypto_bignum *d);
+ 
+ /**
++ * crypto_bignum_sqrmod - c = a^2 (mod b)
++ * @a: Bignum
++ * @b: Bignum
++ * @c: Bignum; used to store the result of a^2 % b
++ * Returns: 0 on success, -1 on failure
++ */
++int crypto_bignum_sqrmod(const struct crypto_bignum *a,
++			 const struct crypto_bignum *b,
++			 struct crypto_bignum *c);
++
++/**
++ * crypto_bignum_sqrtmod - returns sqrt(a) (mod b)
++ * @a: Bignum
++ * @b: Bignum
++ * @c: Bignum; used to store the result
++ * Returns: 0 on success, -1 on failure
++ */
++int crypto_bignum_sqrtmod(const struct crypto_bignum *a,
++			  const struct crypto_bignum *b,
++			  struct crypto_bignum *c);
++
++/**
+  * crypto_bignum_rshift - r = a >> n
+  * @a: Bignum
+  * @n: Number of bits
+@@ -731,6 +773,9 @@ const struct crypto_bignum * crypto_ec_g
+  */
+ const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e);
+ 
++const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e);
++const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e);
++
+ /**
+  * struct crypto_ec_point - Elliptic curve point
+  *
+--- a/src/crypto/crypto_openssl.c
++++ b/src/crypto/crypto_openssl.c
+@@ -1283,6 +1283,24 @@ struct crypto_bignum * crypto_bignum_ini
+ }
+ 
+ 
++struct crypto_bignum * crypto_bignum_init_uint(unsigned int val)
++{
++	BIGNUM *bn;
++
++	if (TEST_FAIL())
++		return NULL;
++
++	bn = BN_new();
++	if (!bn)
++		return NULL;
++	if (BN_set_word(bn, val) != 1) {
++		BN_free(bn);
++		return NULL;
++	}
++	return (struct crypto_bignum *) bn;
++}
++
++
+ void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
+ {
+ 	if (clear)
+@@ -1449,6 +1467,28 @@ int crypto_bignum_div(const struct crypt
+ }
+ 
+ 
++int crypto_bignum_addmod(const struct crypto_bignum *a,
++			 const struct crypto_bignum *b,
++			 const struct crypto_bignum *c,
++			 struct crypto_bignum *d)
++{
++	int res;
++	BN_CTX *bnctx;
++
++	if (TEST_FAIL())
++		return -1;
++
++	bnctx = BN_CTX_new();
++	if (!bnctx)
++		return -1;
++	res = BN_mod_add((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
++			 (const BIGNUM *) c, bnctx);
++	BN_CTX_free(bnctx);
++
++	return res ? 0 : -1;
++}
++
++
+ int crypto_bignum_mulmod(const struct crypto_bignum *a,
+ 			 const struct crypto_bignum *b,
+ 			 const struct crypto_bignum *c,
+@@ -1472,6 +1512,48 @@ int crypto_bignum_mulmod(const struct cr
+ }
+ 
+ 
++int crypto_bignum_sqrmod(const struct crypto_bignum *a,
++			 const struct crypto_bignum *b,
++			 struct crypto_bignum *c)
++{
++	int res;
++	BN_CTX *bnctx;
++
++	if (TEST_FAIL())
++		return -1;
++
++	bnctx = BN_CTX_new();
++	if (!bnctx)
++		return -1;
++	res = BN_mod_sqr((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b,
++			 bnctx);
++	BN_CTX_free(bnctx);
++
++	return res ? 0 : -1;
++}
++
++
++int crypto_bignum_sqrtmod(const struct crypto_bignum *a,
++			  const struct crypto_bignum *b,
++			  struct crypto_bignum *c)
++{
++	BN_CTX *bnctx;
++	BIGNUM *res;
++
++	if (TEST_FAIL())
++		return -1;
++
++	bnctx = BN_CTX_new();
++	if (!bnctx)
++		return -1;
++	res = BN_mod_sqrt((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b,
++			  bnctx);
++	BN_CTX_free(bnctx);
++
++	return res ? 0 : -1;
++}
++
++
+ int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+ 			 struct crypto_bignum *r)
+ {
+@@ -1682,6 +1764,18 @@ const struct crypto_bignum * crypto_ec_g
+ }
+ 
+ 
++const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e)
++{
++	return (const struct crypto_bignum *) e->a;
++}
++
++
++const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e)
++{
++	return (const struct crypto_bignum *) e->b;
++}
++
++
+ void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
+ {
+ 	if (clear)
+--- a/src/crypto/crypto_wolfssl.c
++++ b/src/crypto/crypto_wolfssl.c
+@@ -1042,6 +1042,26 @@ struct crypto_bignum * crypto_bignum_ini
+ }
+ 
+ 
++struct crypto_bignum * crypto_bignum_init_uint(unsigned int val)
++{
++	mp_int *a;
++
++	if (TEST_FAIL())
++		return NULL;
++
++	a = (mp_int *) crypto_bignum_init();
++	if (!a)
++		return NULL;
++
++	if (mp_set_int(a, val) != MP_OKAY) {
++		os_free(a);
++		a = NULL;
++	}
++
++	return (struct crypto_bignum *) a;
++}
++
++
+ void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
+ {
+ 	if (!n)
+@@ -1168,6 +1188,19 @@ int crypto_bignum_div(const struct crypt
+ }
+ 
+ 
++int crypto_bignum_addmod(const struct crypto_bignum *a,
++			 const struct crypto_bignum *b,
++			 const struct crypto_bignum *c,
++			 struct crypto_bignum *d)
++{
++	if (TEST_FAIL())
++		return -1;
++
++	return mp_addmod((mp_int *) a, (mp_int *) b, (mp_int *) c,
++			 (mp_int *) d) == MP_OKAY ?  0 : -1;
++}
++
++
+ int crypto_bignum_mulmod(const struct crypto_bignum *a,
+ 			 const struct crypto_bignum *b,
+ 			 const struct crypto_bignum *m,
+@@ -1181,6 +1214,27 @@ int crypto_bignum_mulmod(const struct cr
+ }
+ 
+ 
++int crypto_bignum_sqrmod(const struct crypto_bignum *a,
++			 const struct crypto_bignum *b,
++			 struct crypto_bignum *c)
++{
++	if (TEST_FAIL())
++		return -1;
++
++	return mp_sqrmod((mp_int *) a, (mp_int *) b,
++			 (mp_int *) c) == MP_OKAY ?  0 : -1;
++}
++
++
++int crypto_bignum_sqrtmod(const struct crypto_bignum *a,
++			  const struct crypto_bignum *b,
++			  struct crypto_bignum *c)
++{
++	/* TODO */
++	return -1;
++}
++
++
+ int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+ 			 struct crypto_bignum *r)
+ {
+@@ -1386,6 +1440,18 @@ const struct crypto_bignum * crypto_ec_g
+ }
+ 
+ 
++const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e)
++{
++	return (const struct crypto_bignum *) &e->a;
++}
++
++
++const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e)
++{
++	return (const struct crypto_bignum *) &e->b;
++}
++
++
+ void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
+ {
+ 	ecc_point *point = (ecc_point *) p;
diff --git a/package/network/services/hostapd/patches/082-dragonfly-Add-sqrt-helper-function.patch b/package/network/services/hostapd/patches/082-dragonfly-Add-sqrt-helper-function.patch
new file mode 100644
index 0000000000..b8b1e078b0
--- /dev/null
+++ b/package/network/services/hostapd/patches/082-dragonfly-Add-sqrt-helper-function.patch
@@ -0,0 +1,65 @@
+From 2232d3d5f188b65dbb6c823ac62175412739eb16 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <j at w1.fi>
+Date: Fri, 7 Jan 2022 13:47:16 +0200
+Subject: [PATCH 2/4] dragonfly: Add sqrt() helper function
+
+This is a backport of "SAE: Move sqrt() implementation into a helper
+function" to introduce the helper function needed for the following
+patches.
+
+Signed-off-by: Jouni Malinen <j at w1.fi>
+---
+ src/common/dragonfly.c | 34 ++++++++++++++++++++++++++++++++++
+ src/common/dragonfly.h |  2 ++
+ 2 files changed, 36 insertions(+)
+
+--- a/src/common/dragonfly.c
++++ b/src/common/dragonfly.c
+@@ -213,3 +213,37 @@ int dragonfly_generate_scalar(const stru
+ 		   "dragonfly: Unable to get randomness for own scalar");
+ 	return -1;
+ }
++
++
++/* res = sqrt(val) */
++int dragonfly_sqrt(struct crypto_ec *ec, const struct crypto_bignum *val,
++		   struct crypto_bignum *res)
++{
++	const struct crypto_bignum *prime;
++	struct crypto_bignum *tmp, *one;
++	int ret = 0;
++	u8 prime_bin[DRAGONFLY_MAX_ECC_PRIME_LEN];
++	size_t prime_len;
++
++	/* For prime p such that p = 3 mod 4, sqrt(w) = w^((p+1)/4) mod p */
++
++	prime = crypto_ec_get_prime(ec);
++	prime_len = crypto_ec_prime_len(ec);
++	tmp = crypto_bignum_init();
++	one = crypto_bignum_init_uint(1);
++
++	if (crypto_bignum_to_bin(prime, prime_bin, sizeof(prime_bin),
++				 prime_len) < 0 ||
++	    (prime_bin[prime_len - 1] & 0x03) != 3 ||
++	    !tmp || !one ||
++	    /* tmp = (p+1)/4 */
++	    crypto_bignum_add(prime, one, tmp) < 0 ||
++	    crypto_bignum_rshift(tmp, 2, tmp) < 0 ||
++	    /* res = sqrt(val) */
++	    crypto_bignum_exptmod(val, tmp, prime, res) < 0)
++		ret = -1;
++
++	crypto_bignum_deinit(tmp, 0);
++	crypto_bignum_deinit(one, 0);
++	return ret;
++}
+--- a/src/common/dragonfly.h
++++ b/src/common/dragonfly.h
+@@ -27,5 +27,7 @@ int dragonfly_generate_scalar(const stru
+ 			      struct crypto_bignum *_rand,
+ 			      struct crypto_bignum *_mask,
+ 			      struct crypto_bignum *scalar);
++int dragonfly_sqrt(struct crypto_ec *ec, const struct crypto_bignum *val,
++		   struct crypto_bignum *res);
+ 
+ #endif /* DRAGONFLY_H */
diff --git a/package/network/services/hostapd/patches/083-SAE-Derive-the-y-coordinate-for-PWE-with-own-impleme.patch b/package/network/services/hostapd/patches/083-SAE-Derive-the-y-coordinate-for-PWE-with-own-impleme.patch
new file mode 100644
index 0000000000..d2a46c68f5
--- /dev/null
+++ b/package/network/services/hostapd/patches/083-SAE-Derive-the-y-coordinate-for-PWE-with-own-impleme.patch
@@ -0,0 +1,94 @@
+From fe534b0baaa8c0e6ddeb24cf529d6e50e33dc501 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <j at w1.fi>
+Date: Fri, 7 Jan 2022 13:47:16 +0200
+Subject: [PATCH 3/4] SAE: Derive the y coordinate for PWE with own
+ implementation
+
+The crypto_ec_point_solve_y_coord() wrapper function might not use
+constant time operations in the crypto library and as such, could leak
+side channel information about the password that is used to generate the
+PWE in the hunting and pecking loop. As such, calculate the two possible
+y coordinate values and pick the correct one to use with constant time
+selection.
+
+Signed-off-by: Jouni Malinen <j at w1.fi>
+---
+ src/common/sae.c | 47 +++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 33 insertions(+), 14 deletions(-)
+
+--- a/src/common/sae.c
++++ b/src/common/sae.c
+@@ -286,14 +286,16 @@ static int sae_derive_pwe_ecc(struct sae
+ 	int pwd_seed_odd = 0;
+ 	u8 prime[SAE_MAX_ECC_PRIME_LEN];
+ 	size_t prime_len;
+-	struct crypto_bignum *x = NULL, *qr = NULL, *qnr = NULL;
++	struct crypto_bignum *x = NULL, *y = 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];
++	u8 x_y[2 * SAE_MAX_ECC_PRIME_LEN];
+ 	int res = -1;
+ 	u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
+ 		       * mask */
++	unsigned int is_eq;
+ 
+ 	os_memset(x_bin, 0, sizeof(x_bin));
+ 
+@@ -402,25 +404,42 @@ static int sae_derive_pwe_ecc(struct sae
+ 		goto fail;
+ 	}
+ 
+-	if (!sae->tmp->pwe_ecc)
+-		sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
+-	if (!sae->tmp->pwe_ecc)
+-		res = -1;
+-	else
+-		res = crypto_ec_point_solve_y_coord(sae->tmp->ec,
+-						    sae->tmp->pwe_ecc, x,
+-						    pwd_seed_odd);
+-	if (res < 0) {
+-		/*
+-		 * This should not happen since we already checked that there
+-		 * is a result.
+-		 */
++	/* y = sqrt(x^3 + ax + b) mod p
++	 * if LSB(save) == LSB(y): PWE = (x, y)
++	 * else: PWE = (x, p - y)
++	 *
++	 * Calculate y and the two possible values for PWE and after that,
++	 * use constant time selection to copy the correct alternative.
++	 */
++	y = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x);
++	if (!y ||
++	    dragonfly_sqrt(sae->tmp->ec, y, y) < 0 ||
++	    crypto_bignum_to_bin(y, x_y, SAE_MAX_ECC_PRIME_LEN,
++				 prime_len) < 0 ||
++	    crypto_bignum_sub(sae->tmp->prime, y, y) < 0 ||
++	    crypto_bignum_to_bin(y, x_y + SAE_MAX_ECC_PRIME_LEN,
++				 SAE_MAX_ECC_PRIME_LEN, prime_len) < 0) {
+ 		wpa_printf(MSG_DEBUG, "SAE: Could not solve y");
++		goto fail;
++	}
++
++	is_eq = const_time_eq(pwd_seed_odd, x_y[prime_len - 1] & 0x01);
++	const_time_select_bin(is_eq, x_y, x_y + SAE_MAX_ECC_PRIME_LEN,
++			      prime_len, x_y + prime_len);
++	os_memcpy(x_y, x_bin, prime_len);
++	wpa_hexdump_key(MSG_DEBUG, "SAE: PWE", x_y, 2 * prime_len);
++	crypto_ec_point_deinit(sae->tmp->pwe_ecc, 1);
++	sae->tmp->pwe_ecc = crypto_ec_point_from_bin(sae->tmp->ec, x_y);
++	if (!sae->tmp->pwe_ecc) {
++		wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
++		res = -1;
+ 	}
+ 
+ fail:
++	forced_memzero(x_y, sizeof(x_y));
+ 	crypto_bignum_deinit(qr, 0);
+ 	crypto_bignum_deinit(qnr, 0);
++	crypto_bignum_deinit(y, 1);
+ 	os_free(dummy_password);
+ 	bin_clear_free(tmp_password, password_len);
+ 	crypto_bignum_deinit(x, 1);
diff --git a/package/network/services/hostapd/patches/084-EAP-pwd-Derive-the-y-coordinate-for-PWE-with-own-imp.patch b/package/network/services/hostapd/patches/084-EAP-pwd-Derive-the-y-coordinate-for-PWE-with-own-imp.patch
new file mode 100644
index 0000000000..c5ddddcec3
--- /dev/null
+++ b/package/network/services/hostapd/patches/084-EAP-pwd-Derive-the-y-coordinate-for-PWE-with-own-imp.patch
@@ -0,0 +1,108 @@
+From 603cd880e7f90595482658a7136fa6a7be5cb485 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <j at w1.fi>
+Date: Fri, 7 Jan 2022 18:52:27 +0200
+Subject: [PATCH 4/4] EAP-pwd: Derive the y coordinate for PWE with own
+ implementation
+
+The crypto_ec_point_solve_y_coord() wrapper function might not use
+constant time operations in the crypto library and as such, could leak
+side channel information about the password that is used to generate the
+PWE in the hunting and pecking loop. As such, calculate the two possible
+y coordinate values and pick the correct one to use with constant time
+selection.
+
+Signed-off-by: Jouni Malinen <j at w1.fi>
+---
+ src/eap_common/eap_pwd_common.c | 46 ++++++++++++++++++++++++++-------
+ 1 file changed, 36 insertions(+), 10 deletions(-)
+
+--- a/src/eap_common/eap_pwd_common.c
++++ b/src/eap_common/eap_pwd_common.c
+@@ -127,7 +127,8 @@ int compute_password_element(EAP_PWD_gro
+ 	u8 qr_or_qnr_bin[MAX_ECC_PRIME_LEN];
+ 	u8 x_bin[MAX_ECC_PRIME_LEN];
+ 	u8 prime_bin[MAX_ECC_PRIME_LEN];
+-	struct crypto_bignum *tmp2 = NULL;
++	u8 x_y[2 * MAX_ECC_PRIME_LEN];
++	struct crypto_bignum *tmp2 = NULL, *y = NULL;
+ 	struct crypto_hash *hash;
+ 	unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
+ 	int ret = 0, res;
+@@ -139,6 +140,7 @@ int compute_password_element(EAP_PWD_gro
+ 	u8 found_ctr = 0, is_odd = 0;
+ 	int cmp_prime;
+ 	unsigned int in_range;
++	unsigned int is_eq;
+ 
+ 	if (grp->pwe)
+ 		return -1;
+@@ -151,11 +153,6 @@ int compute_password_element(EAP_PWD_gro
+ 	if (crypto_bignum_to_bin(prime, prime_bin, sizeof(prime_bin),
+ 				 primebytelen) < 0)
+ 		return -1;
+-	grp->pwe = crypto_ec_point_init(grp->group);
+-	if (!grp->pwe) {
+-		wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums");
+-		goto fail;
+-	}
+ 
+ 	if ((prfbuf = os_malloc(primebytelen)) == NULL) {
+ 		wpa_printf(MSG_INFO, "EAP-pwd: unable to malloc space for prf "
+@@ -261,10 +258,37 @@ int compute_password_element(EAP_PWD_gro
+ 	 */
+ 	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");
++	if (!x_candidate)
++		goto fail;
++
++	/* y = sqrt(x^3 + ax + b) mod p
++	 * if LSB(y) == LSB(pwd-seed): PWE = (x, y)
++	 * else: PWE = (x, p - y)
++	 *
++	 * Calculate y and the two possible values for PWE and after that,
++	 * use constant time selection to copy the correct alternative.
++	 */
++	y = crypto_ec_point_compute_y_sqr(grp->group, x_candidate);
++	if (!y ||
++	    dragonfly_sqrt(grp->group, y, y) < 0 ||
++	    crypto_bignum_to_bin(y, x_y, MAX_ECC_PRIME_LEN, primebytelen) < 0 ||
++	    crypto_bignum_sub(prime, y, y) < 0 ||
++	    crypto_bignum_to_bin(y, x_y + MAX_ECC_PRIME_LEN,
++				 MAX_ECC_PRIME_LEN, primebytelen) < 0) {
++		wpa_printf(MSG_DEBUG, "SAE: Could not solve y");
++		goto fail;
++	}
++
++	/* Constant time selection of the y coordinate from the two
++	 * options */
++	is_eq = const_time_eq(is_odd, x_y[primebytelen - 1] & 0x01);
++	const_time_select_bin(is_eq, x_y, x_y + MAX_ECC_PRIME_LEN,
++			      primebytelen, x_y + primebytelen);
++	os_memcpy(x_y, x_bin, primebytelen);
++	wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: PWE", x_y, 2 * primebytelen);
++	grp->pwe = crypto_ec_point_from_bin(grp->group, x_y);
++	if (!grp->pwe) {
++		wpa_printf(MSG_DEBUG, "EAP-pwd: Could not generate PWE");
+ 		goto fail;
+ 	}
+ 
+@@ -289,6 +313,7 @@ int compute_password_element(EAP_PWD_gro
+ 	/* cleanliness and order.... */
+ 	crypto_bignum_deinit(x_candidate, 1);
+ 	crypto_bignum_deinit(tmp2, 1);
++	crypto_bignum_deinit(y, 1);
+ 	crypto_bignum_deinit(qr, 1);
+ 	crypto_bignum_deinit(qnr, 1);
+ 	bin_clear_free(prfbuf, primebytelen);
+@@ -296,6 +321,7 @@ int compute_password_element(EAP_PWD_gro
+ 	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));
++	forced_memzero(x_y, sizeof(x_y));
+ 
+ 	return ret;
+ }



More information about the lede-commits mailing list