Hold certificates in an SSL_SESSION as CRYPTO_BUFFERSs as well.

This change adds a STACK_OF(CRYPTO_BUFFER) to an SSL_SESSION which
contains the raw form of the received certificates. The X509-based
members still exist, but their |enc| buffer will alias the
CRYPTO_BUFFERs.

(This is a second attempt at
https://boringssl-review.googlesource.com/#/c/12163/.)

BUG=chromium:671420

Change-Id: I508a8a46cab89a5a3fcc0c1224185d63e3d59cb8
Reviewed-on: https://boringssl-review.googlesource.com/12705
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/tls13_both.c b/ssl/tls13_both.c
index 939e530..a47dd26 100644
--- a/ssl/tls13_both.c
+++ b/ssl/tls13_both.c
@@ -177,8 +177,8 @@
       ssl->server && ssl->retain_only_sha256_of_client_certs;
   int ret = 0;
 
-  STACK_OF(X509) *chain = sk_X509_new_null();
-  if (chain == NULL) {
+  STACK_OF(CRYPTO_BUFFER) *certs = sk_CRYPTO_BUFFER_new_null();
+  if (certs == NULL) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     goto err;
@@ -193,28 +193,25 @@
   while (CBS_len(&certificate_list) > 0) {
     CBS certificate, extensions;
     if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
-        !CBS_get_u16_length_prefixed(&certificate_list, &extensions)) {
+        !CBS_get_u16_length_prefixed(&certificate_list, &extensions) ||
+        CBS_len(&certificate) == 0) {
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
       OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
       goto err;
     }
 
     /* Retain the hash of the leaf certificate if requested. */
-    if (sk_X509_num(chain) == 0 && retain_sha256) {
+    if (sk_CRYPTO_BUFFER_num(certs) == 0 && retain_sha256) {
       SHA256(CBS_data(&certificate), CBS_len(&certificate),
              ssl->s3->new_session->peer_sha256);
     }
 
-    X509 *x = ssl_parse_x509(&certificate);
-    if (x == NULL || CBS_len(&certificate) != 0) {
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-      X509_free(x);
-      goto err;
-    }
-    if (!sk_X509_push(chain, x)) {
+    CRYPTO_BUFFER *buf = CRYPTO_BUFFER_new_from_CBS(&certificate, NULL);
+    if (buf == NULL ||
+        !sk_CRYPTO_BUFFER_push(certs, buf)) {
+      CRYPTO_BUFFER_free(buf);
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-      X509_free(x);
       goto err;
     }
 
@@ -253,7 +250,7 @@
         goto err;
       }
 
-      if (sk_X509_num(chain) == 1 &&
+      if (sk_CRYPTO_BUFFER_num(certs) == 1 &&
           !CBS_stow(&ocsp_response, &ssl->s3->new_session->ocsp_response,
                     &ssl->s3->new_session->ocsp_response_length)) {
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
@@ -274,7 +271,7 @@
         goto err;
       }
 
-      if (sk_X509_num(chain) == 1 &&
+      if (sk_CRYPTO_BUFFER_num(certs) == 1 &&
           !CBS_stow(&sct,
                     &ssl->s3->new_session->tlsext_signed_cert_timestamp_list,
                     &ssl->s3->new_session
@@ -291,7 +288,17 @@
     goto err;
   }
 
-  if (sk_X509_num(chain) == 0) {
+  sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, CRYPTO_BUFFER_free);
+  ssl->s3->new_session->certs = certs;
+  certs = NULL;
+
+  if (!ssl_session_x509_cache_objects(ssl->s3->new_session)) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+    goto err;
+  }
+
+  if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0) {
     if (!allow_anonymous) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_CERTIFICATE_REQUIRED);
@@ -310,25 +317,14 @@
   ssl->s3->new_session->peer_sha256_valid = retain_sha256;
 
   if (!ssl_verify_cert_chain(ssl, &ssl->s3->new_session->verify_result,
-                             chain)) {
+                             ssl->s3->new_session->x509_chain)) {
     goto err;
   }
 
-  X509_free(ssl->s3->new_session->x509_peer);
-  X509 *leaf = sk_X509_value(chain, 0);
-  X509_up_ref(leaf);
-  ssl->s3->new_session->x509_peer = leaf;
-
-  sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free);
-  ssl->s3->new_session->x509_chain = chain;
-  chain = NULL;
-  sk_X509_pop_free(ssl->s3->new_session->x509_chain_without_leaf, X509_free);
-  ssl->s3->new_session->x509_chain_without_leaf = NULL;
-
   ret = 1;
 
 err:
-  sk_X509_pop_free(chain, X509_free);
+  sk_CRYPTO_BUFFER_pop_free(certs, CRYPTO_BUFFER_free);
   return ret;
 }