Add BN_get_u64 so that Android doesn't have to reach into the BIGNUM structs
BUG=97
Change-Id: I4799cc99511e73af44def1d4daa36a8b4699f62d
Reviewed-on: https://boringssl-review.googlesource.com/12904
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/bn/bn_test.cc b/crypto/bn/bn_test.cc
index dfca2bc..89d9fed 100644
--- a/crypto/bn/bn_test.cc
+++ b/crypto/bn/bn_test.cc
@@ -1495,7 +1495,7 @@
return true;
}
-static bool TestBNSetU64() {
+static bool TestBNSetGetU64() {
static const struct {
const char *hex;
uint64_t value;
@@ -1517,6 +1517,36 @@
ERR_print_errors_fp(stderr);
return false;
}
+
+ uint64_t tmp;
+ if (!BN_get_u64(bn.get(), &tmp) || tmp != test.value) {
+ fprintf(stderr, "BN_get_u64 test failed for 0x%s.\n", test.hex);
+ return false;
+ }
+
+ BN_set_negative(bn.get(), 1);
+ if (!BN_get_u64(bn.get(), &tmp) || tmp != test.value) {
+ fprintf(stderr, "BN_get_u64 test failed for -0x%s.\n", test.hex);
+ return false;
+ }
+ }
+
+ // Test that BN_get_u64 fails on large numbers.
+ bssl::UniquePtr<BIGNUM> bn(BN_new());
+ if (!BN_lshift(bn.get(), BN_value_one(), 64)) {
+ return false;
+ }
+
+ uint64_t tmp;
+ if (BN_get_u64(bn.get(), &tmp)) {
+ fprintf(stderr, "BN_get_u64 of 2^64 unexpectedly succeeded.\n");
+ return false;
+ }
+
+ BN_set_negative(bn.get(), 1);
+ if (BN_get_u64(bn.get(), &tmp)) {
+ fprintf(stderr, "BN_get_u64 of -2^64 unexpectedly succeeded.\n");
+ return false;
}
return true;
@@ -1548,7 +1578,7 @@
!TestSmallPrime(ctx.get()) ||
!TestCmpWord() ||
!TestBN2Dec() ||
- !TestBNSetU64()) {
+ !TestBNSetGetU64()) {
return 1;
}
diff --git a/crypto/bn/convert.c b/crypto/bn/convert.c
index f03de9e..c44e7a8 100644
--- a/crypto/bn/convert.c
+++ b/crypto/bn/convert.c
@@ -515,6 +515,24 @@
}
}
+int BN_get_u64(const BIGNUM *bn, uint64_t *out) {
+ switch (bn->top) {
+ case 0:
+ *out = 0;
+ return 1;
+ case 1:
+ *out = bn->d[0];
+ return 1;
+#if defined(OPENSSL_32_BIT)
+ case 2:
+ *out = (uint64_t) bn->d[0] | (((uint64_t) bn->d[1]) << 32);
+ return 1;
+#endif
+ default:
+ return 0;
+ }
+}
+
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;
diff --git a/include/openssl/bn.h b/include/openssl/bn.h
index c98e0bd..d3b6644 100644
--- a/include/openssl/bn.h
+++ b/include/openssl/bn.h
@@ -306,6 +306,11 @@
* will be returned. */
OPENSSL_EXPORT BN_ULONG BN_get_word(const BIGNUM *bn);
+/* BN_get_u64 sets |*out| to the absolute value of |bn| as a |uint64_t| and
+ * returns one. If |bn| is too large to be represented as a |uint64_t|, it
+ * returns zero. */
+OPENSSL_EXPORT int BN_get_u64(const BIGNUM *bn, uint64_t *out);
+
/* ASN.1 functions. */