Moving transcript and PRF functions to SSL_TRANSCRIPT.

Change-Id: I98903df561bbf8c5739f892d2ad5e89ac0eb8e6f
Reviewed-on: https://boringssl-review.googlesource.com/13369
Reviewed-by: Steven Valdez <svaldez@google.com>
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/ssl/CMakeLists.txt b/ssl/CMakeLists.txt
index 9b45d6e..5b5ea97 100644
--- a/ssl/CMakeLists.txt
+++ b/ssl/CMakeLists.txt
@@ -14,7 +14,6 @@
   handshake_client.c
   handshake_server.c
   s3_both.c
-  s3_enc.c
   s3_lib.c
   s3_pkt.c
   ssl_aead_ctx.c
@@ -29,6 +28,7 @@
   ssl_privkey_cc.cc
   ssl_session.c
   ssl_stat.c
+  ssl_transcript.c
   ssl_x509.c
   t1_enc.c
   t1_lib.c
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
index 48a5c54..b864e42 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -549,7 +549,14 @@
   }
 
   if (!is_ccs) {
-    ssl3_update_handshake_hash(ssl, data, len);
+    /* TODO(svaldez): Move this up a layer to fix abstraction for SSL_TRANSCRIPT
+     * on hs. */
+    if (ssl->s3->hs != NULL &&
+        !SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, data, len)) {
+      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+      OPENSSL_free(data);
+      return 0;
+    }
     ssl->d1->handshake_write_seq++;
   }
 
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index ad0f06a..66c0142 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -399,7 +399,7 @@
            * record the handshake hashes at this point in the session so that
            * any resumption of this session with ChannelID can sign those
            * hashes. */
-          ret = tls1_record_handshake_hashes_for_channel_id(ssl);
+          ret = tls1_record_handshake_hashes_for_channel_id(hs);
           if (ret <= 0) {
             goto end;
           }
@@ -732,7 +732,7 @@
   /* Now that the length prefixes have been computed, fill in the placeholder
    * PSK binder. */
   if (hs->needs_psk_binder &&
-      !tls13_write_psk_binder(ssl, msg, len)) {
+      !tls13_write_psk_binder(hs, msg, len)) {
     OPENSSL_free(msg);
     goto err;
   }
@@ -748,7 +748,7 @@
   SSL *const ssl = hs->ssl;
   /* The handshake buffer is reset on every ClientHello. Notably, in DTLS, we
    * may send multiple ClientHellos if we receive HelloVerifyRequest. */
-  if (!ssl3_init_handshake_buffer(ssl)) {
+  if (!SSL_TRANSCRIPT_init(&hs->transcript)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return -1;
   }
@@ -819,9 +819,6 @@
     return 1;
   }
 
-  /* The handshake transcript is reset on HelloVerifyRequst, so do not bother
-   * hashing it. */
-
   CBS_init(&hello_verify_request, ssl->init_msg, ssl->init_num);
   if (!CBS_get_u16(&hello_verify_request, &server_version) ||
       !CBS_get_u8_length_prefixed(&hello_verify_request, &cookie) ||
@@ -897,8 +894,6 @@
   assert(ssl->s3->have_version == ssl->s3->initial_handshake_complete);
   if (!ssl->s3->have_version) {
     ssl->version = server_wire_version;
-    ssl->s3->enc_method = ssl3_get_enc_method(server_version);
-    assert(ssl->s3->enc_method != NULL);
     /* At this point, the connection's version is known and ssl->version is
      * fixed. Begin enforcing the record-layer version. */
     ssl->s3->have_version = 1;
@@ -999,8 +994,9 @@
 
   /* Now that the cipher is known, initialize the handshake hash and hash the
    * ServerHello. */
-  if (!ssl3_init_handshake_hash(ssl) ||
-      !ssl_hash_current_message(ssl)) {
+  if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(ssl),
+                                c->algorithm_prf) ||
+      !ssl_hash_current_message(hs)) {
     goto f_err;
   }
 
@@ -1009,7 +1005,7 @@
    * buffer may be released. */
   if (ssl->session != NULL ||
       !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
-    ssl3_free_handshake_buffer(ssl);
+    SSL_TRANSCRIPT_free_buffer(&hs->transcript);
   }
 
   /* Only the NULL compression algorithm is supported. */
@@ -1061,7 +1057,7 @@
   }
 
   if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
-      !ssl_hash_current_message(ssl)) {
+      !ssl_hash_current_message(hs)) {
     return -1;
   }
 
@@ -1115,7 +1111,7 @@
     return 1;
   }
 
-  if (!ssl_hash_current_message(ssl)) {
+  if (!ssl_hash_current_message(hs)) {
     return -1;
   }
 
@@ -1177,7 +1173,7 @@
     return 1;
   }
 
-  if (!ssl_hash_current_message(ssl)) {
+  if (!ssl_hash_current_message(hs)) {
     return -1;
   }
 
@@ -1403,12 +1399,12 @@
     ssl->s3->tmp.reuse_message = 1;
     /* If we get here we don't need the handshake buffer as we won't be doing
      * client auth. */
-    ssl3_free_handshake_buffer(ssl);
+    SSL_TRANSCRIPT_free_buffer(&hs->transcript);
     return 1;
   }
 
   if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_REQUEST) ||
-      !ssl_hash_current_message(ssl)) {
+      !ssl_hash_current_message(hs)) {
     return -1;
   }
 
@@ -1467,7 +1463,7 @@
   }
 
   if (!ssl_check_message_type(ssl, SSL3_MT_SERVER_HELLO_DONE) ||
-      !ssl_hash_current_message(ssl)) {
+      !ssl_hash_current_message(hs)) {
     return -1;
   }
 
@@ -1499,7 +1495,7 @@
 
   if (!ssl_has_certificate(ssl)) {
     /* Without a client certificate, the handshake buffer may be released. */
-    ssl3_free_handshake_buffer(ssl);
+    SSL_TRANSCRIPT_free_buffer(&hs->transcript);
 
     /* In SSL 3.0, the Certificate message is replaced with a warning alert. */
     if (ssl->version == SSL3_VERSION) {
@@ -1680,9 +1676,8 @@
     goto err;
   }
 
-  ssl->s3->new_session->master_key_length =
-      tls1_generate_master_secret(ssl, ssl->s3->new_session->master_key, pms,
-                                  pms_len);
+  ssl->s3->new_session->master_key_length = tls1_generate_master_secret(
+      hs, ssl->s3->new_session->master_key, pms, pms_len);
   if (ssl->s3->new_session->master_key_length == 0) {
     goto err;
   }
@@ -1743,11 +1738,11 @@
         goto err;
       }
 
-      const EVP_MD *md;
       uint8_t digest[EVP_MAX_MD_SIZE];
       size_t digest_len;
-      if (!ssl3_cert_verify_hash(ssl, &md, digest, &digest_len,
-                                 signature_algorithm)) {
+      if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(
+              &hs->transcript, digest, &digest_len, ssl->s3->new_session,
+              signature_algorithm)) {
         goto err;
       }
 
@@ -1756,7 +1751,6 @@
       EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL);
       if (pctx == NULL ||
           !EVP_PKEY_sign_init(pctx) ||
-          !EVP_PKEY_CTX_set_signature_md(pctx, md) ||
           !EVP_PKEY_sign(pctx, ptr, &sig_len, digest, digest_len)) {
         EVP_PKEY_CTX_free(pctx);
         sign_result = ssl_private_key_failure;
@@ -1766,12 +1760,12 @@
     } else {
       sign_result = ssl_private_key_sign(
           ssl, ptr, &sig_len, max_sig_len, signature_algorithm,
-          (const uint8_t *)ssl->s3->handshake_buffer->data,
-          ssl->s3->handshake_buffer->length);
+          (const uint8_t *)hs->transcript.buffer->data,
+          hs->transcript.buffer->length);
     }
 
     /* The handshake buffer is no longer necessary. */
-    ssl3_free_handshake_buffer(ssl);
+    SSL_TRANSCRIPT_free_buffer(&hs->transcript);
   } else {
     assert(hs->state == SSL3_ST_CW_CERT_VRFY_B);
     sign_result = ssl_private_key_complete(ssl, ptr, &sig_len, max_sig_len);
@@ -1834,7 +1828,7 @@
 
   CBB cbb, body;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) ||
-      !tls1_write_channel_id(ssl, &body) ||
+      !tls1_write_channel_id(hs, &body) ||
       !ssl_add_message_cbb(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
@@ -1852,7 +1846,7 @@
   }
 
   if (!ssl_check_message_type(ssl, SSL3_MT_NEW_SESSION_TICKET) ||
-      !ssl_hash_current_message(ssl)) {
+      !ssl_hash_current_message(hs)) {
     return -1;
   }
 
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index 6ebfce4..5e921b6 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -218,13 +218,6 @@
 
       case SSL_ST_ACCEPT:
         ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1);
-
-        if (!ssl3_init_handshake_buffer(ssl)) {
-          OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-          ret = -1;
-          goto end;
-        }
-
         hs->state = SSL3_ST_SR_CLNT_HELLO_A;
         break;
 
@@ -421,7 +414,7 @@
          * hashes in |ssl->s3->new_session| in case we need them to verify a
          * ChannelID signature on a resumption of this session in the future. */
         if (ssl->session == NULL && ssl->s3->tlsext_channel_id_valid) {
-          ret = tls1_record_handshake_hashes_for_channel_id(ssl);
+          ret = tls1_record_handshake_hashes_for_channel_id(hs);
           if (ret <= 0) {
             goto end;
           }
@@ -654,8 +647,6 @@
 
   hs->client_version = client_hello->version;
   ssl->version = ssl->method->version_to_wire(version);
-  ssl->s3->enc_method = ssl3_get_enc_method(version);
-  assert(ssl->s3->enc_method != NULL);
 
   /* At this point, the connection's version is known and |ssl->version| is
    * fixed. Begin enforcing the record-layer version. */
@@ -1053,14 +1044,15 @@
 
   /* Now that all parameters are known, initialize the handshake hash and hash
    * the ClientHello. */
-  if (!ssl3_init_handshake_hash(ssl) ||
-      !ssl_hash_current_message(ssl)) {
+  if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(ssl),
+                                ssl->s3->tmp.new_cipher->algorithm_prf) ||
+      !ssl_hash_current_message(hs)) {
     goto f_err;
   }
 
   /* Release the handshake buffer if client authentication isn't required. */
   if (!hs->cert_request) {
-    ssl3_free_handshake_buffer(ssl);
+    SSL_TRANSCRIPT_free_buffer(&hs->transcript);
   }
 
   ret = 1;
@@ -1457,7 +1449,7 @@
     return -1;
   }
 
-  if (!ssl_hash_current_message(ssl)) {
+  if (!ssl_hash_current_message(hs)) {
     return -1;
   }
 
@@ -1488,7 +1480,7 @@
 
   if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0) {
     /* No client certificate so the handshake buffer may be discarded. */
-    ssl3_free_handshake_buffer(ssl);
+    SSL_TRANSCRIPT_free_buffer(&hs->transcript);
 
     /* In SSL 3.0, sending no certificate is signaled by omitting the
      * Certificate message. */
@@ -1543,7 +1535,7 @@
     }
 
     if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_KEY_EXCHANGE) ||
-        !ssl_hash_current_message(ssl)) {
+        !ssl_hash_current_message(hs)) {
       return -1;
     }
   }
@@ -1771,9 +1763,9 @@
   }
 
   /* Compute the master secret */
-  ssl->s3->new_session->master_key_length = tls1_generate_master_secret(
-      ssl, ssl->s3->new_session->master_key, premaster_secret,
-      premaster_secret_len);
+  ssl->s3->new_session->master_key_length =
+      tls1_generate_master_secret(hs, ssl->s3->new_session->master_key,
+                                  premaster_secret, premaster_secret_len);
   if (ssl->s3->new_session->master_key_length == 0) {
     goto err;
   }
@@ -1805,7 +1797,7 @@
    * CertificateVerify is required if and only if there's a client certificate.
    * */
   if (hs->peer_pubkey == NULL) {
-    ssl3_free_handshake_buffer(ssl);
+    SSL_TRANSCRIPT_free_buffer(&hs->transcript);
     return 1;
   }
 
@@ -1854,26 +1846,25 @@
   /* The SSL3 construction for CertificateVerify does not decompose into a
    * single final digest and signature, and must be special-cased. */
   if (ssl3_protocol_version(ssl) == SSL3_VERSION) {
-    const EVP_MD *md;
     uint8_t digest[EVP_MAX_MD_SIZE];
     size_t digest_len;
-    if (!ssl3_cert_verify_hash(ssl, &md, digest, &digest_len,
-                               signature_algorithm)) {
+    if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(&hs->transcript, digest,
+                                              &digest_len, ssl->s3->new_session,
+                                              signature_algorithm)) {
       goto err;
     }
 
     EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(hs->peer_pubkey, NULL);
     sig_ok = pctx != NULL &&
              EVP_PKEY_verify_init(pctx) &&
-             EVP_PKEY_CTX_set_signature_md(pctx, md) &&
              EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature),
                              digest, digest_len);
     EVP_PKEY_CTX_free(pctx);
   } else {
     sig_ok = ssl_public_key_verify(
         ssl, CBS_data(&signature), CBS_len(&signature), signature_algorithm,
-        hs->peer_pubkey, (const uint8_t *)ssl->s3->handshake_buffer->data,
-        ssl->s3->handshake_buffer->length);
+        hs->peer_pubkey, (const uint8_t *)hs->transcript.buffer->data,
+        hs->transcript.buffer->length);
   }
 
 #if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
@@ -1888,8 +1879,8 @@
 
   /* The handshake buffer is no longer necessary, and we may hash the current
    * message.*/
-  ssl3_free_handshake_buffer(ssl);
-  if (!ssl_hash_current_message(ssl)) {
+  SSL_TRANSCRIPT_free_buffer(&hs->transcript);
+  if (!ssl_hash_current_message(hs)) {
     goto err;
   }
 
@@ -1911,7 +1902,7 @@
   }
 
   if (!ssl_check_message_type(ssl, SSL3_MT_NEXT_PROTO) ||
-      !ssl_hash_current_message(ssl)) {
+      !ssl_hash_current_message(hs)) {
     return -1;
   }
 
@@ -1942,8 +1933,8 @@
   }
 
   if (!ssl_check_message_type(ssl, SSL3_MT_CHANNEL_ID) ||
-      !tls1_verify_channel_id(ssl) ||
-      !ssl_hash_current_message(ssl)) {
+      !tls1_verify_channel_id(hs) ||
+      !ssl_hash_current_message(hs)) {
     return -1;
   }
   return 1;
diff --git a/ssl/internal.h b/ssl/internal.h
index 18ef26a..06bdd04 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -220,10 +220,9 @@
                             const SSL_CIPHER *cipher, uint16_t version);
 
 /* ssl_get_handshake_digest returns the |EVP_MD| corresponding to
- * |algorithm_prf|. It returns SHA-1 for |SSL_HANDSHAKE_DEFAULT|. The caller is
- * responsible for maintaining the additional MD5 digest and switching to
- * SHA-256 in TLS 1.2. */
-const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf);
+ * |algorithm_prf| and the |version|. */
+const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf,
+                                       uint16_t version);
 
 /* ssl_create_cipher_list evaluates |rule_str| according to the ciphers in
  * |ssl_method|. It sets |*out_cipher_list| to a newly-allocated
@@ -260,6 +259,87 @@
 size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher);
 
 
+/* Transcript layer. */
+
+/* SSL_TRANSCRIPT maintains the handshake transcript as a combination of a
+ * buffer and running hash. */
+typedef struct ssl_transcript_st {
+  /* buffer, if non-NULL, contains the handshake transcript. */
+  BUF_MEM *buffer;
+  /* hash, if initialized with an |EVP_MD|, maintains the handshake hash. For
+   * TLS 1.1 and below, it is the SHA-1 half. */
+  EVP_MD_CTX hash;
+  /* md5, if initialized with an |EVP_MD|, maintains the MD5 half of the
+   * handshake hash for TLS 1.1 and below. */
+  EVP_MD_CTX md5;
+} SSL_TRANSCRIPT;
+
+/* SSL_TRANSCRIPT_init initializes the handshake transcript. If called on an
+ * existing transcript, it resets the transcript and hash. It returns one on
+ * success and zero on failure. */
+int SSL_TRANSCRIPT_init(SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_init_hash initializes the handshake hash based on the PRF and
+ * contents of the handshake transcript. Subsequent calls to
+ * |SSL_TRANSCRIPT_update| will update the rolling hash. It returns one on
+ * success and zero on failure. It is an error to call this function after the
+ * handshake buffer is released. */
+int SSL_TRANSCRIPT_init_hash(SSL_TRANSCRIPT *transcript, uint16_t version,
+                             int algorithm_prf);
+
+/* SSL_TRANSCRIPT_cleanup cleans up the hash and transcript. */
+void SSL_TRANSCRIPT_cleanup(SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_free_buffer releases the handshake buffer. Subsequent calls to
+ * |SSL_TRANSCRIPT_update| will not update the handshake buffer. */
+void SSL_TRANSCRIPT_free_buffer(SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_digest_len returns the length of the PRF hash. */
+size_t SSL_TRANSCRIPT_digest_len(const SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_md returns the PRF hash. For TLS 1.1 and below, this is
+ * |EVP_md5_sha1|. */
+const EVP_MD *SSL_TRANSCRIPT_md(const SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_update adds |in| to the handshake buffer and handshake hash,
+ * whichever is enabled. It returns one on success and zero on failure. */
+int SSL_TRANSCRIPT_update(SSL_TRANSCRIPT *transcript, const uint8_t *in,
+                          size_t in_len);
+
+/* SSL_TRANSCRIPT_get_hash writes the handshake hash to |out| which must have
+ * room for at least |SSL_TRANSCRIPT_digest_len| bytes. On success, it returns
+ * one and sets |*out_len| to the number of bytes written. Otherwise, it returns
+ * zero. */
+int SSL_TRANSCRIPT_get_hash(const SSL_TRANSCRIPT *transcript, uint8_t *out,
+                            size_t *out_len);
+
+/* SSL_TRANSCRIPT_ssl3_cert_verify_hash writes the SSL 3.0 CertificateVerify
+ * hash into the bytes pointed to by |out| and writes the number of bytes to
+ * |*out_len|. |out| must have room for |EVP_MAX_MD_SIZE| bytes. It returns one
+ * on success and zero on failure. */
+int SSL_TRANSCRIPT_ssl3_cert_verify_hash(SSL_TRANSCRIPT *transcript,
+                                         uint8_t *out, size_t *out_len,
+                                         const SSL_SESSION *session,
+                                         int signature_algorithm);
+
+/* SSL_TRANSCRIPT_finish_mac computes the MAC for the Finished message into the
+ * bytes pointed by |out| and writes the number of bytes to |*out_len|. |out|
+ * must have room for |EVP_MAX_MD_SIZE| bytes. It returns one on success and
+ * zero on failure. */
+int SSL_TRANSCRIPT_finish_mac(SSL_TRANSCRIPT *transcript, uint8_t *out,
+                              size_t *out_len, const SSL_SESSION *session,
+                              int from_server, uint16_t version);
+
+/* tls1_prf computes the PRF function for |ssl|. It writes |out_len| bytes to
+ * |out|, using |secret| as the secret and |label| as the label. |seed1| and
+ * |seed2| are concatenated to form the seed parameter. It returns one on
+ * success and zero on failure. */
+int tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len,
+             const uint8_t *secret, size_t secret_len, const char *label,
+             size_t label_len, const uint8_t *seed1, size_t seed1_len,
+             const uint8_t *seed2, size_t seed2_len);
+
+
 /* Encryption layer. */
 
 /* SSL_AEAD_CTX contains information about an AEAD that is being used to encrypt
@@ -525,35 +605,6 @@
 int custom_ext_add_serverhello(SSL_HANDSHAKE *hs, CBB *extensions);
 
 
-/* Handshake hash.
- *
- * The TLS handshake maintains a transcript of all handshake messages. At
- * various points in the protocol, this is either a handshake buffer, a rolling
- * hash (selected by cipher suite) or both. */
-
-/* ssl3_init_handshake_buffer initializes the handshake buffer and resets the
- * handshake hash. It returns one success and zero on failure. */
-int ssl3_init_handshake_buffer(SSL *ssl);
-
-/* ssl3_init_handshake_hash initializes the handshake hash based on the pending
- * cipher and the contents of the handshake buffer. Subsequent calls to
- * |ssl3_update_handshake_hash| will update the rolling hash. It returns one on
- * success and zero on failure. It is an error to call this function after the
- * handshake buffer is released. */
-int ssl3_init_handshake_hash(SSL *ssl);
-
-/* ssl3_free_handshake_buffer releases the handshake buffer. Subsequent calls
- * to |ssl3_update_handshake_hash| will not update the handshake buffer. */
-void ssl3_free_handshake_buffer(SSL *ssl);
-
-/* ssl3_free_handshake_hash releases the handshake hash. */
-void ssl3_free_handshake_hash(SSL *ssl);
-
-/* ssl3_update_handshake_hash adds |in| to the handshake buffer and handshake
- * hash, whichever is enabled. It returns one on success and zero on failure. */
-int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len);
-
-
 /* ECDH groups. */
 
 typedef struct ssl_ecdh_ctx_st SSL_ECDH_CTX;
@@ -827,12 +878,6 @@
 int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in,
                                size_t len);
 
-/* tls13_get_context_hash writes Hash(Handshake Context) to |out| which must
- * have room for at least |EVP_MAX_MD_SIZE| bytes. On success, it returns one
- * and sets |*out_len| to the number of bytes written. Otherwise, it returns
- * zero. */
-int tls13_get_context_hash(SSL *ssl, uint8_t *out, size_t *out_len);
-
 /* tls13_set_traffic_key sets the read or write traffic keys to
  * |traffic_secret|. It returns one on success and zero on error. */
 int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
@@ -872,12 +917,13 @@
 /* tls13_write_psk_binder calculates the PSK binder value and replaces the last
  * bytes of |msg| with the resulting value. It returns 1 on success, and 0 on
  * failure. */
-int tls13_write_psk_binder(SSL *ssl, uint8_t *msg, size_t len);
+int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len);
 
 /* tls13_verify_psk_binder verifies that the handshake transcript, truncated
  * 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 *ssl, SSL_SESSION *session, CBS *binders);
+int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session,
+                            CBS *binders);
 
 
 /* Handshake functions. */
@@ -951,6 +997,9 @@
   /* ecdh_ctx is the current ECDH instance. */
   SSL_ECDH_CTX ecdh_ctx;
 
+  /* transcript is the current handshake transcript. */
+  SSL_TRANSCRIPT transcript;
+
   /* cookie is the value of the cookie received from the server, if any. */
   uint8_t *cookie;
   size_t cookie_len;
@@ -1132,7 +1181,7 @@
  * containing the result. The caller must free it with |OPENSSL_free| to release
  * it. This function returns one on success and zero on failure. */
 int tls13_get_cert_verify_signature_input(
-    SSL *ssl, uint8_t **out, size_t *out_len,
+    SSL_HANDSHAKE *hs, uint8_t **out, size_t *out_len,
     enum ssl_cert_verify_context_t cert_verify_context);
 
 /* ssl_negotiate_alpn negotiates the ALPN extension, if applicable. It returns
@@ -1390,20 +1439,6 @@
  * crypto/x509. */
 extern const struct ssl_x509_method_st ssl_crypto_x509_method;
 
-/* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit
- * of a mess of functions, but hell, think of it as an opaque structure. */
-typedef struct ssl3_enc_method {
-  /* prf computes the PRF function for |ssl|. It writes |out_len| bytes to
-   * |out|, using |secret| as the secret and |label| as the label. |seed1| and
-   * |seed2| are concatenated to form the seed parameter. It returns one on
-   * success and zero on failure. */
-  int (*prf)(const SSL *ssl, uint8_t *out, size_t out_len,
-             const uint8_t *secret, size_t secret_len, const char *label,
-             size_t label_len, const uint8_t *seed1, size_t seed1_len,
-             const uint8_t *seed2, size_t seed2_len);
-  int (*final_finish_mac)(SSL *ssl, int from_server, uint8_t *out);
-} SSL3_ENC_METHOD;
-
 typedef struct ssl3_record_st {
   /* type is the record type. */
   uint8_t type;
@@ -1453,15 +1488,6 @@
   int wpend_ret; /* number of bytes submitted */
   const uint8_t *wpend_buf;
 
-  /* handshake_buffer, if non-NULL, contains the handshake transcript. */
-  BUF_MEM *handshake_buffer;
-  /* handshake_hash, if initialized with an |EVP_MD|, maintains the handshake
-   * hash. For TLS 1.1 and below, it is the SHA-1 half. */
-  EVP_MD_CTX handshake_hash;
-  /* handshake_md5, if initialized with an |EVP_MD|, maintains the MD5 half of
-   * the handshake hash for TLS 1.1 and below. */
-  EVP_MD_CTX handshake_md5;
-
   /* recv_shutdown is the shutdown state for the receive half of the
    * connection. */
   enum ssl_shutdown_t recv_shutdown;
@@ -1538,10 +1564,6 @@
   /* aead_write_ctx is the current write cipher state. */
   SSL_AEAD_CTX *aead_write_ctx;
 
-  /* enc_method is the method table corresponding to the current protocol
-   * version. */
-  const SSL3_ENC_METHOD *enc_method;
-
   /* hs is the handshake state for the current handshake or NULL if there isn't
    * one. */
   SSL_HANDSHAKE *hs;
@@ -1865,9 +1887,6 @@
   CRYPTO_BUFFER *ocsp_response;
 };
 
-extern const SSL3_ENC_METHOD TLSv1_enc_data;
-extern const SSL3_ENC_METHOD SSLv3_enc_data;
-
 /* From draft-ietf-tls-tls13-18, used in determining PSK modes. */
 #define SSL_PSK_KE     0x0
 #define SSL_PSK_DHE_KE 0x1
@@ -1904,6 +1923,11 @@
  * zero otherwise. */
 int ssl_session_is_resumable(const SSL *ssl, const SSL_SESSION *session);
 
+/* SSL_SESSION_get_digest returns the digest used in |session|. If the digest is
+ * invalid, it returns NULL. */
+const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session,
+                                     const SSL *ssl);
+
 void ssl_set_session(SSL *ssl, SSL_SESSION *session);
 
 enum ssl_session_result_t {
@@ -1963,13 +1987,6 @@
 void ssl3_get_current_message(const SSL *ssl, CBS *out);
 void ssl3_release_current_message(SSL *ssl, int free_buffer);
 
-/* ssl3_cert_verify_hash writes the SSL 3.0 CertificateVerify hash into the
- * bytes pointed to by |out| and writes the number of bytes to |*out_len|. |out|
- * must have room for |EVP_MAX_MD_SIZE| bytes. It sets |*out_md| to the hash
- * function used. It returns one on success and zero on failure. */
-int ssl3_cert_verify_hash(SSL *ssl, const EVP_MD **out_md, uint8_t *out,
-                          size_t *out_len, uint16_t signature_algorithm);
-
 int ssl3_send_finished(SSL_HANDSHAKE *hs);
 int ssl3_dispatch_alert(SSL *ssl);
 int ssl3_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len,
@@ -2006,7 +2023,7 @@
 
 /* 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 *ssl);
+int ssl_hash_current_message(SSL_HANDSHAKE *hs);
 
 /* 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
@@ -2050,9 +2067,8 @@
 int dtls1_dispatch_alert(SSL *ssl);
 
 int tls1_change_cipher_state(SSL_HANDSHAKE *hs, int which);
-int tls1_handshake_digest(SSL *ssl, uint8_t *out, size_t out_len);
-int tls1_generate_master_secret(SSL *ssl, uint8_t *out, const uint8_t *premaster,
-                                size_t premaster_len);
+int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out,
+                                const uint8_t *premaster, size_t premaster_len);
 
 /* tls1_get_grouplist sets |*out_group_ids| and |*out_group_ids_len| to the
  * locally-configured group preference list. */
@@ -2108,19 +2124,19 @@
 /* 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 *ssl);
+int tls1_verify_channel_id(SSL_HANDSHAKE *hs);
 
 /* 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.
  * This function returns one on success and zero on error. */
-int tls1_write_channel_id(SSL *ssl, CBB *cbb);
+int tls1_write_channel_id(SSL_HANDSHAKE *hs, CBB *cbb);
 
 /* tls1_channel_id_hash computes the hash to be signed by Channel ID and writes
  * it to |out|, which must contain at least |EVP_MAX_MD_SIZE| bytes. It returns
  * one on success and zero on failure. */
-int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len);
+int tls1_channel_id_hash(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len);
 
-int tls1_record_handshake_hashes_for_channel_id(SSL *ssl);
+int tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs);
 
 /* ssl_do_channel_id_callback checks runs |ssl->ctx->channel_id_cb| if
  * necessary. It returns one on success and zero on fatal error. Note that, on
@@ -2132,10 +2148,6 @@
  * otherwise. */
 int ssl3_can_false_start(const SSL *ssl);
 
-/* ssl3_get_enc_method returns the SSL3_ENC_METHOD corresponding to
- * |version|. */
-const SSL3_ENC_METHOD *ssl3_get_enc_method(uint16_t version);
-
 /* ssl_get_version_range sets |*out_min_version| and |*out_max_version| to the
  * minimum and maximum enabled protocol versions, respectively. */
 int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version,
@@ -2145,8 +2157,6 @@
  * call this function before the version is determined. */
 uint16_t ssl3_protocol_version(const SSL *ssl);
 
-uint32_t ssl_get_algorithm_prf(const SSL *ssl);
-
 void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock);
 
 /* ssl_reset_error_state resets state for |SSL_get_error|. */
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 8d2657f..324e9f9 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -141,6 +141,10 @@
   hs->ssl = ssl;
   hs->wait = ssl_hs_ok;
   hs->state = SSL_ST_INIT;
+  if (!SSL_TRANSCRIPT_init(&hs->transcript)) {
+    ssl_handshake_free(hs);
+    return NULL;
+  }
   return hs;
 }
 
@@ -159,6 +163,7 @@
   OPENSSL_cleanse(hs->server_traffic_secret_0,
                   sizeof(hs->server_traffic_secret_0));
   SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
+  SSL_TRANSCRIPT_cleanup(&hs->transcript);
   OPENSSL_free(hs->cookie);
   OPENSSL_free(hs->key_share_bytes);
   OPENSSL_free(hs->public_key);
@@ -264,7 +269,12 @@
   } while (added < len);
 
   ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HANDSHAKE, msg, len);
-  ssl3_update_handshake_hash(ssl, msg, len);
+  /* TODO(svaldez): Move this up a layer to fix abstraction for SSL_TRANSCRIPT
+   * on hs. */
+  if (ssl->s3->hs != NULL &&
+      !SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, msg, len)) {
+    goto err;
+  }
   ret = 1;
 
 err:
@@ -353,17 +363,20 @@
 
 int ssl3_send_finished(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
+  const SSL_SESSION *session = SSL_get_session(ssl);
+
   uint8_t finished[EVP_MAX_MD_SIZE];
-  size_t finished_len =
-      ssl->s3->enc_method->final_finish_mac(ssl, ssl->server, finished);
-  if (finished_len == 0) {
+  size_t finished_len;
+  if (!SSL_TRANSCRIPT_finish_mac(&hs->transcript, finished, &finished_len,
+                                 session, ssl->server,
+                                 ssl3_protocol_version(ssl))) {
     return 0;
   }
 
   /* Log the master secret, if logging is enabled. */
   if (!ssl_log_secret(ssl, "CLIENT_RANDOM",
-                      SSL_get_session(ssl)->master_key,
-                      SSL_get_session(ssl)->master_key_length)) {
+                      session->master_key,
+                      session->master_key_length)) {
     return 0;
   }
 
@@ -409,10 +422,11 @@
 
   /* Snapshot the finished hash before incorporating the new message. */
   uint8_t finished[EVP_MAX_MD_SIZE];
-  size_t finished_len =
-      ssl->s3->enc_method->final_finish_mac(ssl, !ssl->server, finished);
-  if (finished_len == 0 ||
-      !ssl_hash_current_message(ssl)) {
+  size_t finished_len;
+  if (!SSL_TRANSCRIPT_finish_mac(&hs->transcript, finished, &finished_len,
+                                 SSL_get_session(ssl), !ssl->server,
+                                 ssl3_protocol_version(ssl)) ||
+      !ssl_hash_current_message(hs)) {
     return -1;
   }
 
@@ -561,9 +575,11 @@
   CBS_init(&v2_client_hello, ssl_read_buffer(ssl) + 2, msg_length);
 
   /* The V2ClientHello without the length is incorporated into the handshake
-   * hash. */
-  if (!ssl3_update_handshake_hash(ssl, CBS_data(&v2_client_hello),
-                                  CBS_len(&v2_client_hello))) {
+   * hash. This is only ever called at the start of the handshake, so hs is
+   * guaranteed to be non-NULL. */
+  if (!SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript,
+                             CBS_data(&v2_client_hello),
+                             CBS_len(&v2_client_hello))) {
     return -1;
   }
 
@@ -734,15 +750,15 @@
   CBS_init(out, (uint8_t *)ssl->init_buf->data, ssl->init_buf->length);
 }
 
-int ssl_hash_current_message(SSL *ssl) {
+int ssl_hash_current_message(SSL_HANDSHAKE *hs) {
   /* V2ClientHellos are hashed implicitly. */
-  if (ssl->s3->is_v2_hello) {
+  if (hs->ssl->s3->is_v2_hello) {
     return 1;
   }
 
   CBS cbs;
-  ssl->method->get_current_message(ssl, &cbs);
-  return ssl3_update_handshake_hash(ssl, CBS_data(&cbs), CBS_len(&cbs));
+  hs->ssl->method->get_current_message(hs->ssl, &cbs);
+  return SSL_TRANSCRIPT_update(&hs->transcript, CBS_data(&cbs), CBS_len(&cbs));
 }
 
 void ssl3_release_current_message(SSL *ssl, int free_buffer) {
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 3f44629..1c723cd 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -178,9 +178,6 @@
     return 0;
   }
 
-  EVP_MD_CTX_init(&s3->handshake_hash);
-  EVP_MD_CTX_init(&s3->handshake_md5);
-
   ssl->s3 = s3;
 
   /* Set the version to the highest supported version.
@@ -202,8 +199,6 @@
 
   SSL_SESSION_free(ssl->s3->new_session);
   SSL_SESSION_free(ssl->s3->established_session);
-  ssl3_free_handshake_buffer(ssl);
-  ssl3_free_handshake_hash(ssl);
   ssl_handshake_free(ssl->s3->hs);
   OPENSSL_free(ssl->s3->next_proto_negotiated);
   OPENSSL_free(ssl->s3->alpn_selected);
@@ -224,14 +219,3 @@
 
   return ssl->ctx->cipher_list;
 }
-
-/* If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF and
- * handshake macs if required. */
-uint32_t ssl_get_algorithm_prf(const SSL *ssl) {
-  uint32_t algorithm_prf = ssl->s3->tmp.new_cipher->algorithm_prf;
-  if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT &&
-      ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
-    return SSL_HANDSHAKE_MAC_SHA256;
-  }
-  return algorithm_prf;
-}
diff --git a/ssl/ssl_cipher.c b/ssl/ssl_cipher.c
index 480304f..8f1ad73 100644
--- a/ssl/ssl_cipher.c
+++ b/ssl/ssl_cipher.c
@@ -787,10 +787,11 @@
   return 1;
 }
 
-const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf) {
+const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf,
+                                       uint16_t version) {
   switch (algorithm_prf) {
     case SSL_HANDSHAKE_MAC_DEFAULT:
-      return EVP_sha1();
+      return version >= TLS1_2_VERSION ? EVP_sha256() : EVP_md5_sha1();
     case SSL_HANDSHAKE_MAC_SHA256:
       return EVP_sha256();
     case SSL_HANDSHAKE_MAC_SHA384:
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 7fc7233..c946b77 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2383,22 +2383,6 @@
       cipher->algorithm_mac == SSL_AEAD;
 }
 
-const SSL3_ENC_METHOD *ssl3_get_enc_method(uint16_t version) {
-  switch (version) {
-    case SSL3_VERSION:
-      return &SSLv3_enc_data;
-
-    case TLS1_VERSION:
-    case TLS1_1_VERSION:
-    case TLS1_2_VERSION:
-    case TLS1_3_VERSION:
-      return &TLSv1_enc_data;
-
-    default:
-      return NULL;
-  }
-}
-
 const struct {
   uint16_t version;
   uint32_t flag;
diff --git a/ssl/ssl_session.c b/ssl/ssl_session.c
index 9221e92..908d5dc 100644
--- a/ssl/ssl_session.c
+++ b/ssl/ssl_session.c
@@ -494,6 +494,16 @@
   return CRYPTO_get_ex_data(&session->ex_data, idx);
 }
 
+const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session,
+                                     const SSL *ssl) {
+  uint16_t version;
+  if (!ssl->method->version_from_wire(&version, session->ssl_version)) {
+    return NULL;
+  }
+
+  return ssl_get_handshake_digest(session->cipher->algorithm_prf, version);
+}
+
 int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) {
   SSL *const ssl = hs->ssl;
   if (ssl->mode & SSL_MODE_NO_SESSION_CREATION) {
diff --git a/ssl/s3_enc.c b/ssl/ssl_transcript.c
similarity index 64%
rename from ssl/s3_enc.c
rename to ssl/ssl_transcript.c
index bf82e08..9cc3777 100644
--- a/ssl/s3_enc.c
+++ b/ssl/ssl_transcript.c
@@ -138,84 +138,22 @@
 #include <assert.h>
 #include <string.h>
 
+#include <openssl/buf.h>
+#include <openssl/digest.h>
 #include <openssl/err.h>
-#include <openssl/evp.h>
 #include <openssl/mem.h>
 #include <openssl/md5.h>
 #include <openssl/nid.h>
+#include <openssl/sha.h>
 
 #include "../crypto/internal.h"
 #include "internal.h"
 
 
-static int ssl3_prf(const SSL *ssl, uint8_t *out, size_t out_len,
-                    const uint8_t *secret, size_t secret_len, const char *label,
-                    size_t label_len, const uint8_t *seed1, size_t seed1_len,
-                    const uint8_t *seed2, size_t seed2_len) {
-  EVP_MD_CTX md5;
-  EVP_MD_CTX sha1;
-  uint8_t buf[16], smd[SHA_DIGEST_LENGTH];
-  uint8_t c = 'A';
-  size_t i, j, k;
-
-  k = 0;
-  EVP_MD_CTX_init(&md5);
-  EVP_MD_CTX_init(&sha1);
-  for (i = 0; i < out_len; i += MD5_DIGEST_LENGTH) {
-    k++;
-    if (k > sizeof(buf)) {
-      /* bug: 'buf' is too small for this ciphersuite */
-      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-      return 0;
-    }
-
-    for (j = 0; j < k; j++) {
-      buf[j] = c;
-    }
-    c++;
-    if (!EVP_DigestInit_ex(&sha1, EVP_sha1(), NULL)) {
-      OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
-      return 0;
-    }
-    EVP_DigestUpdate(&sha1, buf, k);
-    EVP_DigestUpdate(&sha1, secret, secret_len);
-    /* |label| is ignored for SSLv3. */
-    if (seed1_len) {
-      EVP_DigestUpdate(&sha1, seed1, seed1_len);
-    }
-    if (seed2_len) {
-      EVP_DigestUpdate(&sha1, seed2, seed2_len);
-    }
-    EVP_DigestFinal_ex(&sha1, smd, NULL);
-
-    if (!EVP_DigestInit_ex(&md5, EVP_md5(), NULL)) {
-      OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
-      return 0;
-    }
-    EVP_DigestUpdate(&md5, secret, secret_len);
-    EVP_DigestUpdate(&md5, smd, SHA_DIGEST_LENGTH);
-    if (i + MD5_DIGEST_LENGTH > out_len) {
-      EVP_DigestFinal_ex(&md5, smd, NULL);
-      OPENSSL_memcpy(out, smd, out_len - i);
-    } else {
-      EVP_DigestFinal_ex(&md5, out, NULL);
-    }
-
-    out += MD5_DIGEST_LENGTH;
-  }
-
-  OPENSSL_cleanse(smd, SHA_DIGEST_LENGTH);
-  EVP_MD_CTX_cleanup(&md5);
-  EVP_MD_CTX_cleanup(&sha1);
-
-  return 1;
-}
-
-int ssl3_init_handshake_buffer(SSL *ssl) {
-  ssl3_free_handshake_buffer(ssl);
-  ssl3_free_handshake_hash(ssl);
-  ssl->s3->handshake_buffer = BUF_MEM_new();
-  return ssl->s3->handshake_buffer != NULL;
+int SSL_TRANSCRIPT_init(SSL_TRANSCRIPT *transcript) {
+  SSL_TRANSCRIPT_cleanup(transcript);
+  transcript->buffer = BUF_MEM_new();
+  return transcript->buffer != NULL;
 }
 
 /* init_digest_with_data calls |EVP_DigestInit_ex| on |ctx| with |md| and then
@@ -229,78 +167,113 @@
   return 1;
 }
 
-int ssl3_init_handshake_hash(SSL *ssl) {
-  ssl3_free_handshake_hash(ssl);
+int SSL_TRANSCRIPT_init_hash(SSL_TRANSCRIPT *transcript, uint16_t version,
+                             int algorithm_prf) {
+  const EVP_MD *md = ssl_get_handshake_digest(algorithm_prf, version);
 
-  uint32_t algorithm_prf = ssl_get_algorithm_prf(ssl);
-  if (!init_digest_with_data(&ssl->s3->handshake_hash,
-                             ssl_get_handshake_digest(algorithm_prf),
-                             ssl->s3->handshake_buffer)) {
-    return 0;
+  /* To support SSL 3.0's Finished and CertificateVerify constructions,
+   * EVP_md5_sha1() is split into MD5 and SHA-1 halves. When SSL 3.0 is removed,
+   * we can simplify this. */
+  if (md == EVP_md5_sha1()) {
+    if (!init_digest_with_data(&transcript->md5, EVP_md5(),
+                               transcript->buffer)) {
+      return 0;
+    }
+    md = EVP_sha1();
   }
 
-  if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT &&
-      !init_digest_with_data(&ssl->s3->handshake_md5, EVP_md5(),
-                             ssl->s3->handshake_buffer)) {
+  if (!init_digest_with_data(&transcript->hash, md, transcript->buffer)) {
     return 0;
   }
 
   return 1;
 }
 
-void ssl3_free_handshake_hash(SSL *ssl) {
-  EVP_MD_CTX_cleanup(&ssl->s3->handshake_hash);
-  EVP_MD_CTX_cleanup(&ssl->s3->handshake_md5);
+void SSL_TRANSCRIPT_cleanup(SSL_TRANSCRIPT *transcript) {
+  SSL_TRANSCRIPT_free_buffer(transcript);
+  EVP_MD_CTX_cleanup(&transcript->hash);
+  EVP_MD_CTX_cleanup(&transcript->md5);
 }
 
-void ssl3_free_handshake_buffer(SSL *ssl) {
-  BUF_MEM_free(ssl->s3->handshake_buffer);
-  ssl->s3->handshake_buffer = NULL;
+void SSL_TRANSCRIPT_free_buffer(SSL_TRANSCRIPT *transcript) {
+  BUF_MEM_free(transcript->buffer);
+  transcript->buffer = NULL;
 }
 
-int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len) {
+size_t SSL_TRANSCRIPT_digest_len(const SSL_TRANSCRIPT *transcript) {
+  return EVP_MD_size(SSL_TRANSCRIPT_md(transcript));
+}
+
+const EVP_MD *SSL_TRANSCRIPT_md(const SSL_TRANSCRIPT *transcript) {
+  if (EVP_MD_CTX_md(&transcript->md5) != NULL) {
+    return EVP_md5_sha1();
+  }
+  return EVP_MD_CTX_md(&transcript->hash);
+}
+
+int SSL_TRANSCRIPT_update(SSL_TRANSCRIPT *transcript, const uint8_t *in,
+                          size_t in_len) {
   /* Depending on the state of the handshake, either the handshake buffer may be
    * active, the rolling hash, or both. */
-
-  if (ssl->s3->handshake_buffer != NULL) {
-    size_t new_len = ssl->s3->handshake_buffer->length + in_len;
+  if (transcript->buffer != NULL) {
+    size_t new_len = transcript->buffer->length + in_len;
     if (new_len < in_len) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
       return 0;
     }
-    if (!BUF_MEM_grow(ssl->s3->handshake_buffer, new_len)) {
+    if (!BUF_MEM_grow(transcript->buffer, new_len)) {
       return 0;
     }
-    OPENSSL_memcpy(ssl->s3->handshake_buffer->data + new_len - in_len, in,
-                   in_len);
+    OPENSSL_memcpy(transcript->buffer->data + new_len - in_len, in, in_len);
   }
 
-  if (EVP_MD_CTX_md(&ssl->s3->handshake_hash) != NULL) {
-    EVP_DigestUpdate(&ssl->s3->handshake_hash, in, in_len);
+  if (EVP_MD_CTX_md(&transcript->hash) != NULL) {
+    EVP_DigestUpdate(&transcript->hash, in, in_len);
   }
-  if (EVP_MD_CTX_md(&ssl->s3->handshake_md5) != NULL) {
-    EVP_DigestUpdate(&ssl->s3->handshake_md5, in, in_len);
+  if (EVP_MD_CTX_md(&transcript->md5) != NULL) {
+    EVP_DigestUpdate(&transcript->md5, in, in_len);
   }
+
   return 1;
 }
 
-static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender,
-                              size_t sender_len, uint8_t *p) {
-  unsigned int ret;
+int SSL_TRANSCRIPT_get_hash(const SSL_TRANSCRIPT *transcript, uint8_t *out,
+                            size_t *out_len) {
+  int ret = 0;
+  EVP_MD_CTX ctx;
+  EVP_MD_CTX_init(&ctx);
+  unsigned md5_len = 0;
+  if (EVP_MD_CTX_md(&transcript->md5) != NULL) {
+    if (!EVP_MD_CTX_copy_ex(&ctx, &transcript->md5) ||
+        !EVP_DigestFinal_ex(&ctx, out, &md5_len)) {
+      goto err;
+    }
+  }
+
+  unsigned len;
+  if (!EVP_MD_CTX_copy_ex(&ctx, &transcript->hash) ||
+      !EVP_DigestFinal_ex(&ctx, out + md5_len, &len)) {
+    goto err;
+  }
+
+  *out_len = md5_len + len;
+  ret = 1;
+
+err:
+  EVP_MD_CTX_cleanup(&ctx);
+  return ret;
+}
+
+static int ssl3_handshake_mac(SSL_TRANSCRIPT *transcript,
+                              const SSL_SESSION *session,
+                              const EVP_MD_CTX *ctx_template,
+                              const char *sender, size_t sender_len,
+                              uint8_t *p, size_t *out_len) {
+  unsigned int len;
   size_t npad, n;
   unsigned int i;
   uint8_t md_buf[EVP_MAX_MD_SIZE];
   EVP_MD_CTX ctx;
-  const EVP_MD_CTX *ctx_template;
-
-  if (md_nid == NID_md5) {
-    ctx_template = &ssl->s3->handshake_md5;
-  } else if (md_nid == EVP_MD_CTX_type(&ssl->s3->handshake_hash)) {
-    ctx_template = &ssl->s3->handshake_hash;
-  } else {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_REQUIRED_DIGEST);
-    return 0;
-  }
 
   EVP_MD_CTX_init(&ctx);
   if (!EVP_MD_CTX_copy_ex(&ctx, ctx_template)) {
@@ -325,11 +298,6 @@
 
   n = EVP_MD_CTX_size(&ctx);
 
-  SSL_SESSION *session = ssl->session;
-  if (ssl->s3->new_session != NULL) {
-    session = ssl->s3->new_session;
-  }
-
   npad = (48 / n) * n;
   if (sender != NULL) {
     EVP_DigestUpdate(&ctx, sender, sender_len);
@@ -346,61 +314,92 @@
   EVP_DigestUpdate(&ctx, session->master_key, session->master_key_length);
   EVP_DigestUpdate(&ctx, kPad2, npad);
   EVP_DigestUpdate(&ctx, md_buf, i);
-  EVP_DigestFinal_ex(&ctx, p, &ret);
+  EVP_DigestFinal_ex(&ctx, p, &len);
 
   EVP_MD_CTX_cleanup(&ctx);
 
-  return ret;
+  *out_len = len;
+  return 1;
 }
 
-static int ssl3_final_finish_mac(SSL *ssl, int from_server, uint8_t *out) {
-  const char *sender = from_server ? SSL3_MD_SERVER_FINISHED_CONST
-                                   : SSL3_MD_CLIENT_FINISHED_CONST;
-  const size_t sender_len = 4;
-  int ret, sha1len;
-  ret = ssl3_handshake_mac(ssl, NID_md5, sender, sender_len, out);
-  if (ret == 0) {
-    return 0;
-  }
-
-  out += ret;
-
-  sha1len = ssl3_handshake_mac(ssl, NID_sha1, sender, sender_len, out);
-  if (sha1len == 0) {
-    return 0;
-  }
-
-  ret += sha1len;
-  return ret;
-}
-
-int ssl3_cert_verify_hash(SSL *ssl, const EVP_MD **out_md, uint8_t *out,
-                          size_t *out_len, uint16_t signature_algorithm) {
-  assert(ssl3_protocol_version(ssl) == SSL3_VERSION);
-
-  if (signature_algorithm == SSL_SIGN_RSA_PKCS1_MD5_SHA1) {
-    if (ssl3_handshake_mac(ssl, NID_md5, NULL, 0, out) == 0 ||
-        ssl3_handshake_mac(ssl, NID_sha1, NULL, 0,
-                           out + MD5_DIGEST_LENGTH) == 0) {
-      return 0;
-    }
-    *out_md = EVP_md5_sha1();
-    *out_len = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH;
-  } else if (signature_algorithm == SSL_SIGN_ECDSA_SHA1) {
-    if (ssl3_handshake_mac(ssl, NID_sha1, NULL, 0, out) == 0) {
-      return 0;
-    }
-    *out_md = EVP_sha1();
-    *out_len = SHA_DIGEST_LENGTH;
-  } else {
+int SSL_TRANSCRIPT_ssl3_cert_verify_hash(SSL_TRANSCRIPT *transcript,
+                                         uint8_t *out, size_t *out_len,
+                                         const SSL_SESSION *session,
+                                         int signature_algorithm) {
+  if (SSL_TRANSCRIPT_md(transcript) != EVP_md5_sha1()) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return 0;
   }
 
-  return 1;
+  if (signature_algorithm == SSL_SIGN_RSA_PKCS1_MD5_SHA1) {
+    size_t md5_len, len;
+    if (!ssl3_handshake_mac(transcript, session, &transcript->md5, NULL, 0, out,
+                            &md5_len) ||
+        !ssl3_handshake_mac(transcript, session, &transcript->hash, NULL, 0,
+                            out + md5_len, &len)) {
+      return 0;
+    }
+    *out_len = md5_len + len;
+    return 1;
+  }
+
+  if (signature_algorithm == SSL_SIGN_ECDSA_SHA1) {
+    return ssl3_handshake_mac(transcript, session, &transcript->hash, NULL, 0,
+                              out, out_len);
+  }
+
+  OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+  return 0;
 }
 
-const SSL3_ENC_METHOD SSLv3_enc_data = {
-    ssl3_prf,
-    ssl3_final_finish_mac,
-};
+int SSL_TRANSCRIPT_finish_mac(SSL_TRANSCRIPT *transcript, uint8_t *out,
+                              size_t *out_len, const SSL_SESSION *session,
+                              int from_server, uint16_t version) {
+  if (version == SSL3_VERSION) {
+    if (SSL_TRANSCRIPT_md(transcript) != EVP_md5_sha1()) {
+      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+      return 0;
+    }
+
+    const char *sender = from_server ? SSL3_MD_SERVER_FINISHED_CONST
+                                     : SSL3_MD_CLIENT_FINISHED_CONST;
+    const size_t sender_len = 4;
+    size_t md5_len, len;
+    if (!ssl3_handshake_mac(transcript, session, &transcript->md5, sender,
+                            sender_len, out, &md5_len) ||
+        !ssl3_handshake_mac(transcript, session, &transcript->hash, sender,
+                            sender_len, out + md5_len, &len)) {
+      return 0;
+    }
+
+    *out_len = md5_len + len;
+    return 1;
+  }
+
+  /* At this point, the handshake should have released the handshake buffer on
+   * its own. */
+  assert(transcript->buffer == NULL);
+
+  const char *label = TLS_MD_CLIENT_FINISH_CONST;
+  size_t label_len = TLS_MD_SERVER_FINISH_CONST_SIZE;
+  if (from_server) {
+    label = TLS_MD_SERVER_FINISH_CONST;
+    label_len = TLS_MD_SERVER_FINISH_CONST_SIZE;
+  }
+
+  uint8_t digests[EVP_MAX_MD_SIZE];
+  size_t digests_len;
+  if (!SSL_TRANSCRIPT_get_hash(transcript, digests, &digests_len)) {
+    return 0;
+  }
+
+  static const size_t kFinishedLen = 12;
+  if (!tls1_prf(SSL_TRANSCRIPT_md(transcript), out, kFinishedLen,
+                session->master_key, session->master_key_length, label,
+                label_len, digests, digests_len, NULL, 0)) {
+    return 0;
+  }
+
+  *out_len = kFinishedLen;
+  return 1;
+}
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 5e5c348..d01992e 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -224,18 +224,17 @@
   return ret;
 }
 
-static int tls1_prf(const SSL *ssl, uint8_t *out, size_t out_len,
-                    const uint8_t *secret, size_t secret_len, const char *label,
-                    size_t label_len, const uint8_t *seed1, size_t seed1_len,
-                    const uint8_t *seed2, size_t seed2_len) {
+int tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len,
+             const uint8_t *secret, size_t secret_len, const char *label,
+             size_t label_len, const uint8_t *seed1, size_t seed1_len,
+             const uint8_t *seed2, size_t seed2_len) {
   if (out_len == 0) {
     return 1;
   }
 
   OPENSSL_memset(out, 0, out_len);
 
-  uint32_t algorithm_prf = ssl_get_algorithm_prf(ssl);
-  if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT) {
+  if (digest == EVP_md5_sha1()) {
     /* If using the MD5/SHA1 PRF, |secret| is partitioned between SHA-1 and
      * MD5, MD5 first. */
     size_t secret_half = secret_len - (secret_len / 2);
@@ -248,17 +247,82 @@
     /* Note that, if |secret_len| is odd, the two halves share a byte. */
     secret = secret + (secret_len - secret_half);
     secret_len = secret_half;
+
+    digest = EVP_sha1();
   }
 
-  if (!tls1_P_hash(out, out_len, ssl_get_handshake_digest(algorithm_prf),
-                   secret, secret_len, (const uint8_t *)label, label_len,
-                   seed1, seed1_len, seed2, seed2_len)) {
+  if (!tls1_P_hash(out, out_len, digest, secret, secret_len,
+                   (const uint8_t *)label, label_len, seed1, seed1_len, seed2,
+                   seed2_len)) {
     return 0;
   }
 
   return 1;
 }
 
+static int ssl3_prf(uint8_t *out, size_t out_len, const uint8_t *secret,
+                    size_t secret_len, const char *label, size_t label_len,
+                    const uint8_t *seed1, size_t seed1_len,
+                    const uint8_t *seed2, size_t seed2_len) {
+  EVP_MD_CTX md5;
+  EVP_MD_CTX sha1;
+  uint8_t buf[16], smd[SHA_DIGEST_LENGTH];
+  uint8_t c = 'A';
+  size_t i, j, k;
+
+  k = 0;
+  EVP_MD_CTX_init(&md5);
+  EVP_MD_CTX_init(&sha1);
+  for (i = 0; i < out_len; i += MD5_DIGEST_LENGTH) {
+    k++;
+    if (k > sizeof(buf)) {
+      /* bug: 'buf' is too small for this ciphersuite */
+      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+      return 0;
+    }
+
+    for (j = 0; j < k; j++) {
+      buf[j] = c;
+    }
+    c++;
+    if (!EVP_DigestInit_ex(&sha1, EVP_sha1(), NULL)) {
+      OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
+      return 0;
+    }
+    EVP_DigestUpdate(&sha1, buf, k);
+    EVP_DigestUpdate(&sha1, secret, secret_len);
+    /* |label| is ignored for SSLv3. */
+    if (seed1_len) {
+      EVP_DigestUpdate(&sha1, seed1, seed1_len);
+    }
+    if (seed2_len) {
+      EVP_DigestUpdate(&sha1, seed2, seed2_len);
+    }
+    EVP_DigestFinal_ex(&sha1, smd, NULL);
+
+    if (!EVP_DigestInit_ex(&md5, EVP_md5(), NULL)) {
+      OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
+      return 0;
+    }
+    EVP_DigestUpdate(&md5, secret, secret_len);
+    EVP_DigestUpdate(&md5, smd, SHA_DIGEST_LENGTH);
+    if (i + MD5_DIGEST_LENGTH > out_len) {
+      EVP_DigestFinal_ex(&md5, smd, NULL);
+      OPENSSL_memcpy(out, smd, out_len - i);
+    } else {
+      EVP_DigestFinal_ex(&md5, out, NULL);
+    }
+
+    out += MD5_DIGEST_LENGTH;
+  }
+
+  OPENSSL_cleanse(smd, SHA_DIGEST_LENGTH);
+  EVP_MD_CTX_cleanup(&md5);
+  EVP_MD_CTX_cleanup(&sha1);
+
+  return 1;
+}
+
 static int tls1_setup_key_block(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
   if (hs->key_block_len != 0) {
@@ -385,112 +449,58 @@
 }
 
 int SSL_generate_key_block(const SSL *ssl, uint8_t *out, size_t out_len) {
-  return ssl->s3->enc_method->prf(
-      ssl, out, out_len, SSL_get_session(ssl)->master_key,
-      SSL_get_session(ssl)->master_key_length, TLS_MD_KEY_EXPANSION_CONST,
-      TLS_MD_KEY_EXPANSION_CONST_SIZE, ssl->s3->server_random, SSL3_RANDOM_SIZE,
-      ssl->s3->client_random, SSL3_RANDOM_SIZE);
-}
-
-static int append_digest(const EVP_MD_CTX *ctx, uint8_t *out, size_t *out_len,
-                         size_t max_out) {
-  int ret = 0;
-  EVP_MD_CTX ctx_copy;
-  EVP_MD_CTX_init(&ctx_copy);
-
-  if (EVP_MD_CTX_size(ctx) > max_out) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
-    goto err;
-  }
-  unsigned len;
-  if (!EVP_MD_CTX_copy_ex(&ctx_copy, ctx) ||
-      !EVP_DigestFinal_ex(&ctx_copy, out, &len)) {
-    goto err;
-  }
-  assert(len == EVP_MD_CTX_size(ctx));
-
-  *out_len = len;
-  ret = 1;
-
-err:
-  EVP_MD_CTX_cleanup(&ctx_copy);
-  return ret;
-}
-
-/* tls1_handshake_digest calculates the current handshake hash and writes it to
- * |out|, which has space for |out_len| bytes. It returns the number of bytes
- * written or -1 in the event of an error. This function works on a copy of the
- * underlying digests so can be called multiple times and prior to the final
- * update etc. */
-int tls1_handshake_digest(SSL *ssl, uint8_t *out, size_t out_len) {
-  size_t md5_len = 0;
-  if (EVP_MD_CTX_md(&ssl->s3->handshake_md5) != NULL &&
-      !append_digest(&ssl->s3->handshake_md5, out, &md5_len, out_len)) {
-    return -1;
+  if (ssl3_protocol_version(ssl) == SSL3_VERSION) {
+    return ssl3_prf(out, out_len, SSL_get_session(ssl)->master_key,
+                    SSL_get_session(ssl)->master_key_length,
+                    TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE,
+                    ssl->s3->server_random, SSL3_RANDOM_SIZE,
+                    ssl->s3->client_random, SSL3_RANDOM_SIZE);
   }
 
-  size_t len;
-  if (!append_digest(&ssl->s3->handshake_hash, out + md5_len, &len,
-                     out_len - md5_len)) {
-    return -1;
-  }
-
-  return (int)(md5_len + len);
-}
-
-static int tls1_final_finish_mac(SSL *ssl, int from_server, uint8_t *out) {
-  /* At this point, the handshake should have released the handshake buffer on
-   * its own. */
-  assert(ssl->s3->handshake_buffer == NULL);
-
-  const char *label = TLS_MD_CLIENT_FINISH_CONST;
-  size_t label_len = TLS_MD_SERVER_FINISH_CONST_SIZE;
-  if (from_server) {
-    label = TLS_MD_SERVER_FINISH_CONST;
-    label_len = TLS_MD_SERVER_FINISH_CONST_SIZE;
-  }
-
-  uint8_t buf[EVP_MAX_MD_SIZE];
-  int digests_len = tls1_handshake_digest(ssl, buf, sizeof(buf));
-  if (digests_len < 0) {
+  const EVP_MD *digest = ssl_get_handshake_digest(
+      SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
+  if (digest == NULL) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return 0;
   }
-
-  static const size_t kFinishedLen = 12;
-  if (!ssl->s3->enc_method->prf(ssl, out, kFinishedLen,
-                                SSL_get_session(ssl)->master_key,
-                                SSL_get_session(ssl)->master_key_length, label,
-                                label_len, buf, digests_len, NULL, 0)) {
-    return 0;
-  }
-
-  return (int)kFinishedLen;
+  return tls1_prf(digest, out, out_len, SSL_get_session(ssl)->master_key,
+                  SSL_get_session(ssl)->master_key_length,
+                  TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE,
+                  ssl->s3->server_random, SSL3_RANDOM_SIZE,
+                  ssl->s3->client_random, SSL3_RANDOM_SIZE);
 }
 
-int tls1_generate_master_secret(SSL *ssl, uint8_t *out,
+int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out,
                                 const uint8_t *premaster,
                                 size_t premaster_len) {
+  const SSL *ssl = hs->ssl;
   if (ssl->s3->tmp.extended_master_secret) {
     uint8_t digests[EVP_MAX_MD_SIZE];
-    int digests_len = tls1_handshake_digest(ssl, digests, sizeof(digests));
-    if (digests_len == -1) {
-      return 0;
-    }
-
-    if (!ssl->s3->enc_method->prf(ssl, out, SSL3_MASTER_SECRET_SIZE, premaster,
-                                  premaster_len,
-                                  TLS_MD_EXTENDED_MASTER_SECRET_CONST,
-                                  TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE,
-                                  digests, digests_len, NULL, 0)) {
+    size_t digests_len;
+    if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, digests, &digests_len) ||
+        !tls1_prf(SSL_TRANSCRIPT_md(&hs->transcript), out,
+                  SSL3_MASTER_SECRET_SIZE, premaster, premaster_len,
+                  TLS_MD_EXTENDED_MASTER_SECRET_CONST,
+                  TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE, digests,
+                  digests_len, NULL, 0)) {
       return 0;
     }
   } else {
-    if (!ssl->s3->enc_method->prf(ssl, out, SSL3_MASTER_SECRET_SIZE, premaster,
-                                  premaster_len, TLS_MD_MASTER_SECRET_CONST,
-                                  TLS_MD_MASTER_SECRET_CONST_SIZE,
-                                  ssl->s3->client_random, SSL3_RANDOM_SIZE,
-                                  ssl->s3->server_random, SSL3_RANDOM_SIZE)) {
-      return 0;
+    if (ssl3_protocol_version(ssl) == SSL3_VERSION) {
+      if (!ssl3_prf(out, SSL3_MASTER_SECRET_SIZE, premaster, premaster_len,
+                    TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE,
+                    ssl->s3->client_random, SSL3_RANDOM_SIZE,
+                    ssl->s3->server_random, SSL3_RANDOM_SIZE)) {
+        return 0;
+      }
+    } else {
+      if (!tls1_prf(SSL_TRANSCRIPT_md(&hs->transcript), out,
+                    SSL3_MASTER_SECRET_SIZE, premaster, premaster_len,
+                    TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE,
+                    ssl->s3->client_random, SSL3_RANDOM_SIZE,
+                    ssl->s3->server_random, SSL3_RANDOM_SIZE)) {
+        return 0;
+      }
     }
   }
 
@@ -538,16 +548,15 @@
     OPENSSL_memcpy(seed + 2 * SSL3_RANDOM_SIZE + 2, context, context_len);
   }
 
-  int ret =
-      ssl->s3->enc_method->prf(ssl, out, out_len,
-                               SSL_get_session(ssl)->master_key,
-                               SSL_get_session(ssl)->master_key_length, label,
-                               label_len, seed, seed_len, NULL, 0);
+  const EVP_MD *digest = ssl_get_handshake_digest(
+      SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
+  if (digest == NULL) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    return 0;
+  }
+  int ret = tls1_prf(digest, out, out_len, SSL_get_session(ssl)->master_key,
+                     SSL_get_session(ssl)->master_key_length, label, label_len,
+                     seed, seed_len, NULL, 0);
   OPENSSL_free(seed);
   return ret;
 }
-
-const SSL3_ENC_METHOD TLSv1_enc_data = {
-    tls1_prf,
-    tls1_final_finish_mac,
-};
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index cf46742..b3ba546 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1883,8 +1883,12 @@
     return 0;
   }
 
-  const EVP_MD *digest =
-      ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf);
+  const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl);
+  if (digest == NULL) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    return 0;
+  }
+
   size_t binder_len = EVP_MD_size(digest);
   return 15 + ssl->session->tlsext_ticklen + binder_len;
 }
@@ -1912,8 +1916,13 @@
   /* Fill in a placeholder zero binder of the appropriate length. It will be
    * computed and filled in later after length prefixes are computed. */
   uint8_t zero_binder[EVP_MAX_MD_SIZE] = {0};
-  const EVP_MD *digest =
-      ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf);
+
+  const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl);
+  if (digest == NULL) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    return 0;
+  }
+
   size_t binder_len = EVP_MD_size(digest);
 
   CBB contents, identity, ticket, binders, binder;
@@ -3325,7 +3334,8 @@
   return 0;
 }
 
-int tls1_verify_channel_id(SSL *ssl) {
+int tls1_verify_channel_id(SSL_HANDSHAKE *hs) {
+  SSL *const ssl = hs->ssl;
   int ret = 0;
   uint16_t extension_type;
   CBS extension, channel_id;
@@ -3384,7 +3394,7 @@
 
   uint8_t digest[EVP_MAX_MD_SIZE];
   size_t digest_len;
-  if (!tls1_channel_id_hash(ssl, digest, &digest_len)) {
+  if (!tls1_channel_id_hash(hs, digest, &digest_len)) {
     goto err;
   }
 
@@ -3413,10 +3423,11 @@
   return ret;
 }
 
-int tls1_write_channel_id(SSL *ssl, CBB *cbb) {
+int tls1_write_channel_id(SSL_HANDSHAKE *hs, CBB *cbb) {
+  SSL *const ssl = hs->ssl;
   uint8_t digest[EVP_MAX_MD_SIZE];
   size_t digest_len;
-  if (!tls1_channel_id_hash(ssl, digest, &digest_len)) {
+  if (!tls1_channel_id_hash(hs, digest, &digest_len)) {
     return 0;
   }
 
@@ -3462,11 +3473,12 @@
   return ret;
 }
 
-int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) {
+int tls1_channel_id_hash(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len) {
+  SSL *const ssl = hs->ssl;
   if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
     uint8_t *msg;
     size_t msg_len;
-    if (!tls13_get_cert_verify_signature_input(ssl, &msg, &msg_len,
+    if (!tls13_get_cert_verify_signature_input(hs, &msg, &msg_len,
                                                ssl_cert_verify_channel_id)) {
       return 0;
     }
@@ -3493,13 +3505,12 @@
                   ssl->session->original_handshake_hash_len);
   }
 
-  uint8_t handshake_hash[EVP_MAX_MD_SIZE];
-  int handshake_hash_len = tls1_handshake_digest(ssl, handshake_hash,
-                                                 sizeof(handshake_hash));
-  if (handshake_hash_len < 0) {
+  uint8_t hs_hash[EVP_MAX_MD_SIZE];
+  size_t hs_hash_len;
+  if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, hs_hash, &hs_hash_len)) {
     return 0;
   }
-  SHA256_Update(&ctx, handshake_hash, (size_t)handshake_hash_len);
+  SHA256_Update(&ctx, hs_hash, (size_t)hs_hash_len);
   SHA256_Final(out, &ctx);
   *out_len = SHA256_DIGEST_LENGTH;
   return 1;
@@ -3508,8 +3519,8 @@
 /* tls1_record_handshake_hashes_for_channel_id records the current handshake
  * hashes in |ssl->s3->new_session| so that Channel ID resumptions can sign that
  * data. */
-int tls1_record_handshake_hashes_for_channel_id(SSL *ssl) {
-  int digest_len;
+int tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs) {
+  SSL *const ssl = hs->ssl;
   /* This function should never be called for a resumed session because the
    * handshake hashes that we wish to record are for the original, full
    * handshake. */
@@ -3517,15 +3528,18 @@
     return -1;
   }
 
-  digest_len =
-      tls1_handshake_digest(
-          ssl, ssl->s3->new_session->original_handshake_hash,
-          sizeof(ssl->s3->new_session->original_handshake_hash));
-  if (digest_len < 0) {
+  OPENSSL_COMPILE_ASSERT(
+      sizeof(ssl->s3->new_session->original_handshake_hash) == EVP_MAX_MD_SIZE,
+      original_handshake_hash_is_too_small);
+
+  size_t digest_len;
+  if (!SSL_TRANSCRIPT_get_hash(&hs->transcript,
+                               ssl->s3->new_session->original_handshake_hash,
+                               &digest_len)) {
     return -1;
   }
 
-  assert(sizeof(ssl->s3->new_session->original_handshake_hash) < 256);
+  OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE <= 0xff, max_md_size_is_too_large);
   ssl->s3->new_session->original_handshake_hash_len = (uint8_t)digest_len;
 
   return 1;
diff --git a/ssl/tls13_both.c b/ssl/tls13_both.c
index 9e9da44..134dfd2 100644
--- a/ssl/tls13_both.c
+++ b/ssl/tls13_both.c
@@ -102,7 +102,7 @@
 }
 
 int tls13_get_cert_verify_signature_input(
-    SSL *ssl, uint8_t **out, size_t *out_len,
+    SSL_HANDSHAKE *hs, uint8_t **out, size_t *out_len,
     enum ssl_cert_verify_context_t cert_verify_context) {
   CBB cbb;
   if (!CBB_init(&cbb, 64 + 33 + 1 + 2 * EVP_MAX_MD_SIZE)) {
@@ -140,7 +140,8 @@
 
   uint8_t context_hash[EVP_MAX_MD_SIZE];
   size_t context_hash_len;
-  if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len) ||
+  if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash,
+                               &context_hash_len) ||
       !CBB_add_bytes(&cbb, context_hash, context_hash_len) ||
       !CBB_finish(&cbb, out, out_len)) {
     goto err;
@@ -372,7 +373,7 @@
   ssl->s3->new_session->peer_signature_algorithm = signature_algorithm;
 
   if (!tls13_get_cert_verify_signature_input(
-          ssl, &msg, &msg_len,
+          hs, &msg, &msg_len,
           ssl->server ? ssl_cert_verify_client : ssl_cert_verify_server)) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
     goto err;
@@ -536,7 +537,7 @@
   enum ssl_private_key_result_t sign_result;
   if (is_first_run) {
     if (!tls13_get_cert_verify_signature_input(
-            ssl, &msg, &msg_len,
+            hs, &msg, &msg_len,
             ssl->server ? ssl_cert_verify_server : ssl_cert_verify_client)) {
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
       goto err;
diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c
index fc94d2f..a85f6b3 100644
--- a/ssl/tls13_client.c
+++ b/ssl/tls13_client.c
@@ -135,7 +135,7 @@
     hs->retry_group = group_id;
   }
 
-  if (!ssl_hash_current_message(ssl)) {
+  if (!ssl_hash_current_message(hs)) {
     return ssl_hs_error;
   }
 
@@ -271,8 +271,6 @@
   ssl->s3->tmp.new_cipher = cipher;
 
   /* The PRF hash is now known. Set up the key schedule. */
-  size_t hash_len =
-      EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)));
   if (!tls13_init_key_schedule(hs)) {
     return ssl_hs_error;
   }
@@ -283,7 +281,7 @@
                                     ssl->s3->new_session->master_key_length)) {
       return ssl_hs_error;
     }
-  } else if (!tls13_advance_key_schedule(hs, kZeroes, hash_len)) {
+  } else if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len)) {
     return ssl_hs_error;
   }
 
@@ -327,7 +325,7 @@
     ssl->s3->short_header = 1;
   }
 
-  if (!ssl_hash_current_message(ssl) ||
+  if (!ssl_hash_current_message(hs) ||
       !tls13_derive_handshake_secrets(hs) ||
       !tls13_set_traffic_key(ssl, evp_aead_open, hs->server_handshake_secret,
                              hs->hash_len) ||
@@ -358,7 +356,7 @@
     return ssl_hs_error;
   }
 
-  if (!ssl_hash_current_message(ssl)) {
+  if (!ssl_hash_current_message(hs)) {
     return ssl_hs_error;
   }
 
@@ -414,7 +412,7 @@
   sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free);
   hs->ca_names = ca_sk;
 
-  if (!ssl_hash_current_message(ssl)) {
+  if (!ssl_hash_current_message(hs)) {
     return ssl_hs_error;
   }
 
@@ -426,7 +424,7 @@
   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(ssl)) {
+      !ssl_hash_current_message(hs)) {
     return ssl_hs_error;
   }
 
@@ -439,7 +437,7 @@
   SSL *const ssl = hs->ssl;
   if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) ||
       !tls13_process_certificate_verify(hs) ||
-      !ssl_hash_current_message(ssl)) {
+      !ssl_hash_current_message(hs)) {
     return ssl_hs_error;
   }
 
@@ -451,7 +449,7 @@
   SSL *const ssl = hs->ssl;
   if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) ||
       !tls13_process_finished(hs) ||
-      !ssl_hash_current_message(ssl) ||
+      !ssl_hash_current_message(hs) ||
       /* 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)) {
@@ -536,7 +534,7 @@
 
     CBB cbb, body;
     if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) ||
-        !tls1_write_channel_id(ssl, &body) ||
+        !tls1_write_channel_id(hs, &body) ||
         !ssl_add_message_cbb(ssl, &cbb)) {
       CBB_cleanup(&cbb);
       return ssl_hs_error;
diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
index ea9dce8..4d140e3 100644
--- a/ssl/tls13_enc.c
+++ b/ssl/tls13_enc.c
@@ -29,28 +29,25 @@
 
 
 int tls13_init_key_schedule(SSL_HANDSHAKE *hs) {
-  SSL *const ssl = hs->ssl;
-  const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
+  if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(hs->ssl),
+                                hs->ssl->s3->tmp.new_cipher->algorithm_prf)) {
+    return 0;
+  }
 
-  hs->hash_len = EVP_MD_size(digest);
+
+  hs->hash_len = SSL_TRANSCRIPT_digest_len(&hs->transcript);
 
   /* Initialize the secret to the zero key. */
   OPENSSL_memset(hs->secret, 0, hs->hash_len);
 
-  /* Initialize the rolling hashes and release the handshake buffer. */
-  if (!ssl3_init_handshake_hash(ssl)) {
-    return 0;
-  }
-  ssl3_free_handshake_buffer(ssl);
+  SSL_TRANSCRIPT_free_buffer(&hs->transcript);
   return 1;
 }
 
 int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in,
                                size_t len) {
-  const EVP_MD *digest =
-      ssl_get_handshake_digest(ssl_get_algorithm_prf(hs->ssl));
-
-  return HKDF_extract(hs->secret, &hs->hash_len, digest, in, len, hs->secret,
+  return HKDF_extract(hs->secret, &hs->hash_len,
+                      SSL_TRANSCRIPT_md(&hs->transcript), in, len, hs->secret,
                       hs->hash_len);
 }
 
@@ -83,35 +80,21 @@
   return ret;
 }
 
-int tls13_get_context_hash(SSL *ssl, uint8_t *out, size_t *out_len) {
-  EVP_MD_CTX ctx;
-  EVP_MD_CTX_init(&ctx);
-  unsigned handshake_len = 0;
-  int ok = EVP_MD_CTX_copy_ex(&ctx, &ssl->s3->handshake_hash) &&
-           EVP_DigestFinal_ex(&ctx, out, &handshake_len);
-  EVP_MD_CTX_cleanup(&ctx);
-  if (ok) {
-    *out_len = handshake_len;
-  }
-  return ok;
-}
-
 /* derive_secret derives a secret of length |len| and writes the result in |out|
  * with the given label and the current base secret and most recently-saved
  * handshake context. It returns one on success and zero on error. */
 static int derive_secret(SSL_HANDSHAKE *hs, uint8_t *out, size_t len,
                          const uint8_t *label, size_t label_len) {
-  SSL *const ssl = hs->ssl;
-  const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
-
   uint8_t context_hash[EVP_MAX_MD_SIZE];
   size_t context_hash_len;
-  if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len)) {
+  if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash,
+                               &context_hash_len)) {
     return 0;
   }
 
-  return hkdf_expand_label(out, digest, hs->secret, hs->hash_len, label,
-                           label_len, context_hash, context_hash_len, len);
+  return hkdf_expand_label(out, SSL_TRANSCRIPT_md(&hs->transcript), hs->secret,
+                           hs->hash_len, label, label_len, context_hash,
+                           context_hash_len, len);
 }
 
 int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
@@ -124,7 +107,6 @@
 
   /* Look up cipher suite properties. */
   const EVP_AEAD *aead;
-  const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
   size_t discard;
   if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard,
                                SSL_get_session(ssl)->cipher,
@@ -132,6 +114,9 @@
     return 0;
   }
 
+  const EVP_MD *digest = ssl_get_handshake_digest(
+      SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
+
   /* Derive the key. */
   size_t key_len = EVP_AEAD_key_length(aead);
   uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
@@ -226,7 +211,8 @@
     "application traffic secret";
 
 int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction) {
-  const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
+  const EVP_MD *digest = ssl_get_handshake_digest(
+      SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
 
   uint8_t *secret;
   size_t secret_len;
@@ -287,7 +273,6 @@
 int tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len,
                        int is_server) {
   SSL *const ssl = hs->ssl;
-  const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
 
   const uint8_t *traffic_secret;
   if (is_server == ssl->server) {
@@ -298,9 +283,11 @@
 
   uint8_t context_hash[EVP_MAX_MD_SIZE];
   size_t context_hash_len;
-  if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len) ||
-      !tls13_verify_data(digest, out, out_len, traffic_secret, hs->hash_len,
-                         context_hash, context_hash_len)) {
+  if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash,
+                               &context_hash_len) ||
+      !tls13_verify_data(SSL_TRANSCRIPT_md(&hs->transcript), out, out_len,
+                         traffic_secret, hs->hash_len, context_hash,
+                         context_hash_len)) {
     return 0;
   }
   return 1;
@@ -310,7 +297,8 @@
                                  const char *label, size_t label_len,
                                  const uint8_t *context, size_t context_len,
                                  int use_context) {
-  const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
+  const EVP_MD *digest = ssl_get_handshake_digest(
+      SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
 
   const uint8_t *hash = NULL;
   size_t hash_len = 0;
@@ -325,8 +313,8 @@
 
 static const char kTLS13LabelPSKBinder[] = "resumption psk binder key";
 
-static int tls13_psk_binder(SSL *ssl, uint8_t *out, const EVP_MD *digest,
-                            uint8_t *psk, size_t psk_len, uint8_t *context,
+static int tls13_psk_binder(uint8_t *out, const EVP_MD *digest, uint8_t *psk,
+                            size_t psk_len, uint8_t *context,
                             size_t context_len, size_t hash_len) {
   uint8_t binder_context[EVP_MAX_MD_SIZE];
   unsigned binder_context_len;
@@ -355,9 +343,13 @@
   return 1;
 }
 
-int tls13_write_psk_binder(SSL *ssl, uint8_t *msg, size_t len) {
-  const EVP_MD *digest =
-      ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf);
+int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len) {
+  SSL *const ssl = hs->ssl;
+  const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl);
+  if (digest == NULL) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    return 0;
+  }
   size_t hash_len = EVP_MD_size(digest);
 
   if (len < hash_len + 3) {
@@ -370,8 +362,8 @@
   uint8_t context[EVP_MAX_MD_SIZE];
   unsigned context_len;
   if (!EVP_DigestInit_ex(&ctx, digest, NULL) ||
-      !EVP_DigestUpdate(&ctx, ssl->s3->handshake_buffer->data,
-                        ssl->s3->handshake_buffer->length) ||
+      !EVP_DigestUpdate(&ctx, hs->transcript.buffer->data,
+                        hs->transcript.buffer->length) ||
       !EVP_DigestUpdate(&ctx, msg, len - hash_len - 3) ||
       !EVP_DigestFinal_ex(&ctx, context, &context_len)) {
     EVP_MD_CTX_cleanup(&ctx);
@@ -381,9 +373,9 @@
   EVP_MD_CTX_cleanup(&ctx);
 
   uint8_t verify_data[EVP_MAX_MD_SIZE] = {0};
-  if (!tls13_psk_binder(ssl, verify_data, digest, ssl->session->master_key,
-                        ssl->session->master_key_length, context,
-                        context_len, hash_len)) {
+  if (!tls13_psk_binder(verify_data, digest, ssl->session->master_key,
+                        ssl->session->master_key_length, context, context_len,
+                        hash_len)) {
     return 0;
   }
 
@@ -391,16 +383,14 @@
   return 1;
 }
 
-int tls13_verify_psk_binder(SSL *ssl, SSL_SESSION *session,
+int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session,
                             CBS *binders) {
-  const EVP_MD *digest =
-      ssl_get_handshake_digest(session->cipher->algorithm_prf);
-  size_t hash_len = EVP_MD_size(digest);
+  size_t hash_len = SSL_TRANSCRIPT_digest_len(&hs->transcript);
 
   /* Get the full ClientHello, including message header. It must be large enough
    * to exclude the binders. */
   CBS message;
-  ssl->method->get_current_message(ssl, &message);
+  hs->ssl->method->get_current_message(hs->ssl, &message);
   if (CBS_len(&message) < CBS_len(binders) + 2) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return 0;
@@ -411,23 +401,25 @@
   uint8_t context[EVP_MAX_MD_SIZE];
   unsigned context_len;
   if (!EVP_Digest(CBS_data(&message), CBS_len(&message) - CBS_len(binders) - 2,
-                  context, &context_len, digest, NULL)) {
+                  context, &context_len, SSL_TRANSCRIPT_md(&hs->transcript),
+                  NULL)) {
     return 0;
   }
 
   uint8_t verify_data[EVP_MAX_MD_SIZE] = {0};
   CBS binder;
-  if (!tls13_psk_binder(ssl, verify_data, digest, session->master_key,
-                        session->master_key_length, context, context_len,
-                        hash_len) ||
+  if (!tls13_psk_binder(verify_data, SSL_TRANSCRIPT_md(&hs->transcript),
+                        session->master_key, session->master_key_length,
+                        context, context_len, hash_len) ||
       /* We only consider the first PSK, so compare against the first binder. */
       !CBS_get_u8_length_prefixed(binders, &binder)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return 0;
   }
 
-  int binder_ok = CBS_len(&binder) == hash_len &&
-                  CRYPTO_memcmp(CBS_data(&binder), verify_data, hash_len) == 0;
+  int binder_ok =
+      CBS_len(&binder) == hash_len &&
+      CRYPTO_memcmp(CBS_data(&binder), verify_data, hash_len) == 0;
 #if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
   binder_ok = 1;
 #endif
diff --git a/ssl/tls13_server.c b/ssl/tls13_server.c
index e9ba86f..3ef0c15 100644
--- a/ssl/tls13_server.c
+++ b/ssl/tls13_server.c
@@ -157,6 +157,14 @@
     return ssl_hs_error;
   }
 
+  /* 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)) {
+    return ssl_hs_error;
+  }
+
+
   /* Decode the ticket if we agree on a PSK key exchange mode. */
   uint8_t alert = SSL_AD_DECODE_ERROR;
   SSL_SESSION *session = NULL;
@@ -207,7 +215,7 @@
     }
   } else {
     /* Check the PSK binder. */
-    if (!tls13_verify_psk_binder(ssl, session, &binders)) {
+    if (!tls13_verify_psk_binder(hs, session, &binders)) {
       SSL_SESSION_free(session);
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
       return ssl_hs_error;
@@ -243,22 +251,13 @@
     return ssl_hs_error;
   }
 
-  /* The PRF hash is now known. Set up the key schedule and hash the
-   * ClientHello. */
-  size_t hash_len =
-      EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)));
-  if (!tls13_init_key_schedule(hs) ||
-      !ssl_hash_current_message(ssl)) {
-    return ssl_hs_error;
-  }
-
   /* Incorporate the PSK into the running secret. */
   if (ssl->s3->session_reused) {
     if (!tls13_advance_key_schedule(hs, ssl->s3->new_session->master_key,
                                     ssl->s3->new_session->master_key_length)) {
       return ssl_hs_error;
     }
-  } else if (!tls13_advance_key_schedule(hs, kZeroes, hash_len)) {
+  } else if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len)) {
     return ssl_hs_error;
   }
 
@@ -323,7 +322,7 @@
     return ssl_hs_error;
   }
 
-  if (!ssl_hash_current_message(ssl)) {
+  if (!ssl_hash_current_message(hs)) {
     return ssl_hs_error;
   }
 
@@ -485,7 +484,7 @@
 
   if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
       !tls13_process_certificate(hs, allow_anonymous) ||
-      !ssl_hash_current_message(ssl)) {
+      !ssl_hash_current_message(hs)) {
     return ssl_hs_error;
   }
 
@@ -504,7 +503,7 @@
 
   if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) ||
       !tls13_process_certificate_verify(hs) ||
-      !ssl_hash_current_message(ssl)) {
+      !ssl_hash_current_message(hs)) {
     return ssl_hs_error;
   }
 
@@ -513,15 +512,14 @@
 }
 
 static enum ssl_hs_wait_t do_process_channel_id(SSL_HANDSHAKE *hs) {
-  SSL *const ssl = hs->ssl;
-  if (!ssl->s3->tlsext_channel_id_valid) {
+  if (!hs->ssl->s3->tlsext_channel_id_valid) {
     hs->tls13_state = state_process_client_finished;
     return ssl_hs_ok;
   }
 
-  if (!ssl_check_message_type(ssl, SSL3_MT_CHANNEL_ID) ||
-      !tls1_verify_channel_id(ssl) ||
-      !ssl_hash_current_message(ssl)) {
+  if (!ssl_check_message_type(hs->ssl, SSL3_MT_CHANNEL_ID) ||
+      !tls1_verify_channel_id(hs) ||
+      !ssl_hash_current_message(hs)) {
     return ssl_hs_error;
   }
 
@@ -533,7 +531,7 @@
   SSL *const ssl = hs->ssl;
   if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) ||
       !tls13_process_finished(hs) ||
-      !ssl_hash_current_message(ssl) ||
+      !ssl_hash_current_message(hs) ||
       /* evp_aead_seal keys have already been switched. */
       !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_traffic_secret_0,
                              hs->hash_len) ||