Add ASN1_INTEGER_get_int64 and ASN1_ENUMERATED_get_int64.
Node uses this.
Change-Id: I13e1734a8f60d4ad0c6a7bcab830c3a0406542b1
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/54307
Commit-Queue: Bob Beck <bbe@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/crypto/asn1/a_int.c b/crypto/asn1/a_int.c
index afc88d2..89d6a54 100644
--- a/crypto/asn1/a_int.c
+++ b/crypto/asn1/a_int.c
@@ -333,16 +333,11 @@
return asn1_string_get_uint64(out, a, V_ASN1_ENUMERATED);
}
-static long asn1_string_get_long(const ASN1_STRING *a, int type) {
- if (a == NULL) {
- return 0;
- }
-
+static int asn1_string_get_int64(int64_t *out, const ASN1_STRING *a, int type) {
uint64_t v;
if (!asn1_string_get_abs_uint64(&v, a, type)) {
- goto err;
+ return 0;
}
-
int64_t i64;
int fits_in_i64;
// Check |v != 0| to handle manually-constructed negative zeros.
@@ -353,16 +348,36 @@
i64 = (int64_t)v;
fits_in_i64 = i64 >= 0;
}
- static_assert(sizeof(long) <= sizeof(int64_t), "long is too big");
+ if (!fits_in_i64) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_INTEGER);
+ return 0;
+ }
+ *out = i64;
+ return 1;
+}
- if (fits_in_i64 && LONG_MIN <= i64 && i64 <= LONG_MAX) {
- return (long)i64;
+int ASN1_INTEGER_get_int64(int64_t *out, const ASN1_INTEGER *a) {
+ return asn1_string_get_int64(out, a, V_ASN1_INTEGER);
+}
+
+int ASN1_ENUMERATED_get_int64(int64_t *out, const ASN1_ENUMERATED *a) {
+ return asn1_string_get_int64(out, a, V_ASN1_ENUMERATED);
+}
+
+static long asn1_string_get_long(const ASN1_STRING *a, int type) {
+ if (a == NULL) {
+ return 0;
}
-err:
- // This function's return value does not distinguish overflow from -1.
- ERR_clear_error();
- return -1;
+ int64_t v;
+ if (!asn1_string_get_int64(&v, a, type) || //
+ v < LONG_MIN || v > LONG_MAX) {
+ // This function's return value does not distinguish overflow from -1.
+ ERR_clear_error();
+ return -1;
+ }
+
+ return (long)v;
}
long ASN1_INTEGER_get(const ASN1_INTEGER *a) {
diff --git a/crypto/asn1/asn1_test.cc b/crypto/asn1/asn1_test.cc
index ffb3e4a..4d07a8b 100644
--- a/crypto/asn1/asn1_test.cc
+++ b/crypto/asn1/asn1_test.cc
@@ -328,9 +328,10 @@
EXPECT_EQ(ptr, t.der.data() + t.der.size());
objs["der"] = std::move(by_der);
- // Construct |ASN1_INTEGER| from |long| or |uint64_t|, if it fits.
- bool fits_in_long = false, fits_in_u64 = false;
+ // Construct |ASN1_INTEGER| from various C types, if it fits.
+ bool fits_in_long = false, fits_in_i64 = false, fits_in_u64 = false;
uint64_t u64 = 0;
+ int64_t i64 = 0;
long l = 0;
uint64_t abs_u64;
if (BN_get_u64(bn.get(), &abs_u64)) {
@@ -343,20 +344,26 @@
objs["u64"] = std::move(by_u64);
}
+ fits_in_i64 = BN_cmp(int64_min.get(), bn.get()) <= 0 &&
+ BN_cmp(bn.get(), int64_max.get()) <= 0;
+
+ if (fits_in_i64) {
+ if (BN_is_negative(bn.get())) {
+ i64 = static_cast<int64_t>(0u - abs_u64);
+ } else {
+ i64 = static_cast<int64_t>(abs_u64);
+ }
+ }
+
if (sizeof(long) == 8) {
- fits_in_long = BN_cmp(int64_min.get(), bn.get()) <= 0 &&
- BN_cmp(bn.get(), int64_max.get()) <= 0;
+ fits_in_long = fits_in_i64;
} else {
ASSERT_EQ(4u, sizeof(long));
fits_in_long = BN_cmp(int32_min.get(), bn.get()) <= 0 &&
BN_cmp(bn.get(), int32_max.get()) <= 0;
}
if (fits_in_long) {
- if (BN_is_negative(bn.get())) {
- l = static_cast<long>(0u - abs_u64);
- } else {
- l = static_cast<long>(abs_u64);
- }
+ l = static_cast<long>(i64);
bssl::UniquePtr<ASN1_INTEGER> by_long(ASN1_INTEGER_new());
ASSERT_TRUE(by_long);
ASSERT_TRUE(ASN1_INTEGER_set(by_long.get(), l));
@@ -396,6 +403,15 @@
EXPECT_FALSE(ASN1_INTEGER_get_uint64(&v, obj));
}
+ if (fits_in_i64) {
+ int64_t v;
+ ASSERT_TRUE(ASN1_INTEGER_get_int64(&v, obj));
+ EXPECT_EQ(v, i64);
+ } else {
+ int64_t v;
+ EXPECT_FALSE(ASN1_INTEGER_get_int64(&v, obj));
+ }
+
if (fits_in_long) {
EXPECT_EQ(l, ASN1_INTEGER_get(obj));
} else {
diff --git a/include/openssl/asn1.h b/include/openssl/asn1.h
index b7dfed2..8c43ee0 100644
--- a/include/openssl/asn1.h
+++ b/include/openssl/asn1.h
@@ -1090,6 +1090,11 @@
OPENSSL_EXPORT int ASN1_INTEGER_get_uint64(uint64_t *out,
const ASN1_INTEGER *a);
+// ASN1_INTEGER_get_int64 converts |a| to a |int64_t|. On success, it returns
+// one and sets |*out| to the result. If |a| did not fit or has the wrong type,
+// it returns zero.
+OPENSSL_EXPORT int ASN1_INTEGER_get_int64(int64_t *out, const ASN1_INTEGER *a);
+
// ASN1_INTEGER_get returns the value of |a| as a |long|, or -1 if |a| is out of
// range or the wrong type.
//
@@ -1154,6 +1159,12 @@
OPENSSL_EXPORT int ASN1_ENUMERATED_get_uint64(uint64_t *out,
const ASN1_ENUMERATED *a);
+// ASN1_ENUMERATED_get_int64 converts |a| to a |int64_t|. On success, it
+// returns one and sets |*out| to the result. If |a| did not fit or has the
+// wrong type, it returns zero.
+OPENSSL_EXPORT int ASN1_ENUMERATED_get_int64(int64_t *out,
+ const ASN1_ENUMERATED *a);
+
// ASN1_ENUMERATED_get returns the value of |a| as a |long|, or -1 if |a| is out
// of range or the wrong type.
//