From c18353d214c04da5349e97283d6d70b8176a96f8 Mon Sep 17 00:00:00 2001 From: Kaustubha Govind Date: Thu, 21 Feb 2019 12:40:06 -0500 Subject: [PATCH] Add uint64_t support in CBS and CBB. We need these APIs to parse some Certificate Transparency structures. Bug: chromium:634570 Change-Id: I4eb46058985a7369dc119ba6a1214913b237da39 Reviewed-on: https://boringssl-review.googlesource.com/c/34944 Reviewed-by: David Benjamin Reviewed-by: Adam Langley Commit-Queue: David Benjamin Commit-Queue: Adam Langley --- crypto/bytestring/bytestring_test.cc | 17 ++++++++---- crypto/bytestring/cbb.c | 9 ++++++- crypto/bytestring/cbs.c | 39 ++++++++++++++++++++-------- include/openssl/bytestring.h | 8 ++++++ 4 files changed, 56 insertions(+), 17 deletions(-) diff --git a/crypto/bytestring/bytestring_test.cc b/crypto/bytestring/bytestring_test.cc index e99744d5..1f787996 100644 --- a/crypto/bytestring/bytestring_test.cc +++ b/crypto/bytestring/bytestring_test.cc @@ -42,10 +42,12 @@ TEST(CBSTest, Skip) { } TEST(CBSTest, GetUint) { - static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; uint8_t u8; uint16_t u16; uint32_t u32; + uint64_t u64; CBS data; CBS_init(&data, kData, sizeof(kData)); @@ -57,10 +59,12 @@ TEST(CBSTest, GetUint) { EXPECT_EQ(0x40506u, u32); ASSERT_TRUE(CBS_get_u32(&data, &u32)); EXPECT_EQ(0x708090au, u32); + ASSERT_TRUE(CBS_get_u64(&data, &u64)); + EXPECT_EQ(0xb0c0d0e0f101112u, u64); ASSERT_TRUE(CBS_get_last_u8(&data, &u8)); - EXPECT_EQ(0xcu, u8); + EXPECT_EQ(0x14u, u8); ASSERT_TRUE(CBS_get_last_u8(&data, &u8)); - EXPECT_EQ(0xbu, u8); + EXPECT_EQ(0x13u, u8); EXPECT_FALSE(CBS_get_u8(&data, &u8)); EXPECT_FALSE(CBS_get_last_u8(&data, &u8)); } @@ -310,7 +314,9 @@ TEST(CBBTest, InitUninitialized) { } TEST(CBBTest, Basic) { - static const uint8_t kExpected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc}; + static const uint8_t kExpected[] = {1, 2, 3, 4, 5, 6, 7, + 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, + 0xf, 0x10, 0x11, 0x12, 0x13, 0x14}; uint8_t *buf; size_t buf_len; @@ -323,7 +329,8 @@ TEST(CBBTest, Basic) { ASSERT_TRUE(CBB_add_u16(cbb.get(), 0x203)); ASSERT_TRUE(CBB_add_u24(cbb.get(), 0x40506)); ASSERT_TRUE(CBB_add_u32(cbb.get(), 0x708090a)); - ASSERT_TRUE(CBB_add_bytes(cbb.get(), (const uint8_t *)"\x0b\x0c", 2)); + ASSERT_TRUE(CBB_add_u64(cbb.get(), 0xb0c0d0e0f101112)); + ASSERT_TRUE(CBB_add_bytes(cbb.get(), (const uint8_t *)"\x13\x14", 2)); ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len)); bssl::UniquePtr scoper(buf); diff --git a/crypto/bytestring/cbb.c b/crypto/bytestring/cbb.c index 38e9a83a..7998a48e 100644 --- a/crypto/bytestring/cbb.c +++ b/crypto/bytestring/cbb.c @@ -144,7 +144,7 @@ static int cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out, return 1; } -static int cbb_buffer_add_u(struct cbb_buffer_st *base, uint32_t v, +static int cbb_buffer_add_u(struct cbb_buffer_st *base, uint64_t v, size_t len_len) { if (len_len == 0) { return 1; @@ -459,6 +459,13 @@ int CBB_add_u32(CBB *cbb, uint32_t value) { return cbb_buffer_add_u(cbb->base, value, 4); } +int CBB_add_u64(CBB *cbb, uint64_t value) { + if (!CBB_flush(cbb)) { + return 0; + } + return cbb_buffer_add_u(cbb->base, value, 8); +} + void CBB_discard_child(CBB *cbb) { if (cbb->child == NULL) { return; diff --git a/crypto/bytestring/cbs.c b/crypto/bytestring/cbs.c index 372652c4..f8a8353e 100644 --- a/crypto/bytestring/cbs.c +++ b/crypto/bytestring/cbs.c @@ -88,8 +88,8 @@ int CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len) { return CRYPTO_memcmp(cbs->data, data, len) == 0; } -static int cbs_get_u(CBS *cbs, uint32_t *out, size_t len) { - uint32_t result = 0; +static int cbs_get_u(CBS *cbs, uint64_t *out, size_t len) { + uint64_t result = 0; const uint8_t *data; if (!cbs_get(cbs, &data, len)) { @@ -113,7 +113,7 @@ int CBS_get_u8(CBS *cbs, uint8_t *out) { } int CBS_get_u16(CBS *cbs, uint16_t *out) { - uint32_t v; + uint64_t v; if (!cbs_get_u(cbs, &v, 2)) { return 0; } @@ -122,11 +122,25 @@ int CBS_get_u16(CBS *cbs, uint16_t *out) { } int CBS_get_u24(CBS *cbs, uint32_t *out) { - return cbs_get_u(cbs, out, 3); + uint64_t v; + if (!cbs_get_u(cbs, &v, 3)) { + return 0; + } + *out = v; + return 1; } int CBS_get_u32(CBS *cbs, uint32_t *out) { - return cbs_get_u(cbs, out, 4); + uint64_t v; + if (!cbs_get_u(cbs, &v, 4)) { + return 0; + } + *out = v; + return 1; +} + +int CBS_get_u64(CBS *cbs, uint64_t *out) { + return cbs_get_u(cbs, out, 8); } int CBS_get_last_u8(CBS *cbs, uint8_t *out) { @@ -157,10 +171,13 @@ int CBS_copy_bytes(CBS *cbs, uint8_t *out, size_t len) { } static int cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len) { - uint32_t len; + uint64_t len; if (!cbs_get_u(cbs, &len, len_len)) { return 0; } + // If |len_len| <= 3 then we know that |len| will fit into a |size_t|, even on + // 32-bit systems. + assert(len_len <= 3); return CBS_get_bytes(cbs, out, len); } @@ -274,7 +291,7 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, // encode the number of subsequent octets used to encode the length (ITU-T // X.690 clause 8.1.3.5.b). const size_t num_bytes = length_byte & 0x7f; - uint32_t len32; + uint64_t len64; if (ber_ok && (tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) { // indefinite length @@ -290,20 +307,20 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, if (num_bytes == 0 || num_bytes > 4) { return 0; } - if (!cbs_get_u(&header, &len32, num_bytes)) { + if (!cbs_get_u(&header, &len64, num_bytes)) { return 0; } // ITU-T X.690 section 10.1 (DER length forms) requires encoding the length // with the minimum number of octets. - if (len32 < 128) { + if (len64 < 128) { // Length should have used short-form encoding. return 0; } - if ((len32 >> ((num_bytes-1)*8)) == 0) { + if ((len64 >> ((num_bytes-1)*8)) == 0) { // Length should have been at least one byte shorter. return 0; } - len = len32; + len = len64; if (len + header_len + num_bytes < len) { // Overflow. return 0; diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h index 701466ea..75b84341 100644 --- a/include/openssl/bytestring.h +++ b/include/openssl/bytestring.h @@ -110,6 +110,10 @@ OPENSSL_EXPORT int CBS_get_u24(CBS *cbs, uint32_t *out); // and advances |cbs|. It returns one on success and zero on error. OPENSSL_EXPORT int CBS_get_u32(CBS *cbs, uint32_t *out); +// CBS_get_u64 sets |*out| to the next, big-endian uint64_t value from |cbs| +// and advances |cbs|. It returns one on success and zero on error. +OPENSSL_EXPORT int CBS_get_u64(CBS *cbs, uint64_t *out); + // CBS_get_last_u8 sets |*out| to the last uint8_t from |cbs| and shortens // |cbs|. It returns one on success and zero on error. OPENSSL_EXPORT int CBS_get_last_u8(CBS *cbs, uint8_t *out); @@ -459,6 +463,10 @@ OPENSSL_EXPORT int CBB_add_u24(CBB *cbb, uint32_t value); // returns one on success and zero otherwise. OPENSSL_EXPORT int CBB_add_u32(CBB *cbb, uint32_t value); +// CBB_add_u64 appends a 64-bit, big-endian number from |value| to |cbb|. It +// returns one on success and zero otherwise. +OPENSSL_EXPORT int CBB_add_u64(CBB *cbb, uint64_t value); + // CBB_discard_child discards the current unflushed child of |cbb|. Neither the // child's contents nor the length prefix will be included in the output. OPENSSL_EXPORT void CBB_discard_child(CBB *cbb);