Remove |X509| things from SSL_SESSION.

|SSL_SESSION_from_bytes| now takes an |SSL_CTX*|, from which it uses the
|X509_METHOD| and buffer pool. This is our API so we can do this.

This also requires adding an |SSL_CTX*| argument to |SSL_SESSION_new|
for the same reason. However, |SSL_SESSION_new| already has very few
callers (and none in third-party code that I can see) so I think we can
get away with this.

Change-Id: I1337cd2bd8cff03d4b9405ea3146b3b59584aa72
Reviewed-on: https://boringssl-review.googlesource.com/13584
Reviewed-by: Adam Langley <alangley@gmail.com>
Commit-Queue: Adam Langley <alangley@gmail.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index 66c0142..427213c 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -1077,7 +1077,7 @@
 
   if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0 ||
       CBS_len(&cbs) != 0 ||
-      !ssl_session_x509_cache_objects(ssl->s3->new_session)) {
+      !ssl->ctx->x509_method->session_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);
     return -1;
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index 5e921b6..c352dd9 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -483,10 +483,10 @@
          * now. */
         if (ssl->s3->new_session != NULL &&
             ssl->retain_only_sha256_of_client_certs) {
-          X509_free(ssl->s3->new_session->x509_peer);
-          ssl->s3->new_session->x509_peer = NULL;
-          sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free);
-          ssl->s3->new_session->x509_chain = NULL;
+          sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs,
+                                    CRYPTO_BUFFER_free);
+          ssl->s3->new_session->certs = NULL;
+          ssl->ctx->x509_method->session_clear(ssl->s3->new_session);
         }
 
         SSL_SESSION_free(ssl->s3->established_session);
@@ -1472,7 +1472,7 @@
   }
 
   if (CBS_len(&certificate_msg) != 0 ||
-      !ssl_session_x509_cache_objects(ssl->s3->new_session)) {
+      !ssl->ctx->x509_method->session_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);
     return -1;
diff --git a/ssl/internal.h b/ssl/internal.h
index 06bdd04..5b93f47 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -804,12 +804,6 @@
  * configured and zero otherwise. */
 int ssl_has_certificate(const SSL *ssl);
 
-/* ssl_session_x509_cache_objects fills out |sess->x509_peer| and
- * |sess->x509_chain| from |sess->certs| and erases
- * |sess->x509_chain_without_leaf|. It returns one on success or zero on
- * error. */
-int ssl_session_x509_cache_objects(SSL_SESSION *sess);
-
 /* ssl_parse_cert_chain parses a certificate list from |cbs| in the format used
  * by a TLS Certificate message. On success, it returns a newly-allocated
  * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns NULL and sets
@@ -1433,8 +1427,22 @@
   /* cert_flush_cached_chain drops any cached |X509|-based leaf certificate
    * from |cert|. */
   void (*cert_flush_cached_leaf)(CERT *cert);
+
+  /* session_cache_objects fills out |sess->x509_peer| and |sess->x509_chain|
+   * from |sess->certs| and erases |sess->x509_chain_without_leaf|. It returns
+   * one on success or zero on error. */
+  int (*session_cache_objects)(SSL_SESSION *session);
+  /* session_dup duplicates any needed fields from |session| to |new_session|.
+   * It returns one on success or zero on error. */
+  int (*session_dup)(SSL_SESSION *new_session, const SSL_SESSION *session);
+  /* session_clear frees any X509-related state from |session|. */
+  void (*session_clear)(SSL_SESSION *session);
 };
 
+/* ssl_noop_x509_method is implements the |ssl_x509_method_st| functions by
+ * doing nothing. */
+extern const struct ssl_x509_method_st ssl_noop_x509_method;
+
 /* ssl_crypto_x509_method provides the |ssl_x509_method_st| functions using
  * crypto/x509. */
 extern const struct ssl_x509_method_st ssl_crypto_x509_method;
@@ -1911,6 +1919,15 @@
 int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server);
 int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session);
 
+/* ssl_session_new returns a newly-allocated blank |SSL_SESSION| or NULL on
+ * error. */
+SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method);
+
+/* SSL_SESSION_parse parses an |SSL_SESSION| from |cbs| and advances |cbs| over
+ * the parsed data. */
+SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method,
+                               CRYPTO_BUFFER_POOL *pool);
+
 /* 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.c b/ssl/ssl_asn1.c
index 4c1ee89..3582864 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -575,8 +575,9 @@
   return 1;
 }
 
-static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {
-  SSL_SESSION *ret = SSL_SESSION_new();
+SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method,
+                               CRYPTO_BUFFER_POOL *pool) {
+  SSL_SESSION *ret = ssl_session_new(x509_method);
   if (ret == NULL) {
     goto err;
   }
@@ -738,7 +739,7 @@
 
     if (has_peer) {
       /* TODO(agl): this should use the |SSL_CTX|'s pool. */
-      CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&peer, NULL);
+      CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&peer, pool);
       if (buffer == NULL ||
           !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
         CRYPTO_BUFFER_free(buffer);
@@ -756,7 +757,7 @@
       }
 
       /* TODO(agl): this should use the |SSL_CTX|'s pool. */
-      CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&cert, NULL);
+      CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&cert, pool);
       if (buffer == NULL ||
           !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
         CRYPTO_BUFFER_free(buffer);
@@ -766,7 +767,7 @@
     }
   }
 
-  if (!ssl_session_x509_cache_objects(ret)) {
+  if (!x509_method->session_cache_objects(ret)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     goto err;
   }
@@ -811,10 +812,11 @@
   return NULL;
 }
 
-SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len) {
+SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len,
+                                    const SSL_CTX *ctx) {
   CBS cbs;
   CBS_init(&cbs, in, in_len);
-  SSL_SESSION *ret = SSL_SESSION_parse(&cbs);
+  SSL_SESSION *ret = SSL_SESSION_parse(&cbs, ctx->x509_method, ctx->pool);
   if (ret == NULL) {
     return NULL;
   }
@@ -825,25 +827,3 @@
   }
   return ret;
 }
-
-SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) {
-  if (length < 0) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-    return NULL;
-  }
-
-  CBS cbs;
-  CBS_init(&cbs, *pp, length);
-
-  SSL_SESSION *ret = SSL_SESSION_parse(&cbs);
-  if (ret == NULL) {
-    return NULL;
-  }
-
-  if (a) {
-    SSL_SESSION_free(*a);
-    *a = ret;
-  }
-  *pp = CBS_data(&cbs);
-  return ret;
-}
diff --git a/ssl/ssl_file.c b/ssl/ssl_file.c
index e1ebaa6..59351a3 100644
--- a/ssl/ssl_file.c
+++ b/ssl/ssl_file.c
@@ -573,14 +573,3 @@
 void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *data) {
   ctx->default_passwd_callback_userdata = data;
 }
-
-SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out) {
-  return ASN1_d2i_bio_of(SSL_SESSION, SSL_SESSION_new, d2i_SSL_SESSION, bio,
-                         out);
-}
-
-int i2d_SSL_SESSION_bio(BIO *bio, const SSL_SESSION *session) {
-  return ASN1_i2d_bio_of(SSL_SESSION, i2d_SSL_SESSION, bio, session);
-}
-
-IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION)
diff --git a/ssl/ssl_session.c b/ssl/ssl_session.c
index 908d5dc..b71b994 100644
--- a/ssl/ssl_session.c
+++ b/ssl/ssl_session.c
@@ -160,7 +160,7 @@
 static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session);
 static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock);
 
-SSL_SESSION *SSL_SESSION_new(void) {
+SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method) {
   SSL_SESSION *session = OPENSSL_malloc(sizeof(SSL_SESSION));
   if (session == NULL) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
@@ -168,6 +168,7 @@
   }
   OPENSSL_memset(session, 0, sizeof(SSL_SESSION));
 
+  session->x509_method = x509_method;
   session->verify_result = X509_V_ERR_INVALID_CALL;
   session->references = 1;
   session->timeout = SSL_DEFAULT_SESSION_TIMEOUT;
@@ -177,8 +178,12 @@
   return session;
 }
 
+SSL_SESSION *SSL_SESSION_new(const SSL_CTX *ctx) {
+  return ssl_session_new(ctx->x509_method);
+}
+
 SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) {
-  SSL_SESSION *new_session = SSL_SESSION_new();
+  SSL_SESSION *new_session = ssl_session_new(session->x509_method);
   if (new_session == NULL) {
     goto err;
   }
@@ -214,16 +219,11 @@
       CRYPTO_BUFFER_up_ref(buffer);
     }
   }
-  if (session->x509_peer != NULL) {
-    X509_up_ref(session->x509_peer);
-    new_session->x509_peer = session->x509_peer;
+
+  if (!session->x509_method->session_dup(new_session, session)) {
+    goto err;
   }
-  if (session->x509_chain != NULL) {
-    new_session->x509_chain = X509_chain_up_ref(session->x509_chain);
-    if (new_session->x509_chain == NULL) {
-      goto err;
-    }
-  }
+
   new_session->verify_result = session->verify_result;
 
   new_session->ocsp_response_length = session->ocsp_response_length;
@@ -367,9 +367,7 @@
   OPENSSL_cleanse(session->master_key, sizeof(session->master_key));
   OPENSSL_cleanse(session->session_id, sizeof(session->session_id));
   sk_CRYPTO_BUFFER_pop_free(session->certs, CRYPTO_BUFFER_free);
-  X509_free(session->x509_peer);
-  sk_X509_pop_free(session->x509_chain, X509_free);
-  sk_X509_pop_free(session->x509_chain_without_leaf, X509_free);
+  session->x509_method->session_clear(session);
   OPENSSL_free(session->tlsext_hostname);
   OPENSSL_free(session->tlsext_tick);
   OPENSSL_free(session->tlsext_signed_cert_timestamp_list);
@@ -511,7 +509,7 @@
     return 0;
   }
 
-  SSL_SESSION *session = SSL_SESSION_new();
+  SSL_SESSION *session = ssl_session_new(ssl->ctx->x509_method);
   if (session == NULL) {
     return 0;
   }
@@ -573,53 +571,6 @@
   return 0;
 }
 
-int ssl_session_x509_cache_objects(SSL_SESSION *sess) {
-  STACK_OF(X509) *chain = NULL;
-  const size_t num_certs = sk_CRYPTO_BUFFER_num(sess->certs);
-
-  if (num_certs > 0) {
-    chain = sk_X509_new_null();
-    if (chain == NULL) {
-      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-      goto err;
-    }
-  }
-
-  X509 *leaf = NULL;
-  for (size_t i = 0; i < num_certs; i++) {
-    X509 *x509 = X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(sess->certs, i));
-    if (x509 == NULL) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-      goto err;
-    }
-    if (!sk_X509_push(chain, x509)) {
-      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-      X509_free(x509);
-      goto err;
-    }
-    if (i == 0) {
-      leaf = x509;
-    }
-  }
-
-  sk_X509_pop_free(sess->x509_chain, X509_free);
-  sess->x509_chain = chain;
-  sk_X509_pop_free(sess->x509_chain_without_leaf, X509_free);
-  sess->x509_chain_without_leaf = NULL;
-
-  X509_free(sess->x509_peer);
-  if (leaf != NULL) {
-    X509_up_ref(leaf);
-  }
-  sess->x509_peer = leaf;
-
-  return 1;
-
-err:
-  sk_X509_pop_free(chain, X509_free);
-  return 0;
-}
-
 int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session) {
   int ret = 0;
 
@@ -753,7 +704,8 @@
          /* If the session contains a client certificate (either the full
           * certificate or just the hash) then require that the form of the
           * certificate matches the current configuration. */
-         ((session->x509_peer == NULL && !session->peer_sha256_valid) ||
+         ((sk_CRYPTO_BUFFER_num(session->certs) == 0 &&
+           !session->peer_sha256_valid) ||
           session->peer_sha256_valid ==
               ssl->retain_only_sha256_of_client_certs);
 }
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index aaad1bc..e12c613 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -634,7 +634,12 @@
   }
 
   // Verify the SSL_SESSION decodes.
-  bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(input.data(), input.size()));
+  bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method()));
+  if (!ssl_ctx) {
+    return false;
+  }
+  bssl::UniquePtr<SSL_SESSION> session(
+      SSL_SESSION_from_bytes(input.data(), input.size(), ssl_ctx.get()));
   if (!session) {
     fprintf(stderr, "SSL_SESSION_from_bytes failed\n");
     return false;
@@ -703,7 +708,12 @@
   }
 
   // Verify that the SSL_SESSION fails to decode.
-  bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(input.data(), input.size()));
+  bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method()));
+  if (!ssl_ctx) {
+    return false;
+  }
+  bssl::UniquePtr<SSL_SESSION> session(
+      SSL_SESSION_from_bytes(input.data(), input.size(), ssl_ctx.get()));
   if (session) {
     fprintf(stderr, "SSL_SESSION_from_bytes unexpectedly succeeded\n");
     return false;
@@ -795,8 +805,13 @@
   if (!DecodeBase64(&der, kOpenSSLSession)) {
     return nullptr;
   }
+
+  bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method()));
+  if (!ssl_ctx) {
+    return nullptr;
+  }
   bssl::UniquePtr<SSL_SESSION> session(
-      SSL_SESSION_from_bytes(der.data(), der.size()));
+      SSL_SESSION_from_bytes(der.data(), der.size(), ssl_ctx.get()));
   if (!session) {
     return nullptr;
   }
@@ -989,7 +1004,11 @@
 }
 
 static bssl::UniquePtr<SSL_SESSION> CreateTestSession(uint32_t number) {
-  bssl::UniquePtr<SSL_SESSION> ret(SSL_SESSION_new());
+  bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method()));
+  if (!ssl_ctx) {
+    return nullptr;
+  }
+  bssl::UniquePtr<SSL_SESSION> ret(SSL_SESSION_new(ssl_ctx.get()));
   if (!ret) {
     return nullptr;
   }
@@ -2166,8 +2185,12 @@
   len = static_cast<size_t>(len1 + len2);
 #endif
 
+  bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method()));
+  if (!ssl_ctx) {
+    return false;
+  }
   bssl::UniquePtr<SSL_SESSION> server_session(
-      SSL_SESSION_from_bytes(plaintext.get(), len));
+      SSL_SESSION_from_bytes(plaintext.get(), len, ssl_ctx.get()));
   if (!server_session) {
     return false;
   }
diff --git a/ssl/ssl_x509.c b/ssl/ssl_x509.c
index 9077b61..2955c21 100644
--- a/ssl/ssl_x509.c
+++ b/ssl/ssl_x509.c
@@ -142,6 +142,10 @@
 
 #include <assert.h>
 
+#include <openssl/asn1.h>
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
 #include <openssl/stack.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
@@ -334,10 +338,85 @@
   cert->x509_stash = NULL;
 }
 
+static int ssl_crypto_x509_session_cache_objects(SSL_SESSION *sess) {
+  STACK_OF(X509) *chain = NULL;
+  const size_t num_certs = sk_CRYPTO_BUFFER_num(sess->certs);
+
+  if (num_certs > 0) {
+    chain = sk_X509_new_null();
+    if (chain == NULL) {
+      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
+
+  X509 *leaf = NULL;
+  for (size_t i = 0; i < num_certs; i++) {
+    X509 *x509 = X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(sess->certs, i));
+    if (x509 == NULL) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+      goto err;
+    }
+    if (!sk_X509_push(chain, x509)) {
+      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+      X509_free(x509);
+      goto err;
+    }
+    if (i == 0) {
+      leaf = x509;
+    }
+  }
+
+  sk_X509_pop_free(sess->x509_chain, X509_free);
+  sess->x509_chain = chain;
+  sk_X509_pop_free(sess->x509_chain_without_leaf, X509_free);
+  sess->x509_chain_without_leaf = NULL;
+
+  X509_free(sess->x509_peer);
+  if (leaf != NULL) {
+    X509_up_ref(leaf);
+  }
+  sess->x509_peer = leaf;
+
+  return 1;
+
+err:
+  sk_X509_pop_free(chain, X509_free);
+  return 0;
+}
+
+static int ssl_crypto_x509_session_dup(SSL_SESSION *new_session,
+                                       const SSL_SESSION *session) {
+  if (session->x509_peer != NULL) {
+    X509_up_ref(session->x509_peer);
+    new_session->x509_peer = session->x509_peer;
+  }
+  if (session->x509_chain != NULL) {
+    new_session->x509_chain = X509_chain_up_ref(session->x509_chain);
+    if (new_session->x509_chain == NULL) {
+      return 0;
+    }
+  }
+
+  return 1;
+}
+
+static void ssl_crypto_x509_session_clear(SSL_SESSION *session) {
+  X509_free(session->x509_peer);
+  session->x509_peer = NULL;
+  sk_X509_pop_free(session->x509_chain, X509_free);
+  session->x509_chain = NULL;
+  sk_X509_pop_free(session->x509_chain_without_leaf, X509_free);
+  session->x509_chain_without_leaf = NULL;
+}
+
 const SSL_X509_METHOD ssl_crypto_x509_method = {
   ssl_crypto_x509_clear,
   ssl_crypto_x509_flush_cached_chain,
   ssl_crypto_x509_flush_cached_leaf,
+  ssl_crypto_x509_session_cache_objects,
+  ssl_crypto_x509_session_dup,
+  ssl_crypto_x509_session_clear,
 };
 
 /* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised
@@ -696,3 +775,41 @@
   *out_chain = ssl->cert->x509_chain;
   return 1;
 }
+
+static SSL_SESSION *ssl_session_new_with_crypto_x509(void) {
+  return ssl_session_new(&ssl_crypto_x509_method);
+}
+
+SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out) {
+  return ASN1_d2i_bio_of(SSL_SESSION, ssl_session_new_with_crypto_x509,
+                         d2i_SSL_SESSION, bio, out);
+}
+
+int i2d_SSL_SESSION_bio(BIO *bio, const SSL_SESSION *session) {
+  return ASN1_i2d_bio_of(SSL_SESSION, i2d_SSL_SESSION, bio, session);
+}
+
+IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION)
+
+SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) {
+  if (length < 0) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    return NULL;
+  }
+
+  CBS cbs;
+  CBS_init(&cbs, *pp, length);
+
+  SSL_SESSION *ret = SSL_SESSION_parse(&cbs, &ssl_crypto_x509_method,
+                                       NULL /* no buffer pool */);
+  if (ret == NULL) {
+    return NULL;
+  }
+
+  if (a) {
+    SSL_SESSION_free(*a);
+    *a = ret;
+  }
+  *pp = CBS_data(&cbs);
+  return ret;
+}
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index b3ba546..7723ccd 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -3213,7 +3213,8 @@
 #endif
 
   /* Decode the session. */
-  SSL_SESSION *session = SSL_SESSION_from_bytes(plaintext, plaintext_len);
+  SSL_SESSION *session =
+      SSL_SESSION_from_bytes(plaintext, plaintext_len, ssl->ctx);
   if (session == NULL) {
     ERR_clear_error(); /* Don't leave an error on the queue. */
     goto done;
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 66a71a0..381f4c2 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -1477,7 +1477,7 @@
   }
 
   if (expected_sha256_client_cert &&
-      SSL_get_session(ssl)->x509_peer != nullptr) {
+      SSL_get_session(ssl)->certs != nullptr) {
     fprintf(stderr, "Have both client cert and SHA-256 hash: is_resume:%d.\n",
             is_resume);
     return false;
diff --git a/ssl/tls13_both.c b/ssl/tls13_both.c
index 134dfd2..19dd555 100644
--- a/ssl/tls13_both.c
+++ b/ssl/tls13_both.c
@@ -307,7 +307,7 @@
   ssl->s3->new_session->certs = certs;
   certs = NULL;
 
-  if (!ssl_session_x509_cache_objects(ssl->s3->new_session)) {
+  if (!ssl->ctx->x509_method->session_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;
diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c
index a85f6b3..50f7e5a 100644
--- a/ssl/tls13_client.c
+++ b/ssl/tls13_client.c
@@ -615,9 +615,8 @@
 
 int tls13_process_new_session_ticket(SSL *ssl) {
   int ret = 0;
-  SSL_SESSION *session =
-      SSL_SESSION_dup(ssl->s3->established_session,
-                      SSL_SESSION_INCLUDE_NONAUTH);
+  SSL_SESSION *session = SSL_SESSION_dup(ssl->s3->established_session,
+                                         SSL_SESSION_INCLUDE_NONAUTH);
   if (session == NULL) {
     return 0;
   }
diff --git a/ssl/tls13_server.c b/ssl/tls13_server.c
index 3ef0c15..0278b50 100644
--- a/ssl/tls13_server.c
+++ b/ssl/tls13_server.c
@@ -495,7 +495,7 @@
 static enum ssl_hs_wait_t do_process_client_certificate_verify(
     SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (ssl->s3->new_session->x509_peer == NULL) {
+  if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0) {
     /* Skip this state. */
     hs->tls13_state = state_process_channel_id;
     return ssl_hs_ok;
diff --git a/ssl/tls_method.c b/ssl/tls_method.c
index 5533dfd..eaad2ca 100644
--- a/ssl/tls_method.c
+++ b/ssl/tls_method.c
@@ -257,3 +257,24 @@
 const SSL_METHOD *TLS_client_method(void) {
   return TLS_method();
 }
+
+static void ssl_noop_x509_clear(CERT *cert) {}
+static void ssl_noop_x509_flush_cached_leaf(CERT *cert) {}
+static void ssl_noop_x509_flush_cached_chain(CERT *cert) {}
+static int ssl_noop_x509_session_cache_objects(SSL_SESSION *sess) {
+  return 1;
+}
+static int ssl_noop_x509_session_dup(SSL_SESSION *new_session,
+                                       const SSL_SESSION *session) {
+  return 1;
+}
+static void ssl_noop_x509_session_clear(SSL_SESSION *session) {}
+
+const SSL_X509_METHOD ssl_noop_x509_method = {
+  ssl_noop_x509_clear,
+  ssl_noop_x509_flush_cached_chain,
+  ssl_noop_x509_flush_cached_leaf,
+  ssl_noop_x509_session_cache_objects,
+  ssl_noop_x509_session_dup,
+  ssl_noop_x509_session_clear,
+};