Switch some easy SSL fields to UniquePtr.

Change-Id: I982ecda5a19187708b15e8572e6d0000c22ed87c
Reviewed-on: https://boringssl-review.googlesource.com/29590
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/d1_both.cc b/ssl/d1_both.cc
index 31c83c6..f22a498 100644
--- a/ssl/d1_both.cc
+++ b/ssl/d1_both.cc
@@ -618,12 +618,12 @@
   // |SSL_set_mtu|. Does this need to be so complex?
   if (ssl->d1->mtu < dtls1_min_mtu() &&
       !(SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) {
-    long mtu = BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+    long mtu = BIO_ctrl(ssl->wbio.get(), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
     if (mtu >= 0 && mtu <= (1 << 30) && (unsigned)mtu >= dtls1_min_mtu()) {
       ssl->d1->mtu = (unsigned)mtu;
     } else {
       ssl->d1->mtu = kDefaultMTU;
-      BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_SET_MTU, ssl->d1->mtu, NULL);
+      BIO_ctrl(ssl->wbio.get(), BIO_CTRL_DGRAM_SET_MTU, ssl->d1->mtu, NULL);
     }
   }
 
@@ -803,7 +803,7 @@
       goto err;
     }
 
-    int bio_ret = BIO_write(ssl->wbio, packet, packet_len);
+    int bio_ret = BIO_write(ssl->wbio.get(), packet, packet_len);
     if (bio_ret <= 0) {
       // Retry this packet the next time around.
       ssl->d1->outgoing_written = old_written;
@@ -814,7 +814,7 @@
     }
   }
 
-  if (BIO_flush(ssl->wbio) <= 0) {
+  if (BIO_flush(ssl->wbio.get()) <= 0) {
     ssl->s3->rwstate = SSL_WRITING;
     goto err;
   }
diff --git a/ssl/d1_lib.cc b/ssl/d1_lib.cc
index eff06ee..d73e538 100644
--- a/ssl/d1_lib.cc
+++ b/ssl/d1_lib.cc
@@ -171,7 +171,8 @@
   // Reduce MTU after 2 unsuccessful retransmissions
   if (ssl->d1->num_timeouts > DTLS1_MTU_TIMEOUTS &&
       !(SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) {
-    long mtu = BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL);
+    long mtu =
+        BIO_ctrl(ssl->wbio.get(), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, nullptr);
     if (mtu >= 0 && mtu <= (1 << 30) && (unsigned)mtu >= dtls1_min_mtu()) {
       ssl->d1->mtu = (unsigned)mtu;
     }
diff --git a/ssl/d1_pkt.cc b/ssl/d1_pkt.cc
index d29a5c2..a694c5f 100644
--- a/ssl/d1_pkt.cc
+++ b/ssl/d1_pkt.cc
@@ -260,7 +260,7 @@
 
   // If the alert is fatal, flush the BIO now.
   if (ssl->s3->send_alert[0] == SSL3_AL_FATAL) {
-    BIO_flush(ssl->wbio);
+    BIO_flush(ssl->wbio.get());
   }
 
   ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_ALERT, ssl->s3->send_alert);
diff --git a/ssl/handoff.cc b/ssl/handoff.cc
index 2ad6e4d..85f7f7d 100644
--- a/ssl/handoff.cc
+++ b/ssl/handoff.cc
@@ -149,8 +149,8 @@
 
   // TODO(mab): make sure everything is serialized.
   CBB seq, key_share;
-  SSL_SESSION *session =
-      s3->session_reused ? ssl->session : s3->hs->new_session.get();
+  const SSL_SESSION *session =
+      s3->session_reused ? ssl->session.get() : s3->hs->new_session.get();
   if (!CBB_add_asn1(out, &seq, CBS_ASN1_SEQUENCE) ||
       !CBB_add_asn1_uint64(&seq, kHandbackVersion) ||
       !CBB_add_asn1_uint64(&seq, type) ||
@@ -239,9 +239,8 @@
   s3->hs = ssl_handshake_new(ssl);
   if (session_reused) {
     ssl->session =
-        SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool)
-            .release();
-    session = ssl->session;
+        SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool);
+    session = ssl->session.get();
   } else {
     s3->hs->new_session =
         SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool);
diff --git a/ssl/handshake.cc b/ssl/handshake.cc
index c1837a8..9549f7c 100644
--- a/ssl/handshake.cc
+++ b/ssl/handshake.cc
@@ -162,7 +162,7 @@
       !hs->transcript.Init()) {
     return nullptr;
   }
-  hs->config = ssl->config;
+  hs->config = ssl->config.get();
   if (!hs->config) {
     assert(hs->config);
     return nullptr;
@@ -197,7 +197,7 @@
   static const size_t kMaxMessageLen = 16384;
 
   if (SSL_in_init(ssl)) {
-    SSL_CONFIG *config = ssl->config;  // SSL_in_init() implies not NULL.
+    SSL_CONFIG *config = ssl->config.get();  // SSL_in_init() implies not NULL.
     if ((!ssl->server || (config->verify_mode & SSL_VERIFY_PEER)) &&
         kMaxMessageLen < ssl->max_cert_list) {
       return ssl->max_cert_list;
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc
index eba21f3..5e3bf29 100644
--- a/ssl/handshake_client.cc
+++ b/ssl/handshake_client.cc
@@ -404,7 +404,7 @@
         (ssl->session->session_id_length == 0 &&
          ssl->session->ticket.empty()) ||
         ssl->session->not_resumable ||
-        !ssl_session_is_time_valid(ssl, ssl->session)) {
+        !ssl_session_is_time_valid(ssl, ssl->session.get())) {
       ssl_set_session(ssl, NULL);
     }
   }
@@ -664,7 +664,7 @@
       ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
       return ssl_hs_error;
     }
-    if (!ssl_session_is_context_valid(hs, ssl->session)) {
+    if (!ssl_session_is_context_valid(hs, ssl->session.get())) {
       // This is actually a client application bug.
       OPENSSL_PUT_ERROR(SSL,
                         SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
@@ -1547,7 +1547,7 @@
     // immutable once established, so duplicate all but the ticket of the
     // existing session.
     renewed_session =
-        SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH);
+        SSL_SESSION_dup(ssl->session.get(), SSL_SESSION_INCLUDE_NONAUTH);
     if (!renewed_session) {
       // This should never happen.
       OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
@@ -1575,8 +1575,7 @@
 
   if (renewed_session) {
     session->not_resumable = false;
-    SSL_SESSION_free(ssl->session);
-    ssl->session = renewed_session.release();
+    ssl->session = std::move(renewed_session);
   }
 
   ssl->method->next_message(ssl);
diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc
index edbe617..a0674d1 100644
--- a/ssl/handshake_server.cc
+++ b/ssl/handshake_server.cc
@@ -600,7 +600,7 @@
   if (session) {
     // Use the old session.
     hs->ticket_expected = renew_ticket;
-    ssl->session = session.release();
+    ssl->session = std::move(session);
     ssl->s3->session_reused = true;
   } else {
     hs->ticket_expected = tickets_supported;
@@ -713,8 +713,8 @@
   }
 
   const SSL_SESSION *session = hs->new_session.get();
-  if (ssl->session != NULL) {
-    session = ssl->session;
+  if (ssl->session != nullptr) {
+    session = ssl->session.get();
   }
 
   ScopedCBB cbb;
@@ -1419,7 +1419,8 @@
     } else {
       // We are renewing an existing session. Duplicate the session to adjust
       // the timeout.
-      session_copy = SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH);
+      session_copy =
+          SSL_SESSION_dup(ssl->session.get(), SSL_SESSION_INCLUDE_NONAUTH);
       if (!session_copy) {
         return ssl_hs_error;
       }
diff --git a/ssl/internal.h b/ssl/internal.h
index d8f0cc7..279b332 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -2396,6 +2396,8 @@
 // See SSL_shed_handshake_config() for more about the conditions under which
 // configuration can be shed.
 struct SSL_CONFIG {
+  static constexpr bool kAllowUniquePtr = true;
+
   explicit SSL_CONFIG(SSL *ssl_arg);
   ~SSL_CONFIG();
 
@@ -3125,7 +3127,7 @@
   // should check for nullptr, since configuration may be shed after the
   // handshake completes.  (If you have the |SSL_HANDSHAKE| object at hand, use
   // that instead, and skip the null check.)
-  bssl::SSL_CONFIG *config = nullptr;
+  bssl::UniquePtr<bssl::SSL_CONFIG> config;
 
   // version is the protocol version.
   uint16_t version = 0;
@@ -3135,8 +3137,8 @@
   // There are 2 BIO's even though they are normally both the same. This is so
   // data can be read and written to different handlers
 
-  BIO *rbio = nullptr;  // used by SSL_read
-  BIO *wbio = nullptr;  // used by SSL_write
+  bssl::UniquePtr<BIO> rbio;  // used by SSL_read
+  bssl::UniquePtr<BIO> wbio;  // used by SSL_write
 
   // do_handshake runs the handshake. On completion, it returns |ssl_hs_ok|.
   // Otherwise, it returns a value corresponding to what operation is needed to
@@ -3167,15 +3169,15 @@
 
   // session is the configured session to be offered by the client. This session
   // is immutable.
-  SSL_SESSION *session = nullptr;
+  bssl::UniquePtr<SSL_SESSION> session;
 
   void (*info_callback)(const SSL *ssl, int type, int value) = nullptr;
 
-  SSL_CTX *ctx = nullptr;
+  bssl::UniquePtr<SSL_CTX> ctx;
 
   // session_ctx is the |SSL_CTX| used for the session cache and related
   // settings.
-  SSL_CTX *session_ctx = nullptr;
+  bssl::UniquePtr<SSL_CTX> session_ctx;
 
   // extra application data
   CRYPTO_EX_DATA ex_data;
@@ -3183,7 +3185,7 @@
   uint32_t options = 0;  // protocol behaviour
   uint32_t mode = 0;     // API behaviour
   uint32_t max_cert_list = 0;
-  char *tlsext_hostname = nullptr;
+  bssl::UniquePtr<char> tlsext_hostname;
 
   // renegotiate_mode controls how peer renegotiation attempts are handled.
   ssl_renegotiate_mode_t renegotiate_mode = ssl_renegotiate_never;
diff --git a/ssl/s3_both.cc b/ssl/s3_both.cc
index 2466811..98896a3 100644
--- a/ssl/s3_both.cc
+++ b/ssl/s3_both.cc
@@ -311,7 +311,7 @@
   // Write the pending flight.
   while (ssl->s3->pending_flight_offset < ssl->s3->pending_flight->length) {
     int ret = BIO_write(
-        ssl->wbio,
+        ssl->wbio.get(),
         ssl->s3->pending_flight->data + ssl->s3->pending_flight_offset,
         ssl->s3->pending_flight->length - ssl->s3->pending_flight_offset);
     if (ret <= 0) {
@@ -322,7 +322,7 @@
     ssl->s3->pending_flight_offset += ret;
   }
 
-  if (BIO_flush(ssl->wbio) <= 0) {
+  if (BIO_flush(ssl->wbio.get()) <= 0) {
     ssl->s3->rwstate = SSL_WRITING;
     return -1;
   }
diff --git a/ssl/s3_pkt.cc b/ssl/s3_pkt.cc
index 00ba8df..50e709b 100644
--- a/ssl/s3_pkt.cc
+++ b/ssl/s3_pkt.cc
@@ -414,7 +414,7 @@
 
   // If the alert is fatal, flush the BIO now.
   if (ssl->s3->send_alert[0] == SSL3_AL_FATAL) {
-    BIO_flush(ssl->wbio);
+    BIO_flush(ssl->wbio.get());
   }
 
   ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_ALERT, ssl->s3->send_alert);
diff --git a/ssl/ssl_buffer.cc b/ssl/ssl_buffer.cc
index da1de93..72647a4 100644
--- a/ssl/ssl_buffer.cc
+++ b/ssl/ssl_buffer.cc
@@ -113,7 +113,8 @@
   }
 
   // Read a single packet from |ssl->rbio|. |buf->cap()| must fit in an int.
-  int ret = BIO_read(ssl->rbio, buf->data(), static_cast<int>(buf->cap()));
+  int ret =
+      BIO_read(ssl->rbio.get(), buf->data(), static_cast<int>(buf->cap()));
   if (ret <= 0) {
     ssl->s3->rwstate = SSL_READING;
     return ret;
@@ -134,7 +135,7 @@
   while (buf->size() < len) {
     // The amount of data to read is bounded by |buf->cap|, which must fit in an
     // int.
-    int ret = BIO_read(ssl->rbio, buf->data() + buf->size(),
+    int ret = BIO_read(ssl->rbio.get(), buf->data() + buf->size(),
                        static_cast<int>(len - buf->size()));
     if (ret <= 0) {
       ssl->s3->rwstate = SSL_READING;
@@ -163,7 +164,7 @@
     return -1;
   }
 
-  if (ssl->rbio == NULL) {
+  if (ssl->rbio == nullptr) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET);
     return -1;
   }
@@ -240,7 +241,7 @@
   SSLBuffer *buf = &ssl->s3->write_buffer;
 
   while (!buf->empty()) {
-    int ret = BIO_write(ssl->wbio, buf->data(), buf->size());
+    int ret = BIO_write(ssl->wbio.get(), buf->data(), buf->size());
     if (ret <= 0) {
       ssl->s3->rwstate = SSL_WRITING;
       return ret;
@@ -257,7 +258,7 @@
     return 1;
   }
 
-  int ret = BIO_write(ssl->wbio, buf->data(), buf->size());
+  int ret = BIO_write(ssl->wbio.get(), buf->data(), buf->size());
   if (ret <= 0) {
     ssl->s3->rwstate = SSL_WRITING;
     // If the write failed, drop the write buffer anyway. Datagram transports
@@ -271,7 +272,7 @@
 }
 
 int ssl_write_buffer_flush(SSL *ssl) {
-  if (ssl->wbio == NULL) {
+  if (ssl->wbio == nullptr) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET);
     return -1;
   }
diff --git a/ssl/ssl_cert.cc b/ssl/ssl_cert.cc
index 04c77ad..421b30a 100644
--- a/ssl/ssl_cert.cc
+++ b/ssl/ssl_cert.cc
@@ -872,7 +872,7 @@
   if (!ssl->config) {
     return;
   }
-  ssl->ctx->x509_method->ssl_flush_cached_client_CA(ssl->config);
+  ssl->ctx->x509_method->ssl_flush_cached_client_CA(ssl->config.get());
   sk_CRYPTO_BUFFER_pop_free(ssl->config->client_CA, CRYPTO_BUFFER_free);
   ssl->config->client_CA = name_list;
 }
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index d6d1194..13e6267 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -274,7 +274,7 @@
 
 void ssl_update_cache(SSL_HANDSHAKE *hs, int mode) {
   SSL *const ssl = hs->ssl;
-  SSL_CTX *ctx = ssl->session_ctx;
+  SSL_CTX *ctx = ssl->session_ctx.get();
   // Never cache sessions with empty session IDs.
   if (ssl->s3->established_session->session_id_length == 0 ||
       ssl->s3->established_session->not_resumable ||
@@ -289,7 +289,7 @@
   // A client may see new sessions on abbreviated handshakes if the server
   // decides to renew the ticket. Once the handshake is completed, it should be
   // inserted into the cache.
-  if (ssl->s3->established_session.get() != ssl->session ||
+  if (ssl->s3->established_session.get() != ssl->session.get() ||
       (!ssl->server && hs->ticket_expected)) {
     if (use_internal_cache) {
       SSL_CTX_add_session(ctx, ssl->s3->established_session.get());
@@ -406,7 +406,7 @@
 void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock) {
   // TODO(martinkr): Change callers to |ssl_ctx_get_current_time| and drop the
   // |ssl| arg from |current_time_cb| if possible.
-  ssl_ctx_get_current_time(ssl->ctx, out_clock);
+  ssl_ctx_get_current_time(ssl->ctx.get(), out_clock);
 }
 
 void ssl_ctx_get_current_time(const SSL_CTX *ctx,
@@ -496,8 +496,7 @@
     return;
   }
 
-  Delete(ssl->config);
-  ssl->config = nullptr;
+  ssl->config.reset();
 }
 
 void SSL_set_handoff_mode(SSL *ssl, bool on) {
@@ -637,8 +636,8 @@
       msg_callback(ctx_arg->msg_callback),
       msg_callback_arg(ctx_arg->msg_callback_arg),
       tls13_variant(ctx_arg->tls13_variant),
-      ctx(UpRef(ctx_arg).release()),
-      session_ctx(UpRef(ctx_arg).release()),
+      ctx(UpRef(ctx_arg)),
+      session_ctx(UpRef(ctx_arg)),
       options(ctx->options),
       mode(ctx->mode),
       max_cert_list(ctx->max_cert_list),
@@ -651,22 +650,11 @@
 
 ssl_st::~ssl_st() {
   CRYPTO_free_ex_data(&g_ex_data_class_ssl, this, &ex_data);
-
-  BIO_free_all(rbio);
-  BIO_free_all(wbio);
-
-  Delete(config);
-  config = nullptr;
-
-  SSL_SESSION_free(session);
-
-  OPENSSL_free(tlsext_hostname);
-
+  // |config| refers to |this|, so we must release it earlier.
+  config.reset();
   if (method != NULL) {
     method->ssl_free(this);
   }
-  SSL_CTX_free(ctx);
-  SSL_CTX_free(session_ctx);
 }
 
 SSL *SSL_new(SSL_CTX *ctx) {
@@ -680,7 +668,7 @@
     return nullptr;
   }
 
-  ssl->config = New<SSL_CONFIG>(ssl.get());
+  ssl->config = MakeUnique<SSL_CONFIG>(ssl.get());
   if (ssl->config == nullptr) {
     return nullptr;
   }
@@ -786,13 +774,11 @@
 }
 
 void SSL_set0_rbio(SSL *ssl, BIO *rbio) {
-  BIO_free_all(ssl->rbio);
-  ssl->rbio = rbio;
+  ssl->rbio.reset(rbio);
 }
 
 void SSL_set0_wbio(SSL *ssl, BIO *wbio) {
-  BIO_free_all(ssl->wbio);
-  ssl->wbio = wbio;
+  ssl->wbio.reset(wbio);
 }
 
 void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio) {
@@ -829,9 +815,9 @@
   SSL_set0_wbio(ssl, wbio);
 }
 
-BIO *SSL_get_rbio(const SSL *ssl) { return ssl->rbio; }
+BIO *SSL_get_rbio(const SSL *ssl) { return ssl->rbio.get(); }
 
-BIO *SSL_get_wbio(const SSL *ssl) { return ssl->wbio; }
+BIO *SSL_get_wbio(const SSL *ssl) { return ssl->wbio.get(); }
 
 int SSL_do_handshake(SSL *ssl) {
   ssl_reset_error_state(ssl);
@@ -1891,8 +1877,8 @@
 
   // Historically, |SSL_get_servername| was also the configuration getter
   // corresponding to |SSL_set_tlsext_host_name|.
-  if (ssl->tlsext_hostname != NULL) {
-    return ssl->tlsext_hostname;
+  if (ssl->tlsext_hostname != nullptr) {
+    return ssl->tlsext_hostname.get();
   }
 
   return ssl->s3->hostname.get();
@@ -1971,10 +1957,8 @@
 }
 
 int SSL_set_tlsext_host_name(SSL *ssl, const char *name) {
-  OPENSSL_free(ssl->tlsext_hostname);
-  ssl->tlsext_hostname = NULL;
-
-  if (name == NULL) {
+  ssl->tlsext_hostname.reset();
+  if (name == nullptr) {
     return 1;
   }
 
@@ -1983,8 +1967,8 @@
     OPENSSL_PUT_ERROR(SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME);
     return 0;
   }
-  ssl->tlsext_hostname = BUF_strdup(name);
-  if (ssl->tlsext_hostname == NULL) {
+  ssl->tlsext_hostname.reset(BUF_strdup(name));
+  if (ssl->tlsext_hostname == nullptr) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     return 0;
   }
@@ -2333,14 +2317,14 @@
   return ret;
 }
 
-SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) { return ssl->ctx; }
+SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) { return ssl->ctx.get(); }
 
 SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx) {
   if (!ssl->config) {
     return NULL;
   }
-  if (ssl->ctx == ctx) {
-    return ssl->ctx;
+  if (ssl->ctx.get() == ctx) {
+    return ssl->ctx.get();
   }
 
   // One cannot change the X.509 callbacks during a connection.
@@ -2350,18 +2334,16 @@
   }
 
   if (ctx == NULL) {
-    ctx = ssl->session_ctx;
+    ctx = ssl->session_ctx.get();
   }
 
   Delete(ssl->config->cert);
   ssl->config->cert = ssl_cert_dup(ctx->cert).release();
 
-  SSL_CTX_up_ref(ctx);
-  SSL_CTX_free(ssl->ctx);
-  ssl->ctx = ctx;
+  ssl->ctx = UpRef(ctx);
   ssl->enable_early_data = ssl->ctx->enable_early_data;
 
-  return ssl->ctx;
+  return ssl->ctx.get();
 }
 
 void SSL_set_info_callback(SSL *ssl,
diff --git a/ssl/ssl_session.cc b/ssl/ssl_session.cc
index 379cea7..d5af8aa 100644
--- a/ssl/ssl_session.cc
+++ b/ssl/ssl_session.cc
@@ -478,7 +478,7 @@
 
   // Initialize HMAC and cipher contexts. If callback present it does all the
   // work otherwise use generated values from parent ctx.
-  SSL_CTX *tctx = hs->ssl->session_ctx;
+  SSL_CTX *tctx = hs->ssl->session_ctx.get();
   uint8_t iv[EVP_MAX_IV_LENGTH];
   uint8_t key_name[16];
   if (tctx->tlsext_ticket_key_cb != NULL) {
@@ -696,13 +696,13 @@
     // Add the externally cached session to the internal cache if necessary.
     if (!(ssl->session_ctx->session_cache_mode &
           SSL_SESS_CACHE_NO_INTERNAL_STORE)) {
-      SSL_CTX_add_session(ssl->session_ctx, session.get());
+      SSL_CTX_add_session(ssl->session_ctx.get(), session.get());
     }
   }
 
   if (session && !ssl_session_is_time_valid(ssl, session.get())) {
     // The session was from the cache, so remove it.
-    SSL_CTX_remove_session(ssl->session_ctx, session.get());
+    SSL_CTX_remove_session(ssl->session_ctx.get(), session.get());
     session.reset();
   }
 
@@ -788,15 +788,11 @@
 }
 
 void ssl_set_session(SSL *ssl, SSL_SESSION *session) {
-  if (ssl->session == session) {
+  if (ssl->session.get() == session) {
     return;
   }
 
-  SSL_SESSION_free(ssl->session);
-  ssl->session = session;
-  if (session != NULL) {
-    SSL_SESSION_up_ref(session);
-  }
+  ssl->session = UpRef(session);
 }
 
 // locked by SSL_CTX in the calling function
@@ -1070,7 +1066,7 @@
   if (hs->new_session) {
     return hs->new_session.get();
   }
-  return ssl->session;
+  return ssl->session.get();
 }
 
 SSL_SESSION *SSL_get1_session(SSL *ssl) {
diff --git a/ssl/ssl_x509.cc b/ssl/ssl_x509.cc
index 4f2fc9e..aabf2a0 100644
--- a/ssl/ssl_x509.cc
+++ b/ssl/ssl_x509.cc
@@ -354,7 +354,7 @@
     return 0;
   }
 
-  SSL_CTX *ssl_ctx = hs->ssl->ctx;
+  SSL_CTX *ssl_ctx = hs->ssl->ctx.get();
   X509_STORE *verify_store = ssl_ctx->cert_store;
   if (hs->config->cert->verify_store != NULL) {
     verify_store = hs->config->cert->verify_store;
@@ -1074,7 +1074,7 @@
   if (!ssl->config) {
     return;
   }
-  ssl->ctx->x509_method->ssl_flush_cached_client_CA(ssl->config);
+  ssl->ctx->x509_method->ssl_flush_cached_client_CA(ssl->config.get());
   set_client_CA_list(&ssl->config->client_CA, name_list, ssl->ctx->pool);
   sk_X509_NAME_pop_free(name_list, X509_NAME_free);
 }
@@ -1143,7 +1143,7 @@
         ssl->config->client_CA,
         (STACK_OF(X509_NAME) **)&ssl->config->cached_x509_client_CA);
   }
-  return SSL_CTX_get_client_CA_list(ssl->ctx);
+  return SSL_CTX_get_client_CA_list(ssl->ctx.get());
 }
 
 STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx) {
@@ -1204,7 +1204,7 @@
     return 0;
   }
 
-  ssl_crypto_x509_ssl_flush_cached_client_CA(ssl->config);
+  ssl_crypto_x509_ssl_flush_cached_client_CA(ssl->config.get());
   return 1;
 }
 
@@ -1224,7 +1224,7 @@
     assert(ssl->config);
     return -1;
   }
-  if (ssl_has_certificate(ssl->config) ||
+  if (ssl_has_certificate(ssl->config.get()) ||
       ssl->ctx->client_cert_cb == NULL) {
     return 1;
   }
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index 49c8955..dfabbae 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -606,7 +606,7 @@
 
 static bool ext_sni_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
   SSL *const ssl = hs->ssl;
-  if (ssl->tlsext_hostname == NULL) {
+  if (ssl->tlsext_hostname == nullptr) {
     return true;
   }
 
@@ -616,8 +616,8 @@
       !CBB_add_u16_length_prefixed(&contents, &server_name_list) ||
       !CBB_add_u8(&server_name_list, TLSEXT_NAMETYPE_host_name) ||
       !CBB_add_u16_length_prefixed(&server_name_list, &name) ||
-      !CBB_add_bytes(&name, (const uint8_t *)ssl->tlsext_hostname,
-                     strlen(ssl->tlsext_hostname)) ||
+      !CBB_add_bytes(&name, (const uint8_t *)ssl->tlsext_hostname.get(),
+                     strlen(ssl->tlsext_hostname.get())) ||
       !CBB_flush(out)) {
     return false;
   }
@@ -950,10 +950,10 @@
   // over the state from the previous handshake, such as OpenSSL servers
   // without upstream's 3c3f0259238594d77264a78944d409f2127642c4.
   if (!ssl->s3->initial_handshake_complete &&
-      ssl->session != NULL &&
+      ssl->session != nullptr &&
       !ssl->session->ticket.empty() &&
       // Don't send TLS 1.3 session tickets in the ticket extension.
-      ssl_session_protocol_version(ssl->session) < TLS1_3_VERSION) {
+      ssl_session_protocol_version(ssl->session.get()) < TLS1_3_VERSION) {
     ticket = ssl->session->ticket;
   }
 
@@ -1866,20 +1866,20 @@
 
 static size_t ext_pre_shared_key_clienthello_length(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (hs->max_version < TLS1_3_VERSION || ssl->session == NULL ||
-      ssl_session_protocol_version(ssl->session) < TLS1_3_VERSION) {
+  if (hs->max_version < TLS1_3_VERSION || ssl->session == nullptr ||
+      ssl_session_protocol_version(ssl->session.get()) < TLS1_3_VERSION) {
     return 0;
   }
 
-  size_t binder_len = EVP_MD_size(ssl_session_get_digest(ssl->session));
+  size_t binder_len = EVP_MD_size(ssl_session_get_digest(ssl->session.get()));
   return 15 + ssl->session->ticket.size() + binder_len;
 }
 
 static bool ext_pre_shared_key_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
   SSL *const ssl = hs->ssl;
   hs->needs_psk_binder = false;
-  if (hs->max_version < TLS1_3_VERSION || ssl->session == NULL ||
-      ssl_session_protocol_version(ssl->session) < TLS1_3_VERSION) {
+  if (hs->max_version < TLS1_3_VERSION || ssl->session == nullptr ||
+      ssl_session_protocol_version(ssl->session.get()) < TLS1_3_VERSION) {
     return true;
   }
 
@@ -1899,7 +1899,7 @@
   // Fill in a placeholder zero binder of the appropriate length. It will be
   // computed and filled in later after length prefixes are computed.
   uint8_t zero_binder[EVP_MAX_MD_SIZE] = {0};
-  size_t binder_len = EVP_MD_size(ssl_session_get_digest(ssl->session));
+  size_t binder_len = EVP_MD_size(ssl_session_get_digest(ssl->session.get()));
 
   CBB contents, identity, ticket, binders, binder;
   if (!CBB_add_u16(out, TLSEXT_TYPE_pre_shared_key) ||
@@ -2066,8 +2066,8 @@
   SSL *const ssl = hs->ssl;
   if (!ssl->enable_early_data ||
       // Session must be 0-RTT capable.
-      ssl->session == NULL ||
-      ssl_session_protocol_version(ssl->session) < TLS1_3_VERSION ||
+      ssl->session == nullptr ||
+      ssl_session_protocol_version(ssl->session.get()) < TLS1_3_VERSION ||
       ssl->session->ticket_max_early_data == 0 ||
       // The second ClientHello never offers early data.
       hs->received_hello_retry_request ||
@@ -3525,7 +3525,7 @@
     SSL_HANDSHAKE *hs, uint8_t **out, size_t *out_len, const uint8_t *ticket,
     size_t ticket_len) {
   assert(ticket_len >= SSL_TICKET_KEY_NAME_LEN + EVP_MAX_IV_LENGTH);
-  SSL_CTX *ctx = hs->ssl->session_ctx;
+  SSL_CTX *ctx = hs->ssl->session_ctx.get();
 
   // Rotate the ticket key if necessary.
   if (!ssl_ctx_rotate_ticket_encryption_key(ctx)) {
@@ -3626,7 +3626,7 @@
 
   // Decode the session.
   UniquePtr<SSL_SESSION> session(
-      SSL_SESSION_from_bytes(plaintext, plaintext_len, hs->ssl->ctx));
+      SSL_SESSION_from_bytes(plaintext, plaintext_len, hs->ssl->ctx.get()));
   OPENSSL_free(plaintext);
 
   if (!session) {
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index fe443cb..e2a6c13 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -773,11 +773,12 @@
                        SettingsWriter *writer) {
   int ret;
   SSL *ssl = ssl_uniqueptr->get();
-  SSL_CTX *session_ctx = ssl->ctx;
+  SSL_CTX *session_ctx = SSL_get_SSL_CTX(ssl);
 
   if (!config->implicit_handshake) {
     if (config->handoff) {
-      bssl::UniquePtr<SSL_CTX> ctx_handoff = config->SetupCtx(ssl->ctx);
+      bssl::UniquePtr<SSL_CTX> ctx_handoff =
+          config->SetupCtx(SSL_get_SSL_CTX(ssl));
       if (!ctx_handoff) {
         return false;
       }
@@ -853,7 +854,8 @@
         return false;
       }
 
-      bssl::UniquePtr<SSL_CTX> ctx_handback = config->SetupCtx(ssl->ctx);
+      bssl::UniquePtr<SSL_CTX> ctx_handback =
+          config->SetupCtx(SSL_get_SSL_CTX(ssl));
       if (!ctx_handback) {
         return false;
       }
@@ -891,7 +893,7 @@
       return false;
     }
 
-    CopySessions(session_ctx, ssl->ctx);
+    CopySessions(session_ctx, SSL_get_SSL_CTX(ssl));
 
     if (is_resume && !is_retry && !config->is_server &&
         config->expect_no_offer_early_data && SSL_in_early_data(ssl)) {
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc
index 1f1d4b4..dd0977a 100644
--- a/ssl/tls13_client.cc
+++ b/ssl/tls13_client.cc
@@ -328,7 +328,7 @@
       return ssl_hs_error;
     }
 
-    if (!ssl_session_is_context_valid(hs, ssl->session)) {
+    if (!ssl_session_is_context_valid(hs, ssl->session.get())) {
       // This is actually a client application bug.
       OPENSSL_PUT_ERROR(SSL,
                         SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
@@ -338,7 +338,8 @@
 
     ssl->s3->session_reused = true;
     // Only authentication information carries over in TLS 1.3.
-    hs->new_session = SSL_SESSION_dup(ssl->session, SSL_SESSION_DUP_AUTH_ONLY);
+    hs->new_session =
+        SSL_SESSION_dup(ssl->session.get(), SSL_SESSION_DUP_AUTH_ONLY);
     if (!hs->new_session) {
       ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
       return ssl_hs_error;
diff --git a/ssl/tls13_enc.cc b/ssl/tls13_enc.cc
index cc7afb8..0c2c20d 100644
--- a/ssl/tls13_enc.cc
+++ b/ssl/tls13_enc.cc
@@ -60,7 +60,7 @@
 int tls13_init_early_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *psk,
                                   size_t psk_len) {
   SSL *const ssl = hs->ssl;
-  return init_key_schedule(hs, ssl_session_protocol_version(ssl->session),
+  return init_key_schedule(hs, ssl_session_protocol_version(ssl->session.get()),
                            ssl->session->cipher) &&
          HKDF_extract(hs->secret, &hs->hash_len, hs->transcript.Digest(), psk,
                       psk_len, hs->secret, hs->hash_len);
@@ -413,7 +413,7 @@
 
 int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len) {
   SSL *const ssl = hs->ssl;
-  const EVP_MD *digest = ssl_session_get_digest(ssl->session);
+  const EVP_MD *digest = ssl_session_get_digest(ssl->session.get());
   size_t hash_len = EVP_MD_size(digest);
 
   if (len < hash_len + 3) {