summaryrefslogtreecommitdiffstats
path: root/src/crypto/bn
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/bn')
-rw-r--r--src/crypto/bn/CMakeLists.txt3
-rw-r--r--src/crypto/bn/add.c2
-rw-r--r--src/crypto/bn/asm/armv4-mont.pl2
-rw-r--r--src/crypto/bn/bn.c20
-rw-r--r--src/crypto/bn/bn_asn1.c93
-rw-r--r--src/crypto/bn/bn_test.cc376
-rw-r--r--src/crypto/bn/convert.c178
-rw-r--r--src/crypto/bn/ctx.c6
-rw-r--r--src/crypto/bn/div.c6
-rw-r--r--src/crypto/bn/exponentiation.c30
-rw-r--r--src/crypto/bn/gcd.c32
-rw-r--r--src/crypto/bn/internal.h4
-rw-r--r--src/crypto/bn/montgomery.c6
-rw-r--r--src/crypto/bn/mul.c8
-rw-r--r--src/crypto/bn/prime.c9
-rw-r--r--src/crypto/bn/random.c14
-rw-r--r--src/crypto/bn/rsaz_exp.h68
-rw-r--r--src/crypto/bn/shift.c4
-rw-r--r--src/crypto/bn/sqrt.c24
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;