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>
chromium-5359
David Benjamin 2 years ago committed by Boringssl LUCI CQ
parent e8e6cacca4
commit ea2ad5a876
  1. 43
      crypto/asn1/a_int.c
  2. 34
      crypto/asn1/asn1_test.cc
  3. 11
      include/openssl/asn1.h

@ -333,16 +333,11 @@ int ASN1_ENUMERATED_get_uint64(uint64_t *out, const ASN1_ENUMERATED *a) {
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 @@ static long asn1_string_get_long(const ASN1_STRING *a, int type) {
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;
}
int ASN1_INTEGER_get_int64(int64_t *out, const ASN1_INTEGER *a) {
return asn1_string_get_int64(out, a, V_ASN1_INTEGER);
}
if (fits_in_i64 && LONG_MIN <= i64 && i64 <= LONG_MAX) {
return (long)i64;
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) {

@ -328,9 +328,10 @@ TEST(ASN1Test, Integer) {
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 @@ TEST(ASN1Test, Integer) {
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 @@ TEST(ASN1Test, Integer) {
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 {

@ -1090,6 +1090,11 @@ OPENSSL_EXPORT int ASN1_INTEGER_set(ASN1_INTEGER *a, long v);
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_set(ASN1_ENUMERATED *a, long v);
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.
//

Loading…
Cancel
Save