Add some more utility functions to bytestring.

Change-Id: I7932258890b0b2226ff6841af45926e1b11979ba
Reviewed-on: https://boringssl-review.googlesource.com/24844
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/bytestring/cbb.c b/crypto/bytestring/cbb.c
index eac6aa4..38e9a83 100644
--- a/crypto/bytestring/cbb.c
+++ b/crypto/bytestring/cbb.c
@@ -505,6 +505,28 @@
   return CBB_flush(cbb);
 }
 
+int CBB_add_asn1_octet_string(CBB *cbb, const uint8_t *data, size_t data_len) {
+  CBB child;
+  if (!CBB_add_asn1(cbb, &child, CBS_ASN1_OCTETSTRING) ||
+      !CBB_add_bytes(&child, data, data_len) ||
+      !CBB_flush(cbb)) {
+    return 0;
+  }
+
+  return 1;
+}
+
+int CBB_add_asn1_bool(CBB *cbb, int value) {
+  CBB child;
+  if (!CBB_add_asn1(cbb, &child, CBS_ASN1_BOOLEAN) ||
+      !CBB_add_u8(&child, value != 0 ? 0xff : 0) ||
+      !CBB_flush(cbb)) {
+    return 0;
+  }
+
+  return 1;
+}
+
 // parse_dotted_decimal parses one decimal component from |cbs|, where |cbs| is
 // an OID literal, e.g., "1.2.840.113554.4.1.72585". It consumes both the
 // component and the dot, so |cbs| may be passed into the function again for the
diff --git a/crypto/bytestring/cbs.c b/crypto/bytestring/cbs.c
index e456330..909512e 100644
--- a/crypto/bytestring/cbs.c
+++ b/crypto/bytestring/cbs.c
@@ -425,6 +425,22 @@
   return 1;
 }
 
+int CBS_get_asn1_bool(CBS *cbs, int *out) {
+  CBS bytes;
+  if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_BOOLEAN) ||
+      CBS_len(&bytes) != 1) {
+    return 0;
+  }
+
+  const uint8_t value = *CBS_data(&bytes);
+  if (value != 0 && value != 0xff) {
+    return 0;
+  }
+
+  *out = !!value;
+  return 1;
+}
+
 int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) {
   int present = 0;
 
diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h
index 2f25f14..39462a9 100644
--- a/include/openssl/bytestring.h
+++ b/include/openssl/bytestring.h
@@ -235,6 +235,10 @@
 // in 64 bits.
 OPENSSL_EXPORT int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out);
 
+// 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);
+
 // CBS_get_optional_asn1 gets an optional explicitly-tagged element from |cbs|
 // tagged with |tag| and sets |*out| to its contents. If present and if
 // |out_present| is not NULL, it sets |*out_present| to one, otherwise zero. It
@@ -450,6 +454,15 @@
 // error.
 OPENSSL_EXPORT int CBB_add_asn1_uint64(CBB *cbb, uint64_t value);
 
+// CBB_add_asn1_octet_string writes an ASN.1 OCTET STRING into |cbb| with the
+// given contents. It returns one on success and zero on error.
+OPENSSL_EXPORT int CBB_add_asn1_octet_string(CBB *cbb, const uint8_t *data,
+                                             size_t data_len);
+
+// CBB_add_asn1_bool writes an ASN.1 BOOLEAN into |cbb| which is true iff
+// |value| is non-zero.  It returns one on success and zero on error.
+OPENSSL_EXPORT int CBB_add_asn1_bool(CBB *cbb, int value);
+
 // CBB_add_asn1_oid_from_text decodes |len| bytes from |text| as an ASCII OID
 // representation, e.g. "1.2.840.113554.4.1.72585", and writes the DER-encoded
 // contents to |cbb|. It returns one on success and zero on malloc failure or if
diff --git a/ssl/ssl_asn1.cc b/ssl/ssl_asn1.cc
index eb7df5b..67fd101 100644
--- a/ssl/ssl_asn1.cc
+++ b/ssl/ssl_asn1.cc
@@ -211,12 +211,11 @@
       !CBB_add_asn1_uint64(&session, in->ssl_version) ||
       !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
       !CBB_add_u16(&child, (uint16_t)(in->cipher->id & 0xffff)) ||
-      !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
       // The session ID is irrelevant for a session ticket.
-      !CBB_add_bytes(&child, in->session_id,
-                     for_ticket ? 0 : in->session_id_length) ||
-      !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
-      !CBB_add_bytes(&child, in->master_key, in->master_key_length) ||
+      !CBB_add_asn1_octet_string(&session, in->session_id,
+                                 for_ticket ? 0 : in->session_id_length) ||
+      !CBB_add_asn1_octet_string(&session, in->master_key,
+                                 in->master_key_length) ||
       !CBB_add_asn1(&session, &child, kTimeTag) ||
       !CBB_add_asn1_uint64(&child, in->time) ||
       !CBB_add_asn1(&session, &child, kTimeoutTag) ||
@@ -240,8 +239,7 @@
   // Although it is OPTIONAL and usually empty, OpenSSL has
   // historically always encoded the sid_ctx.
   if (!CBB_add_asn1(&session, &child, kSessionIDContextTag) ||
-      !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
-      !CBB_add_bytes(&child2, in->sid_ctx, in->sid_ctx_length)) {
+      !CBB_add_asn1_octet_string(&child, in->sid_ctx, in->sid_ctx_length)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     return 0;
   }
@@ -256,9 +254,8 @@
 
   if (in->psk_identity) {
     if (!CBB_add_asn1(&session, &child, kPSKIdentityTag) ||
-        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
-        !CBB_add_bytes(&child2, (const uint8_t *)in->psk_identity,
-                       strlen(in->psk_identity))) {
+        !CBB_add_asn1_octet_string(&child, (const uint8_t *)in->psk_identity,
+                                   strlen(in->psk_identity))) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       return 0;
     }
@@ -274,8 +271,8 @@
 
   if (in->tlsext_tick && !for_ticket) {
     if (!CBB_add_asn1(&session, &child, kTicketTag) ||
-        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
-        !CBB_add_bytes(&child2, in->tlsext_tick, in->tlsext_ticklen)) {
+        !CBB_add_asn1_octet_string(&child, in->tlsext_tick,
+                                   in->tlsext_ticklen)) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       return 0;
     }
@@ -283,8 +280,8 @@
 
   if (in->peer_sha256_valid) {
     if (!CBB_add_asn1(&session, &child, kPeerSHA256Tag) ||
-        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
-        !CBB_add_bytes(&child2, in->peer_sha256, sizeof(in->peer_sha256))) {
+        !CBB_add_asn1_octet_string(&child, in->peer_sha256,
+                                   sizeof(in->peer_sha256))) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       return 0;
     }
@@ -292,9 +289,8 @@
 
   if (in->original_handshake_hash_len > 0) {
     if (!CBB_add_asn1(&session, &child, kOriginalHandshakeHashTag) ||
-        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
-        !CBB_add_bytes(&child2, in->original_handshake_hash,
-                       in->original_handshake_hash_len)) {
+        !CBB_add_asn1_octet_string(&child, in->original_handshake_hash,
+                                   in->original_handshake_hash_len)) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       return 0;
     }
@@ -302,10 +298,9 @@
 
   if (in->signed_cert_timestamp_list != nullptr) {
     if (!CBB_add_asn1(&session, &child, kSignedCertTimestampListTag) ||
-        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
-        !CBB_add_bytes(&child2,
-                       CRYPTO_BUFFER_data(in->signed_cert_timestamp_list),
-                       CRYPTO_BUFFER_len(in->signed_cert_timestamp_list))) {
+        !CBB_add_asn1_octet_string(
+            &child, CRYPTO_BUFFER_data(in->signed_cert_timestamp_list),
+            CRYPTO_BUFFER_len(in->signed_cert_timestamp_list))) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       return 0;
     }
@@ -313,9 +308,9 @@
 
   if (in->ocsp_response != nullptr) {
     if (!CBB_add_asn1(&session, &child, kOCSPResponseTag) ||
-        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
-        !CBB_add_bytes(&child2, CRYPTO_BUFFER_data(in->ocsp_response),
-                       CRYPTO_BUFFER_len(in->ocsp_response))) {
+        !CBB_add_asn1_octet_string(&child,
+                                   CRYPTO_BUFFER_data(in->ocsp_response),
+                                   CRYPTO_BUFFER_len(in->ocsp_response))) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       return 0;
     }
@@ -323,8 +318,7 @@
 
   if (in->extended_master_secret) {
     if (!CBB_add_asn1(&session, &child, kExtendedMasterSecretTag) ||
-        !CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
-        !CBB_add_u8(&child2, 0xff)) {
+        !CBB_add_asn1_bool(&child, true)) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       return 0;
     }
@@ -367,8 +361,7 @@
 
   if (!in->is_server) {
     if (!CBB_add_asn1(&session, &child, kIsServerTag) ||
-        !CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
-        !CBB_add_u8(&child2, 0x00)) {
+        !CBB_add_asn1_bool(&child, false)) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       return 0;
     }
@@ -397,9 +390,8 @@
 
   if (in->early_alpn) {
     if (!CBB_add_asn1(&session, &child, kEarlyALPNTag) ||
-        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
-        !CBB_add_bytes(&child2, (const uint8_t *)in->early_alpn,
-                       in->early_alpn_len)) {
+        !CBB_add_asn1_octet_string(&child, (const uint8_t *)in->early_alpn,
+                                   in->early_alpn_len)) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       return 0;
     }