Skip to content

Commit

Permalink
Rename BN_generate_dsa_nonce() to ossl_bn_gen_dsa_nonce_fixed_top()
Browse files Browse the repository at this point in the history
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 openssl#24265)

(cherry picked from commit 9c85f6c)
  • Loading branch information
t8m committed May 2, 2024
1 parent edae00b commit 601518b
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 14 deletions.
41 changes: 31 additions & 10 deletions crypto/bn/bn_rand.c
Expand Up @@ -282,16 +282,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();
/*
Expand All @@ -317,6 +318,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) {
Expand All @@ -335,13 +338,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)
Expand All @@ -355,10 +360,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;

Expand All @@ -383,3 +387,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;
}
5 changes: 3 additions & 2 deletions crypto/dsa/dsa_ossl.c
Expand Up @@ -262,8 +262,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))
goto err;
Expand Down
4 changes: 2 additions & 2 deletions crypto/ec/ecdsa_ossl.c
Expand Up @@ -145,8 +145,8 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in,
/* get random k */
do {
if (dgst != NULL) {
if (!BN_generate_dsa_nonce(k, order, priv_key,
dgst, dlen, ctx)) {
if (!ossl_bn_gen_dsa_nonce_fixed_top(k, order, priv_key,
dgst, dlen, ctx)) {
ERR_raise(ERR_LIB_EC, EC_R_RANDOM_NUMBER_GENERATION_FAILED);
goto err;
}
Expand Down
4 changes: 4 additions & 0 deletions include/crypto/bn.h
Expand Up @@ -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
Expand Down

0 comments on commit 601518b

Please sign in to comment.