Bug 1381214 - Refactor handshake hashing to make it explicit. r=mt NSS_TLS13_DRAFT19_BRANCH
authorEKR <ekr@rtfm.com>
Sat, 25 Mar 2017 19:56:51 -0500
branchNSS_TLS13_DRAFT19_BRANCH
changeset 13463 7abf299e1e6fc9ec0303ea7291b0160d2917059b
parent 13462 e1c050652e1685007a240c9c8c2c5c55d1f8ef2b
child 13464 6dec11c45d4fee11c0f37f0635cc43dd39c5956b
push id2272
push userekr@mozilla.com
push dateSat, 15 Jul 2017 14:58:16 +0000
reviewersmt
bugs1381214
Bug 1381214 - Refactor handshake hashing to make it explicit. r=mt Reviewers: mt Differential Revision: https://nss-review.dev.mozaws.net/D371
gtests/ssl_gtest/ssl_loopback_unittest.cc
gtests/ssl_gtest/tls_connect.cc
lib/ssl/ssl3con.c
lib/ssl/ssl3prot.h
lib/ssl/sslimpl.h
lib/ssl/tls13con.c
lib/ssl/tls13con.h
--- a/gtests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/gtests/ssl_gtest/ssl_loopback_unittest.cc
@@ -310,16 +310,32 @@ TEST_F(TlsConnectStreamTls13, Tls13Faile
   server_->StartConnect();
   client_->Handshake();
   server_->Handshake();  // Send first flight.
   client_->adapter()->CloseWrites();
   client_->Handshake();  // This will get an error, but shouldn't crash.
   client_->CheckErrorCode(SSL_ERROR_SOCKET_WRITE_FAILURE);
 }
 
+TEST_F(TlsConnectTest, ConnectSSLv3) {
+  ConfigureVersion(SSL_LIBRARY_VERSION_3_0);
+  EnableOnlyStaticRsaCiphers();
+  Connect();
+  CheckKeys(ssl_kea_rsa, ssl_grp_none, ssl_auth_rsa_decrypt, ssl_sig_none);
+}
+
+TEST_F(TlsConnectTest, ConnectSSLv3ClientAuth) {
+  ConfigureVersion(SSL_LIBRARY_VERSION_3_0);
+  EnableOnlyStaticRsaCiphers();
+  client_->SetupClientAuth();
+  server_->RequestClientAuth(true);
+  Connect();
+  CheckKeys(ssl_kea_rsa, ssl_grp_none, ssl_auth_rsa_decrypt, ssl_sig_none);
+}
+
 INSTANTIATE_TEST_CASE_P(
     GenericStream, TlsConnectGeneric,
     ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
                        TlsConnectTestBase::kTlsVAll));
 INSTANTIATE_TEST_CASE_P(
     GenericDatagram, TlsConnectGeneric,
     ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
                        TlsConnectTestBase::kTlsV11Plus));
--- a/gtests/ssl_gtest/tls_connect.cc
+++ b/gtests/ssl_gtest/tls_connect.cc
@@ -83,16 +83,18 @@ static const uint16_t kTlsVAllArr[] = {
     SSL_LIBRARY_VERSION_TLS_1_0};
 ::testing::internal::ParamGenerator<uint16_t> TlsConnectTestBase::kTlsVAll =
     ::testing::ValuesIn(kTlsVAllArr);
 
 std::string VersionString(uint16_t version) {
   switch (version) {
     case 0:
       return "(no version)";
+    case SSL_LIBRARY_VERSION_3_0:
+      return "1.0";
     case SSL_LIBRARY_VERSION_TLS_1_0:
       return "1.0";
     case SSL_LIBRARY_VERSION_TLS_1_1:
       return "1.1";
     case SSL_LIBRARY_VERSION_TLS_1_2:
       return "1.2";
     case SSL_LIBRARY_VERSION_TLS_1_3:
       return "1.3";
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -53,20 +53,18 @@ static SECStatus ssl3_HandleClientHelloP
                                              SECItem *suites,
                                              SECItem *comps,
                                              sslSessionID *sid);
 static SECStatus ssl3_HandleServerHelloPart2(sslSocket *ss,
                                              const SECItem *sidBytes,
                                              int *retErrCode);
 static SECStatus ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss,
                                                       PRUint8 *b,
-                                                      PRUint32 length,
-                                                      SSL3Hashes *hashesPtr);
+                                                      PRUint32 length);
 static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
-
 static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
                              int maxOutputLen, const unsigned char *input,
                              int inputLen);
 
 static CK_MECHANISM_TYPE ssl3_GetHashMechanismByHashType(SSLHashType hashType);
 static CK_MECHANISM_TYPE ssl3_GetMgfMechanismByHashType(SSLHashType hash);
 PRBool ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme);
 
@@ -9648,105 +9646,100 @@ ssl3_SendServerHelloDone(sslSocket *ss)
     return SECSuccess;
 }
 
 /* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered
  * a complete ssl3 Certificate Verify message
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
-ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length,
-                             SSL3Hashes *hashes)
+ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
 {
     SECItem signed_hash = { siBuffer, NULL, 0 };
     SECStatus rv;
     int errCode = SSL_ERROR_RX_MALFORMED_CERT_VERIFY;
     SSL3AlertDescription desc = handshake_failure;
     PRBool isTLS;
     SSLSignatureScheme sigScheme;
-    SSLHashType hashAlg;
-    SSL3Hashes localHashes;
-    SSL3Hashes *hashesForVerify = NULL;
+    SSL3Hashes hashes;
+    const PRUint8 *savedMsg = b;
+    const PRUint32 savedLen = length;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake",
                 SSL_GETPID(), ss->fd));
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     if (ss->ssl3.hs.ws != wait_cert_verify) {
         desc = unexpected_message;
         errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY;
         goto alert_loser;
     }
 
     /* TLS 1.3 is handled by tls13_HandleCertificateVerify */
     PORT_Assert(ss->ssl3.prSpec->version <= SSL_LIBRARY_VERSION_TLS_1_2);
 
-    if (!hashes) {
-        PORT_Assert(0);
-        desc = internal_error;
-        errCode = SEC_ERROR_LIBRARY_FAILURE;
-        goto alert_loser;
-    }
-
-    if (ss->ssl3.hs.hashType == handshake_hash_record) {
+    if (ss->ssl3.prSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) {
+        PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_record);
         rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme);
         if (rv != SECSuccess) {
             goto loser; /* malformed or unsupported. */
         }
         rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme,
                                                  ss->sec.peerCert);
         if (rv != SECSuccess) {
             errCode = PORT_GetError();
             desc = decrypt_error;
             goto alert_loser;
         }
 
-        hashAlg = ssl_SignatureSchemeToHashType(sigScheme);
-
-        /* Read from the message buffer, but we need to use only up to the end
-         * of the previous handshake message. The length of the transcript up to
-         * that point is saved in |hashes->u.transcriptLen|. */
         rv = ssl3_ComputeHandshakeHash(ss->ssl3.hs.messages.buf,
-                                       hashes->u.transcriptLen,
-                                       hashAlg, &localHashes);
-
-        if (rv == SECSuccess) {
-            hashesForVerify = &localHashes;
-        } else {
-            errCode = SSL_ERROR_DIGEST_FAILURE;
-            desc = decrypt_error;
-            goto alert_loser;
-        }
+                                       ss->ssl3.hs.messages.len,
+                                       ssl_SignatureSchemeToHashType(sigScheme),
+                                       &hashes);
     } else {
-        hashesForVerify = hashes;
+        PORT_Assert(ss->ssl3.hs.hashType != handshake_hash_record);
         sigScheme = ssl_sig_none;
+        rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.prSpec, &hashes, 0);
+    }
+
+    if (rv != SECSuccess) {
+        errCode = SSL_ERROR_DIGEST_FAILURE;
+        desc = decrypt_error;
+        goto alert_loser;
     }
 
     rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length);
     if (rv != SECSuccess) {
         goto loser; /* malformed. */
     }
 
     isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
 
     /* XXX verify that the key & kea match */
-    rv = ssl3_VerifySignedHashes(ss, sigScheme, hashesForVerify, &signed_hash);
+    rv = ssl3_VerifySignedHashes(ss, sigScheme, &hashes, &signed_hash);
     if (rv != SECSuccess) {
         errCode = PORT_GetError();
         desc = isTLS ? decrypt_error : handshake_failure;
         goto alert_loser;
     }
 
     signed_hash.data = NULL;
 
     if (length != 0) {
         desc = isTLS ? decode_error : illegal_parameter;
         goto alert_loser; /* malformed */
     }
+
+    rv = ssl_HashHandshakeMessage(ss, savedMsg, savedLen);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return rv;
+    }
+
     ss->ssl3.hs.ws = wait_change_cipher;
     return SECSuccess;
 
 alert_loser:
     SSL3_SendAlert(ss, alert_fatal, desc);
 loser:
     PORT_SetError(errCode);
     return SECFailure;
@@ -11309,56 +11302,62 @@ ssl3_CacheWrappedSecret(sslSocket *ss, s
     return rv;
 }
 
 /* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered
  * a complete ssl3 Finished message from the peer.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
-ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length,
-                    const SSL3Hashes *hashes)
+ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
 {
     sslSessionID *sid = ss->sec.ci.sid;
     SECStatus rv = SECSuccess;
     PRBool isServer = ss->sec.isServer;
     PRBool isTLS;
+    SSL3Hashes hashes;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle finished handshake",
                 SSL_GETPID(), ss->fd));
 
     if (ss->ssl3.hs.ws != wait_finished) {
         SSL3_SendAlert(ss, alert_fatal, unexpected_message);
         PORT_SetError(SSL_ERROR_RX_UNEXPECTED_FINISHED);
         return SECFailure;
     }
 
-    if (!hashes) {
-        PORT_Assert(0);
-        SSL3_SendAlert(ss, alert_fatal, internal_error);
+    rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.crSpec, &hashes,
+                                     isServer ? sender_client : sender_server);
+    if (rv != SECSuccess) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
+    rv = ssl_HashHandshakeMessage(ss, b, length);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return rv;
+    }
+
     isTLS = (PRBool)(ss->ssl3.crSpec->version > SSL_LIBRARY_VERSION_3_0);
     if (isTLS) {
         TLSFinished tlsFinished;
 
         if (length != sizeof(tlsFinished)) {
 #ifndef UNSAFE_FUZZER_MODE
             (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
             PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED);
             return SECFailure;
 #endif
         }
         rv = ssl3_ComputeTLSFinished(ss, ss->ssl3.crSpec, !isServer,
-                                     hashes, &tlsFinished);
+                                     &hashes, &tlsFinished);
         if (!isServer)
             ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished;
         else
             ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished;
         ss->ssl3.hs.finishedBytes = sizeof(tlsFinished);
         if (rv != SECSuccess ||
             0 != NSS_SecureMemcmp(&tlsFinished, b,
                                   PR_MIN(length, ss->ssl3.hs.finishedBytes))) {
@@ -11371,22 +11370,22 @@ ssl3_HandleFinished(sslSocket *ss, PRUin
     } else {
         if (length != sizeof(SSL3Finished)) {
             (void)ssl3_IllegalParameter(ss);
             PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED);
             return SECFailure;
         }
 
         if (!isServer)
-            ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes->u.s;
+            ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes.u.s;
         else
-            ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes->u.s;
-        PORT_Assert(hashes->len == sizeof hashes->u.s);
-        ss->ssl3.hs.finishedBytes = sizeof hashes->u.s;
-        if (0 != NSS_SecureMemcmp(&hashes->u.s, b, length)) {
+            ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes.u.s;
+        PORT_Assert(hashes.len == sizeof hashes.u.s);
+        ss->ssl3.hs.finishedBytes = sizeof hashes.u.s;
+        if (0 != NSS_SecureMemcmp(&hashes.u.s, b, length)) {
             (void)ssl3_HandshakeFailure(ss);
             PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
             return SECFailure;
         }
     }
 
     ssl_GetXmitBufLock(ss); /*************************************/
 
@@ -11566,144 +11565,104 @@ ssl3_FinishHandshake(sslSocket *ss)
     ss->ssl3.hs.canFalseStart = PR_FALSE; /* False Start phase is complete */
     ss->ssl3.hs.ws = idle_handshake;
 
     ssl_FinishHandshake(ss);
 
     return SECSuccess;
 }
 
+SECStatus
+ssl_HashHandshakeMessage(sslSocket *ss, const PRUint8 *b, PRUint32 length)
+{
+    PRUint8 hdr[4];
+    PRUint8 dtlsData[8];
+    SECStatus rv;
+
+    hdr[0] = (PRUint8)ss->ssl3.hs.msg_type;
+    hdr[1] = (PRUint8)(length >> 16);
+    hdr[2] = (PRUint8)(length >> 8);
+    hdr[3] = (PRUint8)(length);
+
+    rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)hdr, 4);
+    if (rv != SECSuccess)
+        return rv; /* err code already set. */
+
+    /* Extra data to simulate a complete DTLS handshake fragment */
+    if (IS_DTLS(ss)) {
+        /* Sequence number */
+        dtlsData[0] = MSB(ss->ssl3.hs.recvMessageSeq);
+        dtlsData[1] = LSB(ss->ssl3.hs.recvMessageSeq);
+
+        /* Fragment offset */
+        dtlsData[2] = 0;
+        dtlsData[3] = 0;
+        dtlsData[4] = 0;
+
+        /* Fragment length */
+        dtlsData[5] = (PRUint8)(length >> 16);
+        dtlsData[6] = (PRUint8)(length >> 8);
+        dtlsData[7] = (PRUint8)(length);
+
+        rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)dtlsData,
+                                        sizeof(dtlsData));
+        if (rv != SECSuccess)
+            return rv; /* err code already set. */
+    }
+
+    /* The message body */
+    rv = ssl3_UpdateHandshakeHashes(ss, b, length);
+    if (rv != SECSuccess)
+        return rv; /* err code already set. */
+
+    return SECSuccess;
+}
+
+
 /* Called from ssl3_HandleHandshake() when it has gathered a complete ssl3
- * hanshake message.
+ * handshake message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 SECStatus
 ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length,
                             PRBool endOfRecord)
 {
     SECStatus rv = SECSuccess;
-    SSLHandshakeType type = ss->ssl3.hs.msg_type;
-    SSL3Hashes hashes;            /* computed hashes are put here. */
-    SSL3Hashes *hashesPtr = NULL; /* Set when hashes are computed */
-    PRUint8 hdr[4];
-    PRUint8 dtlsData[8];
-    PRBool computeHashes = PR_FALSE;
     PRUint16 epoch;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
-    /*
-     * We have to compute the hashes before we update them with the
-     * current message.
-     */
-    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
-        if ((type == ssl_hs_finished) && (ss->ssl3.hs.ws == wait_finished)) {
-            computeHashes = PR_TRUE;
-        } else if ((type == ssl_hs_certificate_verify) &&
-                   (ss->ssl3.hs.ws == wait_cert_verify)) {
-            if (ss->ssl3.hs.hashType == handshake_hash_record) {
-                /* We cannot compute the hash yet. We must wait until we have
-                 * decoded the certificate_verify message in
-                 * ssl3_HandleCertificateVerify, which will tell us which
-                 * hash function we must use.
-                 *
-                 * (ssl3_HandleCertificateVerify cannot simply look at the
-                 * buffer length itself, because at the time we reach it,
-                 * additional handshake messages will have been added to the
-                 * buffer, e.g. the certificate_verify message itself.)
-                 *
-                 * Therefore, we use SSL3Hashes.u.transcriptLen to save how much
-                 * data there is and read directly from ss->ssl3.hs.messages
-                 * when calculating the hashes.
-                 *
-                 * ssl3_HandleCertificateVerify will detect
-                 *     hashType == handshake_hash_record
-                 * and use that information to calculate the hash.
-                 */
-                hashes.u.transcriptLen = ss->ssl3.hs.messages.len;
-                hashesPtr = &hashes;
-            } else {
-                computeHashes = PR_TRUE;
-            }
-        }
-    } else {
-        if (type == ssl_hs_certificate_verify) {
-            computeHashes = TLS13_IN_HS_STATE(ss, wait_cert_verify);
-        } else if (type == ssl_hs_finished) {
-            computeHashes =
-                TLS13_IN_HS_STATE(ss, wait_cert_request, wait_finished);
-        }
-    }
-
-    ssl_GetSpecReadLock(ss); /************************************/
-    if (computeHashes) {
-        SSL3Sender sender = (SSL3Sender)0;
-        ssl3CipherSpec *rSpec = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ? ss->ssl3.crSpec
-                                                                           : ss->ssl3.prSpec;
-
-        if (type == ssl_hs_finished) {
-            sender = ss->sec.isServer ? sender_client : sender_server;
-            rSpec = ss->ssl3.crSpec;
-        }
-        rv = ssl3_ComputeHandshakeHashes(ss, rSpec, &hashes, sender);
-        if (rv == SECSuccess) {
-            hashesPtr = &hashes;
-        }
-    }
-    ssl_ReleaseSpecReadLock(ss); /************************************/
-    if (rv != SECSuccess) {
-        return rv; /* error code was set by ssl3_ComputeHandshakeHashes*/
-    }
+
     SSL_TRC(30, ("%d: SSL3[%d]: handle handshake message: %s", SSL_GETPID(),
                  ss->fd, ssl3_DecodeHandshakeType(ss->ssl3.hs.msg_type)));
 
-    hdr[0] = (PRUint8)ss->ssl3.hs.msg_type;
-    hdr[1] = (PRUint8)(length >> 16);
-    hdr[2] = (PRUint8)(length >> 8);
-    hdr[3] = (PRUint8)(length);
 
     /* Start new handshake hashes when we start a new handshake.  Unless this is
      * TLS 1.3 and we sent a HelloRetryRequest. */
     if (ss->ssl3.hs.msg_type == ssl_hs_client_hello && !ss->ssl3.hs.helloRetry) {
         ssl3_RestartHandshakeHashes(ss);
     }
-    /* We should not include hello_request and hello_verify_request messages
-     * in the handshake hashes */
-    if ((ss->ssl3.hs.msg_type != ssl_hs_hello_request) &&
-        (ss->ssl3.hs.msg_type != ssl_hs_hello_verify_request)) {
-        rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)hdr, 4);
-        if (rv != SECSuccess)
-            return rv; /* err code already set. */
-
-        /* Extra data to simulate a complete DTLS handshake fragment */
-        if (IS_DTLS(ss)) {
-            /* Sequence number */
-            dtlsData[0] = MSB(ss->ssl3.hs.recvMessageSeq);
-            dtlsData[1] = LSB(ss->ssl3.hs.recvMessageSeq);
-
-            /* Fragment offset */
-            dtlsData[2] = 0;
-            dtlsData[3] = 0;
-            dtlsData[4] = 0;
-
-            /* Fragment length */
-            dtlsData[5] = (PRUint8)(length >> 16);
-            dtlsData[6] = (PRUint8)(length >> 8);
-            dtlsData[7] = (PRUint8)(length);
-
-            rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)dtlsData,
-                                            sizeof(dtlsData));
-            if (rv != SECSuccess)
-                return rv; /* err code already set. */
-        }
-
-        /* The message body */
-        rv = ssl3_UpdateHandshakeHashes(ss, b, length);
-        if (rv != SECSuccess)
-            return rv; /* err code already set. */
+    switch (ss->ssl3.hs.msg_type) {
+        case ssl_hs_hello_request:
+        case ssl_hs_hello_verify_request:
+            /* We don't include hello_request and hello_verify_request messages
+             * in the handshake hashes */
+            break;
+
+        case ssl_hs_certificate_verify:
+        case ssl_hs_finished:
+            /* Defer hashing of these messages until the message handlers
+             * we need to finalize the hashes there. */
+            break;
+
+        default:
+            rv = ssl_HashHandshakeMessage(ss, b, length);
+            if (rv != SECSuccess) {
+                return SECFailure;
+            }
     }
 
     PORT_SetError(0); /* each message starts with no error. */
 
     if (ss->ssl3.hs.ws == wait_certificate_status &&
         ss->ssl3.hs.msg_type != ssl_hs_certificate_status) {
         /* If we negotiated the certificate_status extension then we deferred
          * certificate validation until we get the CertificateStatus messsage.
@@ -11734,20 +11693,19 @@ ssl3_HandleHandshakeMessage(sslSocket *s
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO);
                 return SECFailure;
             }
             rv = ssl3_HandleServerHello(ss, b, length);
             break;
         default:
             if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
-                rv = ssl3_HandlePostHelloHandshakeMessage(ss, b, length, hashesPtr);
+                rv = ssl3_HandlePostHelloHandshakeMessage(ss, b, length);
             } else {
-                rv = tls13_HandlePostHelloHandshakeMessage(ss, b, length,
-                                                           hashesPtr);
+                rv = tls13_HandlePostHelloHandshakeMessage(ss, b, length);
             }
             break;
     }
     if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
         (epoch != ss->ssl3.crSpec->epoch) && !endOfRecord) {
         /* If we changed read cipher states, there must not be any
          * data in the input queue. */
         (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
@@ -11759,17 +11717,17 @@ ssl3_HandleHandshakeMessage(sslSocket *s
         /* Increment the expected sequence number */
         ss->ssl3.hs.recvMessageSeq++;
     }
     return rv;
 }
 
 static SECStatus
 ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b,
-                                     PRUint32 length, SSL3Hashes *hashesPtr)
+                                     PRUint32 length)
 {
     SECStatus rv;
     PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
 
     switch (ss->ssl3.hs.msg_type) {
         case ssl_hs_hello_request:
             if (length != 0) {
                 (void)ssl3_DecodeError(ss);
@@ -11834,17 +11792,17 @@ ssl3_HandlePostHelloHandshakeMessage(ssl
             rv = ssl3_HandleServerHelloDone(ss);
             break;
         case ssl_hs_certificate_verify:
             if (!ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
                 return SECFailure;
             }
-            rv = ssl3_HandleCertificateVerify(ss, b, length, hashesPtr);
+            rv = ssl3_HandleCertificateVerify(ss, b, length);
             break;
         case ssl_hs_client_key_exchange:
             if (!ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH);
                 return SECFailure;
             }
             rv = ssl3_HandleClientKeyExchange(ss, b, length);
@@ -11853,17 +11811,17 @@ ssl3_HandlePostHelloHandshakeMessage(ssl
             if (ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET);
                 return SECFailure;
             }
             rv = ssl3_HandleNewSessionTicket(ss, b, length);
             break;
         case ssl_hs_finished:
-            rv = ssl3_HandleFinished(ss, b, length, hashesPtr);
+            rv = ssl3_HandleFinished(ss, b, length);
             break;
         default:
             (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
             PORT_SetError(SSL_ERROR_RX_UNKNOWN_HANDSHAKE);
             rv = SECFailure;
     }
 
     return rv;
--- a/lib/ssl/ssl3prot.h
+++ b/lib/ssl/ssl3prot.h
@@ -209,17 +209,16 @@ typedef struct {
  * which, if |hashAlg==ssl_hash_none| is also a SSL3HashesIndividually
  * struct. */
 typedef struct {
     unsigned int len;
     SSLHashType hashAlg;
     union {
         PRUint8 raw[64];
         SSL3HashesIndividually s;
-        unsigned int transcriptLen;
     } u;
 } SSL3Hashes;
 
 typedef struct {
     union {
         PRUint8 anonymous;
         SSL3Hashes certified;
     } u;
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -1340,16 +1340,19 @@ extern SECStatus ssl_CipherPrefSetDefaul
 
 extern SECStatus ssl3_ConstrainRangeByPolicy(void);
 
 extern void ssl3_InitState(sslSocket *ss);
 extern void ssl3_RestartHandshakeHashes(sslSocket *ss);
 extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket *ss,
                                             const unsigned char *b,
                                             unsigned int l);
+SECStatus ssl_HashHandshakeMessage(sslSocket *ss, const PRUint8 *b,
+                                   PRUint32 length);
+
 
 /* Returns PR_TRUE if we are still waiting for the server to complete its
  * response to our client second round. Once we've received the Finished from
  * the server then there is no need to check false start.
  */
 extern PRBool ssl3_WaitingForServerSecondRound(sslSocket *ss);
 
 extern PRInt32 ssl3_SendRecord(sslSocket *ss, ssl3CipherSpec *cwSpec,
--- a/lib/ssl/tls13con.c
+++ b/lib/ssl/tls13con.c
@@ -63,18 +63,17 @@ static SECStatus tls13_HandleEncryptedEx
 static SECStatus tls13_SendCertificate(sslSocket *ss);
 static SECStatus tls13_HandleCertificate(
     sslSocket *ss, PRUint8 *b, PRUint32 length);
 static SECStatus tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b,
                                                 PRUint32 length);
 static SECStatus
 tls13_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey);
 static SECStatus tls13_HandleCertificateVerify(
-    sslSocket *ss, PRUint8 *b, PRUint32 length,
-    SSL3Hashes *hashes);
+                                               sslSocket *ss, PRUint8 *b, PRUint32 length);
 static SECStatus tls13_RecoverWrappedSharedSecret(sslSocket *ss,
                                                   sslSessionID *sid);
 static SECStatus
 tls13_DeriveSecretWrap(sslSocket *ss, PK11SymKey *key,
                        const char *prefix,
                        const char *suffix,
                        PK11SymKey **dest);
 static SECStatus
@@ -89,21 +88,19 @@ static SECStatus tls13_HandleEndOfEarlyD
 static SECStatus tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey);
 static SECStatus tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefix,
                                             SSL3Hashes *hashes);
 static SECStatus tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message,
                                       PK11SymKey *secret,
                                       PRUint8 *b, PRUint32 length,
                                       const SSL3Hashes *hashes);
 static SECStatus tls13_ClientHandleFinished(sslSocket *ss,
-                                            PRUint8 *b, PRUint32 length,
-                                            const SSL3Hashes *hashes);
+                                            PRUint8 *b, PRUint32 length);
 static SECStatus tls13_ServerHandleFinished(sslSocket *ss,
-                                            PRUint8 *b, PRUint32 length,
-                                            const SSL3Hashes *hashes);
+                                            PRUint8 *b, PRUint32 length);
 static SECStatus tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b,
                                               PRUint32 length);
 static SECStatus tls13_ComputeHandshakeHashes(sslSocket *ss,
                                               SSL3Hashes *hashes);
 static SECStatus tls13_ComputeEarlySecrets(sslSocket *ss);
 static SECStatus tls13_ComputeHandshakeSecrets(sslSocket *ss);
 static SECStatus tls13_ComputeApplicationSecrets(sslSocket *ss);
 static SECStatus tls13_ComputeFinalSecrets(sslSocket *ss);
@@ -582,18 +579,17 @@ tls13_HandleKeyShare(sslSocket *ss,
 loser:
     PORT_DestroyCheapArena(&arena);
     errorCode = PORT_GetError(); /* don't overwrite the error code */
     tls13_FatalError(ss, errorCode, illegal_parameter);
     return SECFailure;
 }
 
 SECStatus
-tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b,
-                                      PRUint32 length, SSL3Hashes *hashesPtr)
+tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length)
 {
     if (ss->sec.isServer && ss->ssl3.hs.zeroRttIgnore != ssl_0rtt_ignore_none) {
         SSL_TRC(3, ("%d: TLS13[%d]: %s successfully decrypted handshake after"
                     "failed 0-RTT",
                     SSL_GETPID(), ss->fd));
         ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
     }
 
@@ -601,37 +597,30 @@ tls13_HandlePostHelloHandshakeMessage(ss
     switch (ss->ssl3.hs.msg_type) {
         case ssl_hs_certificate:
             return tls13_HandleCertificate(ss, b, length);
 
         case ssl_hs_certificate_request:
             return tls13_HandleCertificateRequest(ss, b, length);
 
         case ssl_hs_certificate_verify:
-            if (!hashesPtr) {
-                FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY, unexpected_message);
-                return SECFailure;
-            }
-            return tls13_HandleCertificateVerify(ss, b, length, hashesPtr);
+            return tls13_HandleCertificateVerify(ss, b, length);
 
         case ssl_hs_encrypted_extensions:
             return tls13_HandleEncryptedExtensions(ss, b, length);
 
         case ssl_hs_new_session_ticket:
             return tls13_HandleNewSessionTicket(ss, b, length);
 
         case ssl_hs_finished:
-            if (!hashesPtr) {
-                FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, unexpected_message);
-                return SECFailure;
+            if (ss->sec.isServer) {
+                return tls13_ServerHandleFinished(ss, b, length);
+            } else {
+                return tls13_ClientHandleFinished(ss, b, length);
             }
-            if (ss->sec.isServer) {
-                return tls13_ServerHandleFinished(ss, b, length, hashesPtr);
-            }
-            return tls13_ClientHandleFinished(ss, b, length, hashesPtr);
 
         case ssl_hs_end_of_early_data:
             return tls13_HandleEndOfEarlyData(ss, b, length);
 
         default:
             FATAL_ERROR(ss, SSL_ERROR_RX_UNKNOWN_HANDSHAKE, unexpected_message);
             return SECFailure;
     }
@@ -3251,51 +3240,61 @@ done:
     return rv;
 }
 
 /* Called from tls13_CompleteHandleHandshakeMessage() when it has deciphered a complete
  * tls13 CertificateVerify message
  * Caller must hold Handshake and RecvBuf locks.
  */
 SECStatus
-tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length,
-                              SSL3Hashes *hashes)
+tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
 {
     SECItem signed_hash = { siBuffer, NULL, 0 };
     SECStatus rv;
     SSLSignatureScheme sigScheme;
     SSLHashType hashAlg;
     SSL3Hashes tbsHash;
+    SSL3Hashes hashes;
 
     SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_verify handshake",
                 SSL_GETPID(), ss->fd));
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY,
                               wait_cert_verify);
     if (rv != SECSuccess) {
         return SECFailure;
     }
-    PORT_Assert(hashes);
+
+    rv = tls13_ComputeHandshakeHashes(ss, &hashes);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    rv = ssl_HashHandshakeMessage(ss, b, length);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
 
     rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme);
     if (rv != SECSuccess) {
         PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
         return SECFailure;
     }
 
     rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme, ss->sec.peerCert);
     if (rv != SECSuccess) {
         /* Error set already */
         return SECFailure;
     }
     hashAlg = ssl_SignatureSchemeToHashType(sigScheme);
 
-    rv = tls13_AddContextToHashes(ss, hashes, hashAlg, PR_FALSE, &tbsHash);
+    rv = tls13_AddContextToHashes(ss, &hashes, hashAlg, PR_FALSE, &tbsHash);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SSL_ERROR_DIGEST_FAILURE, internal_error);
         return SECFailure;
     }
 
     rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length);
     if (rv != SECSuccess) {
         PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
@@ -3565,48 +3564,60 @@ tls13_VerifyFinished(sslSocket *ss, SSLH
         return SECFailure;
 #endif
     }
 
     return SECSuccess;
 }
 
 static SECStatus
-tls13_ClientHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length,
-                           const SSL3Hashes *hashes)
+tls13_ClientHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
 {
     SECStatus rv;
+    SSL3Hashes hashes;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     SSL_TRC(3, ("%d: TLS13[%d]: client handle finished handshake",
                 SSL_GETPID(), ss->fd));
 
     rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED,
                               wait_finished);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
+    rv = tls13_ComputeHandshakeHashes(ss, &hashes);
+    if (rv != SECSuccess) {
+        LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    rv = ssl_HashHandshakeMessage(ss, b, length);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
     rv = tls13_VerifyFinished(ss, ssl_hs_finished,
                               ss->ssl3.hs.serverHsTrafficSecret,
-                              b, length, hashes);
+                              b, length, &hashes);
     if (rv != SECSuccess)
         return SECFailure;
 
     return tls13_SendClientSecondRound(ss);
 }
 
 static SECStatus
-tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length,
-                           const SSL3Hashes *hashes)
+tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
 {
     SECStatus rv;
     PK11SymKey *secret;
+    SSL3Hashes hashes;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     SSL_TRC(3, ("%d: TLS13[%d]: server handle finished handshake",
                 SSL_GETPID(), ss->fd));
 
     rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, wait_finished);
@@ -3615,17 +3626,29 @@ tls13_ServerHandleFinished(sslSocket *ss
     }
 
     if (TLS13_IN_HS_STATE(ss, wait_finished)) {
         secret = ss->ssl3.hs.clientHsTrafficSecret;
     } else {
         secret = ss->ssl3.hs.clientEarlyTrafficSecret;
     }
 
-    rv = tls13_VerifyFinished(ss, ssl_hs_finished, secret, b, length, hashes);
+    rv = tls13_ComputeHandshakeHashes(ss, &hashes);
+    if (rv != SECSuccess) {
+        LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    rv = ssl_HashHandshakeMessage(ss, b, length);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    rv = tls13_VerifyFinished(ss, ssl_hs_finished, secret, b, length, &hashes);
     if (rv != SECSuccess)
         return SECFailure;
 
     rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
                              CipherSpecRead, PR_TRUE);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
         return SECFailure;
--- a/lib/ssl/tls13con.h
+++ b/lib/ssl/tls13con.h
@@ -62,18 +62,17 @@ PRBool tls13_AllowPskCipher(const sslSoc
                             const ssl3CipherSuiteDef *cipher_def);
 PRBool tls13_PskSuiteEnabled(sslSocket *ss);
 SECStatus tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions);
 SECStatus tls13_HandleClientHelloPart2(sslSocket *ss,
                                        const SECItem *suites,
                                        sslSessionID *sid);
 SECStatus tls13_HandleServerHelloPart2(sslSocket *ss);
 SECStatus tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b,
-                                                PRUint32 length,
-                                                SSL3Hashes *hashesPtr);
+                                                PRUint32 length);
 SECStatus tls13_HandleHelloRetryRequest(sslSocket *ss, PRUint8 *b,
                                         PRUint32 length);
 void tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *entry);
 void tls13_DestroyKeyShares(PRCList *list);
 SECStatus tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef);
 void tls13_DestroyEarlyData(PRCList *list);
 void tls13_CipherSpecAddRef(ssl3CipherSpec *spec);
 void tls13_CipherSpecRelease(ssl3CipherSpec *spec);