diff options
Diffstat (limited to 'deps/openssl/openssl/crypto/bn/bn_lib.c')
-rw-r--r-- | deps/openssl/openssl/crypto/bn/bn_lib.c | 101 |
1 files changed, 70 insertions, 31 deletions
diff --git a/deps/openssl/openssl/crypto/bn/bn_lib.c b/deps/openssl/openssl/crypto/bn/bn_lib.c index f93bbcfcc7..254069ff38 100644 --- a/deps/openssl/openssl/crypto/bn/bn_lib.c +++ b/deps/openssl/openssl/crypto/bn/bn_lib.c @@ -132,20 +132,66 @@ int BN_num_bits_word(BN_ULONG l) return bits; } +/* + * This function still leaks `a->dmax`: it's caller's responsibility to + * expand the input `a` in advance to a public length. + */ +static ossl_inline +int bn_num_bits_consttime(const BIGNUM *a) +{ + int j, ret; + unsigned int mask, past_i; + int i = a->top - 1; + bn_check_top(a); + + for (j = 0, past_i = 0, ret = 0; j < a->dmax; j++) { + mask = constant_time_eq_int(i, j); /* 0xff..ff if i==j, 0x0 otherwise */ + + ret += BN_BITS2 & (~mask & ~past_i); + ret += BN_num_bits_word(a->d[j]) & mask; + + past_i |= mask; /* past_i will become 0xff..ff after i==j */ + } + + /* + * if BN_is_zero(a) => i is -1 and ret contains garbage, so we mask the + * final result. + */ + mask = ~(constant_time_eq_int(i, ((int)-1))); + + return ret & mask; +} + int BN_num_bits(const BIGNUM *a) { int i = a->top - 1; bn_check_top(a); + if (a->flags & BN_FLG_CONSTTIME) { + /* + * We assume that BIGNUMs flagged as CONSTTIME have also been expanded + * so that a->dmax is not leaking secret information. + * + * In other words, it's the caller's responsibility to ensure `a` has + * been preallocated in advance to a public length if we hit this + * branch. + * + */ + return bn_num_bits_consttime(a); + } + if (BN_is_zero(a)) return 0; + return ((i * BN_BITS2) + BN_num_bits_word(a->d[i])); } -static void bn_free_d(BIGNUM *a) +static void bn_free_d(BIGNUM *a, int clear) { if (BN_get_flags(a, BN_FLG_SECURE)) - OPENSSL_secure_free(a->d); + OPENSSL_secure_clear_free(a->d, a->dmax * sizeof(a->d[0])); + else if (clear != 0) + OPENSSL_clear_free(a->d, a->dmax * sizeof(a->d[0])); else OPENSSL_free(a->d); } @@ -155,10 +201,8 @@ void BN_clear_free(BIGNUM *a) { if (a == NULL) return; - if (a->d != NULL && !BN_get_flags(a, BN_FLG_STATIC_DATA)) { - OPENSSL_cleanse(a->d, a->dmax * sizeof(a->d[0])); - bn_free_d(a); - } + if (a->d != NULL && !BN_get_flags(a, BN_FLG_STATIC_DATA)) + bn_free_d(a, 1); if (BN_get_flags(a, BN_FLG_MALLOCED)) { OPENSSL_cleanse(a, sizeof(*a)); OPENSSL_free(a); @@ -170,7 +214,7 @@ void BN_free(BIGNUM *a) if (a == NULL) return; if (!BN_get_flags(a, BN_FLG_STATIC_DATA)) - bn_free_d(a); + bn_free_d(a, 0); if (a->flags & BN_FLG_MALLOCED) OPENSSL_free(a); } @@ -248,10 +292,8 @@ BIGNUM *bn_expand2(BIGNUM *b, int words) BN_ULONG *a = bn_expand_internal(b, words); if (!a) return NULL; - if (b->d) { - OPENSSL_cleanse(b->d, b->dmax * sizeof(b->d[0])); - bn_free_d(b); - } + if (b->d != NULL) + bn_free_d(b, 1); b->d = a; b->dmax = words; } @@ -416,8 +458,11 @@ BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret) return ret; } +typedef enum {big, little} endianess_t; + /* ignore negative */ -static int bn2binpad(const BIGNUM *a, unsigned char *to, int tolen) +static +int bn2binpad(const BIGNUM *a, unsigned char *to, int tolen, endianess_t endianess) { int n; size_t i, lasti, j, atop, mask; @@ -449,10 +494,17 @@ static int bn2binpad(const BIGNUM *a, unsigned char *to, int tolen) lasti = atop - 1; atop = a->top * BN_BYTES; - for (i = 0, j = 0, to += tolen; j < (size_t)tolen; j++) { + if (endianess == big) + to += tolen; /* start from the end of the buffer */ + for (i = 0, j = 0; j < (size_t)tolen; j++) { + unsigned char val; l = a->d[i / BN_BYTES]; mask = 0 - ((j - atop) >> (8 * sizeof(i) - 1)); - *--to = (unsigned char)(l >> (8 * (i % BN_BYTES)) & mask); + val = (unsigned char)(l >> (8 * (i % BN_BYTES)) & mask); + if (endianess == big) + *--to = val; + else + *to++ = val; i += (i - lasti) >> (8 * sizeof(i) - 1); /* stay on last limb */ } @@ -463,12 +515,12 @@ int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen) { if (tolen < 0) return -1; - return bn2binpad(a, to, tolen); + return bn2binpad(a, to, tolen, big); } int BN_bn2bin(const BIGNUM *a, unsigned char *to) { - return bn2binpad(a, to, -1); + return bn2binpad(a, to, -1, big); } BIGNUM *BN_lebin2bn(const unsigned char *s, int len, BIGNUM *ret) @@ -520,22 +572,9 @@ BIGNUM *BN_lebin2bn(const unsigned char *s, int len, BIGNUM *ret) int BN_bn2lebinpad(const BIGNUM *a, unsigned char *to, int tolen) { - int i; - BN_ULONG l; - bn_check_top(a); - i = BN_num_bytes(a); - if (tolen < i) + if (tolen < 0) return -1; - /* Add trailing zeroes if necessary */ - if (tolen > i) - memset(to + i, 0, tolen - i); - to += i; - while (i--) { - l = a->d[i / BN_BYTES]; - to--; - *to = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff; - } - return tolen; + return bn2binpad(a, to, tolen, little); } int BN_ucmp(const BIGNUM *a, const BIGNUM *b) |