Use more scopers.

Change-Id: I34dd0a57efd5435fcdc59a3c7b1ce806bc0cbb3e
Reviewed-on: https://boringssl-review.googlesource.com/21946
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/dtls_method.cc b/ssl/dtls_method.cc
index fab19be..c64c75e 100644
--- a/ssl/dtls_method.cc
+++ b/ssl/dtls_method.cc
@@ -94,8 +94,7 @@
   OPENSSL_memset(&ssl->d1->bitmap, 0, sizeof(ssl->d1->bitmap));
   OPENSSL_memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence));
 
-  Delete(ssl->s3->aead_read_ctx);
-  ssl->s3->aead_read_ctx = aead_ctx.release();
+  ssl->s3->aead_read_ctx = std::move(aead_ctx);
   return true;
 }
 
@@ -107,8 +106,8 @@
   OPENSSL_memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence));
 
   Delete(ssl->d1->last_aead_write_ctx);
-  ssl->d1->last_aead_write_ctx = ssl->s3->aead_write_ctx;
-  ssl->s3->aead_write_ctx = aead_ctx.release();
+  ssl->d1->last_aead_write_ctx = ssl->s3->aead_write_ctx.release();
+  ssl->s3->aead_write_ctx = std::move(aead_ctx);
   return true;
 }
 
diff --git a/ssl/dtls_record.cc b/ssl/dtls_record.cc
index a746640..3a5e50f 100644
--- a/ssl/dtls_record.cc
+++ b/ssl/dtls_record.cc
@@ -278,7 +278,7 @@
     return ssl->d1->last_aead_write_ctx;
   }
 
-  return ssl->s3->aead_write_ctx;
+  return ssl->s3->aead_write_ctx.get();
 }
 
 size_t dtls_max_seal_overhead(const SSL *ssl,
@@ -303,7 +303,7 @@
 
   // Determine the parameters for the current epoch.
   uint16_t epoch = ssl->d1->w_epoch;
-  SSLAEADContext *aead = ssl->s3->aead_write_ctx;
+  SSLAEADContext *aead = ssl->s3->aead_write_ctx.get();
   uint8_t *seq = ssl->s3->write_sequence;
   if (use_epoch == dtls1_use_previous_epoch) {
     assert(ssl->d1->w_epoch >= 1);
diff --git a/ssl/handshake.cc b/ssl/handshake.cc
index 3cb9a9c..df47ed1 100644
--- a/ssl/handshake.cc
+++ b/ssl/handshake.cc
@@ -149,17 +149,15 @@
   ssl->ctx->x509_method->hs_flush_cached_ca_names(this);
 }
 
-SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl) {
+UniquePtr<SSL_HANDSHAKE> ssl_handshake_new(SSL *ssl) {
   UniquePtr<SSL_HANDSHAKE> hs = MakeUnique<SSL_HANDSHAKE>(ssl);
   if (!hs ||
       !hs->transcript.Init()) {
     return nullptr;
   }
-  return hs.release();
+  return hs;
 }
 
-void ssl_handshake_free(SSL_HANDSHAKE *hs) { Delete(hs); }
-
 bool ssl_check_message_type(SSL *ssl, const SSLMessage &msg, int type) {
   if (msg.type != type) {
     ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
@@ -282,7 +280,7 @@
 
 enum ssl_verify_result_t ssl_verify_peer_cert(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  const SSL_SESSION *prev_session = ssl->s3->established_session;
+  const SSL_SESSION *prev_session = ssl->s3->established_session.get();
   if (prev_session != NULL) {
     // If renegotiating, the server must not change the server certificate. See
     // https://mitls.org/pages/attacks/3SHAKE. We never resume on renegotiation,
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc
index 5466b56..ff8ebd8 100644
--- a/ssl/handshake_client.cc
+++ b/ssl/handshake_client.cc
@@ -1476,14 +1476,15 @@
 
   if (hs->next_proto_neg_seen) {
     static const uint8_t kZero[32] = {0};
-    size_t padding_len = 32 - ((ssl->s3->next_proto_negotiated_len + 2) % 32);
+    size_t padding_len =
+        32 - ((ssl->s3->next_proto_negotiated.size() + 2) % 32);
 
     ScopedCBB cbb;
     CBB body, child;
     if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_NEXT_PROTO) ||
         !CBB_add_u8_length_prefixed(&body, &child) ||
-        !CBB_add_bytes(&child, ssl->s3->next_proto_negotiated,
-                       ssl->s3->next_proto_negotiated_len) ||
+        !CBB_add_bytes(&child, ssl->s3->next_proto_negotiated.data(),
+                       ssl->s3->next_proto_negotiated.size()) ||
         !CBB_add_u8_length_prefixed(&body, &child) ||
         !CBB_add_bytes(&child, kZero, padding_len) ||
         !ssl_add_message_cbb(ssl, cbb.get())) {
@@ -1517,8 +1518,8 @@
   // False Start only for TLS 1.2 with an ECDHE+AEAD cipher and ALPN or NPN.
   return !SSL_is_dtls(ssl) &&
          SSL_version(ssl) == TLS1_2_VERSION &&
-         (ssl->s3->alpn_selected != NULL ||
-          ssl->s3->next_proto_negotiated != NULL) &&
+         (!ssl->s3->alpn_selected.empty() ||
+          !ssl->s3->next_proto_negotiated.empty()) &&
          hs->new_cipher->algorithm_mkey == SSL_kECDHE &&
          hs->new_cipher->algorithm_mac == SSL_AEAD;
 }
@@ -1664,18 +1665,16 @@
 
   ssl->method->on_handshake_complete(ssl);
 
-  SSL_SESSION_free(ssl->s3->established_session);
   if (ssl->session != NULL) {
     SSL_SESSION_up_ref(ssl->session);
-    ssl->s3->established_session = ssl->session;
+    ssl->s3->established_session.reset(ssl->session);
   } else {
     // We make a copy of the session in order to maintain the immutability
     // 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.get(), SSL_SESSION_DUP_ALL)
-        .release();
-    if (ssl->s3->established_session == NULL) {
+        SSL_SESSION_dup(hs->new_session.get(), SSL_SESSION_DUP_ALL);
+    if (!ssl->s3->established_session) {
       return ssl_hs_error;
     }
     // Renegotiations do not participate in session resumption.
diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc
index 7b282d8..d346875 100644
--- a/ssl/handshake_server.cc
+++ b/ssl/handshake_server.cc
@@ -1392,8 +1392,7 @@
     return ssl_hs_error;
   }
 
-  if (!CBS_stow(&selected_protocol, &ssl->s3->next_proto_negotiated,
-                &ssl->s3->next_proto_negotiated_len)) {
+  if (!ssl->s3->next_proto_negotiated.CopyFrom(selected_protocol)) {
     return ssl_hs_error;
   }
 
@@ -1510,12 +1509,11 @@
     ssl->ctx->x509_method->session_clear(hs->new_session.get());
   }
 
-  SSL_SESSION_free(ssl->s3->established_session);
   if (ssl->session != NULL) {
     SSL_SESSION_up_ref(ssl->session);
-    ssl->s3->established_session = ssl->session;
+    ssl->s3->established_session.reset(ssl->session);
   } else {
-    ssl->s3->established_session = hs->new_session.release();
+    ssl->s3->established_session = std::move(hs->new_session);
     ssl->s3->established_session->not_resumable = 0;
   }
 
diff --git a/ssl/internal.h b/ssl/internal.h
index 8c373d2..e76be27 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1486,10 +1486,7 @@
   uint16_t early_data_written = 0;
 };
 
-SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl);
-
-// ssl_handshake_free releases all memory associated with |hs|.
-void ssl_handshake_free(SSL_HANDSHAKE *hs);
+UniquePtr<SSL_HANDSHAKE> ssl_handshake_new(SSL *ssl);
 
 // ssl_check_message_type checks if |msg| has type |type|. If so it returns
 // one. Otherwise, it sends an alert and returns zero.
@@ -2196,7 +2193,7 @@
 
   // read_error, if |read_shutdown| is |ssl_shutdown_error|, is the error for
   // the receive half of the connection.
-  ERR_SAVE_STATE *read_error = nullptr;
+  UniquePtr<ERR_SAVE_STATE> read_error;
 
   int alert_dispatch = 0;
 
@@ -2263,21 +2260,21 @@
   // pending_flight is the pending outgoing flight. This is used to flush each
   // handshake flight in a single write. |write_buffer| must be written out
   // before this data.
-  BUF_MEM *pending_flight = nullptr;
+  UniquePtr<BUF_MEM> pending_flight;
 
   // pending_flight_offset is the number of bytes of |pending_flight| which have
   // been successfully written.
   uint32_t pending_flight_offset = 0;
 
   // aead_read_ctx is the current read cipher state.
-  SSLAEADContext *aead_read_ctx = nullptr;
+  UniquePtr<SSLAEADContext> aead_read_ctx;
 
   // aead_write_ctx is the current write cipher state.
-  SSLAEADContext *aead_write_ctx = nullptr;
+  UniquePtr<SSLAEADContext> aead_write_ctx;
 
   // hs is the handshake state for the current handshake or NULL if there isn't
   // one.
-  SSL_HANDSHAKE *hs = nullptr;
+  UniquePtr<SSL_HANDSHAKE> hs;
 
   uint8_t write_traffic_secret[EVP_MAX_MD_SIZE] = {0};
   uint8_t read_traffic_secret[EVP_MAX_MD_SIZE] = {0};
@@ -2307,7 +2304,7 @@
   // established_session is the session established by the connection. This
   // session is only filled upon the completion of the handshake and is
   // immutable.
-  SSL_SESSION *established_session = nullptr;
+  UniquePtr<SSL_SESSION> established_session;
 
   // Next protocol negotiation. For the client, this is the protocol that we
   // sent in NextProtocol and is set when handling ServerHello extensions.
@@ -2315,8 +2312,7 @@
   // For a server, this is the client's selected_protocol from NextProtocol and
   // is set when handling the NextProtocol message, before the Finished
   // message.
-  uint8_t *next_proto_negotiated = nullptr;
-  size_t next_proto_negotiated_len = 0;
+  Array<uint8_t> next_proto_negotiated;
 
   // ALPN information
   // (we are in the process of transitioning from NPN to ALPN.)
@@ -2324,11 +2320,10 @@
   // In a server these point to the selected ALPN protocol after the
   // ClientHello has been processed. In a client these contain the protocol
   // that the server selected once the ServerHello has been processed.
-  uint8_t *alpn_selected = nullptr;
-  size_t alpn_selected_len = 0;
+  Array<uint8_t> alpn_selected;
 
   // hostname, on the server, is the value of the SNI extension.
-  char *hostname = nullptr;
+  UniquePtr<char> hostname;
 
   // For a server:
   //     If |tlsext_channel_id_valid| is true, then this contains the
diff --git a/ssl/s3_both.cc b/ssl/s3_both.cc
index 8c41179..e29d19f 100644
--- a/ssl/s3_both.cc
+++ b/ssl/s3_both.cc
@@ -137,9 +137,9 @@
   // We'll never add a flight while in the process of writing it out.
   assert(ssl->s3->pending_flight_offset == 0);
 
-  if (ssl->s3->pending_flight == NULL) {
-    ssl->s3->pending_flight = BUF_MEM_new();
-    if (ssl->s3->pending_flight == NULL) {
+  if (ssl->s3->pending_flight == nullptr) {
+    ssl->s3->pending_flight.reset(BUF_MEM_new());
+    if (ssl->s3->pending_flight == nullptr) {
       return false;
     }
   }
@@ -152,7 +152,7 @@
   }
 
   size_t len;
-  if (!BUF_MEM_reserve(ssl->s3->pending_flight, new_cap) ||
+  if (!BUF_MEM_reserve(ssl->s3->pending_flight.get(), new_cap) ||
       !tls_seal_record(ssl,
                        (uint8_t *)ssl->s3->pending_flight->data +
                            ssl->s3->pending_flight->length,
@@ -229,7 +229,7 @@
 }
 
 int ssl3_flush_flight(SSL *ssl) {
-  if (ssl->s3->pending_flight == NULL) {
+  if (ssl->s3->pending_flight == nullptr) {
     return 1;
   }
 
@@ -273,8 +273,7 @@
     return -1;
   }
 
-  BUF_MEM_free(ssl->s3->pending_flight);
-  ssl->s3->pending_flight = NULL;
+  ssl->s3->pending_flight.reset();
   ssl->s3->pending_flight_offset = 0;
   return 1;
 }
diff --git a/ssl/s3_lib.cc b/ssl/s3_lib.cc
index f69005b..b925cd7 100644
--- a/ssl/s3_lib.cc
+++ b/ssl/s3_lib.cc
@@ -177,39 +177,21 @@
       key_update_pending(false),
       wpend_pending(false) {}
 
-SSL3_STATE::~SSL3_STATE() {
-  ERR_SAVE_STATE_free(read_error);
-  SSL_SESSION_free(established_session);
-  ssl_handshake_free(hs);
-  OPENSSL_free(next_proto_negotiated);
-  OPENSSL_free(alpn_selected);
-  OPENSSL_free(hostname);
-  Delete(aead_read_ctx);
-  Delete(aead_write_ctx);
-  BUF_MEM_free(pending_flight);
-}
+SSL3_STATE::~SSL3_STATE() {}
 
 bool ssl3_new(SSL *ssl) {
-  UniquePtr<SSLAEADContext> aead_read_ctx =
-      SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl));
-  UniquePtr<SSLAEADContext> aead_write_ctx =
-      SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl));
-  if (!aead_read_ctx || !aead_write_ctx) {
-    return false;
-  }
-
   UniquePtr<SSL3_STATE> s3 = MakeUnique<SSL3_STATE>();
   if (!s3) {
     return false;
   }
 
+  s3->aead_read_ctx = SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl));
+  s3->aead_write_ctx = SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl));
   s3->hs = ssl_handshake_new(ssl);
-  if (s3->hs == NULL) {
+  if (!s3->aead_read_ctx || !s3->aead_write_ctx || !s3->hs) {
     return false;
   }
 
-  s3->aead_read_ctx = aead_read_ctx.release();
-  s3->aead_write_ctx = aead_write_ctx.release();
   ssl->s3 = s3.release();
 
   // Set the version to the highest supported version.
diff --git a/ssl/s3_pkt.cc b/ssl/s3_pkt.cc
index ad4f82a..c4ccecc 100644
--- a/ssl/s3_pkt.cc
+++ b/ssl/s3_pkt.cc
@@ -235,7 +235,7 @@
   }
 
   size_t flight_len = 0;
-  if (ssl->s3->pending_flight != NULL) {
+  if (ssl->s3->pending_flight != nullptr) {
     flight_len =
         ssl->s3->pending_flight->length - ssl->s3->pending_flight_offset;
   }
@@ -255,13 +255,12 @@
   // acknowledgment or 0-RTT key change messages. |pending_flight| must be clear
   // when data is added to |write_buffer| or it will be written in the wrong
   // order.
-  if (ssl->s3->pending_flight != NULL) {
+  if (ssl->s3->pending_flight != nullptr) {
     OPENSSL_memcpy(
         buf->remaining().data(),
         ssl->s3->pending_flight->data + ssl->s3->pending_flight_offset,
         flight_len);
-    BUF_MEM_free(ssl->s3->pending_flight);
-    ssl->s3->pending_flight = NULL;
+    ssl->s3->pending_flight.reset();
     ssl->s3->pending_flight_offset = 0;
     buf->DidWrite(flight_len);
   }
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index f5d1202..c8e6c94 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -208,13 +208,12 @@
 
 void ssl_set_read_error(SSL* ssl) {
   ssl->s3->read_shutdown = ssl_shutdown_error;
-  ERR_SAVE_STATE_free(ssl->s3->read_error);
-  ssl->s3->read_error = ERR_save_state();
+  ssl->s3->read_error.reset(ERR_save_state());
 }
 
 static bool check_read_error(const SSL *ssl) {
   if (ssl->s3->read_shutdown == ssl_shutdown_error) {
-    ERR_restore_state(ssl->s3->read_error);
+    ERR_restore_state(ssl->s3->read_error.get());
     return false;
   }
   return true;
@@ -300,16 +299,16 @@
   // 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 != ssl->session ||
+  if (ssl->s3->established_session.get() != ssl->session ||
       (!ssl->server && hs->ticket_expected)) {
     if (use_internal_cache) {
-      SSL_CTX_add_session(ctx, ssl->s3->established_session);
+      SSL_CTX_add_session(ctx, ssl->s3->established_session.get());
     }
     if (ctx->new_session_cb != NULL) {
-      SSL_SESSION_up_ref(ssl->s3->established_session);
-      if (!ctx->new_session_cb(ssl, ssl->s3->established_session)) {
+      SSL_SESSION_up_ref(ssl->s3->established_session.get());
+      if (!ctx->new_session_cb(ssl, ssl->s3->established_session.get())) {
         // |new_session_cb|'s return value signals whether it took ownership.
-        SSL_SESSION_free(ssl->s3->established_session);
+        SSL_SESSION_free(ssl->s3->established_session.get());
       }
     }
   }
@@ -860,7 +859,7 @@
   }
 
   // Run the handshake.
-  SSL_HANDSHAKE *hs = ssl->s3->hs;
+  SSL_HANDSHAKE *hs = ssl->s3->hs.get();
 
   bool early_return = false;
   int ret = ssl_run_handshake(hs, &early_return);
@@ -872,8 +871,7 @@
 
   // Destroy the handshake object if the handshake has completely finished.
   if (!early_return) {
-    ssl_handshake_free(ssl->s3->hs);
-    ssl->s3->hs = NULL;
+    ssl->s3->hs.reset();
   }
 
   return 1;
@@ -943,12 +941,12 @@
   }
 
   // Begin a new handshake.
-  if (ssl->s3->hs != NULL) {
+  if (ssl->s3->hs != nullptr) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return 0;
   }
   ssl->s3->hs = ssl_handshake_new(ssl);
-  if (ssl->s3->hs == NULL) {
+  if (ssl->s3->hs == nullptr) {
     return 0;
   }
 
@@ -1125,7 +1123,7 @@
       // time out because the peer never received our close_notify. Report to
       // the caller that the channel has fully shut down.
       if (ssl->s3->read_shutdown == ssl_shutdown_error) {
-        ERR_restore_state(ssl->s3->read_error);
+        ERR_restore_state(ssl->s3->read_error.get());
         return -1;
       }
       ssl->s3->read_shutdown = ssl_shutdown_close_notify;
@@ -1190,7 +1188,7 @@
 }
 
 void SSL_reset_early_data_reject(SSL *ssl) {
-  SSL_HANDSHAKE *hs = ssl->s3->hs;
+  SSL_HANDSHAKE *hs = ssl->s3->hs.get();
   if (hs == NULL ||
       hs->wait != ssl_hs_early_data_rejected) {
     abort();
@@ -1863,7 +1861,7 @@
     return ssl->tlsext_hostname;
   }
 
-  return ssl->s3->hostname;
+  return ssl->s3->hostname.get();
 }
 
 int SSL_get_servername_type(const SSL *ssl) {
@@ -1996,8 +1994,8 @@
 
 void SSL_get0_next_proto_negotiated(const SSL *ssl, const uint8_t **out_data,
                                     unsigned *out_len) {
-  *out_data = ssl->s3->next_proto_negotiated;
-  *out_len = ssl->s3->next_proto_negotiated_len;
+  *out_data = ssl->s3->next_proto_negotiated.data();
+  *out_len = ssl->s3->next_proto_negotiated.size();
 }
 
 void SSL_CTX_set_next_protos_advertised_cb(
@@ -2054,8 +2052,8 @@
     *out_data = ssl->s3->hs->early_session->early_alpn;
     *out_len = ssl->s3->hs->early_session->early_alpn_len;
   } else {
-    *out_data = ssl->s3->alpn_selected;
-    *out_len = ssl->s3->alpn_selected_len;
+    *out_data = ssl->s3->alpn_selected.data();
+    *out_len = ssl->s3->alpn_selected.size();
   }
 }
 
@@ -2434,7 +2432,7 @@
   // This returns false once all the handshake state has been finalized, to
   // allow callbacks and getters based on SSL_in_init to return the correct
   // values.
-  SSL_HANDSHAKE *hs = ssl->s3->hs;
+  SSL_HANDSHAKE *hs = ssl->s3->hs.get();
   return hs != nullptr && !hs->handshake_finalized;
 }
 
@@ -2547,7 +2545,7 @@
 }
 
 const SSL_CIPHER *SSL_get_pending_cipher(const SSL *ssl) {
-  SSL_HANDSHAKE *hs = ssl->s3->hs;
+  SSL_HANDSHAKE *hs = ssl->s3->hs.get();
   if (hs == NULL) {
     return NULL;
   }
@@ -2574,10 +2572,10 @@
   // In OpenSSL, reusing a client |SSL| with |SSL_clear| causes the previously
   // established session to be offered the next time around. wpa_supplicant
   // depends on this behavior, so emulate it.
-  SSL_SESSION *session = NULL;
+  UniquePtr<SSL_SESSION> session;
   if (!ssl->server && ssl->s3->established_session != NULL) {
-    session = ssl->s3->established_session;
-    SSL_SESSION_up_ref(session);
+    session.reset(ssl->s3->established_session.get());
+    SSL_SESSION_up_ref(session.get());
   }
 
   // TODO(davidben): Some state on |ssl| is reset both in |SSL_new| and
@@ -2602,7 +2600,6 @@
 
   ssl->method->ssl_free(ssl);
   if (!ssl->method->ssl_new(ssl)) {
-    SSL_SESSION_free(session);
     return 0;
   }
 
@@ -2610,9 +2607,8 @@
     ssl->d1->mtu = mtu;
   }
 
-  if (session != NULL) {
-    SSL_set_session(ssl, session);
-    SSL_SESSION_free(session);
+  if (session != nullptr) {
+    SSL_set_session(ssl, session.get());
   }
 
   return 1;
diff --git a/ssl/ssl_session.cc b/ssl/ssl_session.cc
index ea3c53f..34e7b31 100644
--- a/ssl/ssl_session.cc
+++ b/ssl/ssl_session.cc
@@ -999,9 +999,9 @@
   // we return the intermediate session, either |session| (for resumption) or
   // |new_session| if doing a full handshake.
   if (!SSL_in_init(ssl)) {
-    return ssl->s3->established_session;
+    return ssl->s3->established_session.get();
   }
-  SSL_HANDSHAKE *hs = ssl->s3->hs;
+  SSL_HANDSHAKE *hs = ssl->s3->hs.get();
   if (hs->early_session) {
     return hs->early_session.get();
   }
diff --git a/ssl/ssl_stat.cc b/ssl/ssl_stat.cc
index 37e0324..01153e9 100644
--- a/ssl/ssl_stat.cc
+++ b/ssl/ssl_stat.cc
@@ -89,12 +89,12 @@
 
 
 const char *SSL_state_string_long(const SSL *ssl) {
-  if (ssl->s3->hs == NULL) {
+  if (ssl->s3->hs == nullptr) {
     return "SSL negotiation finished successfully";
   }
 
-  return ssl->server ? ssl_server_handshake_state(ssl->s3->hs)
-                     : ssl_client_handshake_state(ssl->s3->hs);
+  return ssl->server ? ssl_server_handshake_state(ssl->s3->hs.get())
+                     : ssl_client_handshake_state(ssl->s3->hs.get());
 }
 
 const char *SSL_state_string(const SSL *ssl) {
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index 5d85cb0..09110dd 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -640,10 +640,12 @@
   }
 
   // Copy the hostname as a string.
-  if (!CBS_strdup(&host_name, &ssl->s3->hostname)) {
+  char *raw = nullptr;
+  if (!CBS_strdup(&host_name, &raw)) {
     *out_alert = SSL_AD_INTERNAL_ERROR;
     return false;
   }
+  ssl->s3->hostname.reset(raw);
 
   hs->should_ack_sni = true;
   return true;
@@ -862,7 +864,7 @@
   }
 
   // Whether EMS is negotiated may not change on renegotiation.
-  if (ssl->s3->established_session != NULL &&
+  if (ssl->s3->established_session != nullptr &&
       hs->extended_master_secret !=
           !!ssl->s3->established_session->extended_master_secret) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_EMS_MISMATCH);
@@ -1150,7 +1152,7 @@
   assert(!SSL_is_dtls(ssl));
   assert(ssl->ctx->next_proto_select_cb != NULL);
 
-  if (ssl->s3->alpn_selected != NULL) {
+  if (!ssl->s3->alpn_selected.empty()) {
     // NPN and ALPN may not be negotiated in the same connection.
     *out_alert = SSL_AD_ILLEGAL_PARAMETER;
     OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN);
@@ -1172,22 +1174,14 @@
   uint8_t selected_len;
   if (ssl->ctx->next_proto_select_cb(
           ssl, &selected, &selected_len, orig_contents, orig_len,
-          ssl->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK) {
+          ssl->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK ||
+      !ssl->s3->next_proto_negotiated.CopyFrom(
+          MakeConstSpan(selected, selected_len))) {
     *out_alert = SSL_AD_INTERNAL_ERROR;
     return false;
   }
 
-  OPENSSL_free(ssl->s3->next_proto_negotiated);
-  ssl->s3->next_proto_negotiated =
-      (uint8_t *)BUF_memdup(selected, selected_len);
-  if (ssl->s3->next_proto_negotiated == NULL) {
-    *out_alert = SSL_AD_INTERNAL_ERROR;
-    return false;
-  }
-
-  ssl->s3->next_proto_negotiated_len = selected_len;
   hs->next_proto_neg_seen = true;
-
   return true;
 }
 
@@ -1417,8 +1411,7 @@
     }
   }
 
-  if (!CBS_stow(&protocol_name, &ssl->s3->alpn_selected,
-                &ssl->s3->alpn_selected_len)) {
+  if (!ssl->s3->alpn_selected.CopyFrom(protocol_name)) {
     *out_alert = SSL_AD_INTERNAL_ERROR;
     return false;
   }
@@ -1470,13 +1463,11 @@
           ssl, &selected, &selected_len, CBS_data(&protocol_name_list),
           CBS_len(&protocol_name_list),
           ssl->ctx->alpn_select_cb_arg) == SSL_TLSEXT_ERR_OK) {
-    OPENSSL_free(ssl->s3->alpn_selected);
-    ssl->s3->alpn_selected = (uint8_t *)BUF_memdup(selected, selected_len);
-    if (ssl->s3->alpn_selected == NULL) {
+    if (!ssl->s3->alpn_selected.CopyFrom(
+            MakeConstSpan(selected, selected_len))) {
       *out_alert = SSL_AD_INTERNAL_ERROR;
       return false;
     }
-    ssl->s3->alpn_selected_len = selected_len;
   }
 
   return true;
@@ -1484,7 +1475,7 @@
 
 static bool ext_alpn_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
   SSL *const ssl = hs->ssl;
-  if (ssl->s3->alpn_selected == NULL) {
+  if (ssl->s3->alpn_selected.empty()) {
     return true;
   }
 
@@ -1493,8 +1484,8 @@
       !CBB_add_u16_length_prefixed(out, &contents) ||
       !CBB_add_u16_length_prefixed(&contents, &proto_list) ||
       !CBB_add_u8_length_prefixed(&proto_list, &proto) ||
-      !CBB_add_bytes(&proto, ssl->s3->alpn_selected,
-                     ssl->s3->alpn_selected_len) ||
+      !CBB_add_bytes(&proto, ssl->s3->alpn_selected.data(),
+                     ssl->s3->alpn_selected.size()) ||
       !CBB_flush(out)) {
     return false;
   }
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc
index a03c581..b6307ee 100644
--- a/ssl/tls13_client.cc
+++ b/ssl/tls13_client.cc
@@ -390,21 +390,21 @@
   }
 
   // Store the negotiated ALPN in the session.
-  if (ssl->s3->alpn_selected != NULL) {
+  if (!ssl->s3->alpn_selected.empty()) {
     hs->new_session->early_alpn = (uint8_t *)BUF_memdup(
-        ssl->s3->alpn_selected, ssl->s3->alpn_selected_len);
+        ssl->s3->alpn_selected.data(), ssl->s3->alpn_selected.size());
     if (hs->new_session->early_alpn == NULL) {
       ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
       return ssl_hs_error;
     }
-    hs->new_session->early_alpn_len = ssl->s3->alpn_selected_len;
+    hs->new_session->early_alpn_len = ssl->s3->alpn_selected.size();
   }
 
   if (ssl->early_data_accepted) {
     if (hs->early_session->cipher != hs->new_session->cipher ||
-        hs->early_session->early_alpn_len != ssl->s3->alpn_selected_len ||
-        OPENSSL_memcmp(hs->early_session->early_alpn, ssl->s3->alpn_selected,
-                       ssl->s3->alpn_selected_len) != 0) {
+        MakeConstSpan(hs->early_session->early_alpn,
+                      hs->early_session->early_alpn_len) !=
+            ssl->s3->alpn_selected) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_ALPN_MISMATCH_ON_EARLY_DATA);
       return ssl_hs_error;
     }
@@ -781,8 +781,8 @@
     return 1;
   }
 
-  UniquePtr<SSL_SESSION> session(SSL_SESSION_dup(ssl->s3->established_session,
-                                                 SSL_SESSION_INCLUDE_NONAUTH));
+  UniquePtr<SSL_SESSION> session = SSL_SESSION_dup(
+      ssl->s3->established_session.get(), SSL_SESSION_INCLUDE_NONAUTH);
   if (!session) {
     return 0;
   }
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
index 09437a5..89c9d46 100644
--- a/ssl/tls13_server.cc
+++ b/ssl/tls13_server.cc
@@ -371,8 +371,8 @@
       hs->new_session =
           SSL_SESSION_dup(session.get(), SSL_SESSION_DUP_AUTH_ONLY);
 
-      if (// Early data must be acceptable for this ticket.
-          ssl->cert->enable_early_data &&
+      if (ssl->cert->enable_early_data &&
+          // Early data must be acceptable for this ticket.
           session->ticket_max_early_data != 0 &&
           // The client must have offered early data.
           hs->early_data_offered &&
@@ -381,9 +381,8 @@
           // Custom extensions is incompatible with 0-RTT.
           hs->custom_extensions.received == 0 &&
           // The negotiated ALPN must match the one in the ticket.
-          ssl->s3->alpn_selected_len == session->early_alpn_len &&
-          OPENSSL_memcmp(ssl->s3->alpn_selected, session->early_alpn,
-                         ssl->s3->alpn_selected_len) == 0) {
+          ssl->s3->alpn_selected ==
+              MakeConstSpan(session->early_alpn, session->early_alpn_len)) {
         ssl->early_data_accepted = true;
       }
 
@@ -412,14 +411,14 @@
   hs->new_session->cipher = hs->new_cipher;
 
   // Store the initial negotiated ALPN in the session.
-  if (ssl->s3->alpn_selected != NULL) {
+  if (!ssl->s3->alpn_selected.empty()) {
     hs->new_session->early_alpn = (uint8_t *)BUF_memdup(
-        ssl->s3->alpn_selected, ssl->s3->alpn_selected_len);
+        ssl->s3->alpn_selected.data(), ssl->s3->alpn_selected.size());
     if (hs->new_session->early_alpn == NULL) {
       ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
       return ssl_hs_error;
     }
-    hs->new_session->early_alpn_len = ssl->s3->alpn_selected_len;
+    hs->new_session->early_alpn_len = ssl->s3->alpn_selected.size();
   }
 
   if (ssl->ctx->dos_protection_cb != NULL &&
diff --git a/ssl/tls_method.cc b/ssl/tls_method.cc
index 94b9e20..157cff4 100644
--- a/ssl/tls_method.cc
+++ b/ssl/tls_method.cc
@@ -94,16 +94,14 @@
 
   OPENSSL_memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence));
 
-  Delete(ssl->s3->aead_read_ctx);
-  ssl->s3->aead_read_ctx = aead_ctx.release();
+  ssl->s3->aead_read_ctx = std::move(aead_ctx);
   return true;
 }
 
 static bool ssl3_set_write_state(SSL *ssl, UniquePtr<SSLAEADContext> aead_ctx) {
   OPENSSL_memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence));
 
-  Delete(ssl->s3->aead_write_ctx);
-  ssl->s3->aead_write_ctx = aead_ctx.release();
+  ssl->s3->aead_write_ctx = std::move(aead_ctx);
   return true;
 }