Remove the last of SESS_CERT.

Move cert_chain to the SSL_SESSION. Now everything on an SSL_SESSION is
properly serialized. The cert_chain field is, unfortunately, messed up
since it means different things between client and server.

There exists code which calls SSL_get_peer_cert_chain as both client and
server and assumes the existing semantics for each. Since that function
doesn't return a newly-allocated STACK_OF(X509), normalizing between the
two formats is a nuisance (we'd either need to store both cert_chain and
cert_chain_full on the SSL_SESSION or create one of the two variants
on-demand and stash it into the SSL).

This CL does not resolve this and retains the client/server difference
in SSL_SESSION. The SSL_SESSION serialization is a little inefficient
(two copies of the leaf certificate) for a client, but clients don't
typically serialize sessions. Should we wish to resolve it in the
future, we can use a different tag number. Because this was historically
unserialized, existing code must already allow for cert_chain not being
preserved across i2d/d2i.

In keeping with the semantics of retain_only_sha256_of_client_certs,
cert_chain is not retained when that flag is set.

Change-Id: Ieb72fc62c3076dd59750219e550902f1ad039651
Reviewed-on: https://boringssl-review.googlesource.com/5759
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index ab1fd74..2fd7f12 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -114,9 +114,10 @@
  *     signedCertTimestampList [15] OCTET STRING OPTIONAL,
  *                                  -- contents of SCT extension
  *     ocspResponse            [16] OCTET STRING OPTIONAL,
- *                                   -- stapled OCSP response from the server
+ *                                  -- stapled OCSP response from the server
  *     extendedMasterSecret    [17] BOOLEAN OPTIONAL,
  *     keyExchangeInfo         [18] INTEGER OPTIONAL,
+ *     certChain               [19] SEQUENCE OF Certificate OPTIONAL,
  * }
  *
  * Note: historically this serialization has included other optional
@@ -157,6 +158,24 @@
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 17;
 static const int kKeyExchangeInfoTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 18;
+static const int kCertChainTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 19;
+
+static int add_X509(CBB *cbb, X509 *x509) {
+  int len = i2d_X509(x509, NULL);
+  if (len < 0) {
+    return 0;
+  }
+  uint8_t *buf;
+  if (!CBB_add_space(cbb, &buf, len)) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+    return 0;
+  }
+  if (buf != NULL && i2d_X509(x509, &buf) < 0) {
+    return 0;
+  }
+  return 1;
+}
 
 static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
                                      size_t *out_len, int for_ticket) {
@@ -202,17 +221,11 @@
   /* The peer certificate is only serialized if the SHA-256 isn't
    * serialized instead. */
   if (in->peer && !in->peer_sha256_valid) {
-    uint8_t *buf;
-    int len = i2d_X509(in->peer, NULL);
-    if (len < 0) {
-      goto err;
-    }
-    if (!CBB_add_asn1(&session, &child, kPeerTag) ||
-        !CBB_add_space(&child, &buf, len)) {
+    if (!CBB_add_asn1(&session, &child, kPeerTag)) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
     }
-    if (buf != NULL && i2d_X509(in->peer, &buf) < 0) {
+    if (!add_X509(&child, in->peer)) {
       goto err;
     }
   }
@@ -325,6 +338,21 @@
     goto err;
   }
 
+  /* The certificate chain is only serialized if the leaf's SHA-256 isn't
+   * serialized instead. */
+  if (in->cert_chain != NULL && !in->peer_sha256_valid) {
+    if (!CBB_add_asn1(&session, &child, kCertChainTag)) {
+      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+    size_t i;
+    for (i = 0; i < sk_X509_num(in->cert_chain); i++) {
+      if (!add_X509(&child, sk_X509_value(in->cert_chain, i))) {
+        goto err;
+      }
+    }
+  }
+
   if (!CBB_finish(&cbb, out_data, out_len)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     goto err;
@@ -598,8 +626,40 @@
   ret->extended_master_secret = !!extended_master_secret;
 
   if (!SSL_SESSION_parse_u32(&session, &ret->key_exchange_info,
-                             kKeyExchangeInfoTag, 0) ||
-      CBS_len(&session) != 0) {
+                             kKeyExchangeInfoTag, 0)) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+    goto err;
+  }
+
+  CBS cert_chain;
+  int has_cert_chain;
+  if (!CBS_get_optional_asn1(&session, &cert_chain, &has_cert_chain,
+                             kCertChainTag)) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+    goto err;
+  }
+  sk_X509_pop_free(ret->cert_chain, X509_free);
+  ret->cert_chain = NULL;
+  if (has_cert_chain) {
+    ret->cert_chain = sk_X509_new_null();
+    if (ret->cert_chain == NULL) {
+      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+    while (CBS_len(&cert_chain) > 0) {
+      X509 *x509 = parse_x509(&cert_chain);
+      if (x509 == NULL) {
+        goto err;
+      }
+      if (!sk_X509_push(ret->cert_chain, x509)) {
+        OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+        X509_free(x509);
+        goto err;
+      }
+    }
+  }
+
+  if (CBS_len(&session) != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     goto err;
   }