Replace init_msg/init_num with a get_message hook.

Rather than init_msg/init_num, there is a get_message function which
either returns success or try again. This function does not advance the
current message (see the previous preparatory change). It only completes
the current one if necessary.

Being idempotent means it may be freely placed at the top of states
which otherwise have other asychronous operations. It also eases
converting the TLS 1.2 state machine. See
https://docs.google.com/a/google.com/document/d/11n7LHsT3GwE34LAJIe3EFs4165TI4UR_3CqiM9LJVpI/edit?usp=sharing
for details.

The read_message hook (later to be replaced by something which doesn't
depend on BIO) intentionally does not finish the handshake, only "makes
progress". A follow-up change will align both TLS and DTLS on consuming
one handshake record and always consuming the entire record (so init_buf
may contain trailing data). In a few places I've gone ahead and
accounted for that case because it was more natural to do so.

This change also removes a couple pointers of redundant state from every
socket.

Bug: 128
Change-Id: I89d8f3622d3b53147d69ee3ac34bb654ed044a71
Reviewed-on: https://boringssl-review.googlesource.com/18806
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index 1eea758..f213dba 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -339,7 +339,6 @@
 #define SSL3_ST_SR_CLNT_HELLO_A (0x110 | SSL_ST_ACCEPT)
 #define SSL3_ST_SR_CLNT_HELLO_B (0x111 | SSL_ST_ACCEPT)
 #define SSL3_ST_SR_CLNT_HELLO_C (0x112 | SSL_ST_ACCEPT)
-#define SSL3_ST_SR_CLNT_HELLO_D (0x113 | SSL_ST_ACCEPT)
 /* write to client */
 #define SSL3_ST_SW_SRVR_HELLO_A (0x130 | SSL_ST_ACCEPT)
 #define SSL3_ST_SW_CERT_A (0x140 | SSL_ST_ACCEPT)
diff --git a/ssl/d1_both.cc b/ssl/d1_both.cc
index 70af6c1..2538d28 100644
--- a/ssl/d1_both.cc
+++ b/ssl/d1_both.cc
@@ -298,9 +298,7 @@
   return frag;
 }
 
-/* dtls1_process_handshake_record reads a record for the handshake and processes
- * it. It returns one on success and 0 or -1 on error. */
-static int dtls1_process_handshake_record(SSL *ssl) {
+int dtls1_read_message(SSL *ssl) {
   SSL3_RECORD *rr = &ssl->s3->rrec;
   if (rr->length == 0) {
     int ret = dtls1_get_record(ssl);
@@ -419,52 +417,33 @@
   return 1;
 }
 
-int dtls1_get_message(SSL *ssl) {
-  /* Process handshake records until the current message is ready. */
-  while (!dtls1_is_current_message_complete(ssl)) {
-    int ret = dtls1_process_handshake_record(ssl);
-    if (ret <= 0) {
-      return ret;
-    }
+bool dtls1_get_message(SSL *ssl, SSLMessage *out) {
+  if (!dtls1_is_current_message_complete(ssl)) {
+    return false;
   }
 
   hm_fragment *frag = ssl->d1->incoming_messages[ssl->d1->handshake_read_seq %
                                                  SSL_MAX_HANDSHAKE_FLIGHT];
-  assert(frag != NULL);
-  assert(frag->reassembly == NULL);
-  assert(ssl->d1->handshake_read_seq == frag->seq);
-
-  if (ssl->init_msg == NULL) {
+  out->type = frag->type;
+  CBS_init(&out->body, frag->data + DTLS1_HM_HEADER_LENGTH, frag->msg_len);
+  CBS_init(&out->raw, frag->data, DTLS1_HM_HEADER_LENGTH + frag->msg_len);
+  out->is_v2_hello = false;
+  if (!ssl->s3->has_message) {
     ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HANDSHAKE, frag->data,
                         frag->msg_len + DTLS1_HM_HEADER_LENGTH);
+    ssl->s3->has_message = 1;
   }
-
-  /* TODO(davidben): This function has a lot of implicit outputs. Simplify the
-   * |ssl_get_message| API. */
-  ssl->s3->tmp.message_type = frag->type;
-  ssl->init_msg = frag->data + DTLS1_HM_HEADER_LENGTH;
-  ssl->init_num = frag->msg_len;
-  return 1;
-}
-
-void dtls1_get_current_message(const SSL *ssl, CBS *out) {
-  assert(dtls1_is_current_message_complete(ssl));
-
-  hm_fragment *frag = ssl->d1->incoming_messages[ssl->d1->handshake_read_seq %
-                                                 SSL_MAX_HANDSHAKE_FLIGHT];
-  CBS_init(out, frag->data, DTLS1_HM_HEADER_LENGTH + frag->msg_len);
+  return true;
 }
 
 void dtls1_next_message(SSL *ssl) {
-  assert(ssl->init_msg != NULL);
+  assert(ssl->s3->has_message);
   assert(dtls1_is_current_message_complete(ssl));
   size_t index = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT;
   dtls1_hm_fragment_free(ssl->d1->incoming_messages[index]);
   ssl->d1->incoming_messages[index] = NULL;
   ssl->d1->handshake_read_seq++;
-
-  ssl->init_msg = NULL;
-  ssl->init_num = 0;
+  ssl->s3->has_message = 0;
 }
 
 void dtls_clear_incoming_messages(SSL *ssl) {
@@ -478,7 +457,7 @@
   size_t current = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT;
   for (size_t i = 0; i < SSL_MAX_HANDSHAKE_FLIGHT; i++) {
     /* Skip the current message. */
-    if (ssl->init_msg != NULL && i == current) {
+    if (ssl->s3->has_message && i == current) {
       assert(dtls1_is_current_message_complete(ssl));
       continue;
     }
@@ -508,7 +487,7 @@
 int dtls1_read_change_cipher_spec(SSL *ssl) {
   /* Process handshake records until there is a ChangeCipherSpec. */
   while (!ssl->d1->has_change_cipher_spec) {
-    int ret = dtls1_process_handshake_record(ssl);
+    int ret = dtls1_read_message(ssl);
     if (ret <= 0) {
       return ret;
     }
diff --git a/ssl/dtls_method.cc b/ssl/dtls_method.cc
index d17afa6..9189427 100644
--- a/ssl/dtls_method.cc
+++ b/ssl/dtls_method.cc
@@ -113,7 +113,7 @@
     dtls1_new,
     dtls1_free,
     dtls1_get_message,
-    dtls1_get_current_message,
+    dtls1_read_message,
     dtls1_next_message,
     dtls1_read_app_data,
     dtls1_read_change_cipher_spec,
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc
index c43bda3..aa1524b 100644
--- a/ssl/handshake_client.cc
+++ b/ssl/handshake_client.cc
@@ -766,20 +766,19 @@
 
 static int dtls1_get_hello_verify_request(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  CBS hello_verify_request, cookie;
-  uint16_t server_version;
-
-  int ret = ssl->method->ssl_get_message(ssl);
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
   if (ret <= 0) {
     return ret;
   }
 
-  if (ssl->s3->tmp.message_type != DTLS1_MT_HELLO_VERIFY_REQUEST) {
+  if (msg.type != DTLS1_MT_HELLO_VERIFY_REQUEST) {
     ssl->d1->send_cookie = false;
     return 1;
   }
 
-  CBS_init(&hello_verify_request, ssl->init_msg, ssl->init_num);
+  CBS hello_verify_request = msg.body, cookie;
+  uint16_t server_version;
   if (!CBS_get_u16(&hello_verify_request, &server_version) ||
       !CBS_get_u8_length_prefixed(&hello_verify_request, &cookie) ||
       CBS_len(&cookie) > sizeof(ssl->d1->cookie) ||
@@ -797,17 +796,17 @@
   return 1;
 }
 
-static int parse_server_version(SSL_HANDSHAKE *hs, uint16_t *out) {
+static int parse_server_version(SSL_HANDSHAKE *hs, uint16_t *out,
+                                const SSLMessage &msg) {
   SSL *const ssl = hs->ssl;
-  if (ssl->s3->tmp.message_type != SSL3_MT_SERVER_HELLO &&
-      ssl->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST) {
+  if (msg.type != SSL3_MT_SERVER_HELLO &&
+      msg.type != SSL3_MT_HELLO_RETRY_REQUEST) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
     return 0;
   }
 
-  CBS server_hello;
-  CBS_init(&server_hello, ssl->init_msg, ssl->init_num);
+  CBS server_hello = msg.body;
   if (!CBS_get_u16(&server_hello, out)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
@@ -816,8 +815,7 @@
 
   /* The server version may also be in the supported_versions extension if
    * applicable. */
-  if (ssl->s3->tmp.message_type != SSL3_MT_SERVER_HELLO ||
-      *out != TLS1_2_VERSION) {
+  if (msg.type != SSL3_MT_SERVER_HELLO || *out != TLS1_2_VERSION) {
     return 1;
   }
 
@@ -871,7 +869,8 @@
 
 static int ssl3_get_server_hello(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  int ret = ssl->method->ssl_get_message(ssl);
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
   if (ret <= 0) {
     uint32_t err = ERR_peek_error();
     if (ERR_GET_LIB(err) == ERR_LIB_SSL &&
@@ -888,7 +887,7 @@
   }
 
   uint16_t server_version;
-  if (!parse_server_version(hs, &server_version)) {
+  if (!parse_server_version(hs, &server_version, msg)) {
     return -1;
   }
 
@@ -924,14 +923,13 @@
 
   ssl_clear_tls13_state(hs);
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_SERVER_HELLO)) {
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_SERVER_HELLO)) {
     return -1;
   }
 
-  CBS server_hello, server_random, session_id;
+  CBS server_hello = msg.body, server_random, session_id;
   uint16_t cipher_suite;
   uint8_t compression_method;
-  CBS_init(&server_hello, ssl->init_msg, ssl->init_num);
   if (!CBS_skip(&server_hello, 2 /* version */) ||
       !CBS_get_bytes(&server_hello, &server_random, SSL3_RANDOM_SIZE) ||
       !CBS_get_u8_length_prefixed(&server_hello, &session_id) ||
@@ -1015,7 +1013,7 @@
   /* Now that the cipher is known, initialize the handshake hash and hash the
    * ServerHello. */
   if (!hs->transcript.InitHash(ssl3_protocol_version(ssl), c->algorithm_prf) ||
-      !ssl_hash_current_message(hs)) {
+      !ssl_hash_message(hs, msg)) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
     return -1;
   }
@@ -1066,22 +1064,21 @@
 
 static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  int ret = ssl->method->ssl_get_message(ssl);
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
   if (ret <= 0) {
     return ret;
   }
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
-      !ssl_hash_current_message(hs)) {
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_CERTIFICATE) ||
+      !ssl_hash_message(hs, msg)) {
     return -1;
   }
 
-  CBS cbs;
-  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
-
+  CBS body = msg.body;
   uint8_t alert = SSL_AD_DECODE_ERROR;
   UniquePtr<STACK_OF(CRYPTO_BUFFER)> chain;
-  if (!ssl_parse_cert_chain(&alert, &chain, &hs->peer_pubkey, NULL, &cbs,
+  if (!ssl_parse_cert_chain(&alert, &chain, &hs->peer_pubkey, NULL, &body,
                             ssl->ctx->pool)) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     return -1;
@@ -1090,7 +1087,7 @@
   hs->new_session->certs = chain.release();
 
   if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0 ||
-      CBS_len(&cbs) != 0 ||
+      CBS_len(&body) != 0 ||
       !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);
@@ -1137,24 +1134,24 @@
 
 static int ssl3_get_cert_status(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  int ret = ssl->method->ssl_get_message(ssl);
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
   if (ret <= 0) {
     return ret;
   }
 
-  if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_STATUS) {
+  if (msg.type != SSL3_MT_CERTIFICATE_STATUS) {
     /* A server may send status_request in ServerHello and then change
      * its mind about sending CertificateStatus. */
     return 1;
   }
 
-  if (!ssl_hash_current_message(hs)) {
+  if (!ssl_hash_message(hs, msg)) {
     return -1;
   }
 
-  CBS certificate_status, ocsp_response;
+  CBS certificate_status = msg.body, ocsp_response;
   uint8_t status_type;
-  CBS_init(&certificate_status, ssl->init_msg, ssl->init_num);
   if (!CBS_get_u8(&certificate_status, &status_type) ||
       status_type != TLSEXT_STATUSTYPE_ocsp ||
       !CBS_get_u24_length_prefixed(&certificate_status, &ocsp_response) ||
@@ -1178,12 +1175,13 @@
 
 static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  int ret = ssl->method->ssl_get_message(ssl);
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
   if (ret <= 0) {
     return ret;
   }
 
-  if (ssl->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE) {
+  if (msg.type != SSL3_MT_SERVER_KEY_EXCHANGE) {
     /* Some ciphers (pure PSK) have an optional ServerKeyExchange message. */
     if (ssl_cipher_requires_server_key_exchange(hs->new_cipher)) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
@@ -1194,18 +1192,13 @@
     return 1;
   }
 
-  if (!ssl_hash_current_message(hs)) {
+  if (!ssl_hash_message(hs, msg)) {
     return -1;
   }
 
-  /* Retain a copy of the original CBS to compute the signature over. */
-  CBS server_key_exchange;
-  CBS_init(&server_key_exchange, ssl->init_msg, ssl->init_num);
-  CBS server_key_exchange_orig = server_key_exchange;
-
   uint32_t alg_k = hs->new_cipher->algorithm_mkey;
   uint32_t alg_a = hs->new_cipher->algorithm_auth;
-
+  CBS server_key_exchange = msg.body;
   if (alg_a & SSL_aPSK) {
     CBS psk_identity_hint;
 
@@ -1281,11 +1274,11 @@
   }
 
   /* At this point, |server_key_exchange| contains the signature, if any, while
-   * |server_key_exchange_orig| contains the entire message. From that, derive
-   * a CBS containing just the parameter. */
+   * |msg.body| contains the entire message. From that, derive a CBS containing
+   * just the parameter. */
   CBS parameter;
-  CBS_init(&parameter, CBS_data(&server_key_exchange_orig),
-           CBS_len(&server_key_exchange_orig) - CBS_len(&server_key_exchange));
+  CBS_init(&parameter, CBS_data(&msg.body),
+           CBS_len(&msg.body) - CBS_len(&server_key_exchange));
 
   /* ServerKeyExchange should be signed by the server's public key. */
   if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
@@ -1367,29 +1360,27 @@
 
 static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  int msg_ret = ssl->method->ssl_get_message(ssl);
-  if (msg_ret <= 0) {
-    return msg_ret;
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
+  if (ret <= 0) {
+    return ret;
   }
 
-  if (ssl->s3->tmp.message_type == SSL3_MT_SERVER_HELLO_DONE) {
+  if (msg.type == SSL3_MT_SERVER_HELLO_DONE) {
     /* If we get here we don't need the handshake buffer as we won't be doing
      * client auth. */
     hs->transcript.FreeBuffer();
     return 1;
   }
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_REQUEST) ||
-      !ssl_hash_current_message(hs)) {
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_CERTIFICATE_REQUEST) ||
+      !ssl_hash_message(hs, msg)) {
     return -1;
   }
 
-  CBS cbs;
-  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
-
   /* Get the certificate types. */
-  CBS certificate_types;
-  if (!CBS_get_u8_length_prefixed(&cbs, &certificate_types)) {
+  CBS body = msg.body, certificate_types;
+  if (!CBS_get_u8_length_prefixed(&body, &certificate_types)) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     return -1;
@@ -1403,7 +1394,7 @@
 
   if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
     CBS supported_signature_algorithms;
-    if (!CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) ||
+    if (!CBS_get_u16_length_prefixed(&body, &supported_signature_algorithms) ||
         !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) {
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
       OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
@@ -1413,13 +1404,13 @@
 
   uint8_t alert = SSL_AD_DECODE_ERROR;
   UniquePtr<STACK_OF(CRYPTO_BUFFER)> ca_names =
-      ssl_parse_client_CA_list(ssl, &alert, &cbs);
+      ssl_parse_client_CA_list(ssl, &alert, &body);
   if (!ca_names) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     return -1;
   }
 
-  if (CBS_len(&cbs) != 0) {
+  if (CBS_len(&body) != 0) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     return -1;
@@ -1434,18 +1425,19 @@
 
 static int ssl3_get_server_hello_done(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  int ret = ssl->method->ssl_get_message(ssl);
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
   if (ret <= 0) {
     return ret;
   }
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_SERVER_HELLO_DONE) ||
-      !ssl_hash_current_message(hs)) {
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_SERVER_HELLO_DONE) ||
+      !ssl_hash_message(hs, msg)) {
     return -1;
   }
 
   /* ServerHelloDone is empty. */
-  if (ssl->init_num > 0) {
+  if (CBS_len(&msg.body) != 0) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     return -1;
@@ -1796,19 +1788,19 @@
 
 static int ssl3_get_new_session_ticket(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  int ret = ssl->method->ssl_get_message(ssl);
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
   if (ret <= 0) {
     return ret;
   }
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_NEW_SESSION_TICKET) ||
-      !ssl_hash_current_message(hs)) {
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_NEW_SESSION_TICKET) ||
+      !ssl_hash_message(hs, msg)) {
     return -1;
   }
 
-  CBS new_session_ticket, ticket;
+  CBS new_session_ticket = msg.body, ticket;
   uint32_t tlsext_tick_lifetime_hint;
-  CBS_init(&new_session_ticket, ssl->init_msg, ssl->init_num);
   if (!CBS_get_u32(&new_session_ticket, &tlsext_tick_lifetime_hint) ||
       !CBS_get_u16_length_prefixed(&new_session_ticket, &ticket) ||
       CBS_len(&new_session_ticket) != 0) {
diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc
index 1889177..6cccff9 100644
--- a/ssl/handshake_server.cc
+++ b/ssl/handshake_server.cc
@@ -172,7 +172,7 @@
 
 namespace bssl {
 
-static int ssl3_process_client_hello(SSL_HANDSHAKE *hs);
+static int ssl3_read_client_hello(SSL_HANDSHAKE *hs);
 static int ssl3_select_certificate(SSL_HANDSHAKE *hs);
 static int ssl3_select_parameters(SSL_HANDSHAKE *hs);
 static int ssl3_send_server_hello(SSL_HANDSHAKE *hs);
@@ -203,7 +203,7 @@
         break;
 
       case SSL3_ST_SR_CLNT_HELLO_A:
-        ret = ssl->method->ssl_get_message(ssl);
+        ret = ssl3_read_client_hello(hs);
         if (ret <= 0) {
           goto end;
         }
@@ -211,24 +211,16 @@
         break;
 
       case SSL3_ST_SR_CLNT_HELLO_B:
-        ret = ssl3_process_client_hello(hs);
-        if (ret <= 0) {
-          goto end;
-        }
-        hs->state = SSL3_ST_SR_CLNT_HELLO_C;
-        break;
-
-      case SSL3_ST_SR_CLNT_HELLO_C:
         ret = ssl3_select_certificate(hs);
         if (ret <= 0) {
           goto end;
         }
         if (hs->state != SSL_ST_TLS13) {
-          hs->state = SSL3_ST_SR_CLNT_HELLO_D;
+          hs->state = SSL3_ST_SR_CLNT_HELLO_C;
         }
         break;
 
-      case SSL3_ST_SR_CLNT_HELLO_D:
+      case SSL3_ST_SR_CLNT_HELLO_C:
         ret = ssl3_select_parameters(hs);
         if (ret <= 0) {
           goto end;
@@ -685,15 +677,19 @@
   return nullptr;
 }
 
-static int ssl3_process_client_hello(SSL_HANDSHAKE *hs) {
+static int ssl3_read_client_hello(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) {
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
+  if (ret <= 0) {
+    return ret;
+  }
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_CLIENT_HELLO)) {
     return -1;
   }
 
   SSL_CLIENT_HELLO client_hello;
-  if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
-                             ssl->init_num)) {
+  if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     return -1;
@@ -758,6 +754,12 @@
 
 static int ssl3_select_certificate(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
+  if (ret <= 0) {
+    return ret;
+  }
+
   /* Call |cert_cb| to update server certificates if required. */
   if (ssl->cert->cert_cb != NULL) {
     int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
@@ -784,8 +786,7 @@
   }
 
   SSL_CLIENT_HELLO client_hello;
-  if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
-                             ssl->init_num)) {
+  if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
     return -1;
   }
 
@@ -804,9 +805,13 @@
 
 static int ssl3_select_parameters(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
+  if (ret <= 0) {
+    return ret;
+  }
   SSL_CLIENT_HELLO client_hello;
-  if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
-                             ssl->init_num)) {
+  if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
     return -1;
   }
 
@@ -914,7 +919,7 @@
    * the ClientHello. */
   if (!hs->transcript.InitHash(ssl3_protocol_version(ssl),
                                hs->new_cipher->algorithm_prf) ||
-      !ssl_hash_current_message(hs)) {
+      !ssl_hash_message(hs, msg)) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
     return -1;
   }
@@ -1176,14 +1181,15 @@
   SSL *const ssl = hs->ssl;
   assert(hs->cert_request);
 
-  int msg_ret = ssl->method->ssl_get_message(ssl);
-  if (msg_ret <= 0) {
-    return msg_ret;
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
+  if (ret <= 0) {
+    return ret;
   }
 
-  if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE) {
+  if (msg.type != SSL3_MT_CERTIFICATE) {
     if (ssl->version == SSL3_VERSION &&
-        ssl->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) {
+        msg.type == SSL3_MT_CLIENT_KEY_EXCHANGE) {
       /* In SSL 3.0, the Certificate message is omitted to signal no
        * certificate. */
       if (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
@@ -1203,13 +1209,11 @@
     return -1;
   }
 
-  if (!ssl_hash_current_message(hs)) {
+  if (!ssl_hash_message(hs, msg)) {
     return -1;
   }
 
-  CBS certificate_msg;
-  CBS_init(&certificate_msg, ssl->init_msg, ssl->init_num);
-
+  CBS certificate_msg = msg.body;
   uint8_t alert = SSL_AD_DECODE_ERROR;
   UniquePtr<STACK_OF(CRYPTO_BUFFER)> chain;
   if (!ssl_parse_cert_chain(&alert, &chain, &hs->peer_pubkey,
@@ -1263,21 +1267,21 @@
 
 static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  CBS client_key_exchange;
   uint8_t *premaster_secret = NULL;
   size_t premaster_secret_len = 0;
   uint8_t *decrypt_buf = NULL;
 
-  int ret = ssl->method->ssl_get_message(ssl);
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
   if (ret <= 0) {
     return ret;
   }
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_KEY_EXCHANGE)) {
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_CLIENT_KEY_EXCHANGE)) {
     return -1;
   }
 
-  CBS_init(&client_key_exchange, ssl->init_msg, ssl->init_num);
+  CBS client_key_exchange = msg.body;
   uint32_t alg_k = hs->new_cipher->algorithm_mkey;
   uint32_t alg_a = hs->new_cipher->algorithm_auth;
 
@@ -1481,7 +1485,7 @@
     premaster_secret_len = new_len;
   }
 
-  if (!ssl_hash_current_message(hs)) {
+  if (!ssl_hash_message(hs, msg)) {
     goto err;
   }
 
@@ -1510,7 +1514,6 @@
 
 static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  CBS certificate_verify, signature;
 
   /* Only RSA and ECDSA client certificates are supported, so a
    * CertificateVerify is required if and only if there's a client certificate.
@@ -1520,18 +1523,19 @@
     return 1;
   }
 
-  int msg_ret = ssl->method->ssl_get_message(ssl);
-  if (msg_ret <= 0) {
-    return msg_ret;
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
+  if (ret <= 0) {
+    return ret;
   }
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY)) {
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_CERTIFICATE_VERIFY)) {
     return -1;
   }
 
-  CBS_init(&certificate_verify, ssl->init_msg, ssl->init_num);
+  CBS certificate_verify = msg.body, signature;
 
-  /* Determine the digest type if needbe. */
+  /* Determine the signature algorithm. */
   uint16_t signature_algorithm = 0;
   if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
     if (!CBS_get_u16(&certificate_verify, &signature_algorithm)) {
@@ -1597,7 +1601,7 @@
   /* The handshake buffer is no longer necessary, and we may hash the current
    * message.*/
   hs->transcript.FreeBuffer();
-  if (!ssl_hash_current_message(hs)) {
+  if (!ssl_hash_message(hs, msg)) {
     return -1;
   }
 
@@ -1609,18 +1613,18 @@
  * sets the next_proto member in s if found */
 static int ssl3_get_next_proto(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  int ret = ssl->method->ssl_get_message(ssl);
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
   if (ret <= 0) {
     return ret;
   }
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_NEXT_PROTO) ||
-      !ssl_hash_current_message(hs)) {
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_NEXT_PROTO) ||
+      !ssl_hash_message(hs, msg)) {
     return -1;
   }
 
-  CBS next_protocol, selected_protocol, padding;
-  CBS_init(&next_protocol, ssl->init_msg, ssl->init_num);
+  CBS next_protocol = msg.body, selected_protocol, padding;
   if (!CBS_get_u8_length_prefixed(&next_protocol, &selected_protocol) ||
       !CBS_get_u8_length_prefixed(&next_protocol, &padding) ||
       CBS_len(&next_protocol) != 0) {
@@ -1641,14 +1645,15 @@
 /* ssl3_get_channel_id reads and verifies a ClientID handshake message. */
 static int ssl3_get_channel_id(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  int msg_ret = ssl->method->ssl_get_message(ssl);
-  if (msg_ret <= 0) {
-    return msg_ret;
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
+  if (ret <= 0) {
+    return ret;
   }
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_CHANNEL_ID) ||
-      !tls1_verify_channel_id(hs) ||
-      !ssl_hash_current_message(hs)) {
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_CHANNEL_ID) ||
+      !tls1_verify_channel_id(hs, msg) ||
+      !ssl_hash_message(hs, msg)) {
     return -1;
   }
   ssl->method->next_message(ssl);
diff --git a/ssl/internal.h b/ssl/internal.h
index 90236e5..e323049 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -825,6 +825,15 @@
 
 /* Handshake messages. */
 
+struct SSLMessage {
+  bool is_v2_hello;
+  uint8_t type;
+  CBS body;
+  /* raw is the entire serialized handshake message, including the TLS or DTLS
+   * message header. */
+  CBS raw;
+};
+
 /* SSL_MAX_HANDSHAKE_FLIGHT is the number of messages, including
  * ChangeCipherSpec, in the longest handshake flight. Currently this is the
  * client's second leg in a full handshake when client certificates, NPN, and
@@ -835,6 +844,11 @@
  * in a handshake message for |ssl|. */
 size_t ssl_max_handshake_message_len(const SSL *ssl);
 
+/* ssl_read_message reads a message for the old |BIO|-based state machine. On
+ * success, it returns one and sets |*out| to the current message. Otherwise, it
+ * returns <= 0. */
+int ssl_read_message(SSL *ssl, SSLMessage *out);
+
 /* dtls_clear_incoming_messages releases all buffered incoming messages. */
 void dtls_clear_incoming_messages(SSL *ssl);
 
@@ -1048,7 +1062,7 @@
  * up to the binders has a valid signature using the value of |session|'s
  * resumption secret. It returns 1 on success, and 0 on failure. */
 int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session,
-                            CBS *binders);
+                            const SSLMessage &msg, CBS *binders);
 
 
 /* Handshake functions. */
@@ -1058,7 +1072,6 @@
   ssl_hs_ok,
   ssl_hs_read_message,
   ssl_hs_flush,
-  ssl_hs_flush_and_read_message,
   ssl_hs_x509_lookup,
   ssl_hs_channel_id_lookup,
   ssl_hs_private_key_operation,
@@ -1307,9 +1320,9 @@
 /* ssl_handshake_free releases all memory associated with |hs|. */
 void ssl_handshake_free(SSL_HANDSHAKE *hs);
 
-/* ssl_check_message_type checks if the current message has type |type|. If so
- * it returns one. Otherwise, it sends an alert and returns zero. */
-int ssl_check_message_type(SSL *ssl, int type);
+/* ssl_check_message_type checks if |msg| has type |type|. If so it returns
+ * one. Otherwise, it sends an alert and returns zero. */
+int ssl_check_message_type(SSL *ssl, const SSLMessage &msg, int type);
 
 /* tls13_handshake runs the TLS 1.3 handshake. It returns one on success and <=
  * 0 on error. It sets |out_early_return| to one if we've completed the
@@ -1323,15 +1336,17 @@
 
 /* tls13_post_handshake processes a post-handshake message. It returns one on
  * success and zero on failure. */
-int tls13_post_handshake(SSL *ssl);
+int tls13_post_handshake(SSL *ssl, const SSLMessage &msg);
 
-int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous);
-int tls13_process_certificate_verify(SSL_HANDSHAKE *hs);
+int tls13_process_certificate(SSL_HANDSHAKE *hs, const SSLMessage &msg,
+                              int allow_anonymous);
+int tls13_process_certificate_verify(SSL_HANDSHAKE *hs, const SSLMessage &msg);
 
-/* tls13_process_finished processes the current message as a Finished message
- * from the peer. If |use_saved_value| is one, the verify_data is compared
- * against |hs->expected_client_finished| rather than computed fresh. */
-int tls13_process_finished(SSL_HANDSHAKE *hs, int use_saved_value);
+/* tls13_process_finished processes |msg| as a Finished message from the
+ * peer. If |use_saved_value| is one, the verify_data is compared against
+ * |hs->expected_client_finished| rather than computed fresh. */
+int tls13_process_finished(SSL_HANDSHAKE *hs, const SSLMessage &msg,
+                           int use_saved_value);
 
 int tls13_add_certificate(SSL_HANDSHAKE *hs);
 
@@ -1341,7 +1356,7 @@
 enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs);
 
 int tls13_add_finished(SSL_HANDSHAKE *hs);
-int tls13_process_new_session_ticket(SSL *ssl);
+int tls13_process_new_session_ticket(SSL *ssl, const SSLMessage &msg);
 
 int ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t **out_secret,
                                         size_t *out_secret_len,
@@ -1419,8 +1434,8 @@
 
 /* ClientHello functions. */
 
-int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out, const uint8_t *in,
-                          size_t in_len);
+int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out,
+                          const SSLMessage &msg);
 
 int ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello,
                                    CBS *out, uint16_t extension_type);
@@ -1648,6 +1663,10 @@
    * V2ClientHello rather than received from the peer directly. */
   unsigned is_v2_hello:1;
 
+  /* has_message is true if the current handshake message has been returned
+   * at least once by |get_message| and false otherwise. */
+  unsigned has_message:1;
+
   /* initial_handshake_complete is true if the initial handshake has
    * completed. */
   unsigned initial_handshake_complete:1;
@@ -1711,8 +1730,6 @@
    * TODO(davidben): Move everything not needed after the handshake completes to
    * |hs| and remove this. */
   struct {
-    int message_type;
-
     uint8_t new_mac_secret_len;
     uint8_t new_key_len;
     uint8_t new_fixed_iv_len;
@@ -1893,11 +1910,6 @@
 
   BUF_MEM *init_buf; /* buffer used during init */
 
-  /* init_msg is a pointer to the current handshake message body. */
-  const uint8_t *init_msg;
-  /* init_num is the length of the current handshake message body. */
-  uint32_t init_num;
-
   SSL3_STATE *s3;  /* SSLv3 variables */
   DTLS1_STATE *d1; /* DTLSv1 variables */
 
@@ -2137,8 +2149,8 @@
 
 int ssl3_get_finished(SSL_HANDSHAKE *hs);
 int ssl3_send_alert(SSL *ssl, int level, int desc);
-int ssl3_get_message(SSL *ssl);
-void ssl3_get_current_message(const SSL *ssl, CBS *out);
+bool ssl3_get_message(SSL *ssl, SSLMessage *out);
+int ssl3_read_message(SSL *ssl);
 void ssl3_next_message(SSL *ssl);
 
 int ssl3_send_finished(SSL_HANDSHAKE *hs);
@@ -2176,9 +2188,9 @@
  * the pending flight. It returns one on success and zero on error. */
 int ssl_add_message_cbb(SSL *ssl, CBB *cbb);
 
-/* ssl_hash_current_message incorporates the current handshake message into the
- * handshake hash. It returns one on success and zero on allocation failure. */
-int ssl_hash_current_message(SSL_HANDSHAKE *hs);
+/* ssl_hash_message incorporates |msg| into the handshake hash. It returns one
+ * on success and zero on allocation failure. */
+bool ssl_hash_message(SSL_HANDSHAKE *hs, const SSLMessage &msg);
 
 /* dtls1_get_record reads a new input record. On success, it places it in
  * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
@@ -2216,8 +2228,8 @@
 int dtls1_connect(SSL *ssl);
 void dtls1_free(SSL *ssl);
 
-int dtls1_get_message(SSL *ssl);
-void dtls1_get_current_message(const SSL *ssl, CBS *out);
+bool dtls1_get_message(SSL *ssl, SSLMessage *out);
+int dtls1_read_message(SSL *ssl);
 void dtls1_next_message(SSL *ssl);
 int dtls1_dispatch_alert(SSL *ssl);
 
@@ -2280,10 +2292,10 @@
     const uint8_t *ticket, size_t ticket_len, const uint8_t *session_id,
     size_t session_id_len);
 
-/* tls1_verify_channel_id processes the current message as a Channel ID message,
- * and verifies the signature. If the key is valid, it saves the Channel ID and
- * returns one. Otherwise, it returns zero. */
-int tls1_verify_channel_id(SSL_HANDSHAKE *hs);
+/* tls1_verify_channel_id processes |msg| as a Channel ID message, and verifies
+ * the signature. If the key is valid, it saves the Channel ID and returns
+ * one. Otherwise, it returns zero. */
+int tls1_verify_channel_id(SSL_HANDSHAKE *hs, const SSLMessage &msg);
 
 /* tls1_write_channel_id generates a Channel ID message and puts the output in
  * |cbb|. |ssl->tlsext_channel_id_private| must already be set before calling.
@@ -2357,20 +2369,19 @@
   char is_dtls;
   int (*ssl_new)(SSL *ssl);
   void (*ssl_free)(SSL *ssl);
-  /* ssl_get_message completes the current next handshake message. On success,
-   * it returns one and sets |ssl->s3->tmp.message_type|, |ssl->init_msg|, and
-   * |ssl->init_num|. Otherwise, it returns <= 0. */
-  int (*ssl_get_message)(SSL *ssl);
-  /* get_current_message sets |*out| to the current handshake message. This
-   * includes the protocol-specific message header. */
-  void (*get_current_message)(const SSL *ssl, CBS *out);
+  /* get_message sets |*out| to the current handshake message and returns true
+   * if one has been received. It returns false if more input is needed. */
+  bool (*get_message)(SSL *ssl, bssl::SSLMessage *out);
+  /* read_message reads additional handshake data for |get_message|. On success,
+   * it returns one. Otherwise, it returns <= 0. */
+  int (*read_message)(SSL *ssl);
   /* next_message is called to release the current handshake message. */
   void (*next_message)(SSL *ssl);
   /* read_app_data reads up to |len| bytes of application data into |buf|. On
    * success, it returns the number of bytes read. Otherwise, it returns <= 0
    * and sets |*out_got_handshake| to whether the failure was due to a
-   * post-handshake handshake message. If so, it fills in the current message as
-   * in |ssl_get_message|. */
+   * post-handshake handshake message. If so, any handshake messages consumed
+   * may be read with |get_message|. */
   int (*read_app_data)(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len,
                        int peek);
   int (*read_change_cipher_spec)(SSL *ssl);
diff --git a/ssl/s3_both.cc b/ssl/s3_both.cc
index 4ae6f70..9c4aa7f 100644
--- a/ssl/s3_both.cc
+++ b/ssl/s3_both.cc
@@ -187,12 +187,11 @@
 
 void ssl_handshake_free(SSL_HANDSHAKE *hs) { Delete(hs); }
 
-int ssl_check_message_type(SSL *ssl, int type) {
-  if (ssl->s3->tmp.message_type != type) {
+int ssl_check_message_type(SSL *ssl, const SSLMessage &msg, int type) {
+  if (msg.type != type) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
     OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
-    ERR_add_error_dataf("got type %d, wanted type %d",
-                        ssl->s3->tmp.message_type, type);
+    ERR_add_error_dataf("got type %d, wanted type %d", msg.type, type);
     return 0;
   }
 
@@ -422,12 +421,13 @@
 
 int ssl3_get_finished(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  int ret = ssl->method->ssl_get_message(ssl);
+  SSLMessage msg;
+  int ret = ssl_read_message(ssl, &msg);
   if (ret <= 0) {
     return ret;
   }
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED)) {
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_FINISHED)) {
     return -1;
   }
 
@@ -437,12 +437,11 @@
   if (!hs->transcript.GetFinishedMAC(finished, &finished_len,
                                      SSL_get_session(ssl), !ssl->server,
                                      ssl3_protocol_version(ssl)) ||
-      !ssl_hash_current_message(hs)) {
+      !ssl_hash_message(hs, msg)) {
     return -1;
   }
 
-  int finished_ok = ssl->init_num == finished_len &&
-                    CRYPTO_memcmp(ssl->init_msg, finished, finished_len) == 0;
+  int finished_ok = CBS_mem_equal(&msg.body, finished, finished_len);
 #if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
   finished_ok = 1;
 #endif
@@ -516,6 +515,16 @@
   return kMaxMessageLen;
 }
 
+int ssl_read_message(SSL *ssl, SSLMessage *out) {
+  while (!ssl->method->get_message(ssl, out)) {
+    int ret = ssl->method->read_message(ssl);
+    if (ret <= 0) {
+      return ret;
+    }
+  }
+  return 1;
+}
+
 static int extend_handshake_buffer(SSL *ssl, size_t length) {
   if (!BUF_MEM_reserve(ssl->init_buf, length)) {
     return -1;
@@ -683,7 +692,62 @@
   return 1;
 }
 
-int ssl3_get_message(SSL *ssl) {
+/* TODO(davidben): Remove |out_bytes_needed| and inline into |ssl3_get_message|
+ * when the entire record is copied into |init_buf|. */
+static bool parse_message(SSL *ssl, SSLMessage *out, size_t *out_bytes_needed) {
+  if (ssl->init_buf == NULL) {
+    *out_bytes_needed = 4;
+    return false;
+  }
+
+  CBS cbs;
+  uint32_t len;
+  CBS_init(&cbs, reinterpret_cast<const uint8_t *>(ssl->init_buf->data),
+           ssl->init_buf->length);
+  if (!CBS_get_u8(&cbs, &out->type) ||
+      !CBS_get_u24(&cbs, &len)) {
+    *out_bytes_needed = 4;
+    return false;
+  }
+
+  if (!CBS_get_bytes(&cbs, &out->body, len)) {
+    *out_bytes_needed = 4 + len;
+    return false;
+  }
+
+  CBS_init(&out->raw, reinterpret_cast<const uint8_t *>(ssl->init_buf->data),
+           4 + len);
+  out->is_v2_hello = ssl->s3->is_v2_hello;
+  if (!ssl->s3->has_message) {
+    if (!out->is_v2_hello) {
+      ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HANDSHAKE,
+                          CBS_data(&out->raw), CBS_len(&out->raw));
+    }
+    ssl->s3->has_message = 1;
+  }
+  return true;
+}
+
+bool ssl3_get_message(SSL *ssl, SSLMessage *out) {
+  size_t unused;
+  return parse_message(ssl, out, &unused);
+}
+
+int ssl3_read_message(SSL *ssl) {
+  SSLMessage msg;
+  size_t bytes_needed;
+  if (parse_message(ssl, &msg, &bytes_needed)) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    return -1;
+  }
+
+  /* Enforce the limit so the peer cannot force us to buffer 16MB. */
+  if (bytes_needed > 4 + ssl_max_handshake_message_len(ssl)) {
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+    OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+    return -1;
+  }
+
   /* Re-create the handshake buffer if needed. */
   if (ssl->init_buf == NULL) {
     ssl->init_buf = BUF_MEM_new();
@@ -692,79 +756,45 @@
     }
   }
 
+  /* Bypass the record layer for the first message to handle V2ClientHello. */
   if (ssl->server && !ssl->s3->v2_hello_done) {
-    /* Bypass the record layer for the first message to handle V2ClientHello. */
     int ret = read_v2_client_hello(ssl);
-    if (ret <= 0) {
-      return ret;
+    if (ret > 0) {
+      ssl->s3->v2_hello_done = 1;
     }
-    ssl->s3->v2_hello_done = 1;
-  }
-
-  /* Read the message header, if we haven't yet. */
-  int ret = extend_handshake_buffer(ssl, SSL3_HM_HEADER_LENGTH);
-  if (ret <= 0) {
     return ret;
   }
 
-  /* Parse out the length. Cap it so the peer cannot force us to buffer up to
-   * 2^24 bytes. */
-  const uint8_t *p = (uint8_t *)ssl->init_buf->data;
-  size_t msg_len = (((uint32_t)p[1]) << 16) | (((uint32_t)p[2]) << 8) | p[3];
-  if (msg_len > ssl_max_handshake_message_len(ssl)) {
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-    OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
-    return -1;
-  }
-
-  /* Read the message body, if we haven't yet. */
-  ret = extend_handshake_buffer(ssl, SSL3_HM_HEADER_LENGTH + msg_len);
-  if (ret <= 0) {
-    return ret;
-  }
-
-  /* We have now received a complete message. */
-  if (ssl->init_msg == NULL && !ssl->s3->is_v2_hello) {
-    ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HANDSHAKE,
-                        ssl->init_buf->data, ssl->init_buf->length);
-  }
-
-  ssl->s3->tmp.message_type = ((const uint8_t *)ssl->init_buf->data)[0];
-  ssl->init_msg = (uint8_t*)ssl->init_buf->data + SSL3_HM_HEADER_LENGTH;
-  ssl->init_num = ssl->init_buf->length - SSL3_HM_HEADER_LENGTH;
-  return 1;
+  return extend_handshake_buffer(ssl, bytes_needed);
 }
 
-void ssl3_get_current_message(const SSL *ssl, CBS *out) {
-  CBS_init(out, (uint8_t *)ssl->init_buf->data, ssl->init_buf->length);
-}
-
-int ssl_hash_current_message(SSL_HANDSHAKE *hs) {
-  /* V2ClientHellos are hashed implicitly. */
-  if (hs->ssl->s3->is_v2_hello) {
-    return 1;
+bool ssl_hash_message(SSL_HANDSHAKE *hs, const SSLMessage &msg) {
+  /* V2ClientHello messages are pre-hashed. */
+  if (msg.is_v2_hello) {
+    return true;
   }
 
-  CBS cbs;
-  hs->ssl->method->get_current_message(hs->ssl, &cbs);
-  return hs->transcript.Update(CBS_data(&cbs), CBS_len(&cbs));
+  return hs->transcript.Update(CBS_data(&msg.raw), CBS_len(&msg.raw));
 }
 
 void ssl3_next_message(SSL *ssl) {
-  assert(ssl->init_msg != NULL);
+  SSLMessage msg;
+  if (!ssl3_get_message(ssl, &msg) ||
+      ssl->init_buf == NULL ||
+      ssl->init_buf->length < CBS_len(&msg.raw)) {
+    assert(0);
+    return;
+  }
 
-  /* |init_buf| never contains data beyond the current message. */
-  assert(SSL3_HM_HEADER_LENGTH + ssl->init_num == ssl->init_buf->length);
-
-  /* Clear the current message. */
-  ssl->init_msg = NULL;
-  ssl->init_num = 0;
-  ssl->init_buf->length = 0;
+  OPENSSL_memmove(ssl->init_buf->data, ssl->init_buf->data + CBS_len(&msg.raw),
+                  ssl->init_buf->length - CBS_len(&msg.raw));
+  ssl->init_buf->length -= CBS_len(&msg.raw);
   ssl->s3->is_v2_hello = 0;
+  ssl->s3->has_message = 0;
 
   /* Post-handshake messages are rare, so release the buffer after every
    * message. During the handshake, |on_handshake_complete| will release it. */
-  if (!SSL_in_init(ssl)) {
+  if (!SSL_in_init(ssl) && ssl->init_buf->length == 0) {
     BUF_MEM_free(ssl->init_buf);
     ssl->init_buf = NULL;
   }
diff --git a/ssl/s3_pkt.cc b/ssl/s3_pkt.cc
index f929fe3..4f802df 100644
--- a/ssl/s3_pkt.cc
+++ b/ssl/s3_pkt.cc
@@ -411,7 +411,7 @@
       }
 
       /* Parse post-handshake handshake messages. */
-      int ret = ssl3_get_message(ssl);
+      int ret = ssl3_read_message(ssl);
       if (ret <= 0) {
         return ret;
       }
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index 1ca7a95..950bbf8 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -833,7 +833,11 @@
   return SSL_do_handshake(ssl);
 }
 
-static int ssl_do_renegotiate(SSL *ssl) {
+static int ssl_do_post_handshake(SSL *ssl, const SSLMessage &msg) {
+  if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+    return tls13_post_handshake(ssl, msg);
+  }
+
   /* We do not accept renegotiations as a server or SSL 3.0. SSL 3.0 will be
    * removed entirely in the future and requires retaining more data for
    * renegotiation_info. */
@@ -841,8 +845,7 @@
     goto no_renegotiation;
   }
 
-  if (ssl->s3->tmp.message_type != SSL3_MT_HELLO_REQUEST ||
-      ssl->init_num != 0) {
+  if (msg.type != SSL3_MT_HELLO_REQUEST || CBS_len(&msg.body) != 0) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HELLO_REQUEST);
     return 0;
@@ -893,14 +896,6 @@
   return 0;
 }
 
-static int ssl_do_post_handshake(SSL *ssl) {
-  if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
-    return ssl_do_renegotiate(ssl);
-  }
-
-  return tls13_post_handshake(ssl);
-}
-
 static int ssl_read_impl(SSL *ssl, void *buf, int num, int peek) {
   ssl_reset_error_state(ssl);
 
@@ -938,11 +933,14 @@
       continue;
     }
 
-    /* Handle the post-handshake message and try again. */
-    if (!ssl_do_post_handshake(ssl)) {
-      return -1;
+    SSLMessage msg;
+    while (ssl->method->get_message(ssl, &msg)) {
+      /* Handle the post-handshake message and try again. */
+      if (!ssl_do_post_handshake(ssl, msg)) {
+        return -1;
+      }
+      ssl->method->next_message(ssl);
     }
-    ssl->method->next_message(ssl);
   }
 }
 
@@ -2466,8 +2464,6 @@
 
   BUF_MEM_free(ssl->init_buf);
   ssl->init_buf = NULL;
-  ssl->init_msg = NULL;
-  ssl->init_num = 0;
 
   /* The ssl->d1->mtu is simultaneously configuration (preserved across
    * clear) and connection-specific state (gets reset).
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index 27a942a..39f4be6 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -204,12 +204,12 @@
   return ret;
 }
 
-int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out, const uint8_t *in,
-                          size_t in_len) {
+int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out,
+                          const SSLMessage &msg) {
   OPENSSL_memset(out, 0, sizeof(*out));
   out->ssl = ssl;
-  out->client_hello = in;
-  out->client_hello_len = in_len;
+  out->client_hello = CBS_data(&msg.body);
+  out->client_hello_len = CBS_len(&msg.body);
 
   CBS client_hello, random, session_id;
   CBS_init(&client_hello, out->client_hello, out->client_hello_len);
@@ -3276,14 +3276,12 @@
   return 0;
 }
 
-int tls1_verify_channel_id(SSL_HANDSHAKE *hs) {
+int tls1_verify_channel_id(SSL_HANDSHAKE *hs, const SSLMessage &msg) {
   SSL *const ssl = hs->ssl;
-  uint16_t extension_type;
-  CBS extension, channel_id;
-
   /* A Channel ID handshake message is structured to contain multiple
    * extensions, but the only one that can be present is Channel ID. */
-  CBS_init(&channel_id, ssl->init_msg, ssl->init_num);
+  uint16_t extension_type;
+  CBS channel_id = msg.body, extension;
   if (!CBS_get_u16(&channel_id, &extension_type) ||
       !CBS_get_u16_length_prefixed(&channel_id, &extension) ||
       CBS_len(&channel_id) != 0 ||
diff --git a/ssl/tls13_both.cc b/ssl/tls13_both.cc
index 1c2e7f7..39e0cb3 100644
--- a/ssl/tls13_both.cc
+++ b/ssl/tls13_both.cc
@@ -46,21 +46,16 @@
         OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
         return -1;
 
-      case ssl_hs_flush:
-      case ssl_hs_flush_and_read_message: {
+      case ssl_hs_flush: {
         int ret = ssl->method->flush_flight(ssl);
         if (ret <= 0) {
           return ret;
         }
-        if (hs->wait != ssl_hs_flush_and_read_message) {
-          break;
-        }
-        hs->wait = ssl_hs_read_message;
-        SSL_FALLTHROUGH;
+        break;
       }
 
       case ssl_hs_read_message: {
-        int ret = ssl->method->ssl_get_message(ssl);
+        int ret = ssl->method->read_message(ssl);
         if (ret <= 0) {
           return ret;
         }
@@ -190,14 +185,14 @@
   return 1;
 }
 
-int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) {
+int tls13_process_certificate(SSL_HANDSHAKE *hs, const SSLMessage &msg,
+                              int allow_anonymous) {
   SSL *const ssl = hs->ssl;
-  CBS cbs, context, certificate_list;
-  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
-  if (!CBS_get_u8_length_prefixed(&cbs, &context) ||
+  CBS body = msg.body, context, certificate_list;
+  if (!CBS_get_u8_length_prefixed(&body, &context) ||
       CBS_len(&context) != 0 ||
-      !CBS_get_u24_length_prefixed(&cbs, &certificate_list) ||
-      CBS_len(&cbs) != 0) {
+      !CBS_get_u24_length_prefixed(&body, &certificate_list) ||
+      CBS_len(&body) != 0) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     return 0;
@@ -356,19 +351,18 @@
   return 1;
 }
 
-int tls13_process_certificate_verify(SSL_HANDSHAKE *hs) {
+int tls13_process_certificate_verify(SSL_HANDSHAKE *hs, const SSLMessage &msg) {
   SSL *const ssl = hs->ssl;
   if (hs->peer_pubkey == NULL) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return 0;
   }
 
-  CBS cbs, signature;
+  CBS body = msg.body, signature;
   uint16_t signature_algorithm;
-  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
-  if (!CBS_get_u16(&cbs, &signature_algorithm) ||
-      !CBS_get_u16_length_prefixed(&cbs, &signature) ||
-      CBS_len(&cbs) != 0) {
+  if (!CBS_get_u16(&body, &signature_algorithm) ||
+      !CBS_get_u16_length_prefixed(&body, &signature) ||
+      CBS_len(&body) != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     return 0;
@@ -381,19 +375,19 @@
   }
   hs->new_session->peer_signature_algorithm = signature_algorithm;
 
-  uint8_t *msg = NULL;
-  size_t msg_len;
+  uint8_t *input = NULL;
+  size_t input_len;
   if (!tls13_get_cert_verify_signature_input(
-          hs, &msg, &msg_len,
+          hs, &input, &input_len,
           ssl->server ? ssl_cert_verify_client : ssl_cert_verify_server)) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
     return 0;
   }
-  UniquePtr<uint8_t> free_msg(msg);
+  UniquePtr<uint8_t> free_input(input);
 
   int sig_ok = ssl_public_key_verify(ssl, CBS_data(&signature),
                                      CBS_len(&signature), signature_algorithm,
-                                     hs->peer_pubkey.get(), msg, msg_len);
+                                     hs->peer_pubkey.get(), input, input_len);
 #if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
   sig_ok = 1;
   ERR_clear_error();
@@ -407,7 +401,8 @@
   return 1;
 }
 
-int tls13_process_finished(SSL_HANDSHAKE *hs, int use_saved_value) {
+int tls13_process_finished(SSL_HANDSHAKE *hs, const SSLMessage &msg,
+                           int use_saved_value) {
   SSL *const ssl = hs->ssl;
   uint8_t verify_data_buf[EVP_MAX_MD_SIZE];
   const uint8_t *verify_data;
@@ -424,9 +419,7 @@
     verify_data = verify_data_buf;
   }
 
-  int finished_ok =
-      ssl->init_num == verify_data_len &&
-      CRYPTO_memcmp(verify_data, ssl->init_msg, verify_data_len) == 0;
+  int finished_ok = CBS_mem_equal(&msg.body, verify_data, verify_data_len);
 #if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
   finished_ok = 1;
 #endif
@@ -584,12 +577,11 @@
   return 1;
 }
 
-static int tls13_receive_key_update(SSL *ssl) {
-  CBS cbs;
+static int tls13_receive_key_update(SSL *ssl, const SSLMessage &msg) {
+  CBS body = msg.body;
   uint8_t key_update_request;
-  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
-  if (!CBS_get_u8(&cbs, &key_update_request) ||
-      CBS_len(&cbs) != 0 ||
+  if (!CBS_get_u8(&body, &key_update_request) ||
+      CBS_len(&body) != 0 ||
       (key_update_request != SSL_KEY_UPDATE_NOT_REQUESTED &&
        key_update_request != SSL_KEY_UPDATE_REQUESTED)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
@@ -605,9 +597,10 @@
   if (key_update_request == SSL_KEY_UPDATE_REQUESTED &&
       !ssl->s3->key_update_pending) {
     ScopedCBB cbb;
-    CBB body;
-    if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_KEY_UPDATE) ||
-        !CBB_add_u8(&body, SSL_KEY_UPDATE_NOT_REQUESTED) ||
+    CBB body_cbb;
+    if (!ssl->method->init_message(ssl, cbb.get(), &body_cbb,
+                                   SSL3_MT_KEY_UPDATE) ||
+        !CBB_add_u8(&body_cbb, SSL_KEY_UPDATE_NOT_REQUESTED) ||
         !ssl_add_message_cbb(ssl, cbb.get()) ||
         !tls13_rotate_traffic_key(ssl, evp_aead_seal)) {
       return 0;
@@ -623,8 +616,8 @@
   return 1;
 }
 
-int tls13_post_handshake(SSL *ssl) {
-  if (ssl->s3->tmp.message_type == SSL3_MT_KEY_UPDATE) {
+int tls13_post_handshake(SSL *ssl, const SSLMessage &msg) {
+  if (msg.type == SSL3_MT_KEY_UPDATE) {
     ssl->s3->key_update_count++;
     if (ssl->s3->key_update_count > kMaxKeyUpdates) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_KEY_UPDATES);
@@ -632,14 +625,13 @@
       return 0;
     }
 
-    return tls13_receive_key_update(ssl);
+    return tls13_receive_key_update(ssl, msg);
   }
 
   ssl->s3->key_update_count = 0;
 
-  if (ssl->s3->tmp.message_type == SSL3_MT_NEW_SESSION_TICKET &&
-      !ssl->server) {
-    return tls13_process_new_session_ticket(ssl);
+  if (msg.type == SSL3_MT_NEW_SESSION_TICKET && !ssl->server) {
+    return tls13_process_new_session_ticket(ssl, msg);
   }
 
   ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc
index fa4731f..83066be 100644
--- a/ssl/tls13_client.cc
+++ b/ssl/tls13_client.cc
@@ -33,16 +33,15 @@
 namespace bssl {
 
 enum client_hs_state_t {
-  state_process_hello_retry_request = 0,
+  state_read_hello_retry_request = 0,
   state_send_second_client_hello,
-  state_process_server_hello,
+  state_read_server_hello,
   state_process_change_cipher_spec,
-  state_process_encrypted_extensions,
-  state_continue_second_server_flight,
-  state_process_certificate_request,
-  state_process_server_certificate,
-  state_process_server_certificate_verify,
-  state_process_server_finished,
+  state_read_encrypted_extensions,
+  state_read_certificate_request,
+  state_read_server_certificate,
+  state_read_server_certificate_verify,
+  state_read_server_finished,
   state_send_end_of_early_data,
   state_send_client_certificate,
   state_send_client_certificate_verify,
@@ -52,21 +51,24 @@
 
 static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0};
 
-static enum ssl_hs_wait_t do_process_hello_retry_request(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_hello_retry_request(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (ssl->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST) {
-    hs->tls13_state = state_process_server_hello;
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
+  if (msg.type != SSL3_MT_HELLO_RETRY_REQUEST) {
+    hs->tls13_state = state_read_server_hello;
     return ssl_hs_ok;
   }
 
-  CBS cbs, extensions;
+  CBS body = msg.body, extensions;
   uint16_t server_version;
-  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
-  if (!CBS_get_u16(&cbs, &server_version) ||
-      !CBS_get_u16_length_prefixed(&cbs, &extensions) ||
+  if (!CBS_get_u16(&body, &server_version) ||
+      !CBS_get_u16_length_prefixed(&body, &extensions) ||
       /* HelloRetryRequest may not be empty. */
       CBS_len(&extensions) == 0 ||
-      CBS_len(&cbs) != 0) {
+      CBS_len(&body) != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     return ssl_hs_error;
@@ -140,7 +142,7 @@
     hs->retry_group = group_id;
   }
 
-  if (!ssl_hash_current_message(hs)) {
+  if (!ssl_hash_message(hs, msg)) {
     return ssl_hs_error;
   }
 
@@ -164,30 +166,33 @@
     return ssl_hs_error;
   }
 
-  hs->tls13_state = state_process_server_hello;
-  return ssl_hs_flush_and_read_message;
+  hs->tls13_state = state_read_server_hello;
+  return ssl_hs_flush;
 }
 
-static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (!ssl_check_message_type(ssl, SSL3_MT_SERVER_HELLO)) {
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_SERVER_HELLO)) {
     return ssl_hs_error;
   }
 
-  CBS cbs, server_random, session_id, extensions;
+  CBS body = msg.body, server_random, session_id, extensions;
   uint16_t server_version;
   uint16_t cipher_suite;
   uint8_t compression_method;
-  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
-  if (!CBS_get_u16(&cbs, &server_version) ||
-      !CBS_get_bytes(&cbs, &server_random, SSL3_RANDOM_SIZE) ||
+  if (!CBS_get_u16(&body, &server_version) ||
+      !CBS_get_bytes(&body, &server_random, SSL3_RANDOM_SIZE) ||
       (ssl->version == TLS1_3_EXPERIMENT_VERSION &&
-       !CBS_get_u8_length_prefixed(&cbs, &session_id)) ||
-      !CBS_get_u16(&cbs, &cipher_suite) ||
+       !CBS_get_u8_length_prefixed(&body, &session_id)) ||
+      !CBS_get_u16(&body, &cipher_suite) ||
       (ssl->version == TLS1_3_EXPERIMENT_VERSION &&
-       (!CBS_get_u8(&cbs, &compression_method) || compression_method != 0)) ||
-      !CBS_get_u16_length_prefixed(&cbs, &extensions) ||
-      CBS_len(&cbs) != 0) {
+       (!CBS_get_u8(&body, &compression_method) || compression_method != 0)) ||
+      !CBS_get_u16_length_prefixed(&body, &extensions) ||
+      CBS_len(&body) != 0) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     return ssl_hs_error;
@@ -338,7 +343,7 @@
   }
   OPENSSL_free(dhe_secret);
 
-  if (!ssl_hash_current_message(hs) ||
+  if (!ssl_hash_message(hs, msg) ||
       !tls13_derive_handshake_secrets(hs)) {
     return ssl_hs_error;
   }
@@ -368,23 +373,26 @@
     }
   }
 
-  hs->tls13_state = state_process_encrypted_extensions;
-  return ssl_hs_read_message;
+  hs->tls13_state = state_read_encrypted_extensions;
+  return ssl_hs_ok;
 }
 
-static enum ssl_hs_wait_t do_process_encrypted_extensions(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_encrypted_extensions(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (!ssl_check_message_type(ssl, SSL3_MT_ENCRYPTED_EXTENSIONS)) {
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_ENCRYPTED_EXTENSIONS)) {
     return ssl_hs_error;
   }
 
-  CBS cbs;
-  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
-  if (!ssl_parse_serverhello_tlsext(hs, &cbs)) {
+  CBS body = msg.body;
+  if (!ssl_parse_serverhello_tlsext(hs, &body)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
     return ssl_hs_error;
   }
-  if (CBS_len(&cbs) != 0) {
+  if (CBS_len(&body) != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     return ssl_hs_error;
@@ -415,43 +423,42 @@
     }
   }
 
-  if (!ssl_hash_current_message(hs)) {
+  if (!ssl_hash_message(hs, msg)) {
     return ssl_hs_error;
   }
 
   ssl->method->next_message(ssl);
-  hs->tls13_state = state_continue_second_server_flight;
+  hs->tls13_state = state_read_certificate_request;
   if (hs->in_early_data && !ssl->early_data_accepted) {
     return ssl_hs_early_data_rejected;
   }
   return ssl_hs_ok;
 }
 
-static enum ssl_hs_wait_t do_continue_second_server_flight(SSL_HANDSHAKE *hs) {
-  hs->tls13_state = state_process_certificate_request;
-  return ssl_hs_read_message;
-}
-
-static enum ssl_hs_wait_t do_process_certificate_request(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_certificate_request(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
   /* CertificateRequest may only be sent in non-resumption handshakes. */
   if (ssl->s3->session_reused) {
-    hs->tls13_state = state_process_server_finished;
+    hs->tls13_state = state_read_server_finished;
     return ssl_hs_ok;
   }
 
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
+
   /* CertificateRequest is optional. */
-  if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST) {
-    hs->tls13_state = state_process_server_certificate;
+  if (msg.type != SSL3_MT_CERTIFICATE_REQUEST) {
+    hs->tls13_state = state_read_server_certificate;
     return ssl_hs_ok;
   }
 
-  CBS cbs, context, supported_signature_algorithms;
-  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
-  if (!CBS_get_u8_length_prefixed(&cbs, &context) ||
+  CBS body = msg.body, context, supported_signature_algorithms;
+  if (!CBS_get_u8_length_prefixed(&body, &context) ||
       /* The request context is always empty during the handshake. */
       CBS_len(&context) != 0 ||
-      !CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) ||
+      !CBS_get_u16_length_prefixed(&body, &supported_signature_algorithms) ||
       CBS_len(&supported_signature_algorithms) == 0 ||
       !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
@@ -461,7 +468,7 @@
 
   uint8_t alert = SSL_AD_DECODE_ERROR;
   UniquePtr<STACK_OF(CRYPTO_BUFFER)> ca_names =
-      ssl_parse_client_CA_list(ssl, &alert, &cbs);
+      ssl_parse_client_CA_list(ssl, &alert, &body);
   if (!ca_names) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     return ssl_hs_error;
@@ -469,8 +476,8 @@
 
   /* Ignore extensions. */
   CBS extensions;
-  if (!CBS_get_u16_length_prefixed(&cbs, &extensions) ||
-      CBS_len(&cbs) != 0) {
+  if (!CBS_get_u16_length_prefixed(&body, &extensions) ||
+      CBS_len(&body) != 0) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     return ssl_hs_error;
@@ -480,57 +487,69 @@
   hs->ca_names = std::move(ca_names);
   ssl->ctx->x509_method->hs_flush_cached_ca_names(hs);
 
-  if (!ssl_hash_current_message(hs)) {
+  if (!ssl_hash_message(hs, msg)) {
     return ssl_hs_error;
   }
 
   ssl->method->next_message(ssl);
-  hs->tls13_state = state_process_server_certificate;
-  return ssl_hs_read_message;
+  hs->tls13_state = state_read_server_certificate;
+  return ssl_hs_ok;
 }
 
-static enum ssl_hs_wait_t do_process_server_certificate(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_server_certificate(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
-      !tls13_process_certificate(hs, 0 /* certificate required */) ||
-      !ssl_hash_current_message(hs)) {
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_CERTIFICATE) ||
+      !tls13_process_certificate(hs, msg, 0 /* certificate required */) ||
+      !ssl_hash_message(hs, msg)) {
     return ssl_hs_error;
   }
 
   ssl->method->next_message(ssl);
-  hs->tls13_state = state_process_server_certificate_verify;
-  return ssl_hs_read_message;
+  hs->tls13_state = state_read_server_certificate_verify;
+  return ssl_hs_ok;
 }
 
-static enum ssl_hs_wait_t do_process_server_certificate_verify(
+static enum ssl_hs_wait_t do_read_server_certificate_verify(
     SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
   switch (ssl_verify_peer_cert(hs)) {
     case ssl_verify_ok:
       break;
     case ssl_verify_invalid:
       return ssl_hs_error;
     case ssl_verify_retry:
-      hs->tls13_state = state_process_server_certificate_verify;
+      hs->tls13_state = state_read_server_certificate_verify;
       return ssl_hs_certificate_verify;
   }
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) ||
-      !tls13_process_certificate_verify(hs) ||
-      !ssl_hash_current_message(hs)) {
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_CERTIFICATE_VERIFY) ||
+      !tls13_process_certificate_verify(hs, msg) ||
+      !ssl_hash_message(hs, msg)) {
     return ssl_hs_error;
   }
 
   ssl->method->next_message(ssl);
-  hs->tls13_state = state_process_server_finished;
-  return ssl_hs_read_message;
+  hs->tls13_state = state_read_server_finished;
+  return ssl_hs_ok;
 }
 
-static enum ssl_hs_wait_t do_process_server_finished(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_server_finished(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) ||
-      !tls13_process_finished(hs, 0 /* don't use saved value */) ||
-      !ssl_hash_current_message(hs) ||
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_FINISHED) ||
+      !tls13_process_finished(hs, msg, 0 /* don't use saved value */) ||
+      !ssl_hash_message(hs, msg) ||
       /* Update the secret to the master secret and derive traffic keys. */
       !tls13_advance_key_schedule(hs, kZeroes, hs->hash_len) ||
       !tls13_derive_application_secrets(hs)) {
@@ -670,35 +689,32 @@
     enum client_hs_state_t state =
         static_cast<enum client_hs_state_t>(hs->tls13_state);
     switch (state) {
-      case state_process_hello_retry_request:
-        ret = do_process_hello_retry_request(hs);
+      case state_read_hello_retry_request:
+        ret = do_read_hello_retry_request(hs);
         break;
       case state_send_second_client_hello:
         ret = do_send_second_client_hello(hs);
         break;
-      case state_process_server_hello:
-        ret = do_process_server_hello(hs);
+      case state_read_server_hello:
+        ret = do_read_server_hello(hs);
         break;
       case state_process_change_cipher_spec:
         ret = do_process_change_cipher_spec(hs);
         break;
-      case state_process_encrypted_extensions:
-        ret = do_process_encrypted_extensions(hs);
+      case state_read_encrypted_extensions:
+        ret = do_read_encrypted_extensions(hs);
         break;
-      case state_continue_second_server_flight:
-        ret = do_continue_second_server_flight(hs);
+      case state_read_certificate_request:
+        ret = do_read_certificate_request(hs);
         break;
-      case state_process_certificate_request:
-        ret = do_process_certificate_request(hs);
+      case state_read_server_certificate:
+        ret = do_read_server_certificate(hs);
         break;
-      case state_process_server_certificate:
-        ret = do_process_server_certificate(hs);
+      case state_read_server_certificate_verify:
+        ret = do_read_server_certificate_verify(hs);
         break;
-      case state_process_server_certificate_verify:
-        ret = do_process_server_certificate_verify(hs);
-        break;
-      case state_process_server_finished:
-        ret = do_process_server_finished(hs);
+      case state_read_server_finished:
+        ret = do_read_server_finished(hs);
         break;
       case state_send_end_of_early_data:
         ret = do_send_end_of_early_data(hs);
@@ -725,7 +741,7 @@
   return ssl_hs_ok;
 }
 
-int tls13_process_new_session_ticket(SSL *ssl) {
+int tls13_process_new_session_ticket(SSL *ssl, const SSLMessage &msg) {
   UniquePtr<SSL_SESSION> session(SSL_SESSION_dup(ssl->s3->established_session,
                                                  SSL_SESSION_INCLUDE_NONAUTH));
   if (!session) {
@@ -735,14 +751,13 @@
   ssl_session_rebase_time(ssl, session.get());
 
   uint32_t server_timeout;
-  CBS cbs, ticket, extensions;
-  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
-  if (!CBS_get_u32(&cbs, &server_timeout) ||
-      !CBS_get_u32(&cbs, &session->ticket_age_add) ||
-      !CBS_get_u16_length_prefixed(&cbs, &ticket) ||
+  CBS body = msg.body, ticket, extensions;
+  if (!CBS_get_u32(&body, &server_timeout) ||
+      !CBS_get_u32(&body, &session->ticket_age_add) ||
+      !CBS_get_u16_length_prefixed(&body, &ticket) ||
       !CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen) ||
-      !CBS_get_u16_length_prefixed(&cbs, &extensions) ||
-      CBS_len(&cbs) != 0) {
+      !CBS_get_u16_length_prefixed(&body, &extensions) ||
+      CBS_len(&body) != 0) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     return 0;
diff --git a/ssl/tls13_enc.cc b/ssl/tls13_enc.cc
index 1ae4849..f744cf8 100644
--- a/ssl/tls13_enc.cc
+++ b/ssl/tls13_enc.cc
@@ -402,23 +402,21 @@
 }
 
 int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session,
-                            CBS *binders) {
+                            const SSLMessage &msg, CBS *binders) {
   size_t hash_len = hs->transcript.DigestLen();
 
-  /* Get the full ClientHello, including message header. It must be large enough
-   * to exclude the binders. */
-  CBS message;
-  hs->ssl->method->get_current_message(hs->ssl, &message);
-  if (CBS_len(&message) < CBS_len(binders) + 2) {
+  /* The message must be large enough to exclude the binders. */
+  if (CBS_len(&msg.raw) < CBS_len(binders) + 2) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return 0;
   }
 
-  /* Hash a ClientHello prefix up to the binders. For now, this assumes we only
-   * ever verify PSK binders on initial ClientHellos. */
+  /* Hash a ClientHello prefix up to the binders. This includes the header. For
+   * now, this assumes we only ever verify PSK binders on initial
+   * ClientHellos. */
   uint8_t context[EVP_MAX_MD_SIZE];
   unsigned context_len;
-  if (!EVP_Digest(CBS_data(&message), CBS_len(&message) - CBS_len(binders) - 2,
+  if (!EVP_Digest(CBS_data(&msg.raw), CBS_len(&msg.raw) - CBS_len(binders) - 2,
                   context, &context_len, hs->transcript.Digest(), NULL)) {
     return 0;
   }
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
index c2cd682..2b802c4 100644
--- a/ssl/tls13_server.cc
+++ b/ssl/tls13_server.cc
@@ -42,17 +42,17 @@
   state_select_parameters = 0,
   state_select_session,
   state_send_hello_retry_request,
-  state_process_second_client_hello,
+  state_read_second_client_hello,
   state_send_server_hello,
   state_send_server_certificate_verify,
   state_send_server_finished,
   state_read_second_client_flight,
   state_process_change_cipher_spec,
   state_process_end_of_early_data,
-  state_process_client_certificate,
-  state_process_client_certificate_verify,
-  state_process_channel_id,
-  state_process_client_finished,
+  state_read_client_certificate,
+  state_read_client_certificate_verify,
+  state_read_channel_id,
+  state_read_client_finished,
   state_send_new_session_ticket,
   state_done,
 };
@@ -213,11 +213,12 @@
   /* At this point, most ClientHello extensions have already been processed by
    * the common handshake logic. Resolve the remaining non-PSK parameters. */
   SSL *const ssl = hs->ssl;
-
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
   SSL_CLIENT_HELLO client_hello;
-  if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
-                             ssl->init_num) ||
-      client_hello.session_id_len > sizeof(hs->session_id)) {
+  if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     return ssl_hs_error;
@@ -246,7 +247,7 @@
   /* The PRF hash is now known. Set up the key schedule and hash the
    * ClientHello. */
   if (!tls13_init_key_schedule(hs) ||
-      !ssl_hash_current_message(hs)) {
+      !ssl_hash_message(hs, msg)) {
     return ssl_hs_error;
   }
 
@@ -256,7 +257,8 @@
 
 static enum ssl_ticket_aead_result_t select_session(
     SSL_HANDSHAKE *hs, uint8_t *out_alert, UniquePtr<SSL_SESSION> *out_session,
-    int32_t *out_ticket_age_skew, const SSL_CLIENT_HELLO *client_hello) {
+    int32_t *out_ticket_age_skew, const SSLMessage &msg,
+    const SSL_CLIENT_HELLO *client_hello) {
   SSL *const ssl = hs->ssl;
   *out_session = NULL;
 
@@ -331,7 +333,7 @@
       (int32_t)client_ticket_age - (int32_t)server_ticket_age;
 
   /* Check the PSK binder. */
-  if (!tls13_verify_psk_binder(hs, session.get(), &binders)) {
+  if (!tls13_verify_psk_binder(hs, session.get(), msg, &binders)) {
     *out_alert = SSL_AD_DECRYPT_ERROR;
     return ssl_ticket_aead_error;
   }
@@ -342,9 +344,12 @@
 
 static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
   SSL_CLIENT_HELLO client_hello;
-  if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
-                             ssl->init_num)) {
+  if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     return ssl_hs_error;
@@ -352,7 +357,7 @@
 
   uint8_t alert = SSL_AD_DECODE_ERROR;
   UniquePtr<SSL_SESSION> session;
-  switch (select_session(hs, &alert, &session, &ssl->s3->ticket_age_skew,
+  switch (select_session(hs, &alert, &session, &ssl->s3->ticket_age_skew, msg,
                          &client_hello)) {
     case ssl_ticket_aead_ignore_ticket:
       assert(!session);
@@ -487,19 +492,21 @@
     return ssl_hs_error;
   }
 
-  hs->tls13_state = state_process_second_client_hello;
-  return ssl_hs_flush_and_read_message;
+  hs->tls13_state = state_read_second_client_hello;
+  return ssl_hs_flush;
 }
 
-static enum ssl_hs_wait_t do_process_second_client_hello(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_second_client_hello(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) {
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_CLIENT_HELLO)) {
     return ssl_hs_error;
   }
-
   SSL_CLIENT_HELLO client_hello;
-  if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
-                             ssl->init_num)) {
+  if (!ssl_client_hello_init(ssl, &client_hello, msg)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     return ssl_hs_error;
@@ -515,7 +522,7 @@
     return ssl_hs_error;
   }
 
-  if (!ssl_hash_current_message(hs)) {
+  if (!ssl_hash_message(hs, msg)) {
     return ssl_hs_error;
   }
 
@@ -717,12 +724,12 @@
                              hs->hash_len)) {
     return ssl_hs_error;
   }
-  hs->tls13_state = ssl->early_data_accepted ? state_process_client_finished
-                                             : state_process_client_certificate;
-  return ssl_hs_read_message;
+  hs->tls13_state = ssl->early_data_accepted ? state_read_client_finished
+                                             : state_read_client_certificate;
+  return ssl_hs_ok;
 }
 
-static enum ssl_hs_wait_t do_process_client_certificate(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_client_certificate(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
   if (!hs->cert_request) {
     /* OpenSSL returns X509_V_OK when no certificates are requested. This is
@@ -730,78 +737,94 @@
     hs->new_session->verify_result = X509_V_OK;
 
     /* Skip this state. */
-    hs->tls13_state = state_process_channel_id;
+    hs->tls13_state = state_read_channel_id;
     return ssl_hs_ok;
   }
 
   const int allow_anonymous =
       (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) == 0;
-
-  if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
-      !tls13_process_certificate(hs, allow_anonymous) ||
-      !ssl_hash_current_message(hs)) {
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_CERTIFICATE) ||
+      !tls13_process_certificate(hs, msg, allow_anonymous) ||
+      !ssl_hash_message(hs, msg)) {
     return ssl_hs_error;
   }
 
   ssl->method->next_message(ssl);
-  hs->tls13_state = state_process_client_certificate_verify;
-  return ssl_hs_read_message;
+  hs->tls13_state = state_read_client_certificate_verify;
+  return ssl_hs_ok;
 }
 
-static enum ssl_hs_wait_t do_process_client_certificate_verify(
+static enum ssl_hs_wait_t do_read_client_certificate_verify(
     SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
   if (sk_CRYPTO_BUFFER_num(hs->new_session->certs) == 0) {
     /* Skip this state. */
-    hs->tls13_state = state_process_channel_id;
+    hs->tls13_state = state_read_channel_id;
     return ssl_hs_ok;
   }
 
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
+
   switch (ssl_verify_peer_cert(hs)) {
     case ssl_verify_ok:
       break;
     case ssl_verify_invalid:
       return ssl_hs_error;
     case ssl_verify_retry:
-      hs->tls13_state = state_process_client_certificate_verify;
+      hs->tls13_state = state_read_client_certificate_verify;
       return ssl_hs_certificate_verify;
   }
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) ||
-      !tls13_process_certificate_verify(hs) ||
-      !ssl_hash_current_message(hs)) {
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_CERTIFICATE_VERIFY) ||
+      !tls13_process_certificate_verify(hs, msg) ||
+      !ssl_hash_message(hs, msg)) {
     return ssl_hs_error;
   }
 
   ssl->method->next_message(ssl);
-  hs->tls13_state = state_process_channel_id;
-  return ssl_hs_read_message;
+  hs->tls13_state = state_read_channel_id;
+  return ssl_hs_ok;
 }
 
-static enum ssl_hs_wait_t do_process_channel_id(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_channel_id(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
   if (!ssl->s3->tlsext_channel_id_valid) {
-    hs->tls13_state = state_process_client_finished;
+    hs->tls13_state = state_read_client_finished;
     return ssl_hs_ok;
   }
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_CHANNEL_ID) ||
-      !tls1_verify_channel_id(hs) ||
-      !ssl_hash_current_message(hs)) {
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_CHANNEL_ID) ||
+      !tls1_verify_channel_id(hs, msg) ||
+      !ssl_hash_message(hs, msg)) {
     return ssl_hs_error;
   }
 
   ssl->method->next_message(ssl);
-  hs->tls13_state = state_process_client_finished;
-  return ssl_hs_read_message;
+  hs->tls13_state = state_read_client_finished;
+  return ssl_hs_ok;
 }
 
-static enum ssl_hs_wait_t do_process_client_finished(SSL_HANDSHAKE *hs) {
+static enum ssl_hs_wait_t do_read_client_finished(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
-  if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) ||
+  SSLMessage msg;
+  if (!ssl->method->get_message(ssl, &msg)) {
+    return ssl_hs_read_message;
+  }
+  if (!ssl_check_message_type(ssl, msg, SSL3_MT_FINISHED) ||
       /* If early data was accepted, we've already computed the client Finished
        * and derived the resumption secret. */
-      !tls13_process_finished(hs, ssl->early_data_accepted) ||
+      !tls13_process_finished(hs, msg, ssl->early_data_accepted) ||
       /* evp_aead_seal keys have already been switched. */
       !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_traffic_secret_0,
                              hs->hash_len)) {
@@ -809,7 +832,7 @@
   }
 
   if (!ssl->early_data_accepted) {
-    if (!ssl_hash_current_message(hs) ||
+    if (!ssl_hash_message(hs, msg) ||
         !tls13_derive_resumption_secret(hs)) {
       return ssl_hs_error;
     }
@@ -856,8 +879,8 @@
       case state_send_hello_retry_request:
         ret = do_send_hello_retry_request(hs);
         break;
-      case state_process_second_client_hello:
-        ret = do_process_second_client_hello(hs);
+      case state_read_second_client_hello:
+        ret = do_read_second_client_hello(hs);
         break;
       case state_send_server_hello:
         ret = do_send_server_hello(hs);
@@ -877,17 +900,17 @@
       case state_process_change_cipher_spec:
         ret = do_process_change_cipher_spec(hs);
         break;
-      case state_process_client_certificate:
-        ret = do_process_client_certificate(hs);
+      case state_read_client_certificate:
+        ret = do_read_client_certificate(hs);
         break;
-      case state_process_client_certificate_verify:
-        ret = do_process_client_certificate_verify(hs);
+      case state_read_client_certificate_verify:
+        ret = do_read_client_certificate_verify(hs);
         break;
-      case state_process_channel_id:
-        ret = do_process_channel_id(hs);
+      case state_read_channel_id:
+        ret = do_read_channel_id(hs);
         break;
-      case state_process_client_finished:
-        ret = do_process_client_finished(hs);
+      case state_read_client_finished:
+        ret = do_read_client_finished(hs);
         break;
       case state_send_new_session_ticket:
         ret = do_send_new_session_ticket(hs);
diff --git a/ssl/tls_method.cc b/ssl/tls_method.cc
index 1063ca9..2fe4be3 100644
--- a/ssl/tls_method.cc
+++ b/ssl/tls_method.cc
@@ -71,7 +71,7 @@
 
 static void ssl3_on_handshake_complete(SSL *ssl) {
   /* The handshake should have released its final message. */
-  assert(ssl->init_msg == NULL);
+  assert(!ssl->s3->has_message);
 
   /* During the handshake, |init_buf| is retained. Release if it there is no
    * excess in it.
@@ -113,7 +113,7 @@
     ssl3_new,
     ssl3_free,
     ssl3_get_message,
-    ssl3_get_current_message,
+    ssl3_read_message,
     ssl3_next_message,
     ssl3_read_app_data,
     ssl3_read_change_cipher_spec,