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. //