wpa_supplicant/backport-0004-CVE-2022-23303-CVE-2022-23304.patch
2022-01-26 19:17:06 +08:00

110 lines
4.6 KiB
Diff

From 603cd880e7f90595482658a7136fa6a7be5cb485 Mon Sep 17 00:00:00 2001
From: Jouni Malinen <j@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@w1.fi>
---
src/eap_common/eap_pwd_common.c | 42 +++++++++++++++++++++++++++++++++++------
1 file changed, 36 insertions(+), 6 deletions(-)
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index 755aafb..ab8eb92 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -137,7 +137,8 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
u8 qr_or_qnr_bin[MAX_ECC_PRIME_LEN];
u8 x_bin[MAX_ECC_PRIME_LEN];
u8 prime_bin[MAX_ECC_PRIME_LEN];
- struct crypto_bignum *tmp1 = NULL, *tmp2 = NULL, *pm1 = NULL;
+ u8 x_y[2 * MAX_ECC_PRIME_LEN];
+ struct crypto_bignum *tmp1 = NULL, *tmp2 = NULL, *pm1 = NULL, *y = NULL;
struct crypto_hash *hash;
unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
int ret = 0, check, res;
@@ -149,6 +150,7 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
u8 mask, found_ctr = 0, is_odd = 0;
int cmp_prime;
unsigned int in_range;
+ unsigned int is_eq;
if (grp->pwe)
return -1;
@@ -161,7 +163,6 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
if (crypto_bignum_to_bin(prime, prime_bin, sizeof(prime_bin),
primebytelen) < 0)
return -1;
- grp->pwe = crypto_ec_point_init(grp->group);
tmp1 = crypto_bignum_init();
pm1 = crypto_bignum_init();
one = crypto_bignum_init_set((const u8 *) "\x01", 1);
@@ -323,10 +324,37 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
*/
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;
}
@@ -353,6 +381,7 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
crypto_bignum_deinit(pm1, 0);
crypto_bignum_deinit(tmp1, 1);
crypto_bignum_deinit(tmp2, 1);
+ crypto_bignum_deinit(y, 1);
crypto_bignum_deinit(qr, 1);
crypto_bignum_deinit(qnr, 1);
crypto_bignum_deinit(qr_or_qnr, 1);
@@ -362,6 +391,7 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
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;
}
--
1.8.3.1