Blob Blame History Raw
diff --git a/external_tests/ssl_gtest/ssl_loopback_unittest.cc b/external_tests/ssl_gtest/ssl_loopback_unittest.cc
--- a/external_tests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/external_tests/ssl_gtest/ssl_loopback_unittest.cc
@@ -318,23 +318,21 @@ TEST_P(TlsConnectPre12, SignatureAlgorit
   ResetEcdsa();
   client_->SetSignatureAlgorithms(SignatureEcdsaSha384,
                                   PR_ARRAY_SIZE(SignatureEcdsaSha384));
   server_->SetSignatureAlgorithms(SignatureEcdsaSha256,
                                   PR_ARRAY_SIZE(SignatureEcdsaSha256));
   Connect();
 }
 
-// The server requests client auth but doesn't offer a SHA-256 option.
-// This fails because NSS only uses SHA-256 for handshake transcript hashes.
-TEST_P(TlsConnectTls12, RequestClientAuthWithoutSha256) {
+TEST_P(TlsConnectTls12, RequestClientAuthWithSha384) {
   server_->SetSignatureAlgorithms(SignatureRsaSha384,
                                   PR_ARRAY_SIZE(SignatureRsaSha384));
   server_->RequestClientAuth(false);
-  ConnectExpectFail();
+  Connect();
 }
 
 TEST_P(TlsConnectGeneric, ConnectAlpn) {
   EnableAlpn();
   Connect();
   client_->CheckAlpn(SSL_NEXT_PROTO_SELECTED, "a");
   server_->CheckAlpn(SSL_NEXT_PROTO_NEGOTIATED, "a");
 }
diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -3636,16 +3636,29 @@ ssl3_GetPrfHashMechanism(sslSocket *ss)
    SSL3PRF prf_alg = ss->ssl3.hs.suite_def->prf_alg;
 
    if (prf_alg == 0)
 	return CKM_SHA256;
     
    return prf_alg;
 }
 
+static SSLHashType
+ssl3_GetSuitePrfHash(sslSocket *ss)
+{
+    switch (ss->ssl3.hs.suite_def->prf_alg) {
+        case CKM_SHA384:
+            return ssl_hash_sha384;
+        case 0:
+        case CKM_SHA256:
+        default:
+            return ssl_hash_sha256;
+    }
+}
+
 
 /* This method completes the derivation of the MS from the PMS.
 **
 ** 1. Derive the MS, if possible, else return an error.
 **
 ** 2. Check the version if |pms_version| is non-zero and if wrong,
 **    return an error.
 **
@@ -3813,17 +3826,17 @@ tls_ComputeExtendedMasterSecretInt(sslSo
         master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH;
     } else {
         master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE;
         pms_version_ptr = &pms_version;
     }
 
     if (pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
         /* TLS 1.2 */
-        extended_master_params.prfHashMechanism = CKM_SHA256;
+        extended_master_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss);
         key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE;
     } else {
         /* TLS < 1.2 */
         extended_master_params.prfHashMechanism = CKM_TLS_PRF;
 	key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
     }
 
     extended_master_params.pVersion = pms_version_ptr;
@@ -4071,20 +4084,23 @@ loser:
 /* ssl3_InitHandshakeHashes creates handshake hash contexts and hashes in
  * buffered messages in ss->ssl3.hs.messages. */
 static SECStatus
 ssl3_InitHandshakeHashes(sslSocket *ss)
 {
     SSL_TRC(30,("%d: SSL3[%d]: start handshake hashes", SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_unknown);
+    if (ss->version == SSL_LIBRARY_VERSION_TLS_1_2) {
+        ss->ssl3.hs.hashType = handshake_hash_record;
+    } else
 #ifndef NO_PKCS11_BYPASS
     if (ss->opt.bypassPKCS11) {
 	PORT_Assert(!ss->ssl3.hs.sha_obj && !ss->ssl3.hs.sha_clone);
-	if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+	if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
 	    /* If we ever support ciphersuites where the PRF hash isn't SHA-256
 	     * then this will need to be updated. */
 	    HASH_HashType ht;
 	    CK_MECHANISM_TYPE hm;
 	    SECOidTag ot;
 	    SECOidData *hashOid;
 
 	    hm = ssl3_GetPrfHashMechanism(ss);
@@ -4112,17 +4128,17 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
 #endif
     {
 	PORT_Assert(!ss->ssl3.hs.md5 && !ss->ssl3.hs.sha);
 	/*
 	 * note: We should probably lookup an SSL3 slot for these
 	 * handshake hashes in hopes that we wind up with the same slots
 	 * that the master secret will wind up in ...
 	 */
-	if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+	if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
 	    /* determine the hash from the prf */
 	    const SECOidData *hash_oid;
 
 	    PORT_Assert(ss->ssl3.hs.suite_def);
 	    /* Get the PKCS #11 mechanism for the Hash from the cipher suite (prf_alg)
 	     * Convert that to the OidTag. We can then use that OidTag to create our
          * PK11Context */
 	    hash_oid = SECOID_FindOIDByMechanism(ssl3_GetPrfHashMechanism(ss));
@@ -4137,38 +4153,16 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
 		return SECFailure;
 	    }
 	    ss->ssl3.hs.hashType = handshake_hash_single;
 
 	    if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) {
 		ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
 		return SECFailure;
 	    }
-
-	    /* Create a backup SHA-1 hash for a potential client auth
-	     * signature.
-	     *
-	     * In TLS 1.2, ssl3_ComputeHandshakeHashes always uses the
-	     * handshake hash function (SHA-256). If the server or the client
-	     * does not support SHA-256 as a signature hash, we can either
-	     * maintain a backup SHA-1 handshake hash or buffer all handshake
-	     * messages.
-	     */
-	    if (!ss->sec.isServer) {
-		ss->ssl3.hs.backupHash = PK11_CreateDigestContext(SEC_OID_SHA1);
-		if (ss->ssl3.hs.backupHash == NULL) {
-		    ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
-		    return SECFailure;
-		}
-
-		if (PK11_DigestBegin(ss->ssl3.hs.backupHash) != SECSuccess) {
-		    ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
-		    return SECFailure;
-		}
-	    }
 	} else {
 	    /* Both ss->ssl3.hs.md5 and ss->ssl3.hs.sha should be NULL or
 	     * created successfully. */
 	    ss->ssl3.hs.md5 = PK11_CreateDigestContext(SEC_OID_MD5);
 	    if (ss->ssl3.hs.md5 == NULL) {
 		ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
 		return SECFailure;
 	    }
@@ -4187,26 +4181,23 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
 	    }
 	    if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) {
 		ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
 		return SECFailure;
 	    }
 	}
     }
 
-    if (ss->ssl3.hs.messages.len > 0) {
-	if (ssl3_UpdateHandshakeHashes(ss, ss->ssl3.hs.messages.buf,
-				       ss->ssl3.hs.messages.len) !=
-	    SECSuccess) {
-	    return SECFailure;
-	}
-	PORT_Free(ss->ssl3.hs.messages.buf);
-	ss->ssl3.hs.messages.buf = NULL;
-	ss->ssl3.hs.messages.len = 0;
-	ss->ssl3.hs.messages.space = 0;
+    if (ss->ssl3.hs.hashType != handshake_hash_record &&
+        ss->ssl3.hs.messages.len > 0) {
+        if (ssl3_UpdateHandshakeHashes(ss, ss->ssl3.hs.messages.buf,
+                                       ss->ssl3.hs.messages.len) != SECSuccess) {
+            return SECFailure;
+        }
+        sslBuffer_Clear(&ss->ssl3.hs.messages);
     }
 
     return SECSuccess;
 }
 
 static SECStatus 
 ssl3_RestartHandshakeHashes(sslSocket *ss)
 {
@@ -4237,66 +4228,71 @@ ssl3_RestartHandshakeHashes(sslSocket *s
 /* Called from	ssl3_InitHandshakeHashes()
 **		ssl3_AppendHandshake()
 **		ssl3_StartHandshakeHash()
 **		ssl3_HandleV2ClientHello()
 **		ssl3_HandleHandshakeMessage()
 ** Caller must hold the ssl3Handshake lock.
 */
 static SECStatus
-ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b,
-			   unsigned int l)
+ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l)
 {
     SECStatus  rv = SECSuccess;
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
 
-    /* We need to buffer the handshake messages until we have established
-     * which handshake hash function to use. */
-    if (ss->ssl3.hs.hashType == handshake_hash_unknown) {
-	return sslBuffer_Append(&ss->ssl3.hs.messages, b, l);
+    /* With TLS 1.3, and versions TLS.1.1 and older, we keep the hash(es)
+     * always up to date. However, we must initially buffer the handshake
+     * messages, until we know what to do.
+     * If ss->ssl3.hs.hashType != handshake_hash_unknown,
+     * it means we know what to do. We calculate (hash our input),
+     * and we stop appending to the buffer.
+     *
+     * With TLS 1.2, we always append all handshake messages,
+     * and never update the hash, because the hash function we must use for
+     * certificate_verify might be different from the hash function we use
+     * when signing other handshake hashes. */
+
+    if (ss->ssl3.hs.hashType == handshake_hash_unknown ||
+        ss->ssl3.hs.hashType == handshake_hash_record) {
+        return sslBuffer_Append(&ss->ssl3.hs.messages, b, l);
     }
 
     PRINT_BUF(90, (NULL, "handshake hash input:", b, l));
 
 #ifndef NO_PKCS11_BYPASS
     if (ss->opt.bypassPKCS11) {
 	if (ss->ssl3.hs.hashType == handshake_hash_single) {
-	    ss->ssl3.hs.sha_obj->update(ss->ssl3.hs.sha_cx, b, l);
-	} else {
+        PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+        ss->ssl3.hs.sha_obj->update(ss->ssl3.hs.sha_cx, b, l);
+    } else if (ss->ssl3.hs.hashType == handshake_hash_combo) {
 	    MD5_Update((MD5Context *)ss->ssl3.hs.md5_cx, b, l);
 	    SHA1_Update((SHA1Context *)ss->ssl3.hs.sha_cx, b, l);
 	}
 	return rv;
     }
 #endif
     if (ss->ssl3.hs.hashType == handshake_hash_single) {
-	rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
-	if (rv != SECSuccess) {
-	    ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
-	    return rv;
-	}
-	if (ss->ssl3.hs.backupHash) {
-	    rv = PK11_DigestOp(ss->ssl3.hs.backupHash, b, l);
-	    if (rv != SECSuccess) {
-		ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
-		return rv;
-	    }
-	}
-    } else {
-	rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l);
-	if (rv != SECSuccess) {
-	    ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
-	    return rv;
-	}
-	rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
-	if (rv != SECSuccess) {
-	    ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
-	    return rv;
-	}
+        PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+        rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
+        if (rv != SECSuccess) {
+            ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+            return rv;
+        }
+    } else if (ss->ssl3.hs.hashType == handshake_hash_combo) {
+        rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l);
+        if (rv != SECSuccess) {
+            ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+            return rv;
+        }
+        rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
+        if (rv != SECSuccess) {
+            ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+            return rv;
+        }
     }
     return rv;
 }
 
 /**************************************************************************
  * Append Handshake functions.
  * All these functions set appropriate error codes.
  * Most rely on ssl3_AppendHandshake to set the error code.
@@ -4759,16 +4755,68 @@ ssl3_ConsumeSignatureAndHashAlgorithm(ss
     }
     return SECSuccess;
 }
 
 /**************************************************************************
  * end of Consume Handshake functions.
  **************************************************************************/
 
+#ifndef NO_PKCS11_BYPASS
+static SECStatus
+ssl3_ComputeBypassHandshakeHash(unsigned char *buf, unsigned int len,
+                                SSLHashType hashAlg, SSL3Hashes *hashes)
+{
+    const SECHashObject *h_obj = NULL;
+    PRUint64 h_cx[MAX_MAC_CONTEXT_LLONGS];
+    const SECOidData *hashOid =
+        SECOID_FindOIDByMechanism(ssl3_GetHashMechanismByHashType(hashAlg));
+
+    if (hashOid) {
+        h_obj = HASH_GetRawHashObject(HASH_GetHashTypeByOidTag(hashOid->offset));
+    }
+    if (!h_obj) {
+        ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+        return SECFailure;
+    }
+    h_obj->begin(h_cx);
+    h_obj->update(h_cx, buf, len);
+    h_obj->end(h_cx, hashes->u.raw, &hashes->len, sizeof(hashes->u.raw));
+    PRINT_BUF(60, (NULL, "HASH: result", hashes->u.raw, hashes->len));
+    hashes->hashAlg = hashAlg;
+    return SECSuccess;
+}
+#endif
+
+static SECStatus
+ssl3_ComputePkcs11HandshakeHash(unsigned char *buf, unsigned int len,
+                                SSLHashType hashAlg, SSL3Hashes *hashes)
+{
+    SECStatus rv = SECFailure;
+    PK11Context *hashContext = PK11_CreateDigestContext(
+        ssl3_TLSHashAlgorithmToOID(hashAlg));
+
+    if (!hashContext) {
+        return rv;
+    }
+    rv = PK11_DigestBegin(hashContext);
+    if (rv == SECSuccess) {
+        rv = PK11_DigestOp(hashContext, buf, len);
+    }
+    if (rv == SECSuccess) {
+        rv = PK11_DigestFinal(hashContext, hashes->u.raw, &hashes->len,
+                              sizeof(hashes->u.raw));
+    }
+    if (rv == SECSuccess) {
+        hashes->hashAlg = hashAlg;
+    }
+    PK11_DestroyContext(hashContext, PR_TRUE);
+    return rv;
+}
+
 /* Extract the hashes of handshake messages to this point.
  * Called from ssl3_SendCertificateVerify
  *             ssl3_SendFinished
  *             ssl3_HandleHandshakeMessage
  *
  * Caller must hold the SSL3HandshakeLock.
  * Caller must hold a read or write lock on the Spec R/W lock.
  *	(There is presently no way to assert on a Read lock.)
@@ -4798,23 +4846,27 @@ ssl3_ComputeHandshakeHashes(sslSocket * 
 	ss->ssl3.hs.hashType == handshake_hash_single) {
 	/* compute them without PKCS11 */
 	PRUint64      sha_cx[MAX_MAC_CONTEXT_LLONGS];
 
 	ss->ssl3.hs.sha_clone(sha_cx, ss->ssl3.hs.sha_cx);
 	ss->ssl3.hs.sha_obj->end(sha_cx, hashes->u.raw, &hashes->len,
 				 sizeof(hashes->u.raw));
 
-	PRINT_BUF(60, (NULL, "SHA-256: result", hashes->u.raw, hashes->len));
-
-	/* If we ever support ciphersuites where the PRF hash isn't SHA-256
-	 * then this will need to be updated. */
-	hashes->hashAlg = ssl_hash_sha256;
+	PRINT_BUF(60, (NULL, "HASH: result", hashes->u.raw, hashes->len));
+
+	hashes->hashAlg = ssl3_GetSuitePrfHash(ss);
 	rv = SECSuccess;
-    } else if (ss->opt.bypassPKCS11) {
+    } else if (ss->opt.bypassPKCS11 &&
+               ss->ssl3.hs.hashType == handshake_hash_record) {
+        rv = ssl3_ComputeBypassHandshakeHash(ss->ssl3.hs.messages.buf,
+                                             ss->ssl3.hs.messages.len,
+                                             ssl3_GetSuitePrfHash(ss),
+                                             hashes);
+    } else if (ss->opt.bypassPKCS11) { /* TLS 1.1 or lower */
 	/* compute them without PKCS11 */
 	PRUint64      md5_cx[MAX_MAC_CONTEXT_LLONGS];
 	PRUint64      sha_cx[MAX_MAC_CONTEXT_LLONGS];
 
 #define md5cx ((MD5Context *)md5_cx)
 #define shacx ((SHA1Context *)sha_cx)
 
 	MD5_Clone (md5cx,  (MD5Context *)ss->ssl3.hs.md5_cx);
@@ -4942,16 +4994,21 @@ tls12_loser:
 	    if (PK11_RestoreContext(h, stateBuf, stateLen) != SECSuccess) {
 		ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
 		rv = SECFailure;
 	    }
 	    if (stateBuf != stackBuf) {
 		PORT_ZFree(stateBuf, stateLen);
 	    }
 	}
+    } else if (ss->ssl3.hs.hashType == handshake_hash_record) {
+        rv = ssl3_ComputePkcs11HandshakeHash(ss->ssl3.hs.messages.buf,
+                                             ss->ssl3.hs.messages.len,
+                                             ssl3_GetSuitePrfHash(ss),
+                                             hashes);
     } else {
 	/* compute hashes with PKCS11 */
 	PK11Context * md5;
 	PK11Context * sha       = NULL;
 	unsigned char *md5StateBuf = NULL;
 	unsigned char *shaStateBuf = NULL;
 	unsigned int  md5StateLen, shaStateLen;
 	unsigned char md5StackBuf[256];
@@ -5096,41 +5153,16 @@ tls12_loser:
 	    if (shaStateBuf != shaStackBuf) {
 		PORT_ZFree(shaStateBuf, shaStateLen);
 	    }
 	}
     }
     return rv;
 }
 
-static SECStatus
-ssl3_ComputeBackupHandshakeHashes(sslSocket * ss,
-				  SSL3Hashes * hashes) /* output goes here. */
-{
-    SECStatus rv = SECSuccess;
-
-    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
-    PORT_Assert( !ss->sec.isServer );
-    PORT_Assert( ss->ssl3.hs.hashType == handshake_hash_single );
-
-    rv = PK11_DigestFinal(ss->ssl3.hs.backupHash, hashes->u.raw, &hashes->len,
-			  sizeof(hashes->u.raw));
-    if (rv != SECSuccess) {
-	ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
-	rv = SECFailure;
-	goto loser;
-    }
-    hashes->hashAlg = ssl_hash_sha1;
-
-loser:
-    PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE);
-    ss->ssl3.hs.backupHash = NULL;
-    return rv;
-}
-
 /*
  * SSL 2 based implementations pass in the initial outbound buffer
  * so that the handshake hash can contain the included information.
  *
  * Called from ssl2_BeginClientHandshake() in sslcon.c
  */
 SECStatus
 ssl3_StartHandshakeHash(sslSocket *ss, unsigned char * buf, int length)
@@ -6451,26 +6483,44 @@ ssl3_SendCertificateVerify(sslSocket *ss
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     SSL_TRC(3, ("%d: SSL3[%d]: send certificate_verify handshake",
 		SSL_GETPID(), ss->fd));
 
     ssl_GetSpecReadLock(ss);
-    if (ss->ssl3.hs.hashType == handshake_hash_single &&
-	ss->ssl3.hs.backupHash) {
-	rv = ssl3_ComputeBackupHandshakeHashes(ss, &hashes);
-	PORT_Assert(!ss->ssl3.hs.backupHash);
+
+    if (ss->ssl3.hs.hashType == handshake_hash_record &&
+        ss->ssl3.hs.tls12CertVerifyHash != ssl3_GetSuitePrfHash(ss)) {
+#ifndef NO_PKCS11_BYPASS
+        if (ss->opt.bypassPKCS11) {
+            rv = ssl3_ComputeBypassHandshakeHash(ss->ssl3.hs.messages.buf,
+                                                 ss->ssl3.hs.messages.len,
+                                                 ss->ssl3.hs.tls12CertVerifyHash,
+                                                 &hashes);
+        } else
+#endif
+        {
+            rv = ssl3_ComputePkcs11HandshakeHash(ss->ssl3.hs.messages.buf,
+                                                 ss->ssl3.hs.messages.len,
+                                                 ss->ssl3.hs.tls12CertVerifyHash,
+                                                 &hashes);
+        }
+        if (rv != SECSuccess) {
+            ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+            goto done;
+        }
     } else {
-	rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0);
-    }
+        rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0);
+    }
+
     ssl_ReleaseSpecReadLock(ss);
     if (rv != SECSuccess) {
-	goto done;	/* err code was set by ssl3_ComputeHandshakeHashes */
+        goto done;	/* err code was set by ssl3_ComputeHandshakeHashes */
     }
 
     isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
     isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
     keyType = ss->ssl3.clientPrivateKey->keyType;
     rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS);
     if (rv == SECSuccess) {
 	PK11SlotInfo * slot;
@@ -7249,88 +7299,18 @@ ssl3_ExtractClientKeyInfo(sslSocket *ss,
     }
 
 done:
     if (pubk)
 	SECKEY_DestroyPublicKey(pubk);
     return rv;
 }
 
-/* Destroys the backup handshake hash context if we don't need it. Note that
- * this function selects the hash algorithm for client authentication
- * signatures; ssl3_SendCertificateVerify uses the presence of the backup hash
- * to determine whether to use SHA-1, or the PRF hash of the cipher suite. */
 static void
-ssl3_DestroyBackupHandshakeHashIfNotNeeded(sslSocket *ss,
-					   const SECItem *algorithms)
-{
-    SECStatus rv;
-    SSLSignType sigAlg;
-    PRBool preferSha1;
-    PRBool supportsSha1 = PR_FALSE;
-    PRBool supportsHandshakeHash = PR_FALSE;
-    PRBool needBackupHash = PR_FALSE;
-    unsigned int i;
-    SECOidData *hashOid;
-    TLSHashAlgorithm suitePRFHash;
-    PRBool suitePRFIs256Or384 = PR_FALSE;
-
-#ifndef NO_PKCS11_BYPASS
-    /* Backup handshake hash is not supported in PKCS #11 bypass mode. */
-    if (ss->opt.bypassPKCS11) {
-	PORT_Assert(!ss->ssl3.hs.backupHash);
-	return;
-    }
-#endif
-    PORT_Assert(ss->ssl3.hs.backupHash);
-
-    /* Determine the key's signature algorithm and whether it prefers SHA-1. */
-    rv = ssl3_ExtractClientKeyInfo(ss, &sigAlg, &preferSha1);
-    if (rv != SECSuccess) {
-	goto done;
-    }
-
-    hashOid = SECOID_FindOIDByMechanism(ssl3_GetPrfHashMechanism(ss));
-    if (hashOid == NULL) {
-        rv = SECFailure;
-	goto done;
-    }
-
-    if (hashOid->offset == SEC_OID_SHA256) {
-	suitePRFHash = tls_hash_sha256;
-	suitePRFIs256Or384 = PR_TRUE;
-    } else if (hashOid->offset == SEC_OID_SHA384) {
-	suitePRFHash = tls_hash_sha384;
-	suitePRFIs256Or384 = PR_TRUE;
-    } 
-
-    /* Determine the server's hash support for that signature algorithm. */
-    for (i = 0; i < algorithms->len; i += 2) {
-	if (algorithms->data[i+1] == sigAlg) {
-	    if (algorithms->data[i] == ssl_hash_sha1) {
-		supportsSha1 = PR_TRUE;
-	    } else if (suitePRFIs256Or384 &&
-	               algorithms->data[i] == suitePRFHash) {
-		supportsHandshakeHash = PR_TRUE;
-	    }
-	}
-    }
-
-    /* If either the server does not support SHA-256 or the client key prefers
-     * SHA-1, leave the backup hash. */
-    if (supportsSha1 && (preferSha1 || !supportsHandshakeHash)) {
-	needBackupHash = PR_TRUE;
-    }
-
-done:
-    if (!needBackupHash) {
-	PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE);
-	ss->ssl3.hs.backupHash = NULL;
-    }
-}
+ssl3_DecideTls12CertVerifyHash(sslSocket *ss, const SECItem *algorithms);
 
 typedef struct dnameNode {
     struct dnameNode *next;
     SECItem           name;
 } dnameNode;
 
 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
  * ssl3 Certificate Request message.
@@ -7486,19 +7466,20 @@ ssl3_HandleCertificateRequest(sslSocket 
 					certUsageSSLClient, PR_FALSE);
 	if (ss->ssl3.clientCertChain == NULL) {
 	    CERT_DestroyCertificate(ss->ssl3.clientCertificate);
 	    ss->ssl3.clientCertificate = NULL;
 	    SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
 	    ss->ssl3.clientPrivateKey = NULL;
 	    goto send_no_certificate;
 	}
-	if (ss->ssl3.hs.hashType == handshake_hash_single) {
-	    ssl3_DestroyBackupHandshakeHashIfNotNeeded(ss, &algorithms);
-	}
+    if (ss->ssl3.hs.hashType == handshake_hash_record ||
+        ss->ssl3.hs.hashType == handshake_hash_single) {
+        ssl3_DecideTls12CertVerifyHash(ss, &algorithms);
+    }
 	break;	/* not an error */
 
     case SECFailure:
     default:
 send_no_certificate:
 	if (isTLS) {
 	    ss->ssl3.sendEmptyCert = PR_TRUE;
 	} else {
@@ -7639,24 +7620,16 @@ ssl3_SendClientSecondRound(sslSocket *ss
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
 
     sendClientCert = !ss->ssl3.sendEmptyCert &&
 		     ss->ssl3.clientCertChain  != NULL &&
 		     ss->ssl3.clientPrivateKey != NULL;
 
-    if (!sendClientCert &&
-	ss->ssl3.hs.hashType == handshake_hash_single &&
-	ss->ssl3.hs.backupHash) {
-	/* Don't need the backup handshake hash. */
-	PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE);
-	ss->ssl3.hs.backupHash = NULL;
-    }
-
     /* We must wait for the server's certificate to be authenticated before
      * sending the client certificate in order to disclosing the client
      * certificate to an attacker that does not have a valid cert for the
      * domain we are connecting to.
      *
      * XXX: We should do the same for the NPN extension, but for that we
      * need an option to give the application the ability to leak the NPN
      * information to get better performance.
@@ -9415,16 +9388,69 @@ ssl3_PickSignatureHashAlgorithm(sslSocke
             }
         }
     }
 
     PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
     return SECFailure;
 }
 
+static void
+ssl3_DecideTls12CertVerifyHash(sslSocket *ss, const SECItem *algorithms)
+{
+    SECStatus rv;
+    SSLSignType sigAlg;
+    PRBool preferSha1 = PR_FALSE;
+    PRBool supportsSha1 = PR_FALSE;
+    PRBool supportsHandshakeHash = PR_FALSE;
+    unsigned int i;
+    SSLHashType otherHashAlg = ssl_hash_none;
+
+    /* Determine the key's signature algorithm and whether it prefers SHA-1. */
+    rv = ssl3_ExtractClientKeyInfo(ss, &sigAlg, &preferSha1);
+    if (rv != SECSuccess) {
+        return;
+    }
+
+    /* Determine the server's hash support for that signature algorithm. */
+    for (i = 0; i < algorithms->len; i += 2) {
+        if (algorithms->data[i + 1] == sigAlg) {
+            SSLHashType hashAlg = algorithms->data[i];
+            SECOidTag hashOID;
+            PRUint32 policy;
+            if (hashAlg == ssl_hash_sha1 &&
+                ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+                /* TLS 1.3 explicitly forbids using SHA-1 with certificate_verify. */
+                continue;
+            }
+            hashOID = ssl3_TLSHashAlgorithmToOID(hashAlg);
+            if ((NSS_GetAlgorithmPolicy(hashOID, &policy) == SECSuccess) &&
+                !(policy & NSS_USE_ALG_IN_SSL_KX)) {
+                /* we ignore hashes we don't support */
+                continue;
+            }
+            if (hashAlg == ssl_hash_sha1) {
+                supportsSha1 = PR_TRUE;
+            } else if (hashAlg == ssl3_GetSuitePrfHash(ss)) {
+                supportsHandshakeHash = PR_TRUE;
+            }
+            if (otherHashAlg == ssl_hash_none) {
+                otherHashAlg = hashAlg;
+            }
+        }
+    }
+
+    if (supportsSha1 && preferSha1) {
+        ss->ssl3.hs.tls12CertVerifyHash = ssl_hash_sha1;
+    } else if (supportsHandshakeHash) {
+        ss->ssl3.hs.tls12CertVerifyHash = ssl3_GetSuitePrfHash(ss); /* Use suite PRF hash. */
+    } else {
+        ss->ssl3.hs.tls12CertVerifyHash = otherHashAlg;
+    }
+}
 
 static SECStatus
 ssl3_SendServerKeyExchange(sslSocket *ss)
 {
     const ssl3KEADef * kea_def     = ss->ssl3.hs.kea_def;
     SECStatus          rv          = SECFailure;
     int                length;
     PRBool             isTLS;
@@ -9534,38 +9560,32 @@ ssl3_SendServerKeyExchange(sslSocket *ss
     }
 loser:
     if (signed_hash.data != NULL) 
     	PORT_Free(signed_hash.data);
     return SECFailure;
 }
 
 static SECStatus
-ssl3_EncodeCertificateRequestSigAlgs(sslSocket *ss, PRUint8 allowedHashAlg,
-                                     PRUint8 *buf,
+ssl3_EncodeCertificateRequestSigAlgs(sslSocket *ss, PRUint8 *buf,
                                      unsigned maxLen, PRUint32 *len)
 {
     unsigned int i;
 
     PORT_Assert(maxLen >= ss->ssl3.signatureAlgorithmCount * 2);
     if (maxLen < ss->ssl3.signatureAlgorithmCount * 2) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     *len = 0;
     for (i = 0; i < ss->ssl3.signatureAlgorithmCount; ++i) {
         const SSLSignatureAndHashAlg *alg = &ss->ssl3.signatureAlgorithms[i];
-        /* Note that we don't support a handshake hash with anything other than
-         * SHA-256, so asking for a signature from clients for something else
-         * would be inviting disaster. */
-        if (alg->hashAlg == allowedHashAlg) {
-            buf[(*len)++] = (PRUint8)alg->hashAlg;
-            buf[(*len)++] = (PRUint8)alg->sigAlg;
-        }
+        buf[(*len)++] = (PRUint8)alg->hashAlg;
+        buf[(*len)++] = (PRUint8)alg->sigAlg;
     }
 
     if (*len == 0) {
         PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
         return SECFailure;
     }
     return SECSuccess;
 }
@@ -9582,17 +9602,16 @@ ssl3_SendCertificateRequest(sslSocket *s
     int            length;
     int            i;
     int            calen	= 0;
     int            nnames	= 0;
     int            certTypesLength;
     PRUint8        sigAlgs[MAX_SIGNATURE_ALGORITHMS * 2];
     unsigned int   sigAlgsLength = 0;
     SECOidData *hashOid;
-    PRUint8        allowedHashAlg;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send certificate_request handshake",
 		SSL_GETPID(), ss->fd));
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
@@ -9615,27 +9634,19 @@ ssl3_SendCertificateRequest(sslSocket *s
     certTypes       = certificate_types;
     certTypesLength = sizeof certificate_types;
 
     hashOid = SECOID_FindOIDByMechanism(ssl3_GetPrfHashMechanism(ss));
     if (hashOid == NULL) {
 	return SECFailure; 		/* err set by AppendHandshake. */
     }
 
-    if (hashOid->offset == SEC_OID_SHA256) {
-        allowedHashAlg = ssl_hash_sha256;
-    } else if (hashOid->offset == SEC_OID_SHA384) {
-        allowedHashAlg = ssl_hash_sha384;
-    } else {
-	return SECFailure; 		/* err set by AppendHandshake. */
-    }
-
     length = 1 + certTypesLength + 2 + calen;
     if (isTLS12) {
-        rv = ssl3_EncodeCertificateRequestSigAlgs(ss, allowedHashAlg,
+        rv = ssl3_EncodeCertificateRequestSigAlgs(ss,
                                                   sigAlgs, sizeof(sigAlgs),
                                                   &sigAlgsLength);
         if (rv != SECSuccess) {
             return rv;
         }
         length += 2 + sigAlgsLength;
     }
 
@@ -9696,70 +9707,89 @@ ssl3_SendServerHelloDone(sslSocket *ss)
 static SECStatus
 ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
 			     SSL3Hashes *hashes)
 {
     SECItem              signed_hash = {siBuffer, NULL, 0};
     SECStatus            rv;
     int                  errCode     = SSL_ERROR_RX_MALFORMED_CERT_VERIFY;
     SSL3AlertDescription desc        = handshake_failure;
-    PRBool               isTLS, isTLS12;
+    PRBool               isTLS;
     SSLSignatureAndHashAlg sigAndHash;
+    SSL3Hashes localHashes;
+    SSL3Hashes *hashesForVerify = NULL;
 
     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) );
 
+    /* TLS 1.3 is handled by tls13_HandleCertificateVerify */
+    PORT_Assert(ss->ssl3.prSpec->version <= SSL_LIBRARY_VERSION_TLS_1_2);
+
     isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
-    isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
 
     if (ss->ssl3.hs.ws != wait_cert_verify) {
 	desc    = unexpected_message;
 	errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY;
 	goto alert_loser;
     }
 
-    if (!hashes) {
-        PORT_Assert(0);
-	desc    = internal_error;
-	errCode = SEC_ERROR_LIBRARY_FAILURE;
-	goto alert_loser;
-    }
-
-    if (isTLS12) {
+    if (ss->ssl3.hs.hashType != handshake_hash_record) {
+        if (!hashes) {
+            PORT_Assert(0);
+            desc = internal_error;
+            errCode = SEC_ERROR_LIBRARY_FAILURE;
+            goto alert_loser;
+        }
+        hashesForVerify = hashes;
+    } else {
 	rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
 						   &sigAndHash);
 	if (rv != SECSuccess) {
 	    goto loser;	/* malformed or unsupported. */
 	}
 	rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
             ss, &sigAndHash, ss->sec.peerCert);
 	if (rv != SECSuccess) {
 	    errCode = PORT_GetError();
 	    desc = decrypt_error;
 	    goto alert_loser;
 	}
 
-	/* We only support CertificateVerify messages that use the handshake
-	 * hash. */
-        if (sigAndHash.hashAlg != hashes->hashAlg) {
-	    errCode = SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM;
+#ifndef NO_PKCS11_BYPASS
+        if (ss->opt.bypassPKCS11) {
+            rv = ssl3_ComputeBypassHandshakeHash(hashes->u.pointer_to_hash_input.data,
+                                                 hashes->u.pointer_to_hash_input.len,
+                                                 sigAndHash.hashAlg,
+                                                 &localHashes);
+        } else
+#endif
+        {
+            rv = ssl3_ComputePkcs11HandshakeHash(hashes->u.pointer_to_hash_input.data,
+                                                 hashes->u.pointer_to_hash_input.len,
+                                                 sigAndHash.hashAlg,
+                                                 &localHashes);
+        }
+        if (rv == SECSuccess) {
+            hashesForVerify = &localHashes;
+        } else {
+            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. */
     }
 
     /* XXX verify that the key & kea match */
-    rv = ssl3_VerifySignedHashes(hashes, ss->sec.peerCert, &signed_hash,
+    rv = ssl3_VerifySignedHashes(hashesForVerify, ss->sec.peerCert, &signed_hash,
 				 isTLS, ss->pkcs11PinArg);
     if (rv != SECSuccess) {
     	errCode = PORT_GetError();
 	desc = isTLS ? decrypt_error : handshake_failure;
 	goto alert_loser;
     }
 
     signed_hash.data = NULL;
@@ -11638,34 +11668,63 @@ SECStatus
 ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     SECStatus         rv 	= SECSuccess;
     SSL3HandshakeType 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;
 
     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.
      */
     ssl_GetSpecReadLock(ss);	/************************************/
-    if(((type == finished) && (ss->ssl3.hs.ws == wait_finished)) ||
-       ((type == certificate_verify) && (ss->ssl3.hs.ws == wait_cert_verify))) {
-	SSL3Sender      sender = (SSL3Sender)0;
-	ssl3CipherSpec *rSpec  = ss->ssl3.prSpec;
-
-	if (type == finished) {
-	    sender = ss->sec.isServer ? sender_client : sender_server;
-	    rSpec  = ss->ssl3.crSpec;
-	}
-	rv = ssl3_ComputeHandshakeHashes(ss, rSpec, &hashes, sender);
+
+    if ((type == finished) && (ss->ssl3.hs.ws == wait_finished)) {
+        computeHashes = PR_TRUE;
+    } else if ((type == 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.pointer_to_hash_input
+             * to signal the current state of the buffer.
+             *
+             * ssl3_HandleCertificateVerify will detect
+             *     hashType == handshake_hash_record
+             * and use that information to calculate the hash.
+             */
+            hashes.u.pointer_to_hash_input.data = ss->ssl3.hs.messages.buf;
+            hashes.u.pointer_to_hash_input.len = ss->ssl3.hs.messages.len;
+            hashesPtr = &hashes;
+        } else {
+            computeHashes = PR_TRUE;
+        }
+    }
+    if (computeHashes) {
+        SSL3Sender      sender = (SSL3Sender)0;
+        ssl3CipherSpec *rSpec  = ss->ssl3.prSpec;
+
+        if (type == 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*/
     }
@@ -13080,20 +13139,17 @@ ssl3_DestroySSL3Info(sslSocket *ss)
     }
     if (ss->ssl3.hs.sha) {
 	PK11_DestroyContext(ss->ssl3.hs.sha,PR_TRUE);
     }
     if (ss->ssl3.hs.clientSigAndHash) {
 	PORT_Free(ss->ssl3.hs.clientSigAndHash);
     }
     if (ss->ssl3.hs.messages.buf) {
-    	PORT_Free(ss->ssl3.hs.messages.buf);
-	ss->ssl3.hs.messages.buf = NULL;
-	ss->ssl3.hs.messages.len = 0;
-	ss->ssl3.hs.messages.space = 0;
+        sslBuffer_Clear(&ss->ssl3.hs.messages);
     }
 
     /* free the SSL3Buffer (msg_body) */
     PORT_Free(ss->ssl3.hs.msg_body.buf);
 
     SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE);
 
     /* free up the CipherSpecs */
diff --git a/lib/ssl/ssl3prot.h b/lib/ssl/ssl3prot.h
--- a/lib/ssl/ssl3prot.h
+++ b/lib/ssl/ssl3prot.h
@@ -254,16 +254,17 @@ 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;
+        SECItem pointer_to_hash_input;
     } u;
 } SSL3Hashes;
 
 typedef struct {
     union {
         SSL3Opaque anonymous;
         SSL3Hashes certified;
     } u;
diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -847,17 +847,18 @@ typedef struct DTLSQueuedMessageStr {
     SSL3ContentType type; /* The message type */
     unsigned char *data;  /* The data */
     PRUint16 len;         /* The data length */
 } DTLSQueuedMessage;
 
 typedef enum {
     handshake_hash_unknown = 0,
     handshake_hash_combo = 1,  /* The MD5/SHA-1 combination */
-    handshake_hash_single = 2  /* A single hash */
+    handshake_hash_single = 2, /* A single hash */
+    handshake_hash_record
 } SSL3HandshakeHashType;
 
 /*
 ** This is the "hs" member of the "ssl3" struct.
 ** This entire struct is protected by ssl3HandshakeLock
 */
 typedef struct SSL3HandshakeStateStr {
     SSL3Random            server_random;
@@ -880,22 +881,19 @@ typedef struct SSL3HandshakeStateStr {
      * of the freebl <HASH>_Clone functions, so we need a dedicated function
      * pointer for the <HASH>_Clone function. */
     void (*sha_clone)(void *dest, void *src);
 #endif
     /* PKCS #11 mode:
      * SSL 3.0 - TLS 1.1 use both |md5| and |sha|. |md5| is used for MD5 and
      * |sha| for SHA-1.
      * TLS 1.2 and later use only |sha|, for SHA-256. */
-    /* NOTE: On the client side, TLS 1.2 and later use |md5| as a backup
-     * handshake hash for generating client auth signatures. Confusingly, the
-     * backup hash function is SHA-1. */
-#define backupHash md5
     PK11Context *         md5;
     PK11Context *         sha;
+    SSLHashType tls12CertVerifyHash;
 
 const ssl3KEADef *        kea_def;
     ssl3CipherSuite       cipher_suite;
 const ssl3CipherSuiteDef *suite_def;
     SSLCompressionMethod  compression;
     sslBuffer             msg_body;    /* protected by recvBufLock */
                                /* partial handshake message from record layer */
     unsigned int          header_bytes; 
@@ -1452,16 +1450,17 @@ extern SECStatus ssl_SaveWriteData(sslSo
                                    const void* p, unsigned int l);
 extern SECStatus ssl2_BeginClientHandshake(sslSocket *ss);
 extern SECStatus ssl2_BeginServerHandshake(sslSocket *ss);
 extern int       ssl_Do1stHandshake(sslSocket *ss);
 
 extern SECStatus sslBuffer_Grow(sslBuffer *b, unsigned int newLen);
 extern SECStatus sslBuffer_Append(sslBuffer *b, const void * data, 
 		                  unsigned int len);
+extern void sslBuffer_Clear(sslBuffer *b);
 
 extern void      ssl2_UseClearSendFunc(sslSocket *ss);
 extern void      ssl_ChooseSessionIDProcs(sslSecurityInfo *sec);
 
 extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
 extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, 
                                    const char *peerID, const char *urlSvrName);
 extern void      ssl_FreeSID(sslSessionID *sid);
diff --git a/lib/ssl/sslsecur.c b/lib/ssl/sslsecur.c
--- a/lib/ssl/sslsecur.c
+++ b/lib/ssl/sslsecur.c
@@ -528,16 +528,27 @@ sslBuffer_Append(sslBuffer *b, const voi
     rv = sslBuffer_Grow(b, newLen);
     if (rv != SECSuccess)
     	return rv;
     PORT_Memcpy(b->buf + b->len, data, len);
     b->len += len;
     return SECSuccess;
 }
 
+void
+sslBuffer_Clear(sslBuffer *b)
+{
+    if (b->len > 0) {
+        PORT_Free(b->buf);
+        b->buf = NULL;
+        b->len = 0;
+        b->space = 0;
+    }
+}
+
 /*
 ** Save away write data that is trying to be written before the security
 ** handshake has been completed. When the handshake is completed, we will
 ** flush this data out.
 ** Caller must hold xmitBufLock
 */
 SECStatus 
 ssl_SaveWriteData(sslSocket *ss, const void *data, unsigned int len)