Revert "Add |SSL_CTX_set0_buffer_pool|." and "Hold certificates in an SSL_SESSION as CRYPTO_BUFFERSs as well."

This reverts commits 5a6e6169615f205cb788ec9e29aebdd148f586b0 and
e8509090cfa08213d1ab16b7a1201957d0c8f560. I'm going to unify how the
chains are kept in memory between client and server first otherwise the
mess just keeps growing.

Change-Id: I76df0d94c9053b2454821d22a3c97951b6419831
Reviewed-on: https://boringssl-review.googlesource.com/12701
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 85c1adc..15b1bb2 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -149,7 +149,6 @@
 #include <openssl/hmac.h>
 #include <openssl/lhash.h>
 #include <openssl/pem.h>
-#include <openssl/pool.h>
 #include <openssl/ssl3.h>
 #include <openssl/thread.h>
 #include <openssl/tls1.h>
@@ -730,16 +729,6 @@
  * modes enabled for |ssl|. */
 OPENSSL_EXPORT uint32_t SSL_get_mode(const SSL *ssl);
 
-/* SSL_CTX_set0_buffer_pool sets a |CRYPTO_BUFFER_POOL| that will be used to
- * store certificates. This can allow multiple connections to share
- * certificates and thus save memory.
- *
- * The SSL_CTX does not take ownership of |pool| and the caller must ensure
- * that |pool| outlives |ctx| and all objects linked to it, including |SSL|,
- * |X509| and |SSL_SESSION| objects. Basically, don't ever free |pool|. */
-OPENSSL_EXPORT void SSL_CTX_set0_buffer_pool(SSL_CTX *ctx,
-                                             CRYPTO_BUFFER_POOL *pool);
-
 
 /* Configuring certificates and private keys.
  *
@@ -3713,11 +3702,6 @@
   uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH];
 
   char *psk_identity;
-
-  /* certs contains the certificate chain from the peer, starting with the leaf
-   * certificate. */
-  STACK_OF(CRYPTO_BUFFER) *certs;
-
   /* x509_peer is the peer's certificate. */
   X509 *x509_peer;
 
@@ -3784,11 +3768,6 @@
 
   /* ticket_age_add_valid is non-zero if |ticket_age_add| is valid. */
   unsigned ticket_age_add_valid:1;
-
-  /* x509_chain_should_include_leaf is true if the |STACK_OF(X509)| certificate
-   * chain should include the leaf certificate. Due to history, this is false
-   * for server sessions and true for client sessions. */
-  unsigned x509_chain_should_include_leaf:1;
 };
 
 /* ssl_cipher_preference_list_st contains a list of SSL_CIPHERs with
@@ -4079,10 +4058,6 @@
    * TODO(agl): remove once node.js no longer references this. */
   STACK_OF(X509)* extra_certs;
   int freelist_max_len;
-
-  /* pool is used for all |CRYPTO_BUFFER|s in case we wish to share certificate
-   * memory. */
-  CRYPTO_BUFFER_POOL *pool;
 };
 
 typedef struct ssl_handshake_st SSL_HANDSHAKE;
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index 2603fb2..028b905 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -1041,15 +1041,14 @@
 
   CBS cbs;
   CBS_init(&cbs, ssl->init_msg, ssl->init_num);
-  STACK_OF(CRYPTO_BUFFER) *buffers = NULL;
-  STACK_OF(X509) *chain = NULL;
   uint8_t alert;
-  if (!ssl_parse_cert_chain(ssl, &buffers, &chain, &alert, NULL, &cbs)) {
+  STACK_OF(X509) *chain = ssl_parse_cert_chain(ssl, &alert, NULL, &cbs);
+  if (chain == NULL) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     goto err;
   }
 
-  if (sk_CRYPTO_BUFFER_num(buffers) == 0 || CBS_len(&cbs) != 0) {
+  if (sk_X509_num(chain) == 0 || CBS_len(&cbs) != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     goto err;
@@ -1063,11 +1062,8 @@
 
   /* NOTE: Unlike the server half, the client's copy of |x509_chain| includes
    * the leaf. */
-  sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, CRYPTO_BUFFER_free);
-  ssl->s3->new_session->certs = buffers;
   sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free);
   ssl->s3->new_session->x509_chain = chain;
-  ssl->s3->new_session->x509_chain_should_include_leaf = 1;
 
   X509_free(ssl->s3->new_session->x509_peer);
   X509_up_ref(leaf);
@@ -1076,7 +1072,6 @@
   return 1;
 
 err:
-  sk_CRYPTO_BUFFER_pop_free(buffers, CRYPTO_BUFFER_free);
   sk_X509_pop_free(chain, X509_free);
   return -1;
 }
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index 7ba9946..628f2c2 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -1466,14 +1466,13 @@
 
   CBS certificate_msg;
   CBS_init(&certificate_msg, ssl->init_msg, ssl->init_num);
-  STACK_OF(CRYPTO_BUFFER) *buffers = NULL;
-  STACK_OF(X509) *chain = NULL;
   uint8_t alert;
-  if (!ssl_parse_cert_chain(ssl, &buffers, &chain, &alert,
-                            ssl->retain_only_sha256_of_client_certs
-                                ? ssl->s3->new_session->peer_sha256
-                                : NULL,
-                            &certificate_msg)) {
+  STACK_OF(X509) *chain = ssl_parse_cert_chain(
+      ssl, &alert, ssl->retain_only_sha256_of_client_certs
+                       ? ssl->s3->new_session->peer_sha256
+                       : NULL,
+      &certificate_msg);
+  if (chain == NULL) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     goto err;
   }
@@ -1484,7 +1483,7 @@
     goto err;
   }
 
-  if (sk_CRYPTO_BUFFER_num(buffers) == 0) {
+  if (sk_X509_num(chain) == 0) {
     /* No client certificate so the handshake buffer may be discarded. */
     ssl3_free_handshake_buffer(ssl);
 
@@ -1525,13 +1524,10 @@
   ssl->s3->new_session->x509_chain = chain;
   /* Inconsistency alert: x509_chain does *not* include the peer's own
    * certificate, while we do include it in s3_clnt.c */
-  sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, CRYPTO_BUFFER_free);
-  ssl->s3->new_session->certs = buffers;
 
   return 1;
 
 err:
-  sk_CRYPTO_BUFFER_pop_free(buffers, CRYPTO_BUFFER_free);
   sk_X509_pop_free(chain, X509_free);
   return -1;
 }
diff --git a/ssl/internal.h b/ssl/internal.h
index 1802610..d6f19cd 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -744,30 +744,18 @@
  * configured and zero otherwise. */
 int ssl_has_certificate(const SSL *ssl);
 
-/* x509_chain_from_buffers parses a number of X.509 certificates from |buffers|
- * and sets |*out| to a corresponding stack of |X509*|. It returns one on
- * success or zero on error. */
-int x509_chain_from_buffers(STACK_OF(X509) **out,
-                            STACK_OF(CRYPTO_BUFFER) *buffers);
-
-/* ssl_session_set_x509_peer sets |sess->x509_peer| to the first element of
- * |sess->x509_chain| and copies |chain_should_include_leaf| to
- * |sess->x509_chain_should_include_leaf|. If |chain_should_include_leaf| is
- * true then |x509_peer| is a additional reference to the first element of the
- * chain. Otherwise the first element of the chain is removed and |x509_peer|
- * is the only reference to it. */
-void ssl_session_set_x509_peer(SSL_SESSION *sess,
-                               int chain_should_include_leaf);
+/* ssl_parse_x509 parses a X509 certificate from |cbs|. It returns NULL
+ * on error. */
+X509 *ssl_parse_x509(CBS *cbs);
 
 /* ssl_parse_cert_chain parses a certificate list from |cbs| in the format used
- * by a TLS Certificate message. On success, it returns newly-allocated
- * |CRYPTO_BUFFER| and |X509| lists, advances |cbs| and returns one. Otherwise,
- * it returns zero and sets |*out_alert| to an alert to send to the peer. If
- * the list is non-empty and |out_leaf_sha256| is non-NULL, it writes the
- * SHA-256 hash of the leaf to |out_leaf_sha256|. */
-int ssl_parse_cert_chain(SSL *ssl, STACK_OF(CRYPTO_BUFFER) **out_buffers,
-                         STACK_OF(X509) **out_x509s, uint8_t *out_alert,
-                         uint8_t *out_leaf_sha256, CBS *cbs);
+ * by a TLS Certificate message. On success, it returns a newly-allocated
+ * |X509| list and advances |cbs|. Otherwise, it returns NULL and sets
+ * |*out_alert| to an alert to send to the peer. If the list is non-empty and
+ * |out_leaf_sha256| is non-NULL, it writes the SHA-256 hash of the leaf to
+ * |out_leaf_sha256|. */
+STACK_OF(X509) *ssl_parse_cert_chain(SSL *ssl, uint8_t *out_alert,
+                                     uint8_t *out_leaf_sha256, CBS *cbs);
 
 /* ssl_add_cert_to_cbb adds |x509| to |cbb|. It returns one on success and zero
  * on error. */
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index a984e8e..aab6052 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -122,7 +122,6 @@
  *     keyExchangeInfo         [18] INTEGER OPTIONAL,
  *     certChain               [19] SEQUENCE OF Certificate OPTIONAL,
  *     ticketAgeAdd            [21] OCTET STRING OPTIONAL,
- *     x509ChainIncludeLeaf    [22] BOOLEAN OPTIONAL,
  * }
  *
  * Note: historically this serialization has included other optional
@@ -133,16 +132,7 @@
  *     compressionMethod       [11] OCTET STRING OPTIONAL,
  *     srpUsername             [12] OCTET STRING OPTIONAL,
  *     ticketFlags             [20] INTEGER OPTIONAL,
- *
- *
- * When serialising, the first element of |certChain| does not duplicate the
- * contents of |peer|, but that was not always true. When parsing, the returned
- * |x509_chain| sometimes needs to contain the leaf certificate at the
- * beginning (clients) and sometimes not (servers). The |x509ChainIncludeLeaf|
- * value specifies whether this duplication should be done for the in-memory
- * representation. If not given, the parsing code looks to see whether the
- * first cert in |certChain| matches the |peer| and assumes that it's parsing
- * old session data and thus that |x509ChainIncludeLeaf| should be true. */
+ */
 
 static const unsigned kVersion = 1;
 
@@ -180,8 +170,6 @@
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 19;
 static const int kTicketAgeAddTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 21;
-static const int kX509ChainIncludeLeafTag =
-    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 22;
 
 static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
                                      size_t *out_len, int for_ticket) {
@@ -230,14 +218,16 @@
     goto err;
   }
 
-  if (sk_CRYPTO_BUFFER_num(in->certs) > 0 && !in->peer_sha256_valid) {
-    const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(in->certs, 0);
-    if (!CBB_add_asn1(&session, &child, kPeerTag) ||
-        !CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer),
-                       CRYPTO_BUFFER_len(buffer))) {
+  /* The peer certificate is only serialized if the SHA-256 isn't
+   * serialized instead. */
+  if (in->x509_peer && !in->peer_sha256_valid) {
+    if (!CBB_add_asn1(&session, &child, kPeerTag)) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
     }
+    if (!ssl_add_cert_to_cbb(&child, in->x509_peer)) {
+      goto err;
+    }
   }
 
   /* Although it is OPTIONAL and usually empty, OpenSSL has
@@ -350,18 +340,13 @@
 
   /* The certificate chain is only serialized if the leaf's SHA-256 isn't
    * serialized instead. */
-  if (in->certs != NULL &&
-      !in->peer_sha256_valid &&
-      sk_CRYPTO_BUFFER_num(in->certs) > 1) {
+  if (in->x509_chain != NULL && !in->peer_sha256_valid) {
     if (!CBB_add_asn1(&session, &child, kCertChainTag)) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
     }
-    for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(in->certs); i++) {
-      const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(in->certs, i);
-      if (!CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer),
-                         CRYPTO_BUFFER_len(buffer))) {
-        OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+    for (size_t i = 0; i < sk_X509_num(in->x509_chain); i++) {
+      if (!ssl_add_cert_to_cbb(&child, sk_X509_value(in->x509_chain, i))) {
         goto err;
       }
     }
@@ -376,15 +361,6 @@
     }
   }
 
-  if (in->x509_chain_should_include_leaf) {
-    if (!CBB_add_asn1(&session, &child, kX509ChainIncludeLeafTag) ||
-        !CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
-        !CBB_add_u8(&child2, 0xff)) {
-      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-      goto err;
-    }
-  }
-
   if (!CBB_finish(&cbb, out_data, out_len)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     goto err;
@@ -596,12 +572,22 @@
 
   CBS peer;
   int has_peer;
-  if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag) ||
-      (has_peer && CBS_len(&peer) == 0)) {
+  if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     goto err;
   }
-  /* |peer| is processed with the certificate chain. */
+  X509_free(ret->x509_peer);
+  ret->x509_peer = NULL;
+  if (has_peer) {
+    ret->x509_peer = ssl_parse_x509(&peer);
+    if (ret->x509_peer == NULL) {
+      goto err;
+    }
+    if (CBS_len(&peer) != 0) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+      goto err;
+    }
+  }
 
   if (!SSL_SESSION_parse_bounded_octet_string(
           &session, ret->sid_ctx, &ret->sid_ctx_length, sizeof(ret->sid_ctx),
@@ -664,72 +650,28 @@
   }
 
   CBS cert_chain;
-  CBS_init(&cert_chain, NULL, 0);
   int has_cert_chain;
   if (!CBS_get_optional_asn1(&session, &cert_chain, &has_cert_chain,
-                             kCertChainTag) ||
-      (has_cert_chain && CBS_len(&cert_chain) == 0)) {
+                             kCertChainTag)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     goto err;
   }
-  sk_CRYPTO_BUFFER_pop_free(ret->certs, CRYPTO_BUFFER_free);
-  ret->certs = NULL;
-
-  int x509_chain_should_include_leaf_default = 0;
-
-  if (has_peer || has_cert_chain) {
-    ret->certs = sk_CRYPTO_BUFFER_new_null();
-    if (ret->certs == NULL) {
+  sk_X509_pop_free(ret->x509_chain, X509_free);
+  ret->x509_chain = NULL;
+  if (has_cert_chain) {
+    ret->x509_chain = sk_X509_new_null();
+    if (ret->x509_chain == NULL) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
     }
-
-    if (has_peer) {
-      /* TODO(agl): this should use the |SSL_CTX|'s pool. */
-      CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&peer, NULL);
-      if (buffer == NULL) {
-        OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-        goto err;
-      }
-
-      if (!sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
-        CRYPTO_BUFFER_free(buffer);
-        OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-        goto err;
-      }
-    }
-
-    size_t chain_i = 0;
     while (CBS_len(&cert_chain) > 0) {
-      chain_i++;
-
-      CBS cert;
-      if (!CBS_get_any_asn1_element(&cert_chain, &cert, NULL, NULL) ||
-          CBS_len(&cert) == 0) {
-        OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+      X509 *x509 = ssl_parse_x509(&cert_chain);
+      if (x509 == NULL) {
         goto err;
       }
-
-      if (has_peer && chain_i == 1) {
-        /* If a certificate was parsed from |peer| then it may, or may not, be
-         * duplicated as the first element of |cert_chain|. */
-        if (CBS_len(&peer) == CBS_len(&cert) &&
-            memcmp(CBS_data(&peer), CBS_data(&cert), CBS_len(&peer)) == 0) {
-          x509_chain_should_include_leaf_default = 1;
-          continue;
-        }
-      }
-
-      /* TODO(agl): this should use the |SSL_CTX|'s pool. */
-      CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&cert, NULL);
-      if (buffer == NULL) {
+      if (!sk_X509_push(ret->x509_chain, x509)) {
         OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-        goto err;
-      }
-
-      if (!sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
-        CRYPTO_BUFFER_free(buffer);
-        OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+        X509_free(x509);
         goto err;
       }
     }
@@ -746,25 +688,11 @@
   }
   ret->ticket_age_add_valid = age_add_present;
 
-  int x509_chain_should_include_leaf;
-  if (!CBS_get_optional_asn1_bool(&session, &x509_chain_should_include_leaf,
-                                  kX509ChainIncludeLeafTag,
-                                  x509_chain_should_include_leaf_default)) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
-  }
-
   if (CBS_len(&session) != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     goto err;
   }
 
-  if (!x509_chain_from_buffers(&ret->x509_chain, ret->certs)) {
-    goto err;
-  }
-
-  ssl_session_set_x509_peer(ret, x509_chain_should_include_leaf);
-
   return ret;
 
 err:
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index 4297245..c0bdb5c 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -448,18 +448,30 @@
   return ssl->cert->x509_leaf != NULL && ssl_has_private_key(ssl);
 }
 
-int ssl_parse_cert_chain(SSL *ssl, STACK_OF(CRYPTO_BUFFER) **out_buffers,
-                         STACK_OF(X509) **out_x509s, uint8_t *out_alert,
-                         uint8_t *out_leaf_sha256, CBS *cbs) {
-  *out_buffers = NULL;
+X509 *ssl_parse_x509(CBS *cbs) {
+  if (CBS_len(cbs) > LONG_MAX) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+    return NULL;
+  }
+  const uint8_t *ptr = CBS_data(cbs);
+  X509 *ret = d2i_X509(NULL, &ptr, (long)CBS_len(cbs));
+  if (ret == NULL) {
+    return NULL;
+  }
+  CBS_skip(cbs, ptr - CBS_data(cbs));
+  return ret;
+}
 
-  STACK_OF(CRYPTO_BUFFER) *buffers = sk_CRYPTO_BUFFER_new_null();
-  if (buffers == NULL) {
+STACK_OF(X509) *ssl_parse_cert_chain(SSL *ssl, uint8_t *out_alert,
+                                     uint8_t *out_leaf_sha256, CBS *cbs) {
+  STACK_OF(X509) *ret = sk_X509_new_null();
+  if (ret == NULL) {
     *out_alert = SSL_AD_INTERNAL_ERROR;
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-    return 0;
+    return NULL;
   }
 
+  X509 *x = NULL;
   CBS certificate_list;
   if (!CBS_get_u24_length_prefixed(cbs, &certificate_list)) {
     *out_alert = SSL_AD_DECODE_ERROR;
@@ -469,46 +481,36 @@
 
   while (CBS_len(&certificate_list) > 0) {
     CBS certificate;
-    if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
-        CBS_len(&certificate) == 0) {
+    if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate)) {
       *out_alert = 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_CRYPTO_BUFFER_num(buffers) == 0 && out_leaf_sha256 != NULL) {
+    if (sk_X509_num(ret) == 0 && out_leaf_sha256 != NULL) {
       SHA256(CBS_data(&certificate), CBS_len(&certificate), out_leaf_sha256);
     }
 
-    CRYPTO_BUFFER *buffer =
-        CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool);
-    if (buffer == NULL) {
+    x = ssl_parse_x509(&certificate);
+    if (x == NULL || CBS_len(&certificate) != 0) {
+      *out_alert = SSL_AD_DECODE_ERROR;
+      goto err;
+    }
+    if (!sk_X509_push(ret, x)) {
       *out_alert = SSL_AD_INTERNAL_ERROR;
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
     }
-
-    if (!sk_CRYPTO_BUFFER_push(buffers, buffer)) {
-      CRYPTO_BUFFER_free(buffer);
-      *out_alert = SSL_AD_INTERNAL_ERROR;
-      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-      goto err;
-    }
+    x = NULL;
   }
 
-  STACK_OF(X509) *x509s;
-  if (!x509_chain_from_buffers(&x509s, buffers)) {
-    goto err;
-  }
-
-  *out_buffers = buffers;
-  *out_x509s = x509s;
-  return 1;
+  return ret;
 
 err:
-  sk_CRYPTO_BUFFER_pop_free(buffers, CRYPTO_BUFFER_free);
-  return 0;
+  X509_free(x);
+  sk_X509_pop_free(ret, X509_free);
+  return NULL;
 }
 
 int ssl_add_cert_to_cbb(CBB *cbb, X509 *x509) {
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index f3610a5..6c8d8ec 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1080,10 +1080,6 @@
 
 uint32_t SSL_get_mode(const SSL *ssl) { return ssl->mode; }
 
-void SSL_CTX_set0_buffer_pool(SSL_CTX *ctx, CRYPTO_BUFFER_POOL *pool) {
-  ctx->pool = pool;
-}
-
 X509 *SSL_get_peer_certificate(const SSL *ssl) {
   if (ssl == NULL) {
     return NULL;
diff --git a/ssl/ssl_session.c b/ssl/ssl_session.c
index 51c2138..67e809d 100644
--- a/ssl/ssl_session.c
+++ b/ssl/ssl_session.c
@@ -199,20 +199,6 @@
       goto err;
     }
   }
-  if (session->certs != NULL) {
-    new_session->certs = sk_CRYPTO_BUFFER_new_null();
-    if (new_session->certs == NULL) {
-      goto err;
-    }
-    for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(session->certs); i++) {
-      CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(session->certs, i);
-      CRYPTO_BUFFER_up_ref(buffer);
-      if (!sk_CRYPTO_BUFFER_push(new_session->certs, buffer)) {
-        CRYPTO_BUFFER_free(buffer);
-        goto err;
-      }
-    }
-  }
   if (session->x509_peer != NULL) {
     X509_up_ref(session->x509_peer);
     new_session->x509_peer = session->x509_peer;
@@ -340,7 +326,6 @@
   OPENSSL_cleanse(session->master_key, sizeof(session->master_key));
   OPENSSL_cleanse(session->session_id, sizeof(session->session_id));
   X509_free(session->x509_peer);
-  sk_CRYPTO_BUFFER_pop_free(session->certs, CRYPTO_BUFFER_free);
   sk_X509_pop_free(session->x509_chain, X509_free);
   OPENSSL_free(session->tlsext_hostname);
   OPENSSL_free(session->tlsext_tick);
@@ -981,61 +966,6 @@
   }
 }
 
-int x509_chain_from_buffers(STACK_OF(X509) **out,
-                            STACK_OF(CRYPTO_BUFFER) *buffers) {
-  *out = NULL;
-
-  if (sk_CRYPTO_BUFFER_num(buffers) == 0) {
-    return 1;
-  }
-
-  STACK_OF(X509) *ret = sk_X509_new_null();
-  if (ret == NULL) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-    return 0;
-  }
-
-  for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(buffers); i++) {
-    CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(buffers, i);
-    X509 *x509 = X509_parse_from_buffer(buffer);
-    if (x509 == NULL) {
-      OPENSSL_PUT_ERROR(SSL, SSL_AD_DECODE_ERROR);
-      goto err;
-    }
-    if (!sk_X509_push(ret, x509)) {
-      X509_free(x509);
-      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-      goto err;
-    }
-  }
-
-  *out = ret;
-  return 1;
-
-err:
-  sk_X509_pop_free(ret, X509_free);
-  return 0;
-}
-
-void ssl_session_set_x509_peer(SSL_SESSION *sess,
-                               int chain_should_include_leaf) {
-  sess->x509_chain_should_include_leaf = chain_should_include_leaf;
-  X509_free(sess->x509_peer);
-  sess->x509_peer = NULL;
-
-  if (sk_X509_num(sess->x509_chain) > 0) {
-    if (chain_should_include_leaf) {
-      X509 *leaf = sk_X509_value(sess->x509_chain, 0);
-      X509_up_ref(leaf);
-      sess->x509_peer = leaf;
-    } else {
-      sess->x509_peer = sk_X509_shift(sess->x509_chain);
-      /* |sess->x509_chain| may now be empty, but code still expects it to be
-       * non-NULL. */
-    }
-  }
-}
-
 void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx,
                              int (*cb)(SSL *ssl, SSL_SESSION *session)) {
   ctx->new_session_cb = cb;
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index af02e44..5e4485f 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -498,81 +498,6 @@
 
 // kBoringSSLSession is a serialized SSL_SESSION generated from bssl client.
 static const char kBoringSSLSession[] =
-    "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"
-    "n8JzIdPmX4DkjYUiOnMDsWCOrmji9D6X52ASCWg23jrW4kOVWzeBkoEfu43XrVJk"
-    "FleW2V40fsg12DCCA30wggLmoAMCAQICAxK75jANBgkqhkiG9w0BAQUFADBOMQsw"
-    "CQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBT"
-    "ZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTAyMDUyMTA0MDAwMFoXDTE4"
-    "MDgyMTA0MDAwMFowQjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
-    "Yy4xGzAZBgNVBAMTEkdlb1RydXN0IEdsb2JhbCBDQTCCASIwDQYJKoZIhvcNAQEB"
-    "BQADggEPADCCAQoCggEBANrMGGMw/fQXIxpWflvfPGw45HG3eJHUvKHYTPioQ7YD"
-    "6U0hBwiI2lgvZjkpvQV4i5046AW3an5xpObEYKaw74DkiSgPniXW7YPzraaRx5jJ"
-    "Qhg1FJ2tmEaSLk/K8YdDwRaVVy1Q74ktgHpXrfLuX2vSAI25FPgUFTXZwEaje3LI"
-    "kb/JVSvN0Jc+nCZkzN/Ogxlxyk7m1NV7qRnNVd7I7NJeOFPlXE+MLf5QIzb8ZubL"
-    "jqQ5GQC3lQI5kQsO/jgu0R0FmvZNPm8PBx2vLB6PYDni+jZTEznUXiYr2z2oFL0y"
-    "6xgDKFIEceWrMz3hOLsHNoRinHnqFjD0X8Ar6HFr5PkCAwEAAaOB8DCB7TAfBgNV"
-    "HSMEGDAWgBRI5mj5K9KylddH2CMgEE8zmJCf1DAdBgNVHQ4EFgQUwHqYaI2J+6sF"
-    "ZAwRfap9ZbjKzE4wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwOgYD"
-    "VR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9zZWN1"
-    "cmVjYS5jcmwwTgYDVR0gBEcwRTBDBgRVHSAAMDswOQYIKwYBBQUHAgEWLWh0dHBz"
-    "Oi8vd3d3Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvcmVwb3NpdG9yeTANBgkqhkiG"
-    "9w0BAQUFAAOBgQB24RJuTksWEoYwBrKBCM/wCMfHcX5m7sLt1Dsf//DwyE7WQziw"
-    "uTB9GNBVg6JqyzYRnOhIZqNtf7gT1Ef+i1pcc/yu2RsyGTirlzQUqpbS66McFAhJ"
-    "trvlke+DNusdVm/K2rxzY5Dkf3s+Iss9B+1fOHSc4wNQTqGvmO5h8oQ/Eg==";
-
-// kLeafInChainSession is a serialized SSL_SESSION generated from bssl client.
-// It contains a chain that includes the leaf certificate.
-static const char kLeafInChainSession[] =
     "MIIRwQIBAQICAwMEAsAvBCDdoGxGK26mR+8lM0uq6+k9xYuxPnwAjpcF9n0Yli9R"
     "kQQwbyshfWhdi5XQ1++7n2L1qqrcVlmHBPpr6yknT/u4pUrpQB5FZ7vqvNn8MdHf"
     "9rWgoQYCBFXgs7uiBAICHCCjggR6MIIEdjCCA16gAwIBAgIIf+yfD7Y6UicwDQYJ"
@@ -733,8 +658,7 @@
   }
 
   // Verify the SSL_SESSION decodes.
-  bssl::UniquePtr<SSL_SESSION> session(
-      SSL_SESSION_from_bytes(input.data(), input.size()));
+  bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(input.data(), input.size()));
   if (!session) {
     fprintf(stderr, "SSL_SESSION_from_bytes failed\n");
     return false;
@@ -803,8 +727,7 @@
   }
 
   // Verify that the SSL_SESSION fails to decode.
-  bssl::UniquePtr<SSL_SESSION> session(
-      SSL_SESSION_from_bytes(input.data(), input.size()));
+  bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(input.data(), input.size()));
   if (session) {
     fprintf(stderr, "SSL_SESSION_from_bytes unexpectedly succeeded\n");
     return false;
@@ -813,79 +736,6 @@
   return true;
 }
 
-static bool TestLeafInChainSession() {
-  std::vector<uint8_t> input;
-  if (!DecodeBase64(&input, kLeafInChainSession)) {
-    return false;
-  }
-
-  bssl::UniquePtr<SSL_SESSION> session(
-      SSL_SESSION_from_bytes(input.data(), input.size()));
-  if (!session) {
-    fprintf(stderr, "TestLeafInChainSession: failed to decode.\n");
-    return false;
-  }
-
-  // kLeafInChainSession contains a session where the leaf is duplicated in the
-  // certificate chain. |certs| should contain the chain without duplication,
-  // but |x509_chain| should reflect the structure from the serialised session.
-  if (X509_cmp(session->x509_peer, sk_X509_value(session->x509_chain, 0)) !=
-      0) {
-    fprintf(stderr,
-            "TestLeafInChainSession: leaf is not first element of chain.\n");
-    return false;
-  }
-
-  if (sk_X509_num(session->x509_chain) !=
-      sk_CRYPTO_BUFFER_num(session->certs)) {
-    fprintf(
-        stderr,
-        "TestLeafInChainSession: chain length differs from certs length.\n");
-    return false;
-  }
-
-  if (!session->x509_chain_should_include_leaf) {
-    fprintf(stderr,
-            "TestLeafInChainSession: x509_chain_should_include_leaf flag not "
-            "set.\n");
-    return false;
-  }
-
-  size_t encoded_len;
-  bssl::UniquePtr<uint8_t> encoded;
-  uint8_t *encoded_raw;
-  if (!SSL_SESSION_to_bytes(session.get(), &encoded_raw, &encoded_len)) {
-    fprintf(stderr, "TestLeafInChainSession: SSL_SESSION_to_bytes failed\n");
-    return false;
-  }
-  encoded.reset(encoded_raw);
-
-  // After reencoding, the duplication should be eliminated.
-  if (encoded_len >= input.size()) {
-    fprintf(stderr,
-            "TestLeafInChainSession: reencoding didn't end up smaller\n");
-    return false;
-  }
-
-  // But the duplication should be preserved when parsing again.
-  bssl::UniquePtr<SSL_SESSION> session2(
-      SSL_SESSION_from_bytes(encoded_raw, encoded_len));
-  if (!session2) {
-    fprintf(stderr, "TestLeafInChainSession: failed to redecode.\n");
-    return false;
-  }
-
-  if (X509_cmp(session2->x509_peer, sk_X509_value(session2->x509_chain, 0)) !=
-          0 ||
-      sk_X509_num(session2->x509_chain) != sk_X509_num(session->x509_chain)) {
-    fprintf(stderr,
-            "TestLeafInChainSession: redecode didn't preserve duplication.\n");
-    return false;
-  }
-
-  return true;
-}
-
 static bool TestDefaultVersion(uint16_t min_version, uint16_t max_version,
                                const SSL_METHOD *(*method)(void)) {
   bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method()));
@@ -2929,7 +2779,6 @@
       !TestBadSSL_SESSIONEncoding(kBadSessionExtraField) ||
       !TestBadSSL_SESSIONEncoding(kBadSessionVersion) ||
       !TestBadSSL_SESSIONEncoding(kBadSessionTrailingData) ||
-      !TestLeafInChainSession() ||
       // TODO(svaldez): Update this when TLS 1.3 is enabled by default.
       !TestDefaultVersion(SSL3_VERSION, TLS1_2_VERSION, &TLS_method) ||
       !TestDefaultVersion(SSL3_VERSION, SSL3_VERSION, &SSLv3_method) ||
diff --git a/ssl/tls13_both.c b/ssl/tls13_both.c
index 85d804f..1a1d8b9 100644
--- a/ssl/tls13_both.c
+++ b/ssl/tls13_both.c
@@ -177,9 +177,8 @@
       ssl->server && ssl->retain_only_sha256_of_client_certs;
   int ret = 0;
 
-  STACK_OF(X509) *chain = NULL;
-  STACK_OF(CRYPTO_BUFFER) *buffers = sk_CRYPTO_BUFFER_new_null();
-  if (buffers == NULL) {
+  STACK_OF(X509) *chain = sk_X509_new_null();
+  if (chain == NULL) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     goto err;
@@ -194,31 +193,28 @@
   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_len(&certificate) == 0) {
+        !CBS_get_u16_length_prefixed(&certificate_list, &extensions)) {
       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_CRYPTO_BUFFER_num(buffers) == 0 && retain_sha256) {
+    if (sk_X509_num(chain) == 0 && retain_sha256) {
       SHA256(CBS_data(&certificate), CBS_len(&certificate),
              ssl->s3->new_session->peer_sha256);
     }
 
-    CRYPTO_BUFFER *buffer =
-        CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool);
-    if (buffer == NULL) {
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+    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_CRYPTO_BUFFER_push(buffers, buffer)) {
-      CRYPTO_BUFFER_free(buffer);
+    if (!sk_X509_push(chain, x)) {
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+      X509_free(x);
       goto err;
     }
 
@@ -257,7 +253,7 @@
         goto err;
       }
 
-      if (sk_CRYPTO_BUFFER_num(buffers) == 1 &&
+      if (sk_X509_num(chain) == 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);
@@ -278,7 +274,7 @@
         goto err;
       }
 
-      if (sk_CRYPTO_BUFFER_num(buffers) == 1 &&
+      if (sk_X509_num(chain) == 1 &&
           !CBS_stow(&sct,
                     &ssl->s3->new_session->tlsext_signed_cert_timestamp_list,
                     &ssl->s3->new_session
@@ -295,7 +291,7 @@
     goto err;
   }
 
-  if (sk_CRYPTO_BUFFER_num(buffers) == 0) {
+  if (sk_X509_num(chain) == 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);
@@ -313,30 +309,24 @@
 
   ssl->s3->new_session->peer_sha256_valid = retain_sha256;
 
-  if (!x509_chain_from_buffers(&chain, buffers)) {
-    goto err;
-  }
-
   if (!ssl_verify_cert_chain(ssl, &ssl->s3->new_session->verify_result,
                              chain)) {
     goto err;
   }
 
-  sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, CRYPTO_BUFFER_free);
-  ssl->s3->new_session->certs = buffers;
-  buffers = NULL;
+  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;
 
-  ssl_session_set_x509_peer(ssl->s3->new_session,
-                            1 /* chain should include leaf */);
-
   ret = 1;
 
 err:
   sk_X509_pop_free(chain, X509_free);
-  sk_CRYPTO_BUFFER_pop_free(buffers, CRYPTO_BUFFER_free);
   return ret;
 }
 
diff --git a/ssl/tls13_server.c b/ssl/tls13_server.c
index d7545f0..626d2ee 100644
--- a/ssl/tls13_server.c
+++ b/ssl/tls13_server.c
@@ -557,7 +557,6 @@
   if (sk_X509_num(ssl->s3->new_session->x509_chain) > 0) {
     X509_free(sk_X509_shift(ssl->s3->new_session->x509_chain));
   }
-  ssl->s3->new_session->x509_chain_should_include_leaf = 0;
 
   hs->state = state_process_client_certificate_verify;
   return ssl_hs_read_message;