From ff3b8c570633e1f52535eb675d64a23fdaffd85a Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 11 Apr 2024 13:10:09 +0200 Subject: [PATCH 1/5] Make BN_generate_dsa_nonce() constant time and non-biased Co-authored-by: Paul Dale Reviewed-by: Paul Dale Reviewed-by: Neil Horman (cherry picked from commit d7d1bdcb6aa3d5000bf7f5ebc5518be5c91fd5a5) (Merged from https://github.com/openssl/openssl/pull/24317) (cherry picked from commit 0df711a25da6e99a7ce0dbaf992acb644252385f) --- crypto/bn/bn_lib.c | 34 ++++++++++++--- crypto/bn/bn_local.h | 2 + crypto/bn/bn_rand.c | 71 +++++++++++++++++++------------- include/internal/constant_time.h | 12 ++++++ 4 files changed, 86 insertions(+), 33 deletions(-) diff --git a/crypto/bn/bn_lib.c b/crypto/bn/bn_lib.c index cd6aa3448a..2f13e5c028 100644 --- a/crypto/bn/bn_lib.c +++ b/crypto/bn/bn_lib.c @@ -598,14 +598,29 @@ int BN_ucmp(const BIGNUM *a, const BIGNUM *b) int i; BN_ULONG t1, t2, *ap, *bp; + ap = a->d; + bp = b->d; + + if (BN_get_flags(a, BN_FLG_CONSTTIME) + && a->top == b->top) { + int res = 0; + + for (i = 0; i < b->top; i++) { + res = constant_time_select_int(constant_time_lt_bn(ap[i], bp[i]), + -1, res); + res = constant_time_select_int(constant_time_lt_bn(bp[i], ap[i]), + 1, res); + } + return res; + } + bn_check_top(a); bn_check_top(b); i = a->top - b->top; if (i != 0) return i; - ap = a->d; - bp = b->d; + for (i = a->top - 1; i >= 0; i--) { t1 = ap[i]; t2 = bp[i]; @@ -717,11 +732,10 @@ int BN_is_bit_set(const BIGNUM *a, int n) return (int)(((a->d[i]) >> j) & ((BN_ULONG)1)); } -int BN_mask_bits(BIGNUM *a, int n) +int bn_mask_bits_fixed_top(BIGNUM *a, int n) { int b, w; - bn_check_top(a); if (n < 0) return 0; @@ -735,10 +749,20 @@ int BN_mask_bits(BIGNUM *a, int n) a->top = w + 1; a->d[w] &= ~(BN_MASK2 << b); } - bn_correct_top(a); return 1; } +int BN_mask_bits(BIGNUM *a, int n) +{ + int ret; + + bn_check_top(a); + ret = bn_mask_bits_fixed_top(a, n); + if (ret) + bn_correct_top(a); + return ret; +} + void BN_set_negative(BIGNUM *a, int b) { if (b && !BN_is_zero(a)) diff --git a/crypto/bn/bn_local.h b/crypto/bn/bn_local.h index 818e34348e..469ad3aaac 100644 --- a/crypto/bn/bn_local.h +++ b/crypto/bn/bn_local.h @@ -685,4 +685,6 @@ static ossl_inline BIGNUM *bn_expand(BIGNUM *a, int bits) return bn_expand2((a),(bits+BN_BITS2-1)/BN_BITS2); } +int bn_mask_bits_fixed_top(BIGNUM *a, int n); + #endif diff --git a/crypto/bn/bn_rand.c b/crypto/bn/bn_rand.c index 6b4b50a068..3bdc972cc7 100644 --- a/crypto/bn/bn_rand.c +++ b/crypto/bn/bn_rand.c @@ -214,15 +214,17 @@ 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; + unsigned char *k_bytes = NULL; + const int max_n = 64; /* Pr(failure to generate) < 2^max_n */ + int n; int ret = 0; k_bytes = OPENSSL_malloc(num_k_bytes); if (k_bytes == NULL) - goto err; + goto end; /* We copy |priv| into a local buffer to avoid exposing its length. */ if (BN_bn2binpad(priv, private_bytes, sizeof(private_bytes)) < 0) { @@ -232,34 +234,47 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, * length of the private key. */ BNerr(BN_F_BN_GENERATE_DSA_NONCE, BN_R_PRIVATE_KEY_TOO_LARGE); - goto err; + goto end; } + for (n = 0; n < max_n; n++) { + for (done = 0; done < num_k_bytes;) { + if (RAND_priv_bytes(random_bytes, sizeof(random_bytes)) != 1) + goto end; + SHA512_Init(&sha); + SHA512_Update(&sha, &done, sizeof(done)); + SHA512_Update(&sha, private_bytes, sizeof(private_bytes)); + SHA512_Update(&sha, message, message_len); + SHA512_Update(&sha, random_bytes, sizeof(random_bytes)); + SHA512_Final(digest, &sha); + + todo = num_k_bytes - done; + if (todo > SHA512_DIGEST_LENGTH) + todo = SHA512_DIGEST_LENGTH; + memcpy(k_bytes + done, digest, todo); + done += todo; + } - for (done = 0; done < num_k_bytes;) { - if (RAND_priv_bytes(random_bytes, sizeof(random_bytes)) != 1) - goto err; - SHA512_Init(&sha); - SHA512_Update(&sha, &done, sizeof(done)); - SHA512_Update(&sha, private_bytes, sizeof(private_bytes)); - SHA512_Update(&sha, message, message_len); - SHA512_Update(&sha, random_bytes, sizeof(random_bytes)); - SHA512_Final(digest, &sha); - - todo = num_k_bytes - done; - if (todo > SHA512_DIGEST_LENGTH) - todo = SHA512_DIGEST_LENGTH; - memcpy(k_bytes + done, digest, todo); - done += todo; - } + /* 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; - if (!BN_bin2bn(k_bytes, num_k_bytes, out)) - goto err; - if (BN_mod(out, out, range, ctx) != 1) - goto err; - ret = 1; + /* Clear out the top bits and rejection filter into range */ + BN_set_flags(out, BN_FLG_CONSTTIME | BN_FLG_FIXED_TOP); + bn_mask_bits_fixed_top(out, BN_num_bits(range)); - err: - OPENSSL_free(k_bytes); + if (BN_ucmp(out, range) < 0) { + ret = 1; + goto end; + } + } + /* Failed to generate anything */ + BNerr(BN_F_BN_GENERATE_DSA_NONCE, ERR_R_INTERNAL_ERROR); + + end: + OPENSSL_clear_free(k_bytes, num_k_bytes); + OPENSSL_cleanse(digest, sizeof(digest)); + OPENSSL_cleanse(random_bytes, sizeof(random_bytes)); OPENSSL_cleanse(private_bytes, sizeof(private_bytes)); return ret; } diff --git a/include/internal/constant_time.h b/include/internal/constant_time.h index 6600a1d72a..9602bc285a 100644 --- a/include/internal/constant_time.h +++ b/include/internal/constant_time.h @@ -139,6 +139,18 @@ static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b) return constant_time_msb_64(a ^ ((a ^ b) | ((a - b) ^ b))); } +#ifdef BN_ULONG +static ossl_inline BN_ULONG constant_time_msb_bn(BN_ULONG a) +{ + return 0 - (a >> (sizeof(a) * 8 - 1)); +} + +static ossl_inline BN_ULONG constant_time_lt_bn(BN_ULONG a, BN_ULONG b) +{ + return constant_time_msb_bn(a ^ ((a ^ b) | ((a - b) ^ b))); +} +#endif + static ossl_inline unsigned int constant_time_ge(unsigned int a, unsigned int b) { -- Gitee From ab0f80cd9953705bd34fc8022c54ebdef971f55a Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 25 Apr 2024 15:35:36 +0200 Subject: [PATCH 2/5] Add ossl_bn_is_word_fixed_top() Also correct some BN_FLG_FIXED_TOP flag handling. Reviewed-by: Paul Dale Reviewed-by: Neil Horman (cherry picked from commit 2d285fa873028f6cff9484a0cdf690fe05d7fb16) (Merged from https://github.com/openssl/openssl/pull/24317) (cherry picked from commit 5dbb2a8ca2c1ba42dfb9445b5ea76adccbdb9744) --- crypto/bn/bn_lib.c | 17 +++++++++++++++++ crypto/bn/bn_local.h | 2 -- crypto/bn/bn_rand.c | 2 +- crypto/bn/bn_shift.c | 6 +++--- include/crypto/bn.h | 2 ++ include/internal/constant_time.h | 11 +++++++++++ 6 files changed, 34 insertions(+), 6 deletions(-) diff --git a/crypto/bn/bn_lib.c b/crypto/bn/bn_lib.c index 2f13e5c028..914da52ea9 100644 --- a/crypto/bn/bn_lib.c +++ b/crypto/bn/bn_lib.c @@ -749,6 +749,7 @@ int bn_mask_bits_fixed_top(BIGNUM *a, int n) a->top = w + 1; a->d[w] &= ~(BN_MASK2 << b); } + a->flags |= BN_FLG_FIXED_TOP; return 1; } @@ -939,6 +940,22 @@ int BN_is_word(const BIGNUM *a, const BN_ULONG w) return BN_abs_is_word(a, w) && (!w || !a->neg); } +int bn_is_word_fixed_top(const BIGNUM *a, BN_ULONG w) +{ + int res, i; + const BN_ULONG *ap = a->d; + + if (a->neg || a->top == 0) + return 0; + + res = constant_time_select_int(constant_time_eq_bn(ap[0], w), 1, 0); + + for (i = 1; i < a->top; i++) + res = constant_time_select_int(constant_time_is_zero_bn(ap[i]), + res, 0); + return res; +} + int BN_is_odd(const BIGNUM *a) { return (a->top > 0) && (a->d[0] & 1); diff --git a/crypto/bn/bn_local.h b/crypto/bn/bn_local.h index 469ad3aaac..818e34348e 100644 --- a/crypto/bn/bn_local.h +++ b/crypto/bn/bn_local.h @@ -685,6 +685,4 @@ static ossl_inline BIGNUM *bn_expand(BIGNUM *a, int bits) return bn_expand2((a),(bits+BN_BITS2-1)/BN_BITS2); } -int bn_mask_bits_fixed_top(BIGNUM *a, int n); - #endif diff --git a/crypto/bn/bn_rand.c b/crypto/bn/bn_rand.c index 3bdc972cc7..d57cf01273 100644 --- a/crypto/bn/bn_rand.c +++ b/crypto/bn/bn_rand.c @@ -260,7 +260,7 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, goto end; /* Clear out the top bits and rejection filter into range */ - BN_set_flags(out, BN_FLG_CONSTTIME | BN_FLG_FIXED_TOP); + BN_set_flags(out, BN_FLG_CONSTTIME); bn_mask_bits_fixed_top(out, BN_num_bits(range)); if (BN_ucmp(out, range) < 0) { diff --git a/crypto/bn/bn_shift.c b/crypto/bn/bn_shift.c index 210a83f586..4018ad9e68 100644 --- a/crypto/bn/bn_shift.c +++ b/crypto/bn/bn_shift.c @@ -156,6 +156,9 @@ int BN_rshift(BIGNUM *r, const BIGNUM *a, int n) return 0; } + bn_check_top(r); + bn_check_top(a); + ret = bn_rshift_fixed_top(r, a, n); bn_correct_top(r); @@ -177,9 +180,6 @@ int bn_rshift_fixed_top(BIGNUM *r, const BIGNUM *a, int n) BN_ULONG *t, *f; BN_ULONG l, m, mask; - bn_check_top(r); - bn_check_top(a); - assert(n >= 0); nw = n / BN_BITS2; diff --git a/include/crypto/bn.h b/include/crypto/bn.h index 8484047fd0..4b8317871d 100644 --- a/include/crypto/bn.h +++ b/include/crypto/bn.h @@ -89,5 +89,7 @@ int bn_lshift_fixed_top(BIGNUM *r, const BIGNUM *a, int n); int bn_rshift_fixed_top(BIGNUM *r, const BIGNUM *a, int n); int bn_div_fixed_top(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx); +int bn_mask_bits_fixed_top(BIGNUM *a, int n); +int bn_is_word_fixed_top(const BIGNUM *a, BN_ULONG w); #endif diff --git a/include/internal/constant_time.h b/include/internal/constant_time.h index 9602bc285a..9f4034b921 100644 --- a/include/internal/constant_time.h +++ b/include/internal/constant_time.h @@ -149,6 +149,17 @@ static ossl_inline BN_ULONG constant_time_lt_bn(BN_ULONG a, BN_ULONG b) { return constant_time_msb_bn(a ^ ((a ^ b) | ((a - b) ^ b))); } + +static ossl_inline BN_ULONG constant_time_is_zero_bn(BN_ULONG a) +{ + return constant_time_msb_bn(~a & (a - 1)); +} + +static ossl_inline BN_ULONG constant_time_eq_bn(BN_ULONG a, + BN_ULONG b) +{ + return constant_time_is_zero_bn(a ^ b); +} #endif static ossl_inline unsigned int constant_time_ge(unsigned int a, -- Gitee From 7b1c484692465327d4981bcf760396d11865f119 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 25 Apr 2024 19:26:08 +0200 Subject: [PATCH 3/5] Add ossl_bn_priv_rand_range_fixed_top() and use it for EC/DSA Reviewed-by: Paul Dale Reviewed-by: Neil Horman (cherry picked from commit 13b3ca5c998e6db4f7251a56c43541cb1a422bd0) (Merged from https://github.com/openssl/openssl/pull/24317) (cherry picked from commit a70ca93cdbc0ed36bf783b9eadc4cea35986b139) --- crypto/bn/bn_rand.c | 39 +++++++++++++++++++++++++++++++++++++++ crypto/dsa/dsa_ossl.c | 4 ++-- crypto/ec/ecdsa_ossl.c | 4 ++-- include/crypto/bn.h | 1 + include/openssl/bnerr.h | 1 + 5 files changed, 45 insertions(+), 4 deletions(-) diff --git a/crypto/bn/bn_rand.c b/crypto/bn/bn_rand.c index d57cf01273..254b0080b6 100644 --- a/crypto/bn/bn_rand.c +++ b/crypto/bn/bn_rand.c @@ -194,6 +194,45 @@ int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range) return BN_rand_range(r, range); } +int bn_priv_rand_range_fixed_top(BIGNUM *r, const BIGNUM *range) +{ + int n; + int count = 100; + + if (r == NULL) { + BNerr(BN_F_BN_PRIV_RAND_RANGE_FIXED_TOP, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (range->neg || BN_is_zero(range)) { + BNerr(BN_F_BN_PRIV_RAND_RANGE_FIXED_TOP, 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)) + return 0; + + if (!--count) { + BNerr(BN_F_BN_PRIV_RAND_RANGE_FIXED_TOP, BN_R_TOO_MANY_ITERATIONS); + return 0; + } + bn_mask_bits_fixed_top(r, n); + } + while (BN_ucmp(r, range) >= 0); + } + + 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 diff --git a/crypto/dsa/dsa_ossl.c b/crypto/dsa/dsa_ossl.c index a983def64e..ec7009ceb6 100644 --- a/crypto/dsa/dsa_ossl.c +++ b/crypto/dsa/dsa_ossl.c @@ -232,9 +232,9 @@ static int dsa_sign_setup(DSA *dsa, BN_CTX *ctx_in, if (!BN_generate_dsa_nonce(k, dsa->q, dsa->priv_key, dgst, dlen, ctx)) goto err; - } else if (!BN_priv_rand_range(k, dsa->q)) + } else if (!bn_priv_rand_range_fixed_top(k, dsa->q)) goto err; - } while (BN_is_zero(k)); + } while (bn_is_word_fixed_top(k, 0)); BN_set_flags(k, BN_FLG_CONSTTIME); BN_set_flags(l, BN_FLG_CONSTTIME); diff --git a/crypto/ec/ecdsa_ossl.c b/crypto/ec/ecdsa_ossl.c index 1da87bfb5e..d501d1beff 100644 --- a/crypto/ec/ecdsa_ossl.c +++ b/crypto/ec/ecdsa_ossl.c @@ -95,13 +95,13 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, goto err; } } else { - if (!BN_priv_rand_range(k, order)) { + if (!bn_priv_rand_range_fixed_top(k, order)) { ECerr(EC_F_ECDSA_SIGN_SETUP, EC_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; } } - } while (BN_is_zero(k)); + } while (bn_is_word_fixed_top(k, 0)); /* compute r the x-coordinate of generator * k */ if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) { diff --git a/include/crypto/bn.h b/include/crypto/bn.h index 4b8317871d..adaa82e746 100644 --- a/include/crypto/bn.h +++ b/include/crypto/bn.h @@ -91,5 +91,6 @@ int bn_div_fixed_top(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx); int bn_mask_bits_fixed_top(BIGNUM *a, int n); int bn_is_word_fixed_top(const BIGNUM *a, BN_ULONG w); +int bn_priv_rand_range_fixed_top(BIGNUM *r, const BIGNUM *range); #endif diff --git a/include/openssl/bnerr.h b/include/openssl/bnerr.h index f6aef13441..2816710d64 100644 --- a/include/openssl/bnerr.h +++ b/include/openssl/bnerr.h @@ -74,6 +74,7 @@ int ERR_load_BN_strings(void); # define BN_F_BN_USUB 115 # define BN_F_OSSL_BN_RSA_DO_UNBLIND 151 # define BN_F_BN_MOD_EXP_MONT_FIXED_TOP 152 +# define BN_F_BN_PRIV_RAND_RANGE_FIXED_TOP 153 /* * BN reason codes. -- Gitee From 6c9fd2a3d391e27b6b2854e008547a7776bd4b27 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Mon, 29 Apr 2024 17:56:01 +0200 Subject: [PATCH 4/5] Rename BN_generate_dsa_nonce() to ossl_bn_gen_dsa_nonce_fixed_top() 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 Reviewed-by: Neil Horman (cherry picked from commit 9c85f6cd2d6debe5ef6ef475ff4bf17e0985f7a2) (Merged from https://github.com/openssl/openssl/pull/24317) (cherry picked from commit fdc3efc371be43d5092bb19823e084f54541cbe3) --- crypto/bn/bn_rand.c | 45 ++++++++++++++++++++++++++++++----------- crypto/dsa/dsa_ossl.c | 5 +++-- crypto/ec/ecdsa_ossl.c | 4 ++-- include/crypto/bn.h | 5 ++++- include/openssl/bnerr.h | 1 + 5 files changed, 43 insertions(+), 17 deletions(-) diff --git a/crypto/bn/bn_rand.c b/crypto/bn/bn_rand.c index 254b0080b6..70f1e0906b 100644 --- a/crypto/bn/bn_rand.c +++ b/crypto/bn/bn_rand.c @@ -234,16 +234,17 @@ int 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| + * 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 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) { SHA512_CTX sha; /* @@ -264,6 +265,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) { @@ -272,15 +275,17 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, * large and we don't handle this case in order to avoid leaking the * length of the private key. */ - BNerr(BN_F_BN_GENERATE_DSA_NONCE, BN_R_PRIVATE_KEY_TOO_LARGE); + BNerr(BN_F_BN_GEN_DSA_NONCE_FIXED_TOP, BN_R_PRIVATE_KEY_TOO_LARGE); goto end; } for (n = 0; n < max_n; n++) { + unsigned char i = 0; + for (done = 0; done < num_k_bytes;) { if (RAND_priv_bytes(random_bytes, sizeof(random_bytes)) != 1) goto end; SHA512_Init(&sha); - SHA512_Update(&sha, &done, sizeof(done)); + SHA512_Update(&sha, &i, sizeof(i)); SHA512_Update(&sha, private_bytes, sizeof(private_bytes)); SHA512_Update(&sha, message, message_len); SHA512_Update(&sha, random_bytes, sizeof(random_bytes)); @@ -291,10 +296,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; @@ -308,7 +312,7 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, } } /* Failed to generate anything */ - BNerr(BN_F_BN_GENERATE_DSA_NONCE, ERR_R_INTERNAL_ERROR); + BNerr(BN_F_BN_GEN_DSA_NONCE_FIXED_TOP, ERR_R_INTERNAL_ERROR); end: OPENSSL_clear_free(k_bytes, num_k_bytes); @@ -317,3 +321,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 = 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; +} diff --git a/crypto/dsa/dsa_ossl.c b/crypto/dsa/dsa_ossl.c index ec7009ceb6..cd74b0100a 100644 --- a/crypto/dsa/dsa_ossl.c +++ b/crypto/dsa/dsa_ossl.c @@ -229,8 +229,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->q, dsa->priv_key, dgst, - dlen, ctx)) + if (!bn_gen_dsa_nonce_fixed_top(k, dsa->q, + dsa->priv_key, dgst, + dlen, ctx)) goto err; } else if (!bn_priv_rand_range_fixed_top(k, dsa->q)) goto err; diff --git a/crypto/ec/ecdsa_ossl.c b/crypto/ec/ecdsa_ossl.c index d501d1beff..b17731e945 100644 --- a/crypto/ec/ecdsa_ossl.c +++ b/crypto/ec/ecdsa_ossl.c @@ -88,8 +88,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 (!bn_gen_dsa_nonce_fixed_top(k, order, priv_key, + dgst, dlen, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, EC_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; diff --git a/include/crypto/bn.h b/include/crypto/bn.h index adaa82e746..0128191425 100644 --- a/include/crypto/bn.h +++ b/include/crypto/bn.h @@ -92,5 +92,8 @@ int bn_div_fixed_top(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, int bn_mask_bits_fixed_top(BIGNUM *a, int n); int bn_is_word_fixed_top(const BIGNUM *a, BN_ULONG w); int bn_priv_rand_range_fixed_top(BIGNUM *r, const BIGNUM *range); - +int 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); #endif diff --git a/include/openssl/bnerr.h b/include/openssl/bnerr.h index 2816710d64..6b59f4bc56 100644 --- a/include/openssl/bnerr.h +++ b/include/openssl/bnerr.h @@ -75,6 +75,7 @@ int ERR_load_BN_strings(void); # define BN_F_OSSL_BN_RSA_DO_UNBLIND 151 # define BN_F_BN_MOD_EXP_MONT_FIXED_TOP 152 # define BN_F_BN_PRIV_RAND_RANGE_FIXED_TOP 153 +# define BN_F_BN_GEN_DSA_NONCE_FIXED_TOP 154 /* * BN reason codes. -- Gitee From 3899f475934486949926403fc785bc7f3fae579b Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 30 Apr 2024 11:46:26 +0200 Subject: [PATCH 5/5] Correct top for EC/DSA nonces if BN_DEBUG is on Otherwise following operations would bail out in bn_check_top(). Reviewed-by: Paul Dale Reviewed-by: Neil Horman (cherry picked from commit a380ae85be287045b1eaa64d23942101a426c080) (Merged from https://github.com/openssl/openssl/pull/24317) (cherry picked from commit 549208d1f1175aca5cc1ea989c4e9e4a41bc558c) --- crypto/bn/bn_rand.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crypto/bn/bn_rand.c b/crypto/bn/bn_rand.c index 70f1e0906b..46d4d5a82a 100644 --- a/crypto/bn/bn_rand.c +++ b/crypto/bn/bn_rand.c @@ -228,6 +228,10 @@ int bn_priv_rand_range_fixed_top(BIGNUM *r, const BIGNUM *range) 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; @@ -308,6 +312,10 @@ int bn_gen_dsa_nonce_fixed_top(BIGNUM *out, const BIGNUM *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; } } -- Gitee