Skip to content

Commit 05b7a14

Browse files
davidbenSrinivasa Rao Kuppala
authored andcommitted
Rewrite BN_bn2dec.
This is a more complete fix for CVE-2016-2182. The original commit message was: "If an oversize BIGNUM is presented to BN_bn2dec() it can cause BN_div_word() to fail and not reduce the value of 't' resulting in OOB writes to the bn_data buffer and eventually crashing. Fix by checking return value of BN_div_word() and checking writes don't overflow buffer. Thanks to Shi Lei for reporting this bug." BoringSSL's rewrite commit message: "958aaf1ea1b481e8ef32970d5b0add80504be4b2, imported from upstream, had an off-by-one error. Reproducing the failure is fairly easy as it can't even serialize 1. See also upstream's 099e2968ed3c7d256cda048995626664082b1b30. Rewrite the function completely with CBB and add a basic test. BUG=chromium:639740" Change-Id: I41a91514c4bb9e83854824ed5258ffe4e49d9491 Bug: 32096880 (cherry picked from commit 54bf62a81586d99d0a951ca3342d569b59e69b80)
1 parent df97822 commit 05b7a14

File tree

2 files changed

+100
-58
lines changed

2 files changed

+100
-58
lines changed

src/crypto/bn/bn_test.cc

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ static bool test_dec2bn(FILE *fp, BN_CTX *ctx);
122122
static bool test_hex2bn(FILE *fp, BN_CTX *ctx);
123123
static bool test_asc2bn(FILE *fp, BN_CTX *ctx);
124124
static bool test_rand();
125+
static bool TestBN2Dec();
125126

126127
static const uint8_t kSample[] =
127128
"\xC6\x4F\x43\x04\x2A\xEA\xCA\x6E\x58\x36\x80\x5B\xE8\xC9"
@@ -341,6 +342,12 @@ int main(int argc, char *argv[]) {
341342
}
342343
flush_fp(bc_file.get());
343344

345+
message(bc_file.get(), "BN_bn2dec");
346+
if (!TestBN2Dec()) {
347+
return 1;
348+
}
349+
flush_fp(bc_file.get());
350+
344351
printf("PASS\n");
345352
return 0;
346353
}
@@ -1628,3 +1635,38 @@ static bool test_rand() {
16281635

16291636
return true;
16301637
}
1638+
1639+
static bool TestBN2Dec() {
1640+
static const char *kBN2DecTests[] = {
1641+
"0",
1642+
"1",
1643+
"-1",
1644+
"100",
1645+
"-100",
1646+
"123456789012345678901234567890",
1647+
"-123456789012345678901234567890",
1648+
"123456789012345678901234567890123456789012345678901234567890",
1649+
"-123456789012345678901234567890123456789012345678901234567890",
1650+
};
1651+
1652+
for (const char *test : kBN2DecTests) {
1653+
ScopedBIGNUM bn;
1654+
int ret = DecimalToBIGNUM(&bn, test);
1655+
if (ret == 0) {
1656+
return false;
1657+
}
1658+
1659+
ScopedOpenSSLString dec(BN_bn2dec(bn.get()));
1660+
if (!dec) {
1661+
fprintf(stderr, "BN_bn2dec failed on %s.\n", test);
1662+
return false;
1663+
}
1664+
1665+
if (strcmp(dec.get(), test) != 0) {
1666+
fprintf(stderr, "BN_bn2dec gave %s, wanted %s.\n", dec.get(), test);
1667+
return false;
1668+
}
1669+
}
1670+
1671+
return true;
1672+
}

src/crypto/bn/convert.c

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,13 @@
5656

5757
#include <openssl/bn.h>
5858

59+
#include <assert.h>
5960
#include <ctype.h>
6061
#include <stdio.h>
6162
#include <string.h>
6263

6364
#include <openssl/bio.h>
65+
#include <openssl/bytestring.h>
6466
#include <openssl/err.h>
6567
#include <openssl/mem.h>
6668

@@ -348,73 +350,71 @@ int BN_hex2bn(BIGNUM **outp, const char *in) {
348350
}
349351

350352
char *BN_bn2dec(const BIGNUM *a) {
351-
int i = 0, num, ok = 0;
352-
char *buf = NULL;
353-
char *p;
354-
BIGNUM *t = NULL;
355-
BN_ULONG *bn_data = NULL, *lp;
356-
357-
/* get an upper bound for the length of the decimal integer
358-
* num <= (BN_num_bits(a) + 1) * log(2)
359-
* <= 3 * BN_num_bits(a) * 0.1001 + log(2) + 1 (rounding error)
360-
* <= BN_num_bits(a)/10 + BN_num_bits/1000 + 1 + 1
361-
*/
362-
i = BN_num_bits(a) * 3;
363-
num = i / 10 + i / 1000 + 1 + 1;
364-
bn_data =
365-
(BN_ULONG *)OPENSSL_malloc((num / BN_DEC_NUM + 1) * sizeof(BN_ULONG));
366-
buf = (char *)OPENSSL_malloc(num + 3);
367-
if ((buf == NULL) || (bn_data == NULL)) {
368-
OPENSSL_PUT_ERROR(BN, BN_bn2dec, ERR_R_MALLOC_FAILURE);
369-
goto err;
370-
}
371-
t = BN_dup(a);
372-
if (t == NULL) {
373-
goto err;
374-
}
375-
376-
#define BUF_REMAIN (num + 3 - (size_t)(p - buf))
377-
p = buf;
378-
lp = bn_data;
379-
if (BN_is_zero(t)) {
380-
*(p++) = '0';
381-
*(p++) = '\0';
353+
/* It is easier to print strings little-endian, so we assemble it in reverse
354+
* and fix at the end. */
355+
BIGNUM *copy = NULL;
356+
CBB cbb;
357+
if (!CBB_init(&cbb, 16) ||
358+
!CBB_add_u8(&cbb, 0 /* trailing NUL */)) {
359+
goto cbb_err;
360+
}
361+
362+
if (BN_is_zero(a)) {
363+
if (!CBB_add_u8(&cbb, '0')) {
364+
goto cbb_err;
365+
}
382366
} else {
383-
if (BN_is_negative(t)) {
384-
*p++ = '-';
367+
copy = BN_dup(a);
368+
if (copy == NULL) {
369+
goto err;
385370
}
386371

387-
while (!BN_is_zero(t)) {
388-
*lp = BN_div_word(t, BN_DEC_CONV);
389-
lp++;
390-
}
391-
lp--;
392-
/* We now have a series of blocks, BN_DEC_NUM chars
393-
* in length, where the last one needs truncation.
394-
* The blocks need to be reversed in order. */
395-
BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT1, *lp);
396-
while (*p) {
397-
p++;
398-
}
399-
while (lp != bn_data) {
400-
lp--;
401-
BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT2, *lp);
402-
while (*p) {
403-
p++;
372+
while (!BN_is_zero(copy)) {
373+
BN_ULONG word = BN_div_word(copy, BN_DEC_CONV);
374+
if (word == (BN_ULONG)-1) {
375+
goto err;
404376
}
377+
378+
const int add_leading_zeros = !BN_is_zero(copy);
379+
int i;
380+
for (i = 0; i < BN_DEC_NUM && (add_leading_zeros || word != 0); i++) {
381+
if (!CBB_add_u8(&cbb, '0' + word % 10)) {
382+
goto cbb_err;
383+
}
384+
word /= 10;
385+
}
386+
assert(word == 0);
405387
}
406388
}
407-
ok = 1;
408389

409-
err:
410-
OPENSSL_free(bn_data);
411-
BN_free(t);
412-
if (!ok) {
413-
OPENSSL_free(buf);
414-
buf = NULL;
390+
if (BN_is_negative(a) &&
391+
!CBB_add_u8(&cbb, '-')) {
392+
goto cbb_err;
415393
}
416394

417-
return buf;
395+
uint8_t *data;
396+
size_t len;
397+
if (!CBB_finish(&cbb, &data, &len)) {
398+
goto cbb_err;
399+
}
400+
401+
/* Reverse the buffer. */
402+
size_t i;
403+
for (i = 0; i < len/2; i++) {
404+
uint8_t tmp = data[i];
405+
data[i] = data[len - 1 - i];
406+
data[len - 1 - i] = tmp;
407+
}
408+
409+
BN_free(copy);
410+
return (char *)data;
411+
412+
cbb_err:
413+
OPENSSL_PUT_ERROR(BN, BN_bn2dec, ERR_R_MALLOC_FAILURE);
414+
err:
415+
BN_free(copy);
416+
CBB_cleanup(&cbb);
417+
return NULL;
418418
}
419419

420420
int BN_dec2bn(BIGNUM **outp, const char *in) {

0 commit comments

Comments
 (0)