Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/external/bsd/wpa/dist/src/common Try to avoid showing extern...



details:   https://anonhg.NetBSD.org/src/rev/51525f82467c
branches:  trunk
changeset: 998208:51525f82467c
user:      christos <christos%NetBSD.org@localhost>
date:      Wed Apr 10 18:01:08 2019 +0000

description:
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.

diffstat:

 external/bsd/wpa/dist/src/common/sae.c |  75 ++++++++++++++++++++-------------
 1 files changed, 46 insertions(+), 29 deletions(-)

diffs (115 lines):

diff -r a3a4615b9dbb -r 51525f82467c external/bsd/wpa/dist/src/common/sae.c
--- a/external/bsd/wpa/dist/src/common/sae.c    Wed Apr 10 18:00:45 2019 +0000
+++ b/external/bsd/wpa/dist/src/common/sae.c    Wed Apr 10 18:01:08 2019 +0000
@@ -311,14 +311,17 @@
 }
 
 
+/* 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);
 
@@ -330,16 +333,29 @@
        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:
@@ -353,33 +369,34 @@
                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);
+       if (!b)
+               goto fail;
 
-       crypto_bignum_deinit(a, 0);
-       crypto_bignum_deinit(b, 0);
+       res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
+       if (res < 0)
+               goto fail;
 
-       if (res < 0) {
-               wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE");
-               return -1;
-       }
+       /* 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);
 
-       /* if (PWE > 1) --> found */
-       if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) {
-               wpa_printf(MSG_DEBUG, "SAE: PWE <= 1");
-               return 0;
-       }
-
-       wpa_printf(MSG_DEBUG, "SAE: PWE found");
-       return 1;
+fail:
+       crypto_bignum_deinit(a, 1);
+       crypto_bignum_deinit(b, 1);
+       return res;
 }
 
 



Home | Main Index | Thread Index | Old Index