From 01c09f9fde5793e0b3712d602b02e2aed4908e8d Mon Sep 17 00:00:00 2001 From: Rich Salz Date: Mon, 5 Sep 2016 18:08:43 -0400 Subject: [PATCH] Misc BN fixes Never output -0; make "negative zero" an impossibility. Do better checking on BN_rand top/bottom requirements and #bits. Update doc. Ignoring trailing garbage in BN_asc2bn. Port this commit from boringSSL: https://boringssl.googlesource.com/boringssl/+/899b9b19a4cd3fe526aaf5047ab9234cdca19f7d%5E!/ Ensure |BN_div| never gives negative zero in the no_branch code. Have |bn_correct_top| fix |bn->neg| if the input is zero so that we don't have negative zeros lying around. Thanks to Brian Smith for noticing. Reviewed-by: Richard Levitte --- crypto/bn/bn_lib.c | 2 ++ crypto/bn/bn_print.c | 23 +++++++++++++---------- crypto/bn/bn_rand.c | 13 ++++++++----- doc/crypto/BN_bn2bin.pod | 1 + doc/crypto/BN_rand.pod | 4 +++- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/crypto/bn/bn_lib.c b/crypto/bn/bn_lib.c index 0be42f8350..17d34c319e 100644 --- a/crypto/bn/bn_lib.c +++ b/crypto/bn/bn_lib.c @@ -1031,5 +1031,7 @@ void bn_correct_top(BIGNUM *a) } a->top = tmp_top; } + if (a->top == 0) + a->neg = 0; bn_pollute(a); } diff --git a/crypto/bn/bn_print.c b/crypto/bn/bn_print.c index 39fb03412e..a16bde862c 100644 --- a/crypto/bn/bn_print.c +++ b/crypto/bn/bn_print.c @@ -23,12 +23,9 @@ char *BN_bn2hex(const BIGNUM *a) char *buf; char *p; - if (a->neg && BN_is_zero(a)) { - /* "-0" == 3 bytes including NULL terminator */ - buf = OPENSSL_malloc(3); - } else { - buf = OPENSSL_malloc(a->top * BN_BYTES * 2 + 2); - } + if (BN_is_zero(a)) + return OPENSSL_strdup("0"); + buf = OPENSSL_malloc(a->top * BN_BYTES * 2 + 2); if (buf == NULL) { BNerr(BN_F_BN_BN2HEX, ERR_R_MALLOC_FAILURE); goto err; @@ -186,10 +183,12 @@ int BN_hex2bn(BIGNUM **bn, const char *a) } ret->top = h; bn_correct_top(ret); - ret->neg = neg; *bn = ret; bn_check_top(ret); + /* Don't set the negative flag if it's zero. */ + if (ret->top != 0) + ret->neg = neg; return (num); err: if (*bn == NULL) @@ -241,7 +240,7 @@ int BN_dec2bn(BIGNUM **bn, const char *a) if (j == BN_DEC_NUM) j = 0; l = 0; - while (*a) { + while (--i >= 0) { l *= 10; l += *a - '0'; a++; @@ -253,11 +252,13 @@ int BN_dec2bn(BIGNUM **bn, const char *a) j = 0; } } - ret->neg = neg; bn_correct_top(ret); *bn = ret; bn_check_top(ret); + /* Don't set the negative flag if it's zero. */ + if (ret->top != 0) + ret->neg = neg; return (num); err: if (*bn == NULL) @@ -268,6 +269,7 @@ int BN_dec2bn(BIGNUM **bn, const char *a) int BN_asc2bn(BIGNUM **bn, const char *a) { const char *p = a; + if (*p == '-') p++; @@ -278,7 +280,8 @@ int BN_asc2bn(BIGNUM **bn, const char *a) if (!BN_dec2bn(bn, p)) return 0; } - if (*a == '-') + /* Don't set the negative flag if it's zero. */ + if (*a == '-' && (*bn)->top != 0) (*bn)->neg = 1; return 1; } diff --git a/crypto/bn/bn_rand.c b/crypto/bn/bn_rand.c index 5ad80507b0..c577fd169d 100644 --- a/crypto/bn/bn_rand.c +++ b/crypto/bn/bn_rand.c @@ -20,15 +20,14 @@ static int bnrand(int pseudorand, BIGNUM *rnd, int bits, int top, int bottom) int ret = 0, bit, bytes, mask; time_t tim; - if (bits < 0 || (bits == 1 && top > 0)) { - BNerr(BN_F_BNRAND, BN_R_BITS_TOO_SMALL); - return 0; - } - if (bits == 0) { + if (top != BN_RAND_TOP_ANY || bottom != BN_RAND_BOTTOM_ANY) + goto toosmall; BN_zero(rnd); return 1; } + if (bits < 0 || (bits == 1 && top > 0)) + goto toosmall; bytes = (bits + 7) / 8; bit = (bits - 1) % 8; @@ -88,6 +87,10 @@ static int bnrand(int pseudorand, BIGNUM *rnd, int bits, int top, int bottom) OPENSSL_clear_free(buf, bytes); bn_check_top(rnd); return (ret); + +toosmall: + BNerr(BN_F_BNRAND, BN_R_BITS_TOO_SMALL); + return 0; } int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) diff --git a/doc/crypto/BN_bn2bin.pod b/doc/crypto/BN_bn2bin.pod index 14b152e430..b272010ba0 100644 --- a/doc/crypto/BN_bn2bin.pod +++ b/doc/crypto/BN_bn2bin.pod @@ -57,6 +57,7 @@ including the leading character '-' which means negative, to form a valid hexadecimal number representation and converts them to a B and stores it in **B. If *B is NULL, a new B is created. If B is NULL, it only computes the length of valid representation. +A "negative zero" is converted to zero. BN_dec2bn() is the same using the decimal system. BN_print() and BN_print_fp() write the hexadecimal encoding of B, diff --git a/doc/crypto/BN_rand.pod b/doc/crypto/BN_rand.pod index ba505e1e64..ae15ada7e5 100644 --- a/doc/crypto/BN_rand.pod +++ b/doc/crypto/BN_rand.pod @@ -20,7 +20,9 @@ BN_rand, BN_pseudo_rand, BN_rand_range, BN_pseudo_rand_range - generate pseudo-r BN_rand() generates a cryptographically strong pseudo-random number of B in length and stores it in B. -The value of B must be zero or greater. +If B is less than zero, or too small to +accomodate the requirements specified by the B and B +parameters, an error is returned. The B parameters specifies requirements on the most significant bit of the generated number. If it is B, there is no constraint. -- 2.25.1