Skip to content

Commit

Permalink
Add CBS APIs for fetching an implicitly tagged int64/uint64 fields.
Browse files Browse the repository at this point in the history
Change-Id: Iafff08857bf2af8038e2c8bf4e6a57c38cf0b7ec
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/75887
Commit-Queue: David Benjamin <[email protected]>
Reviewed-by: David Benjamin <[email protected]>
Reviewed-by: Bob Beck <[email protected]>
  • Loading branch information
Quanzu authored and Boringssl LUCI CQ committed Feb 5, 2025
1 parent 8ec37a1 commit 0cb7370
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 2 deletions.
98 changes: 98 additions & 0 deletions crypto/bytestring/bytestring_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,24 @@ static const ASN1InvalidUint64Test kASN1InvalidUint64Tests[] = {
{"\x02\x02\x00\x01", 4, false},
};

struct ASN1Uint64WithTagTest {
CBS_ASN1_TAG tag;
uint64_t value;
const char *encoding;
size_t encoding_len;
};

static const ASN1Uint64WithTagTest kASN1Uint64WithTagTests[]{
{CBS_ASN1_CONTEXT_SPECIFIC, 0, "\x80\x01\x00", 3},
{CBS_ASN1_CONTEXT_SPECIFIC | 1, 1, "\x81\x01\x01", 3},
{CBS_ASN1_INTEGER, 127, "\x02\x01\x7f", 3},
{CBS_ASN1_CONTEXT_SPECIFIC, 128, "\x80\x02\x00\x80", 4},
{CBS_ASN1_CONTEXT_SPECIFIC, UINT64_C(0x0102030405060708),
"\x80\x08\x01\x02\x03\x04\x05\x06\x07\x08", 10},
{CBS_ASN1_CONTEXT_SPECIFIC, (0xffffffffffffffff),
"\x80\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff", 11},
};

TEST(CBSTest, ASN1Uint64) {
for (const ASN1Uint64Test &test : kASN1Uint64Tests) {
SCOPED_TRACE(Bytes(test.encoding, test.encoding_len));
Expand Down Expand Up @@ -961,6 +979,37 @@ TEST(CBSTest, ASN1Uint64) {
EXPECT_EQ(test.overflow, !!CBS_is_unsigned_asn1_integer(&child));
}
}

for (const ASN1Uint64WithTagTest &test : kASN1Uint64WithTagTests) {
SCOPED_TRACE(Bytes(test.encoding, test.encoding_len));
SCOPED_TRACE(test.value);
CBS cbs;
uint64_t value;
uint8_t *out;
size_t len;

CBS_init(&cbs, (const uint8_t *)test.encoding, test.encoding_len);
ASSERT_TRUE(CBS_get_asn1_uint64_with_tag(&cbs, &value, test.tag));
EXPECT_EQ(0u, CBS_len(&cbs));
EXPECT_EQ(test.value, value);

CBS child;
int is_negative;
CBS_init(&cbs, (const uint8_t *)test.encoding, test.encoding_len);
ASSERT_TRUE(CBS_get_asn1(&cbs, &child, test.tag));
EXPECT_TRUE(CBS_is_valid_asn1_integer(&child, &is_negative));
EXPECT_EQ(0, is_negative);
EXPECT_TRUE(CBS_is_unsigned_asn1_integer(&child));

{
bssl::ScopedCBB cbb;
ASSERT_TRUE(CBB_init(cbb.get(), 0));
ASSERT_TRUE(CBB_add_asn1_uint64_with_tag(cbb.get(), test.value, test.tag));
ASSERT_TRUE(CBB_finish(cbb.get(), &out, &len));
bssl::UniquePtr<uint8_t> scoper(out);
EXPECT_EQ(Bytes(test.encoding, test.encoding_len), Bytes(out, len));
}
}
}

struct ASN1Int64Test {
Expand Down Expand Up @@ -1007,6 +1056,24 @@ static const ASN1InvalidInt64Test kASN1InvalidInt64Tests[] = {
{"\x02\x02\xff\xff", 4, false},
};

struct ASN1Int64WithTagTest {
CBS_ASN1_TAG tag;
int64_t value;
const char *encoding;
size_t encoding_len;
};

static const ASN1Int64WithTagTest kASN1Int64WithTagTests[] = {
{CBS_ASN1_CONTEXT_SPECIFIC, 0, "\x80\x01\x00", 3},
{CBS_ASN1_CONTEXT_SPECIFIC | 1, 1, "\x81\x01\x01", 3},
{CBS_ASN1_INTEGER, 1, "\x02\x01\x01", 3},
{CBS_ASN1_CONTEXT_SPECIFIC, INT64_MIN,
"\x80\x08\x80\x00\x00\x00\x00\x00\x00\x00", 10},
{CBS_ASN1_CONTEXT_SPECIFIC, INT64_MAX,
"\x80\x08\x7f\xff\xff\xff\xff\xff\xff\xff", 10},
};


TEST(CBSTest, ASN1Int64) {
for (const ASN1Int64Test &test : kASN1Int64Tests) {
SCOPED_TRACE(Bytes(test.encoding, test.encoding_len));
Expand Down Expand Up @@ -1067,6 +1134,37 @@ TEST(CBSTest, ASN1Int64) {
EXPECT_EQ(test.overflow, !!CBS_is_valid_asn1_integer(&child, NULL));
}
}

for (const ASN1Int64WithTagTest &test : kASN1Int64WithTagTests) {
SCOPED_TRACE(Bytes(test.encoding, test.encoding_len));
SCOPED_TRACE(test.value);
CBS cbs;
int64_t value;
uint8_t *out;
size_t len;

CBS_init(&cbs, (const uint8_t *)test.encoding, test.encoding_len);
ASSERT_TRUE(CBS_get_asn1_int64_with_tag(&cbs, &value, test.tag));
EXPECT_EQ(0u, CBS_len(&cbs));
EXPECT_EQ(test.value, value);

CBS child;
int is_negative;
CBS_init(&cbs, (const uint8_t *)test.encoding, test.encoding_len);
ASSERT_TRUE(CBS_get_asn1(&cbs, &child, test.tag));
EXPECT_TRUE(CBS_is_valid_asn1_integer(&child, &is_negative));
EXPECT_EQ(test.value < 0, !!is_negative);
EXPECT_EQ(test.value >= 0, !!CBS_is_unsigned_asn1_integer(&child));

{
bssl::ScopedCBB cbb;
ASSERT_TRUE(CBB_init(cbb.get(), 0));
ASSERT_TRUE(CBB_add_asn1_int64_with_tag(cbb.get(), test.value, test.tag));
ASSERT_TRUE(CBB_finish(cbb.get(), &out, &len));
bssl::UniquePtr<uint8_t> scoper(out);
EXPECT_EQ(Bytes(test.encoding, test.encoding_len), Bytes(out, len));
}
}
}

TEST(CBBTest, Zero) {
Expand Down
12 changes: 10 additions & 2 deletions crypto/bytestring/cbs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -472,8 +472,12 @@ int CBS_peek_asn1_tag(const CBS *cbs, CBS_ASN1_TAG tag_value) {
}

int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
return CBS_get_asn1_uint64_with_tag(cbs, out, CBS_ASN1_INTEGER);
}

int CBS_get_asn1_uint64_with_tag(CBS *cbs, uint64_t *out, CBS_ASN1_TAG tag) {
CBS bytes;
if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER) ||
if (!CBS_get_asn1(cbs, &bytes, tag) ||
!CBS_is_unsigned_asn1_integer(&bytes)) {
return 0;
}
Expand All @@ -494,9 +498,13 @@ int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
}

int CBS_get_asn1_int64(CBS *cbs, int64_t *out) {
return CBS_get_asn1_int64_with_tag(cbs, out, CBS_ASN1_INTEGER);
}

int CBS_get_asn1_int64_with_tag(CBS *cbs, int64_t *out, CBS_ASN1_TAG tag) {
int is_negative;
CBS bytes;
if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER) ||
if (!CBS_get_asn1(cbs, &bytes, tag) ||
!CBS_is_valid_asn1_integer(&bytes, &is_negative)) {
return 0;
}
Expand Down
17 changes: 17 additions & 0 deletions include/openssl/bytestring.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,11 +292,28 @@ OPENSSL_EXPORT int CBS_get_any_ber_asn1_element(CBS *cbs, CBS *out,
// in 64 bits.
OPENSSL_EXPORT int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out);

// CBS_get_asn1_uint64_with_tag gets an ASN.1 INTEGER from |cbs| using
// |CBS_get_asn1| and sets |*out| to its value. |tag| is used to handle to
// handle implicitly tagged INTEGER fields. It returns one on success and zero
// on error, where error includes the integer being negative, or too large to
// represent in 64 bits.
OPENSSL_EXPORT int CBS_get_asn1_uint64_with_tag(CBS *cbs, uint64_t *out,
CBS_ASN1_TAG tag);


// CBS_get_asn1_int64 gets an ASN.1 INTEGER from |cbs| using |CBS_get_asn1|
// and sets |*out| to its value. It returns one on success and zero on error,
// where error includes the integer being too large to represent in 64 bits.
OPENSSL_EXPORT int CBS_get_asn1_int64(CBS *cbs, int64_t *out);

// CBS_get_asn1_int64_with_tag gets an ASN.1 INTEGER from |cbs| using
// |CBS_get_asn1| and sets |*out| to its value. |tag| is used to handle to
// handle implicitly tagged INTEGER fields. It returns one on success and zero
// on error, where error includes the integer being too large to represent in 64
// bits.
OPENSSL_EXPORT int CBS_get_asn1_int64_with_tag(CBS *cbs, int64_t *out,
CBS_ASN1_TAG tag);

// CBS_get_asn1_bool gets an ASN.1 BOOLEAN from |cbs| and sets |*out| to zero
// or one based on its value. It returns one on success or zero on error.
OPENSSL_EXPORT int CBS_get_asn1_bool(CBS *cbs, int *out);
Expand Down

0 comments on commit 0cb7370

Please sign in to comment.