|  | @@ -1,5 +1,5 @@
 | 
	
		
			
				|  |  |  /*
 | 
	
		
			
				|  |  | - * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
 | 
	
		
			
				|  |  | + * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  |   * Licensed under the Apache License 2.0 (the "License").  You may not use
 | 
	
		
			
				|  |  |   * this file except in compliance with the License.  You can obtain a copy
 | 
	
	
		
			
				|  | @@ -184,8 +184,8 @@ static int bnrand_range(BNRAND_FLAG flag, BIGNUM *r, const BIGNUM *range,
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |          do {
 | 
	
		
			
				|  |  |              /* range = 11..._2  or  range = 101..._2 */
 | 
	
		
			
				|  |  | -            if (!bnrand(flag, r, n, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY, 0,
 | 
	
		
			
				|  |  | -                        ctx))
 | 
	
		
			
				|  |  | +            if (!bnrand(flag, r, n, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY,
 | 
	
		
			
				|  |  | +                        strength, ctx))
 | 
	
		
			
				|  |  |                  return 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              if (!--count) {
 | 
	
	
		
			
				|  | @@ -238,17 +238,63 @@ int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range)
 | 
	
		
			
				|  |  |  # endif
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +int ossl_bn_priv_rand_range_fixed_top(BIGNUM *r, const BIGNUM *range,
 | 
	
		
			
				|  |  | +                                      unsigned int strength, BN_CTX *ctx)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    int n;
 | 
	
		
			
				|  |  | +    int count = 100;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (r == NULL) {
 | 
	
		
			
				|  |  | +        ERR_raise(ERR_LIB_BN, ERR_R_PASSED_NULL_PARAMETER);
 | 
	
		
			
				|  |  | +        return 0;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (range->neg || BN_is_zero(range)) {
 | 
	
		
			
				|  |  | +        ERR_raise(ERR_LIB_BN, BN_R_INVALID_RANGE);
 | 
	
		
			
				|  |  | +        return 0;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    n = BN_num_bits(range);     /* n > 0 */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /* BN_is_bit_set(range, n - 1) always holds */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (n == 1) {
 | 
	
		
			
				|  |  | +        BN_zero(r);
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        BN_set_flags(r, BN_FLG_CONSTTIME);
 | 
	
		
			
				|  |  | +        do {
 | 
	
		
			
				|  |  | +            if (!bnrand(PRIVATE, r, n + 1, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY,
 | 
	
		
			
				|  |  | +                        strength, ctx))
 | 
	
		
			
				|  |  | +                return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (!--count) {
 | 
	
		
			
				|  |  | +                ERR_raise(ERR_LIB_BN, BN_R_TOO_MANY_ITERATIONS);
 | 
	
		
			
				|  |  | +                return 0;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            ossl_bn_mask_bits_fixed_top(r, n);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        while (BN_ucmp(r, range) >= 0);
 | 
	
		
			
				|  |  | +#ifdef BN_DEBUG
 | 
	
		
			
				|  |  | +        /* With BN_DEBUG on a fixed top number cannot be returned */
 | 
	
		
			
				|  |  | +        bn_correct_top(r);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return 1;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /*
 | 
	
		
			
				|  |  | - * 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();
 | 
	
		
			
				|  |  |      /*
 | 
	
	
		
			
				|  | @@ -258,20 +304,24 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
 | 
	
		
			
				|  |  |      unsigned char random_bytes[64];
 | 
	
		
			
				|  |  |      unsigned char digest[SHA512_DIGEST_LENGTH];
 | 
	
		
			
				|  |  |      unsigned done, todo;
 | 
	
		
			
				|  |  | -    /* We generate |range|+8 bytes of random output. */
 | 
	
		
			
				|  |  | -    const unsigned num_k_bytes = BN_num_bytes(range) + 8;
 | 
	
		
			
				|  |  | +    /* We generate |range|+1 bytes of random output. */
 | 
	
		
			
				|  |  | +    const unsigned num_k_bytes = BN_num_bytes(range) + 1;
 | 
	
		
			
				|  |  |      unsigned char private_bytes[96];
 | 
	
		
			
				|  |  |      unsigned char *k_bytes = NULL;
 | 
	
		
			
				|  |  | +    const int max_n = 64;           /* Pr(failure to generate) < 2^max_n */
 | 
	
		
			
				|  |  | +    int n;
 | 
	
		
			
				|  |  |      int ret = 0;
 | 
	
		
			
				|  |  |      EVP_MD *md = NULL;
 | 
	
		
			
				|  |  |      OSSL_LIB_CTX *libctx = ossl_bn_get_libctx(ctx);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (mdctx == NULL)
 | 
	
		
			
				|  |  | -        goto err;
 | 
	
		
			
				|  |  | +        goto end;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      k_bytes = OPENSSL_malloc(num_k_bytes);
 | 
	
		
			
				|  |  |      if (k_bytes == NULL)
 | 
	
		
			
				|  |  | -        goto err;
 | 
	
		
			
				|  |  | +        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) {
 | 
	
	
		
			
				|  | @@ -281,41 +331,60 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
 | 
	
		
			
				|  |  |           * length of the private key.
 | 
	
		
			
				|  |  |           */
 | 
	
		
			
				|  |  |          ERR_raise(ERR_LIB_BN, BN_R_PRIVATE_KEY_TOO_LARGE);
 | 
	
		
			
				|  |  | -        goto err;
 | 
	
		
			
				|  |  | +        goto end;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      md = EVP_MD_fetch(libctx, "SHA512", NULL);
 | 
	
		
			
				|  |  |      if (md == NULL) {
 | 
	
		
			
				|  |  |          ERR_raise(ERR_LIB_BN, BN_R_NO_SUITABLE_DIGEST);
 | 
	
		
			
				|  |  | -        goto err;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    for (done = 0; done < num_k_bytes;) {
 | 
	
		
			
				|  |  | -        if (RAND_priv_bytes_ex(libctx, random_bytes, sizeof(random_bytes), 0) <= 0)
 | 
	
		
			
				|  |  | -            goto err;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if (!EVP_DigestInit_ex(mdctx, md, NULL)
 | 
	
		
			
				|  |  | -                || !EVP_DigestUpdate(mdctx, &done, sizeof(done))
 | 
	
		
			
				|  |  | -                || !EVP_DigestUpdate(mdctx, private_bytes,
 | 
	
		
			
				|  |  | -                                     sizeof(private_bytes))
 | 
	
		
			
				|  |  | -                || !EVP_DigestUpdate(mdctx, message, message_len)
 | 
	
		
			
				|  |  | -                || !EVP_DigestUpdate(mdctx, random_bytes, sizeof(random_bytes))
 | 
	
		
			
				|  |  | -                || !EVP_DigestFinal_ex(mdctx, digest, NULL))
 | 
	
		
			
				|  |  | -            goto err;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        todo = num_k_bytes - done;
 | 
	
		
			
				|  |  | -        if (todo > SHA512_DIGEST_LENGTH)
 | 
	
		
			
				|  |  | -            todo = SHA512_DIGEST_LENGTH;
 | 
	
		
			
				|  |  | -        memcpy(k_bytes + done, digest, todo);
 | 
	
		
			
				|  |  | -        done += todo;
 | 
	
		
			
				|  |  | +        goto end;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    for (n = 0; n < max_n; n++) {
 | 
	
		
			
				|  |  | +        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, &i, sizeof(i))
 | 
	
		
			
				|  |  | +                    || !EVP_DigestUpdate(mdctx, private_bytes,
 | 
	
		
			
				|  |  | +                                         sizeof(private_bytes))
 | 
	
		
			
				|  |  | +                    || !EVP_DigestUpdate(mdctx, message, message_len)
 | 
	
		
			
				|  |  | +                    || !EVP_DigestUpdate(mdctx, random_bytes,
 | 
	
		
			
				|  |  | +                                         sizeof(random_bytes))
 | 
	
		
			
				|  |  | +                    || !EVP_DigestFinal_ex(mdctx, digest, NULL))
 | 
	
		
			
				|  |  | +                goto end;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            todo = num_k_bytes - done;
 | 
	
		
			
				|  |  | +            if (todo > SHA512_DIGEST_LENGTH)
 | 
	
		
			
				|  |  | +                todo = SHA512_DIGEST_LENGTH;
 | 
	
		
			
				|  |  | +            memcpy(k_bytes + done, digest, todo);
 | 
	
		
			
				|  |  | +            done += todo;
 | 
	
		
			
				|  |  | +            ++i;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    if (!BN_bin2bn(k_bytes, num_k_bytes, out))
 | 
	
		
			
				|  |  | -        goto err;
 | 
	
		
			
				|  |  | -    if (BN_mod(out, out, range, ctx) != 1)
 | 
	
		
			
				|  |  | -        goto err;
 | 
	
		
			
				|  |  | -    ret = 1;
 | 
	
		
			
				|  |  | +        if (!BN_bin2bn(k_bytes, num_k_bytes, out))
 | 
	
		
			
				|  |  | +            goto end;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | - err:
 | 
	
		
			
				|  |  | +        /* Clear out the top bits and rejection filter into range */
 | 
	
		
			
				|  |  | +        BN_set_flags(out, BN_FLG_CONSTTIME);
 | 
	
		
			
				|  |  | +        ossl_bn_mask_bits_fixed_top(out, BN_num_bits(range));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (BN_ucmp(out, range) < 0) {
 | 
	
		
			
				|  |  | +            ret = 1;
 | 
	
		
			
				|  |  | +#ifdef BN_DEBUG
 | 
	
		
			
				|  |  | +            /* With BN_DEBUG on a fixed top number cannot be returned */
 | 
	
		
			
				|  |  | +            bn_correct_top(out);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +            goto end;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    /* Failed to generate anything */
 | 
	
		
			
				|  |  | +    ERR_raise(ERR_LIB_BN, ERR_R_INTERNAL_ERROR);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | + end:
 | 
	
		
			
				|  |  |      EVP_MD_CTX_free(mdctx);
 | 
	
		
			
				|  |  |      EVP_MD_free(md);
 | 
	
		
			
				|  |  |      OPENSSL_clear_free(k_bytes, num_k_bytes);
 | 
	
	
		
			
				|  | @@ -324,3 +393,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;
 | 
	
		
			
				|  |  | +}
 |