diff options
Diffstat (limited to 'src/crypto/bn')
-rw-r--r-- | src/crypto/bn/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/crypto/bn/add.c | 2 | ||||
-rw-r--r-- | src/crypto/bn/asm/armv4-mont.pl | 2 | ||||
-rw-r--r-- | src/crypto/bn/bn.c | 20 | ||||
-rw-r--r-- | src/crypto/bn/bn_asn1.c | 93 | ||||
-rw-r--r-- | src/crypto/bn/bn_test.cc | 376 | ||||
-rw-r--r-- | src/crypto/bn/convert.c | 178 | ||||
-rw-r--r-- | src/crypto/bn/ctx.c | 6 | ||||
-rw-r--r-- | src/crypto/bn/div.c | 6 | ||||
-rw-r--r-- | src/crypto/bn/exponentiation.c | 30 | ||||
-rw-r--r-- | src/crypto/bn/gcd.c | 32 | ||||
-rw-r--r-- | src/crypto/bn/internal.h | 4 | ||||
-rw-r--r-- | src/crypto/bn/montgomery.c | 6 | ||||
-rw-r--r-- | src/crypto/bn/mul.c | 8 | ||||
-rw-r--r-- | src/crypto/bn/prime.c | 9 | ||||
-rw-r--r-- | src/crypto/bn/random.c | 14 | ||||
-rw-r--r-- | src/crypto/bn/rsaz_exp.h | 68 | ||||
-rw-r--r-- | src/crypto/bn/shift.c | 4 | ||||
-rw-r--r-- | src/crypto/bn/sqrt.c | 24 |
19 files changed, 696 insertions, 189 deletions
diff --git a/src/crypto/bn/CMakeLists.txt b/src/crypto/bn/CMakeLists.txt index 2e0cb45..232e40a 100644 --- a/src/crypto/bn/CMakeLists.txt +++ b/src/crypto/bn/CMakeLists.txt @@ -1,4 +1,4 @@ -include_directories(. .. ../../include) +include_directories(../../include) if (${ARCH} STREQUAL "x86_64") set( @@ -39,6 +39,7 @@ add_library( add.c asm/x86_64-gcc.c bn.c + bn_asn1.c cmp.c convert.c ctx.c diff --git a/src/crypto/bn/add.c b/src/crypto/bn/add.c index 1c6b2d7..a043d83 100644 --- a/src/crypto/bn/add.c +++ b/src/crypto/bn/add.c @@ -267,7 +267,7 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { if (dif < 0) /* hmm... should not be happening */ { - OPENSSL_PUT_ERROR(BN, BN_usub, BN_R_ARG2_LT_ARG3); + OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3); return 0; } diff --git a/src/crypto/bn/asm/armv4-mont.pl b/src/crypto/bn/asm/armv4-mont.pl index 0f1b6a9..4206fd8 100644 --- a/src/crypto/bn/asm/armv4-mont.pl +++ b/src/crypto/bn/asm/armv4-mont.pl @@ -79,7 +79,7 @@ $_n0="$num,#14*4"; $_num="$num,#15*4"; $_bpend=$_num; $code=<<___; -#include "arm_arch.h" +#include <openssl/arm_arch.h> .text .code 32 diff --git a/src/crypto/bn/bn.c b/src/crypto/bn/bn.c index f32d6b0..b342749 100644 --- a/src/crypto/bn/bn.c +++ b/src/crypto/bn/bn.c @@ -69,7 +69,7 @@ BIGNUM *BN_new(void) { BIGNUM *bn = OPENSSL_malloc(sizeof(BIGNUM)); if (bn == NULL) { - OPENSSL_PUT_ERROR(BN, BN_new, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); return NULL; } @@ -279,26 +279,26 @@ void BN_set_negative(BIGNUM *bn, int sign) { } } -BIGNUM *bn_wexpand(BIGNUM *bn, unsigned words) { +BIGNUM *bn_wexpand(BIGNUM *bn, size_t words) { BN_ULONG *a; - if (words <= (unsigned) bn->dmax) { + if (words <= (size_t)bn->dmax) { return bn; } if (words > (INT_MAX / (4 * BN_BITS2))) { - OPENSSL_PUT_ERROR(BN, bn_wexpand, BN_R_BIGNUM_TOO_LONG); + OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG); return NULL; } if (bn->flags & BN_FLG_STATIC_DATA) { - OPENSSL_PUT_ERROR(BN, bn_wexpand, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA); + OPENSSL_PUT_ERROR(BN, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA); return NULL; } a = (BN_ULONG *)OPENSSL_malloc(sizeof(BN_ULONG) * words); if (a == NULL) { - OPENSSL_PUT_ERROR(BN, bn_wexpand, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); return NULL; } @@ -306,12 +306,16 @@ BIGNUM *bn_wexpand(BIGNUM *bn, unsigned words) { OPENSSL_free(bn->d); bn->d = a; - bn->dmax = words; + bn->dmax = (int)words; return bn; } -BIGNUM *bn_expand(BIGNUM *bn, unsigned bits) { +BIGNUM *bn_expand(BIGNUM *bn, size_t bits) { + if (bits + BN_BITS2 - 1 < bits) { + OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG); + return NULL; + } return bn_wexpand(bn, (bits+BN_BITS2-1)/BN_BITS2); } diff --git a/src/crypto/bn/bn_asn1.c b/src/crypto/bn/bn_asn1.c new file mode 100644 index 0000000..9d70ba8 --- /dev/null +++ b/src/crypto/bn/bn_asn1.c @@ -0,0 +1,93 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include <openssl/bn.h> + +#include <openssl/bytestring.h> +#include <openssl/err.h> + + +int BN_cbs2unsigned(CBS *cbs, BIGNUM *ret) { + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_INTEGER) || + CBS_len(&child) == 0) { + OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING); + return 0; + } + + if (CBS_data(&child)[0] & 0x80) { + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); + return 0; + } + + /* INTEGERs must be minimal. */ + if (CBS_data(&child)[0] == 0x00 && + CBS_len(&child) > 1 && + !(CBS_data(&child)[1] & 0x80)) { + OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING); + return 0; + } + + return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL; +} + +int BN_cbs2unsigned_buggy(CBS *cbs, BIGNUM *ret) { + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_INTEGER) || + CBS_len(&child) == 0) { + OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING); + return 0; + } + + /* This function intentionally does not reject negative numbers or non-minimal + * encodings. Estonian IDs issued between September 2014 to September 2015 are + * broken. See https://crbug.com/532048 and https://crbug.com/534766. + * + * TODO(davidben): Remove this code and callers in March 2016. */ + return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL; +} + +int BN_bn2cbb(CBB *cbb, const BIGNUM *bn) { + /* Negative numbers are unsupported. */ + if (BN_is_negative(bn)) { + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); + return 0; + } + + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) { + OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR); + return 0; + } + + /* The number must be padded with a leading zero if the high bit would + * otherwise be set (or |bn| is zero). */ + if (BN_num_bits(bn) % 8 == 0 && + !CBB_add_u8(&child, 0x00)) { + OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR); + return 0; + } + + uint8_t *out; + if (!CBB_add_space(&child, &out, BN_num_bytes(bn))) { + OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR); + return 0; + } + BN_bn2bin(bn, out); + if (!CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR); + return 0; + } + return 1; +} diff --git a/src/crypto/bn/bn_test.cc b/src/crypto/bn/bn_test.cc index 6a7d48c..47093a7 100644 --- a/src/crypto/bn/bn_test.cc +++ b/src/crypto/bn/bn_test.cc @@ -82,6 +82,7 @@ #include <openssl/mem.h> #include "../crypto/test/scoped_types.h" +#include "../crypto/test/test_util.h" // This program tests the BIGNUM implementation. It takes an optional -bc @@ -117,11 +118,13 @@ static bool test_exp_mod_zero(void); static bool test_small_prime(FILE *fp, BN_CTX *ctx); static bool test_mod_exp_mont5(FILE *fp, BN_CTX *ctx); static bool test_sqrt(FILE *fp, BN_CTX *ctx); -static bool test_bn2bin_padded(FILE *fp, BN_CTX *ctx); -static bool test_dec2bn(FILE *fp, BN_CTX *ctx); -static bool test_hex2bn(FILE *fp, BN_CTX *ctx); -static bool test_asc2bn(FILE *fp, BN_CTX *ctx); +static bool test_bn2bin_padded(BN_CTX *ctx); +static bool test_dec2bn(BN_CTX *ctx); +static bool test_hex2bn(BN_CTX *ctx); +static bool test_asc2bn(BN_CTX *ctx); +static bool test_mpi(); static bool test_rand(); +static bool test_asn1(); static const uint8_t kSample[] = "\xC6\x4F\x43\x04\x2A\xEA\xCA\x6E\x58\x36\x80\x5B\xE8\xC9" @@ -311,35 +314,15 @@ int main(int argc, char *argv[]) { } flush_fp(bc_file.get()); - message(bc_file.get(), "BN_bn2bin_padded"); - if (!test_bn2bin_padded(bc_file.get(), ctx.get())) { + if (!test_bn2bin_padded(ctx.get()) || + !test_dec2bn(ctx.get()) || + !test_hex2bn(ctx.get()) || + !test_asc2bn(ctx.get()) || + !test_mpi() || + !test_rand() || + !test_asn1()) { return 1; } - flush_fp(bc_file.get()); - - message(bc_file.get(), "BN_dec2bn"); - if (!test_dec2bn(bc_file.get(), ctx.get())) { - return 1; - } - flush_fp(bc_file.get()); - - message(bc_file.get(), "BN_hex2bn"); - if (!test_hex2bn(bc_file.get(), ctx.get())) { - return 1; - } - flush_fp(bc_file.get()); - - message(bc_file.get(), "BN_asc2bn"); - if (!test_asc2bn(bc_file.get(), ctx.get())) { - return 1; - } - flush_fp(bc_file.get()); - - message(bc_file.get(), "BN_rand"); - if (!test_rand()) { - return 1; - } - flush_fp(bc_file.get()); printf("PASS\n"); return 0; @@ -440,6 +423,16 @@ static bool test_div(FILE *fp, BN_CTX *ctx) { return false; } + if (!BN_one(a.get())) { + return false; + } + BN_zero(b.get()); + if (BN_div(d.get(), c.get(), a.get(), b.get(), ctx)) { + fprintf(stderr, "Division by zero succeeded!\n"); + return false; + } + ERR_clear_error(); + for (int i = 0; i < num0 + num1; i++) { if (i < num1) { if (!BN_rand(a.get(), 400, 0, 0) || @@ -837,18 +830,17 @@ static bool test_div_word(FILE *fp) { } for (int i = 0; i < num0; i++) { - BN_ULONG s; do { if (!BN_rand(a.get(), 512, -1, 0) || !BN_rand(b.get(), BN_BITS2, -1, 0)) { return false; } - s = b->d[0]; - } while (!s); + } while (BN_is_zero(b.get())); if (!BN_copy(b.get(), a.get())) { return false; } + BN_ULONG s = b->d[0]; BN_ULONG r = BN_div_word(b.get(), s); if (r == (BN_ULONG)-1) { return false; @@ -891,8 +883,27 @@ static bool test_mont(FILE *fp, BN_CTX *ctx) { ScopedBIGNUM B(BN_new()); ScopedBIGNUM n(BN_new()); ScopedBN_MONT_CTX mont(BN_MONT_CTX_new()); - if (!a || !b || !c || !d || !A || !B || !n || !mont || - !BN_rand(a.get(), 100, 0, 0) || + if (!a || !b || !c || !d || !A || !B || !n || !mont) { + return false; + } + + BN_zero(n.get()); + if (BN_MONT_CTX_set(mont.get(), n.get(), ctx)) { + fprintf(stderr, "BN_MONT_CTX_set succeeded for zero modulus!\n"); + return false; + } + ERR_clear_error(); + + if (!BN_set_word(n.get(), 16)) { + return false; + } + if (BN_MONT_CTX_set(mont.get(), n.get(), ctx)) { + fprintf(stderr, "BN_MONT_CTX_set succeeded for even modulus!\n"); + return false; + } + ERR_clear_error(); + + if (!BN_rand(a.get(), 100, 0, 0) || !BN_rand(b.get(), 100, 0, 0)) { return false; } @@ -932,6 +943,7 @@ static bool test_mont(FILE *fp, BN_CTX *ctx) { return false; } } + return true; } @@ -985,6 +997,16 @@ static bool test_mod_mul(FILE *fp, BN_CTX *ctx) { return false; } + if (!BN_one(a.get()) || !BN_one(b.get())) { + return false; + } + BN_zero(c.get()); + if (BN_mod_mul(e.get(), a.get(), b.get(), c.get(), ctx)) { + fprintf(stderr, "BN_mod_mul with zero modulus succeeded!\n"); + return false; + } + ERR_clear_error(); + for (int j = 0; j < 3; j++) { if (!BN_rand(c.get(), 1024, 0, 0)) { return false; @@ -1039,8 +1061,21 @@ static bool test_mod_exp(FILE *fp, BN_CTX *ctx) { ScopedBIGNUM c(BN_new()); ScopedBIGNUM d(BN_new()); ScopedBIGNUM e(BN_new()); - if (!a || !b || !c || !d || !e || - !BN_rand(c.get(), 30, 0, 1)) { // must be odd for montgomery + if (!a || !b || !c || !d || !e) { + return false; + } + + if (!BN_one(a.get()) || !BN_one(b.get())) { + return false; + } + BN_zero(c.get()); + if (BN_mod_exp(d.get(), a.get(), b.get(), c.get(), ctx)) { + fprintf(stderr, "BN_mod_exp with zero modulus succeeded!\n"); + return 0; + } + ERR_clear_error(); + + if (!BN_rand(c.get(), 30, 0, 1)) { // must be odd for montgomery return false; } for (int i = 0; i < num2; i++) { @@ -1079,8 +1114,32 @@ static bool test_mod_exp_mont_consttime(FILE *fp, BN_CTX *ctx) { ScopedBIGNUM c(BN_new()); ScopedBIGNUM d(BN_new()); ScopedBIGNUM e(BN_new()); - if (!a || !b || !c || !d || !e || - !BN_rand(c.get(), 30, 0, 1)) { // must be odd for montgomery + if (!a || !b || !c || !d || !e) { + return false; + } + + if (!BN_one(a.get()) || !BN_one(b.get())) { + return false; + } + BN_zero(c.get()); + if (BN_mod_exp_mont_consttime(d.get(), a.get(), b.get(), c.get(), ctx, + nullptr)) { + fprintf(stderr, "BN_mod_exp_mont_consttime with zero modulus succeeded!\n"); + return 0; + } + ERR_clear_error(); + + if (!BN_set_word(c.get(), 16)) { + return false; + } + if (BN_mod_exp_mont_consttime(d.get(), a.get(), b.get(), c.get(), ctx, + nullptr)) { + fprintf(stderr, "BN_mod_exp_mont_consttime with even modulus succeeded!\n"); + return 0; + } + ERR_clear_error(); + + if (!BN_rand(c.get(), 30, 0, 1)) { // must be odd for montgomery return false; } for (int i = 0; i < num2; i++) { @@ -1208,8 +1267,9 @@ static bool test_exp(FILE *fp, BN_CTX *ctx) { if (!BN_one(e.get())) { return false; } - for (; !BN_is_zero(b.get()); BN_sub(b.get(), b.get(), BN_value_one())) { - if (!BN_mul(e.get(), e.get(), a.get(), ctx)) { + while (!BN_is_zero(b.get())) { + if (!BN_mul(e.get(), e.get(), a.get(), ctx) || + !BN_sub(b.get(), b.get(), BN_value_one())) { return false; } } @@ -1371,7 +1431,7 @@ static bool test_sqrt(FILE *fp, BN_CTX *ctx) { return true; } -static bool test_bn2bin_padded(FILE *fp, BN_CTX *ctx) { +static bool test_bn2bin_padded(BN_CTX *ctx) { uint8_t zeros[256], out[256], reference[128]; memset(zeros, 0, sizeof(zeros)); @@ -1448,7 +1508,7 @@ static int DecimalToBIGNUM(ScopedBIGNUM *out, const char *in) { return ret; } -static bool test_dec2bn(FILE *fp, BN_CTX *ctx) { +static bool test_dec2bn(BN_CTX *ctx) { ScopedBIGNUM bn; int ret = DecimalToBIGNUM(&bn, "0"); if (ret != 1 || !BN_is_zero(bn.get()) || BN_is_negative(bn.get())) { @@ -1490,7 +1550,7 @@ static int HexToBIGNUM(ScopedBIGNUM *out, const char *in) { return ret; } -static bool test_hex2bn(FILE *fp, BN_CTX *ctx) { +static bool test_hex2bn(BN_CTX *ctx) { ScopedBIGNUM bn; int ret = HexToBIGNUM(&bn, "0"); if (ret != 1 || !BN_is_zero(bn.get()) || BN_is_negative(bn.get())) { @@ -1533,7 +1593,7 @@ static ScopedBIGNUM ASCIIToBIGNUM(const char *in) { return ScopedBIGNUM(raw); } -static bool test_asc2bn(FILE *fp, BN_CTX *ctx) { +static bool test_asc2bn(BN_CTX *ctx) { ScopedBIGNUM bn = ASCIIToBIGNUM("0"); if (!bn || !BN_is_zero(bn.get()) || BN_is_negative(bn.get())) { fprintf(stderr, "BN_asc2bn gave a bad result.\n"); @@ -1585,6 +1645,63 @@ static bool test_asc2bn(FILE *fp, BN_CTX *ctx) { return true; } +struct MPITest { + const char *base10; + const char *mpi; + size_t mpi_len; +}; + +static const MPITest kMPITests[] = { + { "0", "\x00\x00\x00\x00", 4 }, + { "1", "\x00\x00\x00\x01\x01", 5 }, + { "-1", "\x00\x00\x00\x01\x81", 5 }, + { "128", "\x00\x00\x00\x02\x00\x80", 6 }, + { "256", "\x00\x00\x00\x02\x01\x00", 6 }, + { "-256", "\x00\x00\x00\x02\x81\x00", 6 }, +}; + +static bool test_mpi() { + uint8_t scratch[8]; + + for (size_t i = 0; i < sizeof(kMPITests) / sizeof(kMPITests[0]); i++) { + const MPITest &test = kMPITests[i]; + ScopedBIGNUM bn(ASCIIToBIGNUM(test.base10)); + const size_t mpi_len = BN_bn2mpi(bn.get(), NULL); + if (mpi_len > sizeof(scratch)) { + fprintf(stderr, "MPI test #%u: MPI size is too large to test.\n", + (unsigned)i); + return false; + } + + const size_t mpi_len2 = BN_bn2mpi(bn.get(), scratch); + if (mpi_len != mpi_len2) { + fprintf(stderr, "MPI test #%u: length changes.\n", (unsigned)i); + return false; + } + + if (mpi_len != test.mpi_len || + memcmp(test.mpi, scratch, mpi_len) != 0) { + fprintf(stderr, "MPI test #%u failed:\n", (unsigned)i); + hexdump(stderr, "Expected: ", test.mpi, test.mpi_len); + hexdump(stderr, "Got: ", scratch, mpi_len); + return false; + } + + ScopedBIGNUM bn2(BN_mpi2bn(scratch, mpi_len, NULL)); + if (bn2.get() == nullptr) { + fprintf(stderr, "MPI test #%u: failed to parse\n", (unsigned)i); + return false; + } + + if (BN_cmp(bn.get(), bn2.get()) != 0) { + fprintf(stderr, "MPI test #%u: wrong result\n", (unsigned)i); + return false; + } + } + + return true; +} + static bool test_rand() { ScopedBIGNUM bn(BN_new()); if (!bn) { @@ -1628,3 +1745,170 @@ static bool test_rand() { return true; } + +struct ASN1Test { + const char *value_ascii; + const char *der; + size_t der_len; +}; + +static const ASN1Test kASN1Tests[] = { + {"0", "\x02\x01\x00", 3}, + {"1", "\x02\x01\x01", 3}, + {"127", "\x02\x01\x7f", 3}, + {"128", "\x02\x02\x00\x80", 4}, + {"0xdeadbeef", "\x02\x05\x00\xde\xad\xbe\xef", 7}, + {"0x0102030405060708", + "\x02\x08\x01\x02\x03\x04\x05\x06\x07\x08", 10}, + {"0xffffffffffffffff", + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff", 11}, +}; + +struct ASN1InvalidTest { + const char *der; + size_t der_len; +}; + +static const ASN1InvalidTest kASN1InvalidTests[] = { + // Bad tag. + {"\x03\x01\x00", 3}, + // Empty contents. + {"\x02\x00", 2}, +}; + +// kASN1BuggyTests are incorrect encodings and how |BN_cbs2unsigned_buggy| +// should interpret them. +static const ASN1Test kASN1BuggyTests[] = { + // Negative numbers. + {"128", "\x02\x01\x80", 3}, + {"255", "\x02\x01\xff", 3}, + // Unnecessary leading zeros. + {"1", "\x02\x02\x00\x01", 4}, +}; + +static bool test_asn1() { + for (const ASN1Test &test : kASN1Tests) { + ScopedBIGNUM bn = ASCIIToBIGNUM(test.value_ascii); + if (!bn) { + return false; + } + + // Test that the input is correctly parsed. + ScopedBIGNUM bn2(BN_new()); + if (!bn2) { + return false; + } + CBS cbs; + CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len); + if (!BN_cbs2unsigned(&cbs, bn2.get()) || CBS_len(&cbs) != 0) { + fprintf(stderr, "Parsing ASN.1 INTEGER failed.\n"); + return false; + } + if (BN_cmp(bn.get(), bn2.get()) != 0) { + fprintf(stderr, "Bad parse.\n"); + return false; + } + + // Test the value serializes correctly. + CBB cbb; + uint8_t *der; + size_t der_len; + CBB_zero(&cbb); + if (!CBB_init(&cbb, 0) || + !BN_bn2cbb(&cbb, bn.get()) || + !CBB_finish(&cbb, &der, &der_len)) { + CBB_cleanup(&cbb); + return false; + } + ScopedOpenSSLBytes delete_der(der); + if (der_len != test.der_len || + memcmp(der, reinterpret_cast<const uint8_t*>(test.der), der_len) != 0) { + fprintf(stderr, "Bad serialization.\n"); + return false; + } + + // |BN_cbs2unsigned_buggy| parses all valid input. + CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len); + if (!BN_cbs2unsigned_buggy(&cbs, bn2.get()) || CBS_len(&cbs) != 0) { + fprintf(stderr, "Parsing ASN.1 INTEGER failed.\n"); + return false; + } + if (BN_cmp(bn.get(), bn2.get()) != 0) { + fprintf(stderr, "Bad parse.\n"); + return false; + } + } + + for (const ASN1InvalidTest &test : kASN1InvalidTests) { + ScopedBIGNUM bn(BN_new()); + if (!bn) { + return false; + } + CBS cbs; + CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len); + if (BN_cbs2unsigned(&cbs, bn.get())) { + fprintf(stderr, "Parsed invalid input.\n"); + return false; + } + ERR_clear_error(); + + // All tests in kASN1InvalidTests are also rejected by + // |BN_cbs2unsigned_buggy|. + CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len); + if (BN_cbs2unsigned_buggy(&cbs, bn.get())) { + fprintf(stderr, "Parsed invalid input.\n"); + return false; + } + ERR_clear_error(); + } + + for (const ASN1Test &test : kASN1BuggyTests) { + // These broken encodings are rejected by |BN_cbs2unsigned|. + ScopedBIGNUM bn(BN_new()); + if (!bn) { + return false; + } + + CBS cbs; + CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len); + if (BN_cbs2unsigned(&cbs, bn.get())) { + fprintf(stderr, "Parsed invalid input.\n"); + return false; + } + ERR_clear_error(); + + // However |BN_cbs2unsigned_buggy| accepts them. + ScopedBIGNUM bn2 = ASCIIToBIGNUM(test.value_ascii); + if (!bn2) { + return false; + } + + CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len); + if (!BN_cbs2unsigned_buggy(&cbs, bn.get()) || CBS_len(&cbs) != 0) { + fprintf(stderr, "Parsing (invalid) ASN.1 INTEGER failed.\n"); + return false; + } + + if (BN_cmp(bn.get(), bn2.get()) != 0) { + fprintf(stderr, "\"Bad\" parse.\n"); + return false; + } + } + + // Serializing negative numbers is not supported. + ScopedBIGNUM bn = ASCIIToBIGNUM("-1"); + if (!bn) { + return false; + } + CBB cbb; + CBB_zero(&cbb); + if (!CBB_init(&cbb, 0) || + BN_bn2cbb(&cbb, bn.get())) { + fprintf(stderr, "Serialized negative number.\n"); + CBB_cleanup(&cbb); + return false; + } + CBB_cleanup(&cbb); + + return true; +} diff --git a/src/crypto/bn/convert.c b/src/crypto/bn/convert.c index 531b661..0122709 100644 --- a/src/crypto/bn/convert.c +++ b/src/crypto/bn/convert.c @@ -56,7 +56,9 @@ #include <openssl/bn.h> +#include <assert.h> #include <ctype.h> +#include <limits.h> #include <stdio.h> #include <string.h> @@ -67,7 +69,8 @@ #include "internal.h" BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret) { - unsigned num_words, m; + size_t num_words; + unsigned m; BN_ULONG word = 0; BIGNUM *bn = NULL; @@ -93,7 +96,10 @@ BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret) { return NULL; } - ret->top = num_words; + /* |bn_wexpand| must check bounds on |num_words| to write it into + * |ret->dmax|. */ + assert(num_words <= INT_MAX); + ret->top = (int)num_words; ret->neg = 0; while (len--) { @@ -198,7 +204,7 @@ char *BN_bn2hex(const BIGNUM *bn) { buf = (char *)OPENSSL_malloc(bn->top * BN_BYTES * 2 + 2); if (buf == NULL) { - OPENSSL_PUT_ERROR(BN, BN_bn2hex, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); return NULL; } @@ -227,47 +233,59 @@ char *BN_bn2hex(const BIGNUM *bn) { return buf; } -/* decode_hex decodes |i| bytes of hex data from |in| and updates |bn|. */ -static void decode_hex(BIGNUM *bn, const char *in, int i) { - int h, m, j, k, c; - BN_ULONG l=0; - - j = i; /* least significant 'hex' */ - h = 0; - while (j > 0) { - m = ((BN_BYTES * 2) <= j) ? (BN_BYTES * 2) : j; - l = 0; - for (;;) { - c = in[j - m]; - if ((c >= '0') && (c <= '9')) { - k = c - '0'; - } else if ((c >= 'a') && (c <= 'f')) { - k = c - 'a' + 10; - } else if ((c >= 'A') && (c <= 'F')) { - k = c - 'A' + 10; - } else { - k = 0; /* paranoia */ - } +/* decode_hex decodes |in_len| bytes of hex data from |in| and updates |bn|. */ +static int decode_hex(BIGNUM *bn, const char *in, int in_len) { + if (in_len > INT_MAX/4) { + OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG); + return 0; + } + /* |in_len| is the number of hex digits. */ + if (bn_expand(bn, in_len * 4) == NULL) { + return 0; + } - l = (l << 4) | k; + int i = 0; + while (in_len > 0) { + /* Decode one |BN_ULONG| at a time. */ + int todo = BN_BYTES * 2; + if (todo > in_len) { + todo = in_len; + } - if (--m <= 0) { - bn->d[h++] = l; - break; + BN_ULONG word = 0; + int j; + for (j = todo; j > 0; j--) { + char c = in[in_len - j]; + + BN_ULONG hex; + if (c >= '0' && c <= '9') { + hex = c - '0'; + } else if (c >= 'a' && c <= 'f') { + hex = c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + hex = c - 'A' + 10; + } else { + hex = 0; + /* This shouldn't happen. The caller checks |isxdigit|. */ + assert(0); } + word = (word << 4) | hex; } - j -= (BN_BYTES * 2); + bn->d[i++] = word; + in_len -= todo; } - - bn->top = h; + assert(i <= bn->dmax); + bn->top = i; + return 1; } /* decode_dec decodes |in_len| bytes of decimal data from |in| and updates |bn|. */ -static void decode_dec(BIGNUM *bn, const char *in, int in_len) { +static int decode_dec(BIGNUM *bn, const char *in, int in_len) { int i, j; BN_ULONG l = 0; + /* Decode |BN_DEC_NUM| digits at a time. */ j = BN_DEC_NUM - (in_len % BN_DEC_NUM); if (j == BN_DEC_NUM) { j = 0; @@ -277,15 +295,18 @@ static void decode_dec(BIGNUM *bn, const char *in, int in_len) { l *= 10; l += in[i] - '0'; if (++j == BN_DEC_NUM) { - BN_mul_word(bn, BN_DEC_CONV); - BN_add_word(bn, l); + if (!BN_mul_word(bn, BN_DEC_CONV) || + !BN_add_word(bn, l)) { + return 0; + } l = 0; j = 0; } } + return 1; } -typedef void (*decode_func) (BIGNUM *bn, const char *in, int i); +typedef int (*decode_func) (BIGNUM *bn, const char *in, int in_len); typedef int (*char_test_func) (int c); static int bn_x2bn(BIGNUM **outp, const char *in, decode_func decode, char_test_func want_char) { @@ -302,7 +323,7 @@ static int bn_x2bn(BIGNUM **outp, const char *in, decode_func decode, char_test_ in++; } - for (i = 0; want_char((unsigned char)in[i]); i++) {} + for (i = 0; want_char((unsigned char)in[i]) && i + neg < INT_MAX; i++) {} num = i + neg; if (outp == NULL) { @@ -320,13 +341,10 @@ static int bn_x2bn(BIGNUM **outp, const char *in, decode_func decode, char_test_ BN_zero(ret); } - /* i is the number of hex digests; */ - if (bn_expand(ret, i * 4) == NULL) { + if (!decode(ret, in, i)) { goto err; } - decode(ret, in, i); - bn_correct_top(ret); if (!BN_is_zero(ret)) { ret->neg = neg; @@ -365,7 +383,7 @@ char *BN_bn2dec(const BIGNUM *a) { (BN_ULONG *)OPENSSL_malloc((num / BN_DEC_NUM + 1) * sizeof(BN_ULONG)); buf = (char *)OPENSSL_malloc(num + 3); if ((buf == NULL) || (bn_data == NULL)) { - OPENSSL_PUT_ERROR(BN, BN_bn2dec, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); goto err; } t = BN_dup(a); @@ -499,3 +517,81 @@ BN_ULONG BN_get_word(const BIGNUM *bn) { return BN_MASK2; } } + +size_t BN_bn2mpi(const BIGNUM *in, uint8_t *out) { + const size_t bits = BN_num_bits(in); + const size_t bytes = (bits + 7) / 8; + /* If the number of bits is a multiple of 8, i.e. if the MSB is set, + * prefix with a zero byte. */ + int extend = 0; + if (bytes != 0 && (bits & 0x07) == 0) { + extend = 1; + } + + const size_t len = bytes + extend; + if (len < bytes || + 4 + len < len || + (len & 0xffffffff) != len) { + /* If we cannot represent the number then we emit zero as the interface + * doesn't allow an error to be signalled. */ + if (out) { + memset(out, 0, 4); + } + return 4; + } + + if (out == NULL) { + return 4 + len; + } + + out[0] = len >> 24; + out[1] = len >> 16; + out[2] = len >> 8; + out[3] = len; + if (extend) { + out[4] = 0; + } + BN_bn2bin(in, out + 4 + extend); + if (in->neg && len > 0) { + out[4] |= 0x80; + } + return len + 4; +} + +BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out) { + if (len < 4) { + OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING); + return NULL; + } + const size_t in_len = ((size_t)in[0] << 24) | + ((size_t)in[1] << 16) | + ((size_t)in[2] << 8) | + ((size_t)in[3]); + if (in_len != len - 4) { + OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING); + return NULL; + } + + if (out == NULL) { + out = BN_new(); + } + if (out == NULL) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (in_len == 0) { + BN_zero(out); + return out; + } + + in += 4; + if (BN_bin2bn(in, in_len, out) == NULL) { + return NULL; + } + out->neg = ((*in) & 0x80) != 0; + if (out->neg) { + BN_clear_bit(out, BN_num_bits(out) - 1); + } + return out; +} diff --git a/src/crypto/bn/ctx.c b/src/crypto/bn/ctx.c index 0578376..48d9adf 100644 --- a/src/crypto/bn/ctx.c +++ b/src/crypto/bn/ctx.c @@ -124,7 +124,7 @@ struct bignum_ctx { BN_CTX *BN_CTX_new(void) { BN_CTX *ret = OPENSSL_malloc(sizeof(BN_CTX)); if (!ret) { - OPENSSL_PUT_ERROR(BN, BN_CTX_new, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); return NULL; } @@ -153,7 +153,7 @@ void BN_CTX_start(BN_CTX *ctx) { ctx->err_stack++; } else if (!BN_STACK_push(&ctx->stack, ctx->used)) { /* (Try to) get a new frame pointer */ - OPENSSL_PUT_ERROR(BN, BN_CTX_start, BN_R_TOO_MANY_TEMPORARY_VARIABLES); + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_TEMPORARY_VARIABLES); ctx->err_stack++; } } @@ -169,7 +169,7 @@ BIGNUM *BN_CTX_get(BN_CTX *ctx) { /* Setting too_many prevents repeated "get" attempts from * cluttering the error stack. */ ctx->too_many = 1; - OPENSSL_PUT_ERROR(BN, BN_CTX_get, BN_R_TOO_MANY_TEMPORARY_VARIABLES); + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_TEMPORARY_VARIABLES); return NULL; } diff --git a/src/crypto/bn/div.c b/src/crypto/bn/div.c index 3588ea1..779dda2 100644 --- a/src/crypto/bn/div.c +++ b/src/crypto/bn/div.c @@ -125,7 +125,7 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, * so don't just rely on bn_check_top() here */ if ((num->top > 0 && num->d[num->top - 1] == 0) || (divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) { - OPENSSL_PUT_ERROR(BN, BN_div, BN_R_NOT_INITIALIZED); + OPENSSL_PUT_ERROR(BN, BN_R_NOT_INITIALIZED); return 0; } @@ -135,7 +135,7 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, } if (BN_is_zero(divisor)) { - OPENSSL_PUT_ERROR(BN, BN_div, BN_R_DIV_BY_ZERO); + OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO); return 0; } @@ -511,7 +511,7 @@ int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m) { /* max_shift >= 0 */ if (max_shift < 0) { - OPENSSL_PUT_ERROR(BN, BN_mod_lshift_quick, BN_R_INPUT_NOT_REDUCED); + OPENSSL_PUT_ERROR(BN, BN_R_INPUT_NOT_REDUCED); return 0; } diff --git a/src/crypto/bn/exponentiation.c b/src/crypto/bn/exponentiation.c index d3063c9..6c5e11b 100644 --- a/src/crypto/bn/exponentiation.c +++ b/src/crypto/bn/exponentiation.c @@ -131,7 +131,7 @@ int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) { if ((p->flags & BN_FLG_CONSTTIME) != 0) { /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */ - OPENSSL_PUT_ERROR(BN, BN_exp, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } @@ -173,8 +173,8 @@ int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) { } } - if (r != rr) { - BN_copy(r, rr); + if (r != rr && !BN_copy(r, rr)) { + goto err; } ret = 1; @@ -333,7 +333,7 @@ static int BN_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, j = 0; while (BN_ucmp(r, &(recp->N)) >= 0) { if (j++ > 2) { - OPENSSL_PUT_ERROR(BN, BN_div_recp, BN_R_BAD_RECIPROCAL); + OPENSSL_PUT_ERROR(BN, BN_R_BAD_RECIPROCAL); goto err; } if (!BN_usub(r, r, &(recp->N))) { @@ -427,7 +427,7 @@ static int mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) { /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */ - OPENSSL_PUT_ERROR(BN, mod_exp_recp, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } @@ -616,7 +616,7 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, } if (!BN_is_odd(m)) { - OPENSSL_PUT_ERROR(BN, BN_mod_exp_mont, BN_R_CALLED_WITH_EVEN_MODULUS); + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); return 0; } bits = BN_num_bits(p); @@ -862,13 +862,13 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, unsigned char *powerbuf = NULL; BIGNUM tmp, am; - top = m->top; - - if (!(m->d[0] & 1)) { - OPENSSL_PUT_ERROR(BN, BN_mod_exp_mont_consttime, - BN_R_CALLED_WITH_EVEN_MODULUS); + if (!BN_is_odd(m)) { + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); return 0; } + + top = m->top; + bits = BN_num_bits(p); if (bits == 0) { ret = BN_one(rr); @@ -926,7 +926,6 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, } } #endif - (void)0; /* Allocate a buffer large enough to hold all of the pre-computed * powers of am, am itself and tmp. @@ -1223,13 +1222,12 @@ int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p, if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) { /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */ - OPENSSL_PUT_ERROR(BN, BN_mod_exp_mont_word, - ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } if (!BN_is_odd(m)) { - OPENSSL_PUT_ERROR(BN, BN_mod_exp_mont_word, BN_R_CALLED_WITH_EVEN_MODULUS); + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); return 0; } @@ -1372,7 +1370,7 @@ int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1, BN_MONT_CTX *mont = NULL; if (!(m->d[0] & 1)) { - OPENSSL_PUT_ERROR(BN, BN_mod_exp2_mont, BN_R_CALLED_WITH_EVEN_MODULUS); + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); return 0; } bits1 = BN_num_bits(p1); diff --git a/src/crypto/bn/gcd.c b/src/crypto/bn/gcd.c index 3132c29..e106149 100644 --- a/src/crypto/bn/gcd.c +++ b/src/crypto/bn/gcd.c @@ -223,20 +223,23 @@ err: } /* solves ax == 1 (mod n) */ -static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, const BIGNUM *a, - const BIGNUM *n, BN_CTX *ctx); +static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse, + const BIGNUM *a, const BIGNUM *n, + BN_CTX *ctx); -BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n, - BN_CTX *ctx) { +BIGNUM *BN_mod_inverse_ex(BIGNUM *out, int *out_no_inverse, const BIGNUM *a, + const BIGNUM *n, BN_CTX *ctx) { BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL; BIGNUM *ret = NULL; int sign; if ((a->flags & BN_FLG_CONSTTIME) != 0 || (n->flags & BN_FLG_CONSTTIME) != 0) { - return BN_mod_inverse_no_branch(out, a, n, ctx); + return BN_mod_inverse_no_branch(out, out_no_inverse, a, n, ctx); } + *out_no_inverse = 0; + BN_CTX_start(ctx); A = BN_CTX_get(ctx); B = BN_CTX_get(ctx); @@ -522,7 +525,8 @@ BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n, } } } else { - OPENSSL_PUT_ERROR(BN, BN_mod_inverse, BN_R_NO_INVERSE); + *out_no_inverse = 1; + OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE); goto err; } ret = R; @@ -535,16 +539,25 @@ err: return ret; } +BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n, + BN_CTX *ctx) { + int no_inverse; + return BN_mod_inverse_ex(out, &no_inverse, a, n, ctx); +} + /* BN_mod_inverse_no_branch is a special version of BN_mod_inverse. * It does not contain branches that may leak sensitive information. */ -static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, const BIGNUM *a, - const BIGNUM *n, BN_CTX *ctx) { +static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse, + const BIGNUM *a, const BIGNUM *n, + BN_CTX *ctx) { BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL; BIGNUM local_A, local_B; BIGNUM *pA, *pB; BIGNUM *ret = NULL; int sign; + *out_no_inverse = 0; + BN_CTX_start(ctx); A = BN_CTX_get(ctx); B = BN_CTX_get(ctx); @@ -682,7 +695,8 @@ static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, const BIGNUM *a, } } } else { - OPENSSL_PUT_ERROR(BN, BN_mod_inverse_no_branch, BN_R_NO_INVERSE); + *out_no_inverse = 1; + OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE); goto err; } ret = R; diff --git a/src/crypto/bn/internal.h b/src/crypto/bn/internal.h index 2674b3c..0d0eb44 100644 --- a/src/crypto/bn/internal.h +++ b/src/crypto/bn/internal.h @@ -136,9 +136,9 @@ extern "C" { #endif -/* bn_expand acts the same as |BN_wexpand|, but takes a number of bits rather +/* bn_expand acts the same as |bn_wexpand|, but takes a number of bits rather * than a number of words. */ -BIGNUM *bn_expand(BIGNUM *bn, unsigned bits); +BIGNUM *bn_expand(BIGNUM *bn, size_t bits); #if defined(OPENSSL_64_BIT) diff --git a/src/crypto/bn/montgomery.c b/src/crypto/bn/montgomery.c index 152cf2d..c6c9c88 100644 --- a/src/crypto/bn/montgomery.c +++ b/src/crypto/bn/montgomery.c @@ -110,6 +110,7 @@ #include <string.h> +#include <openssl/err.h> #include <openssl/mem.h> #include <openssl/thread.h> @@ -176,6 +177,11 @@ int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) { BIGNUM tmod; BN_ULONG buf[2]; + if (BN_is_zero(mod)) { + OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO); + return 0; + } + BN_CTX_start(ctx); Ri = BN_CTX_get(ctx); if (Ri == NULL) { diff --git a/src/crypto/bn/mul.c b/src/crypto/bn/mul.c index a17d766..029a59e 100644 --- a/src/crypto/bn/mul.c +++ b/src/crypto/bn/mul.c @@ -666,8 +666,8 @@ int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { end: bn_correct_top(rr); - if (r != rr) { - BN_copy(r, rr); + if (r != rr && !BN_copy(r, rr)) { + goto err; } ret = 1; @@ -877,8 +877,8 @@ int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) { rr->top = max; } - if (rr != r) { - BN_copy(r, rr); + if (rr != r && !BN_copy(r, rr)) { + goto err; } ret = 1; diff --git a/src/crypto/bn/prime.c b/src/crypto/bn/prime.c index cf3afcf..bbb8fe0 100644 --- a/src/crypto/bn/prime.c +++ b/src/crypto/bn/prime.c @@ -362,11 +362,11 @@ int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, const BIGNUM *add, if (bits < 2) { /* There are no prime numbers this small. */ - OPENSSL_PUT_ERROR(BN, BN_generate_prime_ex, BN_R_BITS_TOO_SMALL); + OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL); return 0; } else if (bits == 2 && safe) { /* The smallest safe prime (7) is three bits. */ - OPENSSL_PUT_ERROR(BN, BN_generate_prime_ex, BN_R_BITS_TOO_SMALL); + OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL); return 0; } @@ -515,11 +515,10 @@ int BN_is_prime_fasttest_ex(const BIGNUM *a, int checks, BN_CTX *ctx_passed, /* A := abs(a) */ if (a->neg) { - BIGNUM *t; - if ((t = BN_CTX_get(ctx)) == NULL) { + BIGNUM *t = BN_CTX_get(ctx); + if (t == NULL || !BN_copy(t, a)) { goto err; } - BN_copy(t, a); t->neg = 0; A = t; } else { diff --git a/src/crypto/bn/random.c b/src/crypto/bn/random.c index 549ac48..3116e54 100644 --- a/src/crypto/bn/random.c +++ b/src/crypto/bn/random.c @@ -134,7 +134,7 @@ int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) { buf = OPENSSL_malloc(bytes); if (buf == NULL) { - OPENSSL_PUT_ERROR(BN, BN_rand, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); goto err; } @@ -186,7 +186,7 @@ int BN_rand_range(BIGNUM *r, const BIGNUM *range) { unsigned count = 100; if (range->neg || BN_is_zero(range)) { - OPENSSL_PUT_ERROR(BN, BN_rand_range, BN_R_INVALID_RANGE); + OPENSSL_PUT_ERROR(BN, BN_R_INVALID_RANGE); return 0; } @@ -219,7 +219,7 @@ int BN_rand_range(BIGNUM *r, const BIGNUM *range) { } if (!--count) { - OPENSSL_PUT_ERROR(BN, BN_rand_range, BN_R_TOO_MANY_ITERATIONS); + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); return 0; } } while (BN_cmp(r, range) >= 0); @@ -231,7 +231,7 @@ int BN_rand_range(BIGNUM *r, const BIGNUM *range) { } if (!--count) { - OPENSSL_PUT_ERROR(BN, BN_rand_range, BN_R_TOO_MANY_ITERATIONS); + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); return 0; } } while (BN_cmp(r, range) >= 0); @@ -264,13 +264,13 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv, } if (BN_is_zero(range)) { - OPENSSL_PUT_ERROR(BN, BN_generate_dsa_nonce, BN_R_DIV_BY_ZERO); + OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO); goto err; } k_bytes = OPENSSL_malloc(num_k_bytes); if (!k_bytes) { - OPENSSL_PUT_ERROR(BN, BN_generate_dsa_nonce, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); goto err; } @@ -281,7 +281,7 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv, /* No reasonable DSA or ECDSA key should have a private key * this large and we don't handle this case in order to avoid * leaking the length of the private key. */ - OPENSSL_PUT_ERROR(BN, BN_generate_dsa_nonce, BN_R_PRIVATE_KEY_TOO_LARGE); + OPENSSL_PUT_ERROR(BN, BN_R_PRIVATE_KEY_TOO_LARGE); goto err; } memcpy(private_bytes, priv->d, todo); diff --git a/src/crypto/bn/rsaz_exp.h b/src/crypto/bn/rsaz_exp.h index 0bb6b0c..c752b45 100644 --- a/src/crypto/bn/rsaz_exp.h +++ b/src/crypto/bn/rsaz_exp.h @@ -1,32 +1,44 @@ -/****************************************************************************** -* Copyright(c) 2012, Intel Corp. -* Developers and authors: -* Shay Gueron (1, 2), and Vlad Krasnov (1) -* (1) Intel Corporation, Israel Development Center, Haifa, Israel -* (2) University of Haifa, Israel +/***************************************************************************** +* * +* Copyright (c) 2012, Intel Corporation * +* * +* All rights reserved. * +* * +* Redistribution and use in source and binary forms, with or without * +* modification, are permitted provided that the following conditions are * +* met: * +* * +* * Redistributions of source code must retain the above copyright * +* notice, this list of conditions and the following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above copyright * +* notice, this list of conditions and the following disclaimer in the * +* documentation and/or other materials provided with the * +* distribution. * +* * +* * Neither the name of the Intel Corporation nor the names of its * +* contributors may be used to endorse or promote products derived from * +* this software without specific prior written permission. * +* * +* * +* THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY * +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * +* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR * +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * +* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * +* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +* * ****************************************************************************** -* LICENSE: -* This submission to OpenSSL is to be made available under the OpenSSL -* license, and only to the OpenSSL project, in order to allow integration -* into the publicly distributed code. -* The use of this code, or portions of this code, or concepts embedded in -* this code, or modification of this code and/or algorithm(s) in it, or the -* use of this code for any other purpose than stated above, requires special -* licensing. -****************************************************************************** -* DISCLAIMER: -* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS AND THE COPYRIGHT OWNERS -* ``AS IS''. ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS OR THE COPYRIGHT -* OWNERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -* POSSIBILITY OF SUCH DAMAGE. -******************************************************************************/ +* Developers and authors: * +* Shay Gueron (1, 2), and Vlad Krasnov (1) * +* (1) Intel Corporation, Israel Development Center, Haifa, Israel * +* (2) University of Haifa, Israel * +*****************************************************************************/ #ifndef RSAZ_EXP_H #define RSAZ_EXP_H diff --git a/src/crypto/bn/shift.c b/src/crypto/bn/shift.c index f143996..defec92 100644 --- a/src/crypto/bn/shift.c +++ b/src/crypto/bn/shift.c @@ -69,7 +69,7 @@ int BN_lshift(BIGNUM *r, const BIGNUM *a, int n) { BN_ULONG l; if (n < 0) { - OPENSSL_PUT_ERROR(BN, BN_lshift, BN_R_NEGATIVE_NUMBER); + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); return 0; } @@ -138,7 +138,7 @@ int BN_rshift(BIGNUM *r, const BIGNUM *a, int n) { BN_ULONG l, tmp; if (n < 0) { - OPENSSL_PUT_ERROR(BN, BN_rshift, BN_R_NEGATIVE_NUMBER); + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); return 0; } diff --git a/src/crypto/bn/sqrt.c b/src/crypto/bn/sqrt.c index e71a818..2ed66c2 100644 --- a/src/crypto/bn/sqrt.c +++ b/src/crypto/bn/sqrt.c @@ -86,7 +86,7 @@ BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) { return ret; } - OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_P_IS_NOT_PRIME); + OPENSSL_PUT_ERROR(BN, BN_R_P_IS_NOT_PRIME); return (NULL); } @@ -260,7 +260,7 @@ BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) { } if (r == 0) { /* m divides p */ - OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_P_IS_NOT_PRIME); + OPENSSL_PUT_ERROR(BN, BN_R_P_IS_NOT_PRIME); goto end; } } while (r == 1 && ++i < 82); @@ -271,7 +271,7 @@ BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) { * Even if p is not prime, we should have found some y * such that r == -1. */ - OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_TOO_MANY_ITERATIONS); + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); goto end; } @@ -286,7 +286,7 @@ BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) { goto end; } if (BN_is_one(y)) { - OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_P_IS_NOT_PRIME); + OPENSSL_PUT_ERROR(BN, BN_R_P_IS_NOT_PRIME); goto end; } @@ -377,7 +377,7 @@ BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) { while (!BN_is_one(t)) { i++; if (i == e) { - OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_NOT_A_SQUARE); + OPENSSL_PUT_ERROR(BN, BN_R_NOT_A_SQUARE); goto end; } if (!BN_mod_mul(t, t, t, p, ctx)) { @@ -413,7 +413,7 @@ vrfy: } if (!err && 0 != BN_cmp(x, A)) { - OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_NOT_A_SQUARE); + OPENSSL_PUT_ERROR(BN, BN_R_NOT_A_SQUARE); err = 1; } } @@ -434,7 +434,7 @@ int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx) { int ok = 0, last_delta_valid = 0; if (in->neg) { - OPENSSL_PUT_ERROR(BN, BN_sqrt, BN_R_NEGATIVE_NUMBER); + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); return 0; } if (BN_is_zero(in)) { @@ -452,7 +452,7 @@ int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx) { last_delta = BN_CTX_get(ctx); delta = BN_CTX_get(ctx); if (estimate == NULL || tmp == NULL || last_delta == NULL || delta == NULL) { - OPENSSL_PUT_ERROR(BN, BN_sqrt, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); goto err; } @@ -470,7 +470,7 @@ int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx) { !BN_sqr(tmp, estimate, ctx) || /* |delta| = |in| - |tmp| */ !BN_sub(delta, in, tmp)) { - OPENSSL_PUT_ERROR(BN, BN_sqrt, ERR_R_BN_LIB); + OPENSSL_PUT_ERROR(BN, ERR_R_BN_LIB); goto err; } @@ -490,15 +490,15 @@ int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx) { } if (BN_cmp(tmp, in) != 0) { - OPENSSL_PUT_ERROR(BN, BN_sqrt, BN_R_NOT_A_SQUARE); + OPENSSL_PUT_ERROR(BN, BN_R_NOT_A_SQUARE); goto err; } ok = 1; err: - if (ok && out_sqrt == in) { - BN_copy(out_sqrt, estimate); + if (ok && out_sqrt == in && !BN_copy(out_sqrt, estimate)) { + ok = 0; } BN_CTX_end(ctx); return ok; |