Rename BN_generate_dsa_nonce() to ossl_bn_gen_dsa_nonce_fixed_top()
authorTomas Mraz <tomas@openssl.org>
Mon, 29 Apr 2024 15:56:01 +0000 (17:56 +0200)
committerTomas Mraz <tomas@openssl.org>
Thu, 2 May 2024 07:21:30 +0000 (09:21 +0200)
And create a new BN_generate_dsa_nonce() that corrects the BIGNUM top.
We do this to avoid leaking fixed top numbers via the public API.

Also add a slight optimization in ossl_bn_gen_dsa_nonce_fixed_top()
and make it LE/BE agnostic.

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

crypto/bn/bn_rand.c
crypto/dsa/dsa_ossl.c
crypto/ec/ecdsa_ossl.c
include/crypto/bn.h

index 1131987ac7d367334878b545df8cdbdf17077fe6..a93bd68c736b252d09f4e63e9a08862bcc3e223a 100644 (file)
@@ -280,16 +280,17 @@ int ossl_bn_priv_rand_range_fixed_top(BIGNUM *r, const BIGNUM *range,
 }
 
 /*
- * BN_generate_dsa_nonce generates a random number 0 <= out < range. Unlike
- * BN_rand_range, it also includes the contents of |priv| and |message| in
- * the generation so that an RNG failure isn't fatal as long as |priv|
+ * ossl_bn_gen_dsa_nonce_fixed_top generates a random number 0 <= out < range.
+ * Unlike BN_rand_range, it also includes the contents of |priv| and |message|
+ * in the generation so that an RNG failure isn't fatal as long as |priv|
  * remains secret. This is intended for use in DSA and ECDSA where an RNG
  * weakness leads directly to private key exposure unless this function is
  * used.
  */
-int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
-                          const BIGNUM *priv, const unsigned char *message,
-                          size_t message_len, BN_CTX *ctx)
+int ossl_bn_gen_dsa_nonce_fixed_top(BIGNUM *out, const BIGNUM *range,
+                                    const BIGNUM *priv,
+                                    const unsigned char *message,
+                                    size_t message_len, BN_CTX *ctx)
 {
     EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
     /*
@@ -315,6 +316,8 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
     k_bytes = OPENSSL_malloc(num_k_bytes);
     if (k_bytes == NULL)
         goto end;
+    /* Ensure top byte is set to avoid non-constant time in bin2bn */
+    k_bytes[0] = 0xff;
 
     /* We copy |priv| into a local buffer to avoid exposing its length. */
     if (BN_bn2binpad(priv, private_bytes, sizeof(private_bytes)) < 0) {
@@ -333,13 +336,15 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
         goto end;
     }
     for (n = 0; n < max_n; n++) {
-        for (done = 0; done < num_k_bytes;) {
+        unsigned char i = 0;
+
+        for (done = 1; done < num_k_bytes;) {
             if (RAND_priv_bytes_ex(libctx, random_bytes, sizeof(random_bytes),
                                    0) <= 0)
                 goto end;
 
             if (!EVP_DigestInit_ex(mdctx, md, NULL)
-                    || !EVP_DigestUpdate(mdctx, &done, sizeof(done))
+                    || !EVP_DigestUpdate(mdctx, &i, sizeof(i))
                     || !EVP_DigestUpdate(mdctx, private_bytes,
                                          sizeof(private_bytes))
                     || !EVP_DigestUpdate(mdctx, message, message_len)
@@ -353,10 +358,9 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
                 todo = SHA512_DIGEST_LENGTH;
             memcpy(k_bytes + done, digest, todo);
             done += todo;
+            ++i;
         }
 
-        /* Ensure top byte is set to avoid non-constant time in bin2bn */
-        k_bytes[0] = 0x80;
         if (!BN_bin2bn(k_bytes, num_k_bytes, out))
             goto end;
 
@@ -381,3 +385,20 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
     OPENSSL_cleanse(private_bytes, sizeof(private_bytes));
     return ret;
 }
+
+int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
+                          const BIGNUM *priv, const unsigned char *message,
+                          size_t message_len, BN_CTX *ctx)
+{
+    int ret;
+
+    ret = ossl_bn_gen_dsa_nonce_fixed_top(out, range, priv, message,
+                                          message_len, ctx);
+    /*
+     * This call makes the BN_generate_dsa_nonce non-const-time, thus we
+     * do not use it internally. But fixed_top BNs currently cannot be returned
+     * from public API calls.
+     */
+    bn_correct_top(out);
+    return ret;
+}
index 6a00a0fa89d572eb1c0c2b8e001481c67e1da3bb..409830092dc6360f56928f37e01e3a6dbf26dc37 100644 (file)
@@ -282,8 +282,9 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in,
                  * We calculate k from SHA512(private_key + H(message) + random).
                  * This protects the private key from a weak PRNG.
                  */
-                if (!BN_generate_dsa_nonce(k, dsa->params.q, dsa->priv_key, dgst,
-                                           dlen, ctx))
+                if (!ossl_bn_gen_dsa_nonce_fixed_top(k, dsa->params.q,
+                                                     dsa->priv_key, dgst,
+                                                     dlen, ctx))
                     goto err;
             }
         } else if (!ossl_bn_priv_rand_range_fixed_top(k, dsa->params.q, 0, ctx))
index 69d966ae14bb0fb0ee3be3903c9801cb96c19383..1e611f7ffce0b147aca1eaa67b78f751ef43194a 100644 (file)
@@ -198,8 +198,8 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in,
                                                                libctx, propq);
 #endif
                 } else {
-                    res = BN_generate_dsa_nonce(k, order, priv_key, dgst, dlen,
-                                                ctx);
+                    res = ossl_bn_gen_dsa_nonce_fixed_top(k, order, priv_key,
+                                                          dgst, dlen, ctx);
                 }
             } else {
                 res = ossl_bn_priv_rand_range_fixed_top(k, order, 0, ctx);
index 308cf575024a8e1cbe65c8a772d458dd2ffa3153..9a988a467de27ec02a1725a8f4c193f4e44a7072 100644 (file)
@@ -91,6 +91,10 @@ int ossl_bn_mask_bits_fixed_top(BIGNUM *a, int n);
 int ossl_bn_is_word_fixed_top(const BIGNUM *a, BN_ULONG w);
 int ossl_bn_priv_rand_range_fixed_top(BIGNUM *r, const BIGNUM *range,
                                       unsigned int strength, BN_CTX *ctx);
+int ossl_bn_gen_dsa_nonce_fixed_top(BIGNUM *out, const BIGNUM *range,
+                                    const BIGNUM *priv,
+                                    const unsigned char *message,
+                                    size_t message_len, BN_CTX *ctx);
 
 #define BN_PRIMETEST_COMPOSITE                    0
 #define BN_PRIMETEST_COMPOSITE_WITH_FACTOR        1