Add CBB_reserve and CBB_did_write.

These will be needed when we start writing variable-length things to a
CBB.

Change-Id: Ie7b9b140f5f875b43adedc8203ce9d3f4068dfea
Reviewed-on: https://boringssl-review.googlesource.com/6764
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/bytestring/bytestring_test.cc b/crypto/bytestring/bytestring_test.cc
index 8a17812..188c63d 100644
--- a/crypto/bytestring/bytestring_test.cc
+++ b/crypto/bytestring/bytestring_test.cc
@@ -703,12 +703,32 @@
   return true;
 }
 
-static int TestZero() {
+static bool TestZero() {
   CBB cbb;
   CBB_zero(&cbb);
   // Calling |CBB_cleanup| on a zero-state |CBB| must not crash.
   CBB_cleanup(&cbb);
-  return 1;
+  return true;
+}
+
+static bool TestCBBReserve() {
+  uint8_t buf[10];
+  uint8_t *ptr;
+  size_t len;
+  ScopedCBB cbb;
+  if (!CBB_init_fixed(cbb.get(), buf, sizeof(buf)) ||
+      // Too large.
+      CBB_reserve(cbb.get(), &ptr, 11) ||
+      // Successfully reserve the entire space.
+      !CBB_reserve(cbb.get(), &ptr, 10) ||
+      ptr != buf ||
+      // Advancing under the maximum bytes is legal.
+      !CBB_did_write(cbb.get(), 5) ||
+      !CBB_finish(cbb.get(), NULL, &len) ||
+      len != 5) {
+    return false;
+  }
+  return true;
 }
 
 int main(void) {
@@ -729,7 +749,8 @@
       !TestBerConvert() ||
       !TestASN1Uint64() ||
       !TestGetOptionalASN1Bool() ||
-      !TestZero()) {
+      !TestZero() ||
+      !TestCBBReserve()) {
     return 1;
   }
 
diff --git a/crypto/bytestring/cbb.c b/crypto/bytestring/cbb.c
index a1bc012..a9e9b3c 100644
--- a/crypto/bytestring/cbb.c
+++ b/crypto/bytestring/cbb.c
@@ -84,8 +84,8 @@
   cbb->base = NULL;
 }
 
-static int cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out,
-                          size_t len) {
+static int cbb_buffer_reserve(struct cbb_buffer_st *base, uint8_t **out,
+                              size_t len) {
   size_t newlen;
 
   if (base == NULL) {
@@ -121,7 +121,17 @@
   if (out) {
     *out = base->buf + base->len;
   }
-  base->len = newlen;
+
+  return 1;
+}
+
+static int cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out,
+                          size_t len) {
+  if (!cbb_buffer_reserve(base, out, len)) {
+    return 0;
+  }
+  /* This will not overflow or |cbb_buffer_reserve| would have failed. */
+  base->len += len;
   return 1;
 }
 
@@ -339,6 +349,25 @@
   return 1;
 }
 
+int CBB_reserve(CBB *cbb, uint8_t **out_data, size_t len) {
+  if (!CBB_flush(cbb) ||
+      !cbb_buffer_reserve(cbb->base, out_data, len)) {
+    return 0;
+  }
+  return 1;
+}
+
+int CBB_did_write(CBB *cbb, size_t len) {
+  size_t newlen = cbb->base->len + len;
+  if (cbb->child != NULL ||
+      newlen < cbb->base->len ||
+      newlen > cbb->base->cap) {
+    return 0;
+  }
+  cbb->base->len = newlen;
+  return 1;
+}
+
 int CBB_add_u8(CBB *cbb, uint8_t value) {
   if (!CBB_flush(cbb)) {
     return 0;
diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h
index 9e12d49..fe26111 100644
--- a/include/openssl/bytestring.h
+++ b/include/openssl/bytestring.h
@@ -331,6 +331,17 @@
  * otherwise. */
 OPENSSL_EXPORT int CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len);
 
+/* CBB_reserve ensures |cbb| has room for |len| additional bytes and sets
+ * |*out_data| to point to the beginning of that space. It returns one on
+ * success and zero otherwise. The caller may write up to |len| bytes to
+ * |*out_data| and call |CBB_did_write| to complete the write. |*out_data| is
+ * valid until the next operation on |cbb| or an ancestor |CBB|. */
+OPENSSL_EXPORT int CBB_reserve(CBB *cbb, uint8_t **out_data, size_t len);
+
+/* CBB_did_write advances |cbb| by |len| bytes, assuming the space has been
+ * written to by the caller. It returns one on success and zero on error. */
+OPENSSL_EXPORT int CBB_did_write(CBB *cbb, size_t len);
+
 /* CBB_add_u8 appends an 8-bit number from |value| to |cbb|. It returns one on
  * success and zero otherwise. */
 OPENSSL_EXPORT int CBB_add_u8(CBB *cbb, uint8_t value);