]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Fix timing side-channel in ECDSA signature computation
authorTomas Mraz <tomas@openssl.org>
Wed, 15 Jan 2025 17:27:02 +0000 (18:27 +0100)
committerTomas Mraz <tomas@openssl.org>
Mon, 20 Jan 2025 08:30:48 +0000 (09:30 +0100)
There is a timing signal of around 300 nanoseconds when the top word of
the inverted ECDSA nonce value is zero. This can happen with significant
probability only for some of the supported elliptic curves. In particular
the NIST P-521 curve is affected. To be able to measure this leak, the
attacker process must either be located in the same physical computer or
must have a very fast network connection with low latency.

Attacks on ECDSA nonce are also known as Minerva attack.

Fixes CVE-2024-13176

Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/26429)

crypto/bn/bn_exp.c
crypto/ec/ec_lib.c
include/crypto/bn.h

index b876edbfac36e3e71a51d00465e7ddf322713351..af52e2ced6914b2b7e109548ee4d6915977095e7 100644 (file)
@@ -606,7 +606,7 @@ static int MOD_EXP_CTIME_COPY_FROM_PREBUF(BIGNUM *b, int top,
  * out by Colin Percival,
  * http://www.daemonology.net/hyperthreading-considered-harmful/)
  */
-int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
+int bn_mod_exp_mont_fixed_top(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
                               const BIGNUM *m, BN_CTX *ctx,
                               BN_MONT_CTX *in_mont)
 {
@@ -623,10 +623,6 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
     unsigned int t4 = 0;
 #endif
 
-    bn_check_top(a);
-    bn_check_top(p);
-    bn_check_top(m);
-
     if (!BN_is_odd(m)) {
         ERR_raise(ERR_LIB_BN, BN_R_CALLED_WITH_EVEN_MODULUS);
         return 0;
@@ -1146,7 +1142,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
             goto err;
     } else
 #endif
-    if (!BN_from_montgomery(rr, &tmp, mont, ctx))
+    if (!bn_from_mont_fixed_top(rr, &tmp, mont, ctx))
         goto err;
     ret = 1;
  err:
@@ -1160,6 +1156,19 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
     return ret;
 }
 
+int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
+                              const BIGNUM *m, BN_CTX *ctx,
+                              BN_MONT_CTX *in_mont)
+{
+    bn_check_top(a);
+    bn_check_top(p);
+    bn_check_top(m);
+    if (!bn_mod_exp_mont_fixed_top(rr, a, p, m, ctx, in_mont))
+        return 0;
+    bn_correct_top(rr);
+    return 1;
+}
+
 int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p,
                          const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
 {
index 19384eba186b52b55af4ba07fdba24d583c6e110..3f8d65c1bf1a1e74de229491e615ac578fc866eb 100644 (file)
@@ -21,6 +21,7 @@
 #include <openssl/opensslv.h>
 #include <openssl/param_build.h>
 #include "crypto/ec.h"
+#include "crypto/bn.h"
 #include "internal/nelem.h"
 #include "ec_local.h"
 
@@ -1265,10 +1266,10 @@ static int ec_field_inverse_mod_ord(const EC_GROUP *group, BIGNUM *r,
     if (!BN_sub(e, group->order, e))
         goto err;
     /*-
-     * Exponent e is public.
-     * No need for scatter-gather or BN_FLG_CONSTTIME.
+     * Although the exponent is public we want the result to be
+     * fixed top.
      */
-    if (!BN_mod_exp_mont(r, x, e, group->order, ctx, group->mont_data))
+    if (!bn_mod_exp_mont_fixed_top(r, x, e, group->order, ctx, group->mont_data))
         goto err;
 
     ret = 1;
index 47d9b44f879f013b6a62cff46b109144e340aeea..bdee28625ce60d0cdb55f4db26dd68e2cec37007 100644 (file)
@@ -73,6 +73,9 @@ int bn_set_words(BIGNUM *a, const BN_ULONG *words, int num_words);
  */
 int bn_mul_mont_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
                           BN_MONT_CTX *mont, BN_CTX *ctx);
+int bn_mod_exp_mont_fixed_top(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
+                              const BIGNUM *m, BN_CTX *ctx,
+                              BN_MONT_CTX *in_mont);
 int bn_to_mont_fixed_top(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont,
                          BN_CTX *ctx);
 int bn_from_mont_fixed_top(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont,