Expose ssl_session_serialize to libssl.

This function can serialise a session to a |CBB|.

Change-Id: Icdb7aef900f03f947c3fa4625dd218401eb8eafc
Reviewed-on: https://boringssl-review.googlesource.com/25385
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/internal.h b/ssl/internal.h
index 441f62f..04d534a 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -2704,6 +2704,11 @@
                                          const SSL_X509_METHOD *x509_method,
                                          CRYPTO_BUFFER_POOL *pool);
 
+// ssl_session_serialize writes |in| to |cbb| as if it were serialising a
+// session for Session-ID resumption. It returns one on success and zero on
+// error.
+int ssl_session_serialize(const SSL_SESSION *in, CBB *cbb);
+
 // ssl_session_is_context_valid returns one if |session|'s session ID context
 // matches the one set on |ssl| and zero otherwise.
 int ssl_session_is_context_valid(const SSL *ssl, const SSL_SESSION *session);
diff --git a/ssl/ssl_asn1.cc b/ssl/ssl_asn1.cc
index 67fd101..078ad1f 100644
--- a/ssl/ssl_asn1.cc
+++ b/ssl/ssl_asn1.cc
@@ -197,16 +197,14 @@
 static const unsigned kEarlyALPNTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 26;
 
-static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
-                                     size_t *out_len, int for_ticket) {
+static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, CBB *cbb,
+                                     int for_ticket) {
   if (in == NULL || in->cipher == NULL) {
     return 0;
   }
 
-  ScopedCBB cbb;
   CBB session, child, child2;
-  if (!CBB_init(cbb.get(), 0) ||
-      !CBB_add_asn1(cbb.get(), &session, CBS_ASN1_SEQUENCE) ||
+  if (!CBB_add_asn1(cbb, &session, CBS_ASN1_SEQUENCE) ||
       !CBB_add_asn1_uint64(&session, kVersion) ||
       !CBB_add_asn1_uint64(&session, in->ssl_version) ||
       !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
@@ -397,11 +395,7 @@
     }
   }
 
-  if (!CBB_finish(cbb.get(), out_data, out_len)) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-    return 0;
-  }
-  return 1;
+  return CBB_flush(cbb);
 }
 
 // SSL_SESSION_parse_string gets an optional ASN.1 OCTET STRING
@@ -762,6 +756,10 @@
   return ret;
 }
 
+int ssl_session_serialize(const SSL_SESSION *in, CBB *cbb) {
+  return SSL_SESSION_to_bytes_full(in, cbb, 0);
+}
+
 }  // namespace bssl
 
 using namespace bssl;
@@ -784,12 +782,26 @@
     return 1;
   }
 
-  return SSL_SESSION_to_bytes_full(in, out_data, out_len, 0);
+  ScopedCBB cbb;
+  if (!CBB_init(cbb.get(), 256) ||
+      !SSL_SESSION_to_bytes_full(in, cbb.get(), 0) ||
+      !CBB_finish(cbb.get(), out_data, out_len)) {
+    return 0;
+  }
+
+  return 1;
 }
 
 int SSL_SESSION_to_bytes_for_ticket(const SSL_SESSION *in, uint8_t **out_data,
                                     size_t *out_len) {
-  return SSL_SESSION_to_bytes_full(in, out_data, out_len, 1);
+  ScopedCBB cbb;
+  if (!CBB_init(cbb.get(), 256) ||
+      !SSL_SESSION_to_bytes_full(in, cbb.get(), 1) ||
+      !CBB_finish(cbb.get(), out_data, out_len)) {
+    return 0;
+  }
+
+  return 1;
 }
 
 int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp) {