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 <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
Commit-Queue: Adam Langley <agl@google.com>
diff --git a/crypto/bytestring/bytestring_test.cc b/crypto/bytestring/bytestring_test.cc
index e99744d..1f78799 100644
--- a/crypto/bytestring/bytestring_test.cc
+++ b/crypto/bytestring/bytestring_test.cc
@@ -42,10 +42,12 @@
 }
 
 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 @@
   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, 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 @@
   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<uint8_t> scoper(buf);
diff --git a/crypto/bytestring/cbb.c b/crypto/bytestring/cbb.c
index 38e9a83..7998a48 100644
--- a/crypto/bytestring/cbb.c
+++ b/crypto/bytestring/cbb.c
@@ -144,7 +144,7 @@
   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 @@
   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 372652c..f8a8353 100644
--- a/crypto/bytestring/cbs.c
+++ b/crypto/bytestring/cbs.c
@@ -88,8 +88,8 @@
   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_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_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 @@
 }
 
 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 @@
     // 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 @@
     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 701466e..75b8434 100644
--- a/include/openssl/bytestring.h
+++ b/include/openssl/bytestring.h
@@ -110,6 +110,10 @@
 // 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 @@
 // 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);