Add a bunch of scopers.

I started by switching a couple fields to SSL_HANDSHAKE and then kept
following transitive bits.

Bug: 132
Change-Id: I640dadd3558615fa38c7e8498d4efe7449b0658f
Reviewed-on: https://boringssl-review.googlesource.com/18245
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc
index 6460458..12947f0 100644
--- a/ssl/handshake_client.cc
+++ b/ssl/handshake_client.cc
@@ -152,6 +152,8 @@
 #include <assert.h>
 #include <string.h>
 
+#include <utility>
+
 #include <openssl/aead.h>
 #include <openssl/bn.h>
 #include <openssl/buf.h>
@@ -247,8 +249,8 @@
         /* Stash the early data session, so connection properties may be queried
          * out of it. */
         hs->in_early_data = 1;
-        hs->early_session = ssl->session;
         SSL_SESSION_up_ref(ssl->session);
+        hs->early_session.reset(ssl->session);
 
         hs->state = SSL3_ST_CR_SRVR_HELLO_A;
         hs->can_early_write = 1;
@@ -506,15 +508,15 @@
            * of the new established_session due to False Start. The caller may
            * have taken a reference to the temporary session. */
           ssl->s3->established_session =
-              SSL_SESSION_dup(hs->new_session, SSL_SESSION_DUP_ALL);
+              SSL_SESSION_dup(hs->new_session.get(), SSL_SESSION_DUP_ALL)
+                  .release();
           if (ssl->s3->established_session == NULL) {
             ret = -1;
             goto end;
           }
           ssl->s3->established_session->not_resumable = 0;
 
-          SSL_SESSION_free(hs->new_session);
-          hs->new_session = NULL;
+          hs->new_session.reset();
         }
 
         hs->state = SSL_ST_OK;
@@ -1099,10 +1101,10 @@
 
   uint8_t alert = SSL_AD_DECODE_ERROR;
   sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
-  EVP_PKEY_free(hs->peer_pubkey);
-  hs->peer_pubkey = NULL;
-  hs->new_session->certs = ssl_parse_cert_chain(&alert, &hs->peer_pubkey, NULL,
-                                                &cbs, ssl->ctx->pool);
+  hs->peer_pubkey.reset();
+  hs->new_session->certs =
+      ssl_parse_cert_chain(&alert, &hs->peer_pubkey, NULL, &cbs, ssl->ctx->pool)
+          .release();
   if (hs->new_session->certs == NULL) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     return -1;
@@ -1110,14 +1112,14 @@
 
   if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0 ||
       CBS_len(&cbs) != 0 ||
-      !ssl->ctx->x509_method->session_cache_objects(hs->new_session)) {
+      !ssl->ctx->x509_method->session_cache_objects(hs->new_session.get())) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     return -1;
   }
 
   if (!ssl_check_leaf_certificate(
-          hs, hs->peer_pubkey,
+          hs, hs->peer_pubkey.get(),
           sk_CRYPTO_BUFFER_value(hs->new_session->certs, 0))) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
     return -1;
@@ -1255,12 +1257,14 @@
      * (omit ServerKeyExchange) or an empty hint, while ECDHE_PSK can only spell
      * empty hint. Having different capabilities is odd, so we interpret empty
      * and missing as identical. */
+    char *raw = nullptr;
     if (CBS_len(&psk_identity_hint) != 0 &&
-        !CBS_strdup(&psk_identity_hint, &hs->peer_psk_identity_hint)) {
+        !CBS_strdup(&psk_identity_hint, &raw)) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
       return -1;
     }
+    hs->peer_psk_identity_hint.reset(raw);
   }
 
   if (alg_k & SSL_kECDHE) {
@@ -1319,7 +1323,7 @@
       }
       hs->new_session->peer_signature_algorithm = signature_algorithm;
     } else if (!tls1_get_legacy_signature_algorithm(&signature_algorithm,
-                                                    hs->peer_pubkey)) {
+                                                    hs->peer_pubkey.get())) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_CERTIFICATE);
       return -1;
@@ -1353,7 +1357,7 @@
 
     int sig_ok = ssl_public_key_verify(
         ssl, CBS_data(&signature), CBS_len(&signature), signature_algorithm,
-        hs->peer_pubkey, transcript_data, transcript_len);
+        hs->peer_pubkey.get(), transcript_data, transcript_len);
     OPENSSL_free(transcript_data);
 
 #if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
@@ -1427,23 +1431,21 @@
   }
 
   uint8_t alert = SSL_AD_DECODE_ERROR;
-  STACK_OF(CRYPTO_BUFFER) *ca_names =
+  UniquePtr<STACK_OF(CRYPTO_BUFFER)> ca_names =
       ssl_parse_client_CA_list(ssl, &alert, &cbs);
-  if (ca_names == NULL) {
+  if (!ca_names) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     return -1;
   }
 
   if (CBS_len(&cbs) != 0) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-    sk_CRYPTO_BUFFER_pop_free(ca_names, CRYPTO_BUFFER_free);
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     return -1;
   }
 
   hs->cert_request = 1;
-  sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free);
-  hs->ca_names = ca_names;
+  hs->ca_names = std::move(ca_names);
   ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
   return 1;
 }
@@ -1536,8 +1538,8 @@
     char identity[PSK_MAX_IDENTITY_LEN + 1];
     OPENSSL_memset(identity, 0, sizeof(identity));
     psk_len =
-        ssl->psk_client_callback(ssl, hs->peer_psk_identity_hint, identity,
-                                 sizeof(identity), psk, sizeof(psk));
+        ssl->psk_client_callback(ssl, hs->peer_psk_identity_hint.get(),
+                                 identity, sizeof(identity), psk, sizeof(psk));
     if (psk_len == 0) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND);
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
@@ -1571,7 +1573,7 @@
       goto err;
     }
 
-    RSA *rsa = EVP_PKEY_get0_RSA(hs->peer_pubkey);
+    RSA *rsa = EVP_PKEY_get0_RSA(hs->peer_pubkey.get());
     if (rsa == NULL) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
       goto err;
@@ -1712,7 +1714,7 @@
   }
 
   /* Set aside space for the signature. */
-  const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey);
+  const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey.get());
   uint8_t *ptr;
   if (!CBB_add_u16_length_prefixed(&body, &child) ||
       !CBB_reserve(&child, &ptr, max_sig_len)) {
@@ -1730,9 +1732,9 @@
 
     uint8_t digest[EVP_MAX_MD_SIZE];
     size_t digest_len;
-    if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(&hs->transcript, digest,
-                                              &digest_len, hs->new_session,
-                                              signature_algorithm)) {
+    if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(
+            &hs->transcript, digest, &digest_len, hs->new_session.get(),
+            signature_algorithm)) {
       return -1;
     }
 
@@ -1842,14 +1844,14 @@
     return 1;
   }
 
-  SSL_SESSION *session = hs->new_session;
+  SSL_SESSION *session = hs->new_session.get();
   UniquePtr<SSL_SESSION> renewed_session;
   if (ssl->session != NULL) {
     /* The server is sending a new ticket for an existing session. Sessions are
      * immutable once established, so duplicate all but the ticket of the
      * existing session. */
-    renewed_session.reset(
-        SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH));
+    renewed_session =
+        SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH);
     if (!renewed_session) {
       /* This should never happen. */
       OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc
index 397f071..48d3426 100644
--- a/ssl/handshake_server.cc
+++ b/ssl/handshake_server.cc
@@ -430,7 +430,7 @@
             ssl->retain_only_sha256_of_client_certs) {
           sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
           hs->new_session->certs = NULL;
-          ssl->ctx->x509_method->session_clear(hs->new_session);
+          ssl->ctx->x509_method->session_clear(hs->new_session.get());
         }
 
         SSL_SESSION_free(ssl->s3->established_session);
@@ -438,9 +438,8 @@
           SSL_SESSION_up_ref(ssl->session);
           ssl->s3->established_session = ssl->session;
         } else {
-          ssl->s3->established_session = hs->new_session;
+          ssl->s3->established_session = hs->new_session.release();
           ssl->s3->established_session->not_resumable = 0;
-          hs->new_session = NULL;
         }
 
         ssl->s3->initial_handshake_complete = 1;
@@ -605,8 +604,8 @@
   uint32_t mask_a = 0;
 
   if (ssl_has_certificate(ssl)) {
-    mask_a |= ssl_cipher_auth_mask_for_key(hs->local_pubkey);
-    if (EVP_PKEY_id(hs->local_pubkey) == EVP_PKEY_RSA) {
+    mask_a |= ssl_cipher_auth_mask_for_key(hs->local_pubkey.get());
+    if (EVP_PKEY_id(hs->local_pubkey.get()) == EVP_PKEY_RSA) {
       mask_k |= SSL_kRSA;
     }
   }
@@ -895,7 +894,7 @@
     /* On new sessions, stash the SNI value in the session. */
     if (hs->hostname != NULL) {
       OPENSSL_free(hs->new_session->tlsext_hostname);
-      hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname);
+      hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname.get());
       if (hs->new_session->tlsext_hostname == NULL) {
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
         return -1;
@@ -977,7 +976,7 @@
   /* TODO(davidben): Implement the TLS 1.1 and 1.2 downgrade sentinels once TLS
    * 1.3 is finalized and we are not implementing a draft version. */
 
-  const SSL_SESSION *session = hs->new_session;
+  const SSL_SESSION *session = hs->new_session.get();
   if (ssl->session != NULL) {
     session = ssl->session;
   }
@@ -1121,7 +1120,7 @@
     }
 
     /* Add space for the signature. */
-    const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey);
+    const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey.get());
     uint8_t *ptr;
     if (!CBB_add_u16_length_prefixed(&body, &child) ||
         !CBB_reserve(&child, &ptr, max_sig_len)) {
@@ -1229,21 +1228,22 @@
   CBS_init(&certificate_msg, ssl->init_msg, ssl->init_num);
 
   sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
-  EVP_PKEY_free(hs->peer_pubkey);
-  hs->peer_pubkey = NULL;
+  hs->peer_pubkey.reset();
   uint8_t alert = SSL_AD_DECODE_ERROR;
-  hs->new_session->certs = ssl_parse_cert_chain(
-      &alert, &hs->peer_pubkey,
-      ssl->retain_only_sha256_of_client_certs ? hs->new_session->peer_sha256
-                                              : NULL,
-      &certificate_msg, ssl->ctx->pool);
+  hs->new_session->certs =
+      ssl_parse_cert_chain(&alert, &hs->peer_pubkey,
+                           ssl->retain_only_sha256_of_client_certs
+                               ? hs->new_session->peer_sha256
+                               : NULL,
+                           &certificate_msg, ssl->ctx->pool)
+          .release();
   if (hs->new_session->certs == NULL) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     return -1;
   }
 
   if (CBS_len(&certificate_msg) != 0 ||
-      !ssl->ctx->x509_method->session_cache_objects(hs->new_session)) {
+      !ssl->ctx->x509_method->session_cache_objects(hs->new_session.get())) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     return -1;
@@ -1348,7 +1348,7 @@
     }
 
     /* Allocate a buffer large enough for an RSA decryption. */
-    const size_t rsa_size = EVP_PKEY_size(hs->local_pubkey);
+    const size_t rsa_size = EVP_PKEY_size(hs->local_pubkey.get());
     decrypt_buf = (uint8_t *)OPENSSL_malloc(rsa_size);
     if (decrypt_buf == NULL) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
@@ -1539,7 +1539,7 @@
   /* Only RSA and ECDSA client certificates are supported, so a
    * CertificateVerify is required if and only if there's a client certificate.
    * */
-  if (hs->peer_pubkey == NULL) {
+  if (!hs->peer_pubkey) {
     SSL_TRANSCRIPT_free_buffer(&hs->transcript);
     return 1;
   }
@@ -1570,7 +1570,7 @@
     }
     hs->new_session->peer_signature_algorithm = signature_algorithm;
   } else if (!tls1_get_legacy_signature_algorithm(&signature_algorithm,
-                                                  hs->peer_pubkey)) {
+                                                  hs->peer_pubkey.get())) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_CERTIFICATE);
     return -1;
@@ -1590,13 +1590,14 @@
   if (ssl3_protocol_version(ssl) == SSL3_VERSION) {
     uint8_t digest[EVP_MAX_MD_SIZE];
     size_t digest_len;
-    if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(&hs->transcript, digest,
-                                              &digest_len, hs->new_session,
-                                              signature_algorithm)) {
+    if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(
+            &hs->transcript, digest, &digest_len, hs->new_session.get(),
+            signature_algorithm)) {
       return -1;
     }
 
-    UniquePtr<EVP_PKEY_CTX> pctx(EVP_PKEY_CTX_new(hs->peer_pubkey, NULL));
+    UniquePtr<EVP_PKEY_CTX> pctx(
+        EVP_PKEY_CTX_new(hs->peer_pubkey.get(), nullptr));
     sig_ok = pctx &&
              EVP_PKEY_verify_init(pctx.get()) &&
              EVP_PKEY_verify(pctx.get(), CBS_data(&signature),
@@ -1604,7 +1605,7 @@
   } else {
     sig_ok = ssl_public_key_verify(
         ssl, CBS_data(&signature), CBS_len(&signature), signature_algorithm,
-        hs->peer_pubkey, (const uint8_t *)hs->transcript.buffer->data,
+        hs->peer_pubkey.get(), (const uint8_t *)hs->transcript.buffer->data,
         hs->transcript.buffer->length);
   }
 
@@ -1684,13 +1685,12 @@
     UniquePtr<SSL_SESSION> session_copy;
     if (ssl->session == NULL) {
       /* Fix the timeout to measure from the ticket issuance time. */
-      ssl_session_rebase_time(ssl, hs->new_session);
-      session = hs->new_session;
+      ssl_session_rebase_time(ssl, hs->new_session.get());
+      session = hs->new_session.get();
     } else {
       /* We are renewing an existing session. Duplicate the session to adjust
        * the timeout. */
-      session_copy.reset(
-          SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH));
+      session_copy = SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH);
       if (!session_copy) {
         return -1;
       }
diff --git a/ssl/internal.h b/ssl/internal.h
index 74f20f3..160247a 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -935,19 +935,17 @@
 
 /* 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
- * |*out_alert| to an alert to send to the peer.
+ * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns nullptr and
+ * sets |*out_alert| to an alert to send to the peer.
  *
  * If the list is non-empty then |*out_pubkey| will be set to a freshly
  * allocated public-key from the leaf certificate.
  *
  * 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(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert,
-                                              EVP_PKEY **out_pubkey,
-                                              uint8_t *out_leaf_sha256,
-                                              CBS *cbs,
-                                              CRYPTO_BUFFER_POOL *pool);
+UniquePtr<STACK_OF(CRYPTO_BUFFER)> ssl_parse_cert_chain(
+    uint8_t *out_alert, UniquePtr<EVP_PKEY> *out_pubkey,
+    uint8_t *out_leaf_sha256, CBS *cbs, CRYPTO_BUFFER_POOL *pool);
 
 /* ssl_add_cert_chain adds |ssl|'s certificate chain to |cbb| in the format used
  * by a TLS Certificate message. If there is no certificate chain, it emits an
@@ -961,16 +959,17 @@
 int ssl_cert_check_digital_signature_key_usage(const CBS *in);
 
 /* ssl_cert_parse_pubkey extracts the public key from the DER-encoded, X.509
- * certificate in |in|. It returns an allocated |EVP_PKEY| or else returns NULL
- * and pushes to the error queue. */
-EVP_PKEY *ssl_cert_parse_pubkey(const CBS *in);
+ * certificate in |in|. It returns an allocated |EVP_PKEY| or else returns
+ * nullptr and pushes to the error queue. */
+UniquePtr<EVP_PKEY> ssl_cert_parse_pubkey(const CBS *in);
 
 /* ssl_parse_client_CA_list parses a CA list from |cbs| in the format used by a
  * TLS CertificateRequest message. On success, it returns a newly-allocated
- * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns NULL and sets
- * |*out_alert| to an alert to send to the peer. */
-STACK_OF(CRYPTO_BUFFER) *
-    ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs);
+ * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns nullptr and
+ * sets |*out_alert| to an alert to send to the peer. */
+UniquePtr<STACK_OF(CRYPTO_BUFFER)> ssl_parse_client_CA_list(SSL *ssl,
+                                                            uint8_t *out_alert,
+                                                            CBS *cbs);
 
 /* ssl_add_client_CA_list adds the configured CA list to |cbb| in the format
  * used by a TLS CertificateRequest message. It returns one on success and zero
@@ -1194,11 +1193,11 @@
 
   /* peer_psk_identity_hint, on the client, is the psk_identity_hint sent by the
    * server when using a TLS 1.2 PSK key exchange. */
-  char *peer_psk_identity_hint = nullptr;
+  UniquePtr<char> peer_psk_identity_hint;
 
   /* ca_names, on the client, contains the list of CAs received in a
    * CertificateRequest message. */
-  STACK_OF(CRYPTO_BUFFER) *ca_names = nullptr;
+  UniquePtr<STACK_OF(CRYPTO_BUFFER)> ca_names;
 
   /* cached_x509_ca_names contains a cache of parsed versions of the elements
    * of |ca_names|. */
@@ -1210,21 +1209,21 @@
   size_t num_certificate_types = 0;
 
   /* hostname, on the server, is the value of the SNI extension. */
-  char *hostname = nullptr;
+  UniquePtr<char> hostname;
 
   /* local_pubkey is the public key we are authenticating as. */
-  EVP_PKEY *local_pubkey = nullptr;
+  UniquePtr<EVP_PKEY> local_pubkey;
 
   /* peer_pubkey is the public key parsed from the peer's leaf certificate. */
-  EVP_PKEY *peer_pubkey = nullptr;
+  UniquePtr<EVP_PKEY> peer_pubkey;
 
   /* new_session is the new mutable session being established by the current
    * handshake. It should not be cached. */
-  SSL_SESSION *new_session = nullptr;
+  UniquePtr<SSL_SESSION> new_session;
 
   /* early_session is the session corresponding to the current 0-RTT state on
    * the client if |in_early_data| is true. */
-  SSL_SESSION *early_session = nullptr;
+  UniquePtr<SSL_SESSION> early_session;
 
   /* new_cipher is the cipher being negotiated in this handshake. */
   const SSL_CIPHER *new_cipher = nullptr;
@@ -2048,14 +2047,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
+/* ssl_session_new returns a newly-allocated blank |SSL_SESSION| or nullptr on
  * error. */
-SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method);
+UniquePtr<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);
+UniquePtr<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. */
@@ -2104,10 +2104,10 @@
   (SSL_SESSION_INCLUDE_TICKET | SSL_SESSION_INCLUDE_NONAUTH)
 
 /* SSL_SESSION_dup returns a newly-allocated |SSL_SESSION| with a copy of the
- * fields in |session| or NULL on error. The new session is non-resumable and
+ * fields in |session| or nullptr on error. The new session is non-resumable and
  * must be explicitly marked resumable once it has been filled in. */
-OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session,
-                                            int dup_flags);
+OPENSSL_EXPORT UniquePtr<SSL_SESSION> SSL_SESSION_dup(SSL_SESSION *session,
+                                                      int dup_flags);
 
 /* ssl_session_rebase_time updates |session|'s start time to the current time,
  * adjusting the timeout so the expiration time is unchanged. */
diff --git a/ssl/s3_both.cc b/ssl/s3_both.cc
index ae0022b..3423234 100644
--- a/ssl/s3_both.cc
+++ b/ssl/s3_both.cc
@@ -167,14 +167,10 @@
   OPENSSL_free(cookie);
   OPENSSL_free(key_share_bytes);
   OPENSSL_free(ecdh_public_key);
-  SSL_SESSION_free(new_session);
-  SSL_SESSION_free(early_session);
   OPENSSL_free(peer_sigalgs);
   OPENSSL_free(peer_supported_group_list);
   OPENSSL_free(peer_key);
   OPENSSL_free(server_params);
-  OPENSSL_free(peer_psk_identity_hint);
-  sk_CRYPTO_BUFFER_pop_free(ca_names, CRYPTO_BUFFER_free);
   ssl->ctx->x509_method->hs_flush_cached_ca_names(this);
   OPENSSL_free(certificate_types);
 
@@ -182,10 +178,6 @@
     OPENSSL_cleanse(key_block, key_block_len);
     OPENSSL_free(key_block);
   }
-
-  OPENSSL_free(hostname);
-  EVP_PKEY_free(peer_pubkey);
-  EVP_PKEY_free(local_pubkey);
 }
 
 SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl) {
@@ -855,8 +847,8 @@
         break;
     }
   } else {
-    ret = ssl->ctx->x509_method->session_verify_cert_chain(hs->new_session, ssl,
-                                                           &alert)
+    ret = ssl->ctx->x509_method->session_verify_cert_chain(
+              hs->new_session.get(), ssl, &alert)
               ? ssl_verify_ok
               : ssl_verify_invalid;
   }
diff --git a/ssl/ssl_asn1.cc b/ssl/ssl_asn1.cc
index 887606a..d360a7a 100644
--- a/ssl/ssl_asn1.cc
+++ b/ssl/ssl_asn1.cc
@@ -522,11 +522,12 @@
   return 1;
 }
 
-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;
+UniquePtr<SSL_SESSION> SSL_SESSION_parse(CBS *cbs,
+                                         const SSL_X509_METHOD *x509_method,
+                                         CRYPTO_BUFFER_POOL *pool) {
+  UniquePtr<SSL_SESSION> ret = ssl_session_new(x509_method);
+  if (!ret) {
+    return nullptr;
   }
 
   CBS session;
@@ -543,7 +544,7 @@
       ssl_version > UINT16_MAX ||
       !ssl_protocol_version_from_wire(&unused, ssl_version)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
+    return nullptr;
   }
   ret->ssl_version = ssl_version;
 
@@ -553,12 +554,12 @@
       !CBS_get_u16(&cipher, &cipher_value) ||
       CBS_len(&cipher) != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
+    return nullptr;
   }
   ret->cipher = SSL_get_cipher_by_value(cipher_value);
   if (ret->cipher == NULL) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_CIPHER);
-    goto err;
+    return nullptr;
   }
 
   CBS session_id, master_key;
@@ -567,7 +568,7 @@
       !CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING) ||
       CBS_len(&master_key) > SSL_MAX_MASTER_KEY_LENGTH) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
+    return nullptr;
   }
   OPENSSL_memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id));
   ret->session_id_length = CBS_len(&session_id);
@@ -582,7 +583,7 @@
       !CBS_get_asn1_uint64(&child, &timeout) ||
       timeout > UINT32_MAX) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
+    return nullptr;
   }
 
   ret->timeout = (uint32_t)timeout;
@@ -592,7 +593,7 @@
   if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag) ||
       (has_peer && CBS_len(&peer) == 0)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
+    return nullptr;
   }
   /* |peer| is processed with the certificate chain. */
 
@@ -609,7 +610,7 @@
                              kTicketLifetimeHintTag, 0) ||
       !SSL_SESSION_parse_octet_string(&session, &ret->tlsext_tick,
                                       &ret->tlsext_ticklen, kTicketTag)) {
-    goto err;
+    return nullptr;
   }
 
   if (CBS_peek_asn1_tag(&session, kPeerSHA256Tag)) {
@@ -619,7 +620,7 @@
         CBS_len(&peer_sha256) != sizeof(ret->peer_sha256) ||
         CBS_len(&child) != 0) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-      goto err;
+      return nullptr;
     }
     OPENSSL_memcpy(ret->peer_sha256, CBS_data(&peer_sha256),
                    sizeof(ret->peer_sha256));
@@ -639,7 +640,7 @@
       !SSL_SESSION_parse_octet_string(
           &session, &ret->ocsp_response, &ret->ocsp_response_length,
           kOCSPResponseTag)) {
-    goto err;
+    return nullptr;
   }
 
   int extended_master_secret;
@@ -647,13 +648,13 @@
                                   kExtendedMasterSecretTag,
                                   0 /* default to false */)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
+    return nullptr;
   }
   ret->extended_master_secret = !!extended_master_secret;
 
   if (!SSL_SESSION_parse_u16(&session, &ret->group_id, kGroupIDTag, 0)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
+    return nullptr;
   }
 
   CBS cert_chain;
@@ -663,17 +664,17 @@
                              kCertChainTag) ||
       (has_cert_chain && CBS_len(&cert_chain) == 0)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
+    return nullptr;
   }
   if (has_cert_chain && !has_peer) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
+    return nullptr;
   }
   if (has_peer || has_cert_chain) {
     ret->certs = sk_CRYPTO_BUFFER_new_null();
     if (ret->certs == NULL) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-      goto err;
+      return nullptr;
     }
 
     if (has_peer) {
@@ -683,7 +684,7 @@
           !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
         CRYPTO_BUFFER_free(buffer);
         OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-        goto err;
+        return nullptr;
       }
     }
 
@@ -692,7 +693,7 @@
       if (!CBS_get_any_asn1_element(&cert_chain, &cert, NULL, NULL) ||
           CBS_len(&cert) == 0) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-        goto err;
+        return nullptr;
       }
 
       /* TODO(agl): this should use the |SSL_CTX|'s pool. */
@@ -701,14 +702,14 @@
           !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
         CRYPTO_BUFFER_free(buffer);
         OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-        goto err;
+        return nullptr;
       }
     }
   }
 
-  if (!x509_method->session_cache_objects(ret)) {
+  if (!x509_method->session_cache_objects(ret.get())) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
+    return nullptr;
   }
 
   CBS age_add;
@@ -718,7 +719,7 @@
       (age_add_present &&
        !CBS_get_u32(&age_add, &ret->ticket_age_add)) ||
       CBS_len(&age_add) != 0) {
-    goto err;
+    return nullptr;
   }
   ret->ticket_age_add_valid = age_add_present;
 
@@ -726,7 +727,7 @@
   if (!CBS_get_optional_asn1_bool(&session, &is_server, kIsServerTag,
                                   1 /* default to true */)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
+    return nullptr;
   }
   /* TODO: in time we can include |is_server| for servers too, then we can
      enforce that client and server sessions are never mixed up. */
@@ -743,14 +744,10 @@
                                       &ret->early_alpn_len, kEarlyALPNTag) ||
       CBS_len(&session) != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
+    return nullptr;
   }
 
   return ret;
-
-err:
-  SSL_SESSION_free(ret);
-  return NULL;
 }
 
 }  // namespace bssl
@@ -810,14 +807,14 @@
                                     const SSL_CTX *ctx) {
   CBS cbs;
   CBS_init(&cbs, in, in_len);
-  SSL_SESSION *ret = SSL_SESSION_parse(&cbs, ctx->x509_method, ctx->pool);
-  if (ret == NULL) {
+  UniquePtr<SSL_SESSION> ret =
+      SSL_SESSION_parse(&cbs, ctx->x509_method, ctx->pool);
+  if (!ret) {
     return NULL;
   }
   if (CBS_len(&cbs) != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    SSL_SESSION_free(ret);
     return NULL;
   }
-  return ret;
+  return ret.release();
 }
diff --git a/ssl/ssl_cert.cc b/ssl/ssl_cert.cc
index caa4801..4f457f6 100644
--- a/ssl/ssl_cert.cc
+++ b/ssl/ssl_cert.cc
@@ -118,6 +118,8 @@
 #include <limits.h>
 #include <string.h>
 
+#include <utility>
+
 #include <openssl/bn.h>
 #include <openssl/buf.h>
 #include <openssl/bytestring.h>
@@ -254,19 +256,17 @@
  * |leaf_cert_and_privkey_ok|. */
 static enum leaf_cert_and_privkey_result_t check_leaf_cert_and_privkey(
     CRYPTO_BUFFER *leaf_buffer, EVP_PKEY *privkey) {
-  enum leaf_cert_and_privkey_result_t ret = leaf_cert_and_privkey_error;
-
   CBS cert_cbs;
   CRYPTO_BUFFER_init_CBS(leaf_buffer, &cert_cbs);
-  EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs);
-  if (pubkey == NULL) {
+  UniquePtr<EVP_PKEY> pubkey = ssl_cert_parse_pubkey(&cert_cbs);
+  if (!pubkey) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-    goto out;
+    return leaf_cert_and_privkey_error;
   }
 
   if (!ssl_is_key_type_supported(pubkey->type)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
-    goto out;
+    return leaf_cert_and_privkey_error;
   }
 
   /* An ECC certificate may be usable for ECDH or ECDSA. We only support ECDSA
@@ -274,22 +274,17 @@
   if (pubkey->type == EVP_PKEY_EC &&
       !ssl_cert_check_digital_signature_key_usage(&cert_cbs)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
-    goto out;
+    return leaf_cert_and_privkey_error;
   }
 
   if (privkey != NULL &&
       /* Sanity-check that the private key and the certificate match. */
-      !ssl_compare_public_and_private_key(pubkey, privkey)) {
+      !ssl_compare_public_and_private_key(pubkey.get(), privkey)) {
     ERR_clear_error();
-    ret = leaf_cert_and_privkey_mismatch;
-    goto out;
+    return leaf_cert_and_privkey_mismatch;
   }
 
-  ret = leaf_cert_and_privkey_ok;
-
-out:
-  EVP_PKEY_free(pubkey);
-  return ret;
+  return leaf_cert_and_privkey_ok;
 }
 
 static int cert_set_chain_and_key(
@@ -387,25 +382,23 @@
          ssl_has_private_key(ssl);
 }
 
-STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert,
-                                              EVP_PKEY **out_pubkey,
-                                              uint8_t *out_leaf_sha256,
-                                              CBS *cbs,
-                                              CRYPTO_BUFFER_POOL *pool) {
-  *out_pubkey = NULL;
-
-  STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null();
-  if (ret == NULL) {
+UniquePtr<STACK_OF(CRYPTO_BUFFER)>
+    ssl_parse_cert_chain(uint8_t *out_alert, UniquePtr<EVP_PKEY> *out_pubkey,
+                         uint8_t *out_leaf_sha256, CBS *cbs,
+                         CRYPTO_BUFFER_POOL *pool) {
+  UniquePtr<EVP_PKEY> pubkey;
+  UniquePtr<STACK_OF(CRYPTO_BUFFER)> ret(sk_CRYPTO_BUFFER_new_null());
+  if (!ret) {
     *out_alert = SSL_AD_INTERNAL_ERROR;
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-    return NULL;
+    return nullptr;
   }
 
   CBS certificate_list;
   if (!CBS_get_u24_length_prefixed(cbs, &certificate_list)) {
     *out_alert = SSL_AD_DECODE_ERROR;
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-    goto err;
+    return nullptr;
   }
 
   while (CBS_len(&certificate_list) > 0) {
@@ -414,14 +407,14 @@
         CBS_len(&certificate) == 0) {
       *out_alert = SSL_AD_DECODE_ERROR;
       OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
-      goto err;
+      return nullptr;
     }
 
-    if (sk_CRYPTO_BUFFER_num(ret) == 0) {
-      *out_pubkey = ssl_cert_parse_pubkey(&certificate);
-      if (*out_pubkey == NULL) {
+    if (sk_CRYPTO_BUFFER_num(ret.get()) == 0) {
+      pubkey = ssl_cert_parse_pubkey(&certificate);
+      if (!pubkey) {
         *out_alert = SSL_AD_DECODE_ERROR;
-        goto err;
+        return nullptr;
       }
 
       /* Retain the hash of the leaf certificate if requested. */
@@ -432,26 +425,17 @@
 
     CRYPTO_BUFFER *buf =
         CRYPTO_BUFFER_new_from_CBS(&certificate, pool);
-    if (buf == NULL) {
-      *out_alert = SSL_AD_DECODE_ERROR;
-      goto err;
-    }
-
-    if (!sk_CRYPTO_BUFFER_push(ret, buf)) {
+    if (buf == NULL ||
+        !sk_CRYPTO_BUFFER_push(ret.get(), buf)) {
       *out_alert = SSL_AD_INTERNAL_ERROR;
       CRYPTO_BUFFER_free(buf);
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-      goto err;
+      return nullptr;
     }
   }
 
+  *out_pubkey = std::move(pubkey);
   return ret;
-
-err:
-  EVP_PKEY_free(*out_pubkey);
-  *out_pubkey = NULL;
-  sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free);
-  return NULL;
 }
 
 int ssl_add_cert_chain(SSL *ssl, CBB *cbb) {
@@ -526,14 +510,14 @@
   return 1;
 }
 
-EVP_PKEY *ssl_cert_parse_pubkey(const CBS *in) {
+UniquePtr<EVP_PKEY> ssl_cert_parse_pubkey(const CBS *in) {
   CBS buf = *in, tbs_cert;
   if (!ssl_cert_skip_to_spki(&buf, &tbs_cert)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_CANNOT_PARSE_LEAF_CERT);
-    return NULL;
+    return nullptr;
   }
 
-  return EVP_parse_public_key(&tbs_cert);
+  return UniquePtr<EVP_PKEY>(EVP_parse_public_key(&tbs_cert));
 }
 
 int ssl_compare_public_and_private_key(const EVP_PKEY *pubkey,
@@ -581,15 +565,13 @@
 
   CBS cert_cbs;
   CRYPTO_BUFFER_init_CBS(sk_CRYPTO_BUFFER_value(cert->chain, 0), &cert_cbs);
-  EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs);
+  UniquePtr<EVP_PKEY> pubkey = ssl_cert_parse_pubkey(&cert_cbs);
   if (!pubkey) {
     OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE);
     return 0;
   }
 
-  const int ok = ssl_compare_public_and_private_key(pubkey, privkey);
-  EVP_PKEY_free(pubkey);
-  return ok;
+  return ssl_compare_public_and_private_key(pubkey.get(), privkey);
 }
 
 int ssl_cert_check_digital_signature_key_usage(const CBS *in) {
@@ -669,22 +651,23 @@
   return 0;
 }
 
-STACK_OF(CRYPTO_BUFFER) *
-    ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs) {
+UniquePtr<STACK_OF(CRYPTO_BUFFER)> ssl_parse_client_CA_list(SSL *ssl,
+                                                            uint8_t *out_alert,
+                                                            CBS *cbs) {
   CRYPTO_BUFFER_POOL *const pool = ssl->ctx->pool;
 
-  STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null();
-  if (ret == NULL) {
+  UniquePtr<STACK_OF(CRYPTO_BUFFER)> ret(sk_CRYPTO_BUFFER_new_null());
+  if (!ret) {
     *out_alert = SSL_AD_INTERNAL_ERROR;
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-    return NULL;
+    return nullptr;
   }
 
   CBS child;
   if (!CBS_get_u16_length_prefixed(cbs, &child)) {
     *out_alert = SSL_AD_DECODE_ERROR;
     OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH);
-    goto err;
+    return nullptr;
   }
 
   while (CBS_len(&child) > 0) {
@@ -692,31 +675,27 @@
     if (!CBS_get_u16_length_prefixed(&child, &distinguished_name)) {
       *out_alert = SSL_AD_DECODE_ERROR;
       OPENSSL_PUT_ERROR(SSL, SSL_R_CA_DN_TOO_LONG);
-      goto err;
+      return nullptr;
     }
 
     CRYPTO_BUFFER *buffer =
         CRYPTO_BUFFER_new_from_CBS(&distinguished_name, pool);
     if (buffer == NULL ||
-        !sk_CRYPTO_BUFFER_push(ret, buffer)) {
+        !sk_CRYPTO_BUFFER_push(ret.get(), buffer)) {
       CRYPTO_BUFFER_free(buffer);
       *out_alert = SSL_AD_INTERNAL_ERROR;
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-      goto err;
+      return nullptr;
     }
   }
 
-  if (!ssl->ctx->x509_method->check_client_CA_list(ret)) {
+  if (!ssl->ctx->x509_method->check_client_CA_list(ret.get())) {
     *out_alert = SSL_AD_INTERNAL_ERROR;
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-    goto err;
+    return nullptr;
   }
 
   return ret;
-
-err:
-  sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free);
-  return NULL;
 }
 
 int ssl_add_client_CA_list(SSL *ssl, CBB *cbb) {
@@ -801,7 +780,6 @@
   CBS leaf;
   CRYPTO_BUFFER_init_CBS(sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0), &leaf);
 
-  EVP_PKEY_free(hs->local_pubkey);
   hs->local_pubkey = ssl_cert_parse_pubkey(&leaf);
   return hs->local_pubkey != NULL;
 }
@@ -869,7 +847,7 @@
   if (ssl->s3->hs == NULL) {
     return NULL;
   }
-  return ssl->s3->hs->ca_names;
+  return ssl->s3->hs->ca_names.get();
 }
 
 static int set_signed_cert_timestamp_list(CERT *cert, const uint8_t *list,
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index 28e6cc0..8e7bd88 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -1085,8 +1085,7 @@
 
   hs->wait = ssl_hs_ok;
   hs->in_early_data = 0;
-  SSL_SESSION_free(hs->early_session);
-  hs->early_session = NULL;
+  hs->early_session.reset();
 
   /* Discard any unfinished writes from the perspective of |SSL_write|'s
    * retry. The handshake will transparently flush out the pending record
@@ -1730,7 +1729,7 @@
 
   /* During the handshake, report the handshake value. */
   if (ssl->s3->hs != NULL) {
-    return ssl->s3->hs->hostname;
+    return ssl->s3->hs->hostname.get();
   }
 
   /* SSL_get_servername may also be called after the handshake to look up the
diff --git a/ssl/ssl_privkey.cc b/ssl/ssl_privkey.cc
index 0660714..3e3fa94 100644
--- a/ssl/ssl_privkey.cc
+++ b/ssl/ssl_privkey.cc
@@ -288,7 +288,7 @@
 int ssl_private_key_supports_signature_algorithm(SSL_HANDSHAKE *hs,
                                                  uint16_t sigalg) {
   SSL *const ssl = hs->ssl;
-  if (!pkey_supports_algorithm(ssl, hs->local_pubkey, sigalg)) {
+  if (!pkey_supports_algorithm(ssl, hs->local_pubkey.get(), sigalg)) {
     return 0;
   }
 
@@ -299,9 +299,8 @@
    * SHA-512. 1024-bit RSA is sometimes used for test credentials, so check the
    * size so that we can fall back to another algorithm in that case. */
   const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg);
-  if (alg->is_rsa_pss &&
-      (size_t)EVP_PKEY_size(hs->local_pubkey) <
-          2 * EVP_MD_size(alg->digest_func()) + 2) {
+  if (alg->is_rsa_pss && (size_t)EVP_PKEY_size(hs->local_pubkey.get()) <
+                             2 * EVP_MD_size(alg->digest_func()) + 2) {
     return 0;
   }
 
diff --git a/ssl/ssl_session.cc b/ssl/ssl_session.cc
index f065292..02d6422 100644
--- a/ssl/ssl_session.cc
+++ b/ssl/ssl_session.cc
@@ -139,6 +139,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <utility>
+
 #include <openssl/err.h>
 #include <openssl/lhash.h>
 #include <openssl/mem.h>
@@ -162,13 +164,14 @@
 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(const SSL_X509_METHOD *x509_method) {
-  SSL_SESSION *session = (SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION));
-  if (session == NULL) {
+UniquePtr<SSL_SESSION> ssl_session_new(const SSL_X509_METHOD *x509_method) {
+  UniquePtr<SSL_SESSION> session(
+      (SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION)));
+  if (!session) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     return 0;
   }
-  OPENSSL_memset(session, 0, sizeof(SSL_SESSION));
+  OPENSSL_memset(session.get(), 0, sizeof(SSL_SESSION));
 
   session->x509_method = x509_method;
   session->verify_result = X509_V_ERR_INVALID_CALL;
@@ -180,10 +183,10 @@
   return session;
 }
 
-SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) {
-  SSL_SESSION *new_session = ssl_session_new(session->x509_method);
-  if (new_session == NULL) {
-    goto err;
+UniquePtr<SSL_SESSION> SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) {
+  UniquePtr<SSL_SESSION> new_session = ssl_session_new(session->x509_method);
+  if (!new_session) {
+    return nullptr;
   }
 
   new_session->is_server = session->is_server;
@@ -201,25 +204,25 @@
   if (session->psk_identity != NULL) {
     new_session->psk_identity = BUF_strdup(session->psk_identity);
     if (new_session->psk_identity == NULL) {
-      goto err;
+      return nullptr;
     }
   }
   if (session->certs != NULL) {
     new_session->certs = sk_CRYPTO_BUFFER_new_null();
     if (new_session->certs == NULL) {
-      goto err;
+      return nullptr;
     }
     for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(session->certs); i++) {
       CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(session->certs, i);
       if (!sk_CRYPTO_BUFFER_push(new_session->certs, buffer)) {
-        goto err;
+        return nullptr;
       }
       CRYPTO_BUFFER_up_ref(buffer);
     }
   }
 
-  if (!session->x509_method->session_dup(new_session, session)) {
-    goto err;
+  if (!session->x509_method->session_dup(new_session.get(), session)) {
+    return nullptr;
   }
 
   new_session->verify_result = session->verify_result;
@@ -229,7 +232,7 @@
     new_session->ocsp_response = (uint8_t *)BUF_memdup(
         session->ocsp_response, session->ocsp_response_length);
     if (new_session->ocsp_response == NULL) {
-      goto err;
+      return nullptr;
     }
   }
 
@@ -240,7 +243,7 @@
         session->tlsext_signed_cert_timestamp_list,
         session->tlsext_signed_cert_timestamp_list_length);
     if (new_session->tlsext_signed_cert_timestamp_list == NULL) {
-      goto err;
+      return nullptr;
     }
   }
 
@@ -251,7 +254,7 @@
   if (session->tlsext_hostname != NULL) {
     new_session->tlsext_hostname = BUF_strdup(session->tlsext_hostname);
     if (new_session->tlsext_hostname == NULL) {
-      goto err;
+      return nullptr;
     }
   }
 
@@ -283,7 +286,7 @@
       new_session->early_alpn =
           (uint8_t *)BUF_memdup(session->early_alpn, session->early_alpn_len);
       if (new_session->early_alpn == NULL) {
-        goto err;
+        return nullptr;
       }
     }
     new_session->early_alpn_len = session->early_alpn_len;
@@ -295,7 +298,7 @@
       new_session->tlsext_tick =
           (uint8_t *)BUF_memdup(session->tlsext_tick, session->tlsext_ticklen);
       if (new_session->tlsext_tick == NULL) {
-        goto err;
+        return nullptr;
       }
     }
     new_session->tlsext_ticklen = session->tlsext_ticklen;
@@ -305,11 +308,6 @@
 
   new_session->not_resumable = 1;
   return new_session;
-
-err:
-  SSL_SESSION_free(new_session);
-  OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-  return 0;
 }
 
 void ssl_session_rebase_time(SSL *ssl, SSL_SESSION *session) {
@@ -381,7 +379,7 @@
     return 0;
   }
 
-  SSL_SESSION *session = ssl_session_new(ssl->ctx->x509_method);
+  UniquePtr<SSL_SESSION> session = ssl_session_new(ssl->ctx->x509_method);
   if (session == NULL) {
     return 0;
   }
@@ -415,7 +413,7 @@
     } else {
       session->session_id_length = SSL3_SSL_SESSION_ID_LENGTH;
       if (!RAND_bytes(session->session_id, session->session_id_length)) {
-        goto err;
+        return 0;
       }
     }
   } else {
@@ -424,7 +422,7 @@
 
   if (ssl->cert->sid_ctx_length > sizeof(session->sid_ctx)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-    goto err;
+    return 0;
   }
   OPENSSL_memcpy(session->sid_ctx, ssl->cert->sid_ctx,
                  ssl->cert->sid_ctx_length);
@@ -434,14 +432,9 @@
   session->not_resumable = 1;
   session->verify_result = X509_V_ERR_INVALID_CALL;
 
-  SSL_SESSION_free(hs->new_session);
-  hs->new_session = session;
+  hs->new_session = std::move(session);
   ssl_set_session(ssl, NULL);
   return 1;
-
-err:
-  SSL_SESSION_free(session);
-  return 0;
 }
 
 static int ssl_encrypt_ticket_with_cipher_ctx(SSL *ssl, CBB *out,
@@ -827,7 +820,7 @@
 using namespace bssl;
 
 SSL_SESSION *SSL_SESSION_new(const SSL_CTX *ctx) {
-  return ssl_session_new(ctx->x509_method);
+  return ssl_session_new(ctx->x509_method).release();
 }
 
 int SSL_SESSION_up_ref(SSL_SESSION *session) {
@@ -939,11 +932,11 @@
     return ssl->s3->established_session;
   }
   SSL_HANDSHAKE *hs = ssl->s3->hs;
-  if (hs->early_session != NULL) {
-    return hs->early_session;
+  if (hs->early_session) {
+    return hs->early_session.get();
   }
-  if (hs->new_session != NULL) {
-    return hs->new_session;
+  if (hs->new_session) {
+    return hs->new_session.get();
   }
   return ssl->session;
 }
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index 45cebd7..a57298f 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -1526,8 +1526,8 @@
                                      nullptr /* no session */));
 
   SSL_SESSION *session0 = SSL_get_session(client.get());
-  bssl::UniquePtr<SSL_SESSION> session1(
-      bssl::SSL_SESSION_dup(session0, SSL_SESSION_DUP_ALL));
+  bssl::UniquePtr<SSL_SESSION> session1 =
+      bssl::SSL_SESSION_dup(session0, SSL_SESSION_DUP_ALL);
   ASSERT_TRUE(session1);
 
   session1->not_resumable = 0;
diff --git a/ssl/ssl_x509.cc b/ssl/ssl_x509.cc
index a4d21b1..fd64308 100644
--- a/ssl/ssl_x509.cc
+++ b/ssl/ssl_x509.cc
@@ -1052,7 +1052,7 @@
 }
 
 static SSL_SESSION *ssl_session_new_with_crypto_x509(void) {
-  return ssl_session_new(&ssl_crypto_x509_method);
+  return ssl_session_new(&ssl_crypto_x509_method).release();
 }
 
 SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out) {
@@ -1075,18 +1075,18 @@
   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) {
+  UniquePtr<SSL_SESSION> ret = SSL_SESSION_parse(&cbs, &ssl_crypto_x509_method,
+                                                 NULL /* no buffer pool */);
+  if (!ret) {
     return NULL;
   }
 
   if (a) {
     SSL_SESSION_free(*a);
-    *a = ret;
+    *a = ret.get();
   }
   *pp = CBS_data(&cbs);
-  return ret;
+  return ret.release();
 }
 
 STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) {
@@ -1186,7 +1186,7 @@
    * indeterminate mode and |ssl->server| is unset. */
   if (ssl->handshake_func != NULL && !ssl->server) {
     if (ssl->s3->hs != NULL) {
-      return buffer_names_to_x509(ssl->s3->hs->ca_names,
+      return buffer_names_to_x509(ssl->s3->hs->ca_names.get(),
                                   &ssl->s3->hs->cached_x509_ca_names);
     }
 
diff --git a/ssl/t1_enc.cc b/ssl/t1_enc.cc
index af43018..4fbc6c4 100644
--- a/ssl/t1_enc.cc
+++ b/ssl/t1_enc.cc
@@ -323,8 +323,8 @@
   }
 
   SSL_SESSION *session = ssl->session;
-  if (hs->new_session != NULL) {
-    session = hs->new_session;
+  if (hs->new_session) {
+    session = hs->new_session.get();
   }
 
   const EVP_AEAD *aead = NULL;
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index 368ec39..118bc4a 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -674,10 +674,12 @@
   }
 
   /* Copy the hostname as a string. */
-  if (!CBS_strdup(&host_name, &hs->hostname)) {
+  char *hostname_raw = nullptr;
+  if (!CBS_strdup(&host_name, &hostname_raw)) {
     *out_alert = SSL_AD_INTERNAL_ERROR;
     return 0;
   }
+  hs->hostname.reset(hostname_raw);
 
   hs->should_ack_sni = 1;
   return 1;
@@ -3241,7 +3243,7 @@
   /* Before TLS 1.2, the signature algorithm isn't negotiated as part of the
    * handshake. */
   if (ssl3_protocol_version(ssl) < TLS1_2_VERSION) {
-    if (!tls1_get_legacy_signature_algorithm(out, hs->local_pubkey)) {
+    if (!tls1_get_legacy_signature_algorithm(out, hs->local_pubkey.get())) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS);
       return 0;
     }
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 20abf67..a056be0 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -1078,8 +1078,8 @@
 
 static void ssl_ctx_add_session(SSL_SESSION *session, void *void_param) {
   SSL_CTX *ctx = reinterpret_cast<SSL_CTX *>(void_param);
-  bssl::UniquePtr<SSL_SESSION> new_session(bssl::SSL_SESSION_dup(
-      session, SSL_SESSION_INCLUDE_NONAUTH | SSL_SESSION_INCLUDE_TICKET));
+  bssl::UniquePtr<SSL_SESSION> new_session = bssl::SSL_SESSION_dup(
+      session, SSL_SESSION_INCLUDE_NONAUTH | SSL_SESSION_INCLUDE_TICKET);
   if (new_session != nullptr) {
     SSL_CTX_add_session(ctx, new_session.get());
   }
diff --git a/ssl/tls13_both.cc b/ssl/tls13_both.cc
index 3bda39d..90fbf1c 100644
--- a/ssl/tls13_both.cc
+++ b/ssl/tls13_both.cc
@@ -17,6 +17,8 @@
 #include <assert.h>
 #include <string.h>
 
+#include <utility>
+
 #include <openssl/bytestring.h>
 #include <openssl/err.h>
 #include <openssl/hkdf.h>
@@ -201,24 +203,22 @@
     return 0;
   }
 
-  const int retain_sha256 =
-      ssl->server && ssl->retain_only_sha256_of_client_certs;
-  int ret = 0;
-
-  EVP_PKEY *pkey = NULL;
-  STACK_OF(CRYPTO_BUFFER) *certs = sk_CRYPTO_BUFFER_new_null();
-  if (certs == NULL) {
+  UniquePtr<STACK_OF(CRYPTO_BUFFER)> certs(sk_CRYPTO_BUFFER_new_null());
+  if (!certs) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-    goto err;
+    return 0;
   }
 
   if (!CBS_get_u24_length_prefixed(&cbs, &certificate_list)) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-    goto err;
+    return 0;
   }
 
+  const bool retain_sha256 =
+      ssl->server && ssl->retain_only_sha256_of_client_certs;
+  UniquePtr<EVP_PKEY> pkey;
   while (CBS_len(&certificate_list) > 0) {
     CBS certificate, extensions;
     if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
@@ -226,21 +226,21 @@
         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;
+      return 0;
     }
 
-    if (sk_CRYPTO_BUFFER_num(certs) == 0) {
+    if (sk_CRYPTO_BUFFER_num(certs.get()) == 0) {
       pkey = ssl_cert_parse_pubkey(&certificate);
-      if (pkey == NULL) {
+      if (!pkey) {
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
         OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-        goto err;
+        return 0;
       }
       /* TLS 1.3 always uses certificate keys for signing thus the correct
        * keyUsage is enforced. */
       if (!ssl_cert_check_digital_signature_key_usage(&certificate)) {
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-        goto err;
+        return 0;
       }
 
       if (retain_sha256) {
@@ -253,11 +253,11 @@
     CRYPTO_BUFFER *buf =
         CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool);
     if (buf == NULL ||
-        !sk_CRYPTO_BUFFER_push(certs, buf)) {
+        !sk_CRYPTO_BUFFER_push(certs.get(), buf)) {
       CRYPTO_BUFFER_free(buf);
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-      goto err;
+      return 0;
     }
 
     /* Parse out the extensions. */
@@ -273,7 +273,7 @@
                               OPENSSL_ARRAY_SIZE(ext_types),
                               0 /* reject unknown */)) {
       ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
-      goto err;
+      return 0;
     }
 
     /* All Certificate extensions are parsed, but only the leaf extensions are
@@ -282,7 +282,7 @@
       if (ssl->server || !ssl->ocsp_stapling_enabled) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
-        goto err;
+        return 0;
       }
 
       uint8_t status_type;
@@ -293,14 +293,14 @@
           CBS_len(&ocsp_response) == 0 ||
           CBS_len(&status_request) != 0) {
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-        goto err;
+        return 0;
       }
 
-      if (sk_CRYPTO_BUFFER_num(certs) == 1 &&
+      if (sk_CRYPTO_BUFFER_num(certs.get()) == 1 &&
           !CBS_stow(&ocsp_response, &hs->new_session->ocsp_response,
                     &hs->new_session->ocsp_response_length)) {
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-        goto err;
+        return 0;
       }
     }
 
@@ -308,21 +308,21 @@
       if (ssl->server || !ssl->signed_cert_timestamps_enabled) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
-        goto err;
+        return 0;
       }
 
       if (!ssl_is_sct_list_valid(&sct)) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-        goto err;
+        return 0;
       }
 
-      if (sk_CRYPTO_BUFFER_num(certs) == 1 &&
+      if (sk_CRYPTO_BUFFER_num(certs.get()) == 1 &&
           !CBS_stow(
               &sct, &hs->new_session->tlsext_signed_cert_timestamp_list,
               &hs->new_session->tlsext_signed_cert_timestamp_list_length)) {
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-        goto err;
+        return 0;
       }
     }
   }
@@ -330,28 +330,25 @@
   if (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;
+    return 0;
   }
 
-  EVP_PKEY_free(hs->peer_pubkey);
-  hs->peer_pubkey = pkey;
-  pkey = NULL;
+  hs->peer_pubkey = std::move(pkey);
 
   sk_CRYPTO_BUFFER_pop_free(hs->new_session->certs, CRYPTO_BUFFER_free);
-  hs->new_session->certs = certs;
-  certs = NULL;
+  hs->new_session->certs = certs.release();
 
-  if (!ssl->ctx->x509_method->session_cache_objects(hs->new_session)) {
+  if (!ssl->ctx->x509_method->session_cache_objects(hs->new_session.get())) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-    goto err;
+    return 0;
   }
 
   if (sk_CRYPTO_BUFFER_num(hs->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);
-      goto err;
+      return 0;
     }
 
     /* OpenSSL returns X509_V_OK when no certificates are requested. This is
@@ -359,17 +356,11 @@
     hs->new_session->verify_result = X509_V_OK;
 
     /* No certificate, so nothing more to do. */
-    ret = 1;
-    goto err;
+    return 1;
   }
 
   hs->new_session->peer_sha256_valid = retain_sha256;
-  ret = 1;
-
-err:
-  sk_CRYPTO_BUFFER_pop_free(certs, CRYPTO_BUFFER_free);
-  EVP_PKEY_free(pkey);
-  return ret;
+  return 1;
 }
 
 int tls13_process_certificate_verify(SSL_HANDSHAKE *hs) {
@@ -407,9 +398,9 @@
   }
   UniquePtr<uint8_t> free_msg(msg);
 
-  int sig_ok =
-      ssl_public_key_verify(ssl, CBS_data(&signature), CBS_len(&signature),
-                            signature_algorithm, hs->peer_pubkey, msg, msg_len);
+  int sig_ok = ssl_public_key_verify(ssl, CBS_data(&signature),
+                                     CBS_len(&signature), signature_algorithm,
+                                     hs->peer_pubkey.get(), msg, msg_len);
 #if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
   sig_ok = 1;
   ERR_clear_error();
@@ -545,7 +536,7 @@
 
   /* Sign the digest. */
   CBB child;
-  const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey);
+  const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey.get());
   uint8_t *sig;
   size_t sig_len;
   if (!CBB_add_u16_length_prefixed(&body, &child) ||
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc
index 217dd34..5f8cbe1 100644
--- a/ssl/tls13_client.cc
+++ b/ssl/tls13_client.cc
@@ -18,6 +18,8 @@
 #include <limits.h>
 #include <string.h>
 
+#include <utility>
+
 #include <openssl/bytestring.h>
 #include <openssl/digest.h>
 #include <openssl/err.h>
@@ -280,14 +282,14 @@
     ssl->s3->session_reused = 1;
     /* Only authentication information carries over in TLS 1.3. */
     hs->new_session = SSL_SESSION_dup(ssl->session, SSL_SESSION_DUP_AUTH_ONLY);
-    if (hs->new_session == NULL) {
+    if (!hs->new_session) {
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
       return ssl_hs_error;
     }
     ssl_set_session(ssl, NULL);
 
     /* Resumption incorporates fresh key material, so refresh the timeout. */
-    ssl_session_renew_timeout(ssl, hs->new_session,
+    ssl_session_renew_timeout(ssl, hs->new_session.get(),
                               ssl->session_ctx->session_psk_dhe_timeout);
   } else if (!ssl_get_new_session(hs, 0)) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
@@ -454,9 +456,9 @@
   }
 
   uint8_t alert = SSL_AD_DECODE_ERROR;
-  STACK_OF(CRYPTO_BUFFER) *ca_names =
+  UniquePtr<STACK_OF(CRYPTO_BUFFER)> ca_names =
       ssl_parse_client_CA_list(ssl, &alert, &cbs);
-  if (ca_names == NULL) {
+  if (!ca_names) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     return ssl_hs_error;
   }
@@ -466,14 +468,12 @@
   if (!CBS_get_u16_length_prefixed(&cbs, &extensions) ||
       CBS_len(&cbs) != 0) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-    sk_CRYPTO_BUFFER_pop_free(ca_names, CRYPTO_BUFFER_free);
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     return ssl_hs_error;
   }
 
   hs->cert_request = 1;
-  sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free);
-  hs->ca_names = ca_names;
+  hs->ca_names = std::move(ca_names);
   ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
 
   if (!ssl_hash_current_message(hs)) {
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
index f1c5a2d..e455d68 100644
--- a/ssl/tls13_server.cc
+++ b/ssl/tls13_server.cc
@@ -159,37 +159,36 @@
    * the client makes several connections before getting a renewal. */
   static const int kNumTickets = 2;
 
-  SSL_SESSION *session = hs->new_session;
-
   /* Rebase the session timestamp so that it is measured from ticket
    * issuance. */
-  ssl_session_rebase_time(ssl, session);
+  ssl_session_rebase_time(ssl, hs->new_session.get());
 
   for (int i = 0; i < kNumTickets; i++) {
-    if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) {
+    if (!RAND_bytes((uint8_t *)&hs->new_session->ticket_age_add, 4)) {
       return 0;
     }
-    session->ticket_age_add_valid = 1;
+    hs->new_session->ticket_age_add_valid = 1;
 
     ScopedCBB cbb;
     CBB body, ticket, extensions;
     if (!ssl->method->init_message(ssl, cbb.get(), &body,
                                    SSL3_MT_NEW_SESSION_TICKET) ||
-        !CBB_add_u32(&body, session->timeout) ||
-        !CBB_add_u32(&body, session->ticket_age_add) ||
+        !CBB_add_u32(&body, hs->new_session->timeout) ||
+        !CBB_add_u32(&body, hs->new_session->ticket_age_add) ||
         !CBB_add_u16_length_prefixed(&body, &ticket) ||
-        !ssl_encrypt_ticket(ssl, &ticket, session) ||
+        !ssl_encrypt_ticket(ssl, &ticket, hs->new_session.get()) ||
         !CBB_add_u16_length_prefixed(&body, &extensions)) {
       return 0;
     }
 
     if (ssl->cert->enable_early_data) {
-      session->ticket_max_early_data = kMaxEarlyDataAccepted;
+      hs->new_session->ticket_max_early_data = kMaxEarlyDataAccepted;
 
       CBB early_data_info;
       if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) ||
           !CBB_add_u16_length_prefixed(&extensions, &early_data_info) ||
-          !CBB_add_u32(&early_data_info, session->ticket_max_early_data) ||
+          !CBB_add_u32(&early_data_info,
+                       hs->new_session->ticket_max_early_data) ||
           !CBB_flush(&extensions)) {
         return 0;
       }
@@ -394,7 +393,7 @@
       ssl->s3->session_reused = 1;
 
       /* Resumption incorporates fresh key material, so refresh the timeout. */
-      ssl_session_renew_timeout(ssl, hs->new_session,
+      ssl_session_renew_timeout(ssl, hs->new_session.get(),
                                 ssl->session_ctx->session_psk_dhe_timeout);
       break;
 
@@ -412,7 +411,7 @@
 
   if (hs->hostname != NULL) {
     OPENSSL_free(hs->new_session->tlsext_hostname);
-    hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname);
+    hs->new_session->tlsext_hostname = BUF_strdup(hs->hostname.get());
     if (hs->new_session->tlsext_hostname == NULL) {
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
       return ssl_hs_error;