diff --git a/SOURCES/call-restartmodules-in-nssinit.patch b/SOURCES/call-restartmodules-in-nssinit.patch
new file mode 100644
index 0000000..6a72aa8
--- /dev/null
+++ b/SOURCES/call-restartmodules-in-nssinit.patch
@@ -0,0 +1,35 @@
+diff --git a/lib/nss/nssinit.c b/lib/nss/nssinit.c
+--- a/lib/nss/nssinit.c
++++ b/lib/nss/nssinit.c
+@@ -621,16 +621,31 @@ nss_Init(const char *configdir, const ch
+ 		initParams->minPWLen);
+ 	    if (configStrings == NULL) {
+ 		PORT_SetError(SEC_ERROR_NO_MEMORY);
+ 		goto loser;
+ 	    }
+ 	    configName = initParams->libraryDescription;
+ 	    passwordRequired = initParams->passwordRequired;
+ 	}
++
++	/* If we're NSS_ContextInit, we're probably a library. It could be
++	 * possible that the application initialized NSS then forked(). The
++	 * library would have no knowledge of that. If we call 
++	 * SECMOD_RestartModules() here, we will be able to continue on with
++	 * NSS as normal. SECMOD_RestartModules() does have the side affect
++	 * of losing all our PKCS #11 objects in the new process, but only if
++	 * the module needs to be reinited. If it needs to be reinit those
++	 * objects are inaccessible anyway, it it's always save to call
++	 * SECMOD_RestartModules(PR_FALSE).
++	 */
++	/* NOTE: We could call SECMOD_Init() here, but if we aren't already
++	 * inited, then there's no modules to restart, so SECMOD_RestartModules
++	 * will return immediately */
++	SECMOD_RestartModules(PR_FALSE);
+     } else {
+ 	configStrings = pk11_config_strings;
+ 	configName = pk11_config_name;
+ 	passwordRequired = pk11_password_required;
+     }
+ 
+     /* Skip the module init if we are already initted and we are trying
+      * to init with noCertDB and noModDB */
diff --git a/SOURCES/disable-ems-gtests.patch b/SOURCES/disable-ems-gtests.patch
new file mode 100644
index 0000000..62ebf74
--- /dev/null
+++ b/SOURCES/disable-ems-gtests.patch
@@ -0,0 +1,195 @@
+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
+@@ -516,134 +516,16 @@ TEST_P(TlsConnectStream, ShortRead) {
+   // Read the first tranche.
+   WAIT_(client_->received_bytes() == 1024, 2000);
+   ASSERT_EQ(1024U, client_->received_bytes());
+   // The second tranche should now immediately be available.
+   client_->ReadBytes();
+   ASSERT_EQ(1200U, client_->received_bytes());
+ }
+ 
+-TEST_P(TlsConnectGeneric, ConnectExtendedMasterSecret) {
+-  EnableExtendedMasterSecret();
+-  Connect();
+-  ResetRsa();
+-  ExpectResumption(RESUME_SESSIONID);
+-  EnableExtendedMasterSecret();
+-  Connect();
+-}
+-
+-
+-TEST_P(TlsConnectGeneric, ConnectExtendedMasterSecretStaticRSA) {
+-  DisableDheAndEcdheCiphers();
+-  EnableExtendedMasterSecret();
+-  Connect();
+-}
+-
+-// This test is stream so we can catch the bad_record_mac alert.
+-TEST_P(TlsConnectStream, ConnectExtendedMasterSecretStaticRSABogusCKE) {
+-  DisableDheAndEcdheCiphers();
+-  EnableExtendedMasterSecret();
+-  TlsInspectorReplaceHandshakeMessage* inspect =
+-      new TlsInspectorReplaceHandshakeMessage(kTlsHandshakeClientKeyExchange,
+-                                              DataBuffer(
+-                                                  kBogusClientKeyExchange,
+-                                                  sizeof(kBogusClientKeyExchange)));
+-  client_->SetPacketFilter(inspect);
+-  auto alert_recorder = new TlsAlertRecorder();
+-  server_->SetPacketFilter(alert_recorder);
+-  ConnectExpectFail();
+-  EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+-  EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
+-}
+-
+-// This test is stream so we can catch the bad_record_mac alert.
+-TEST_P(TlsConnectStream, ConnectExtendedMasterSecretStaticRSABogusPMSVersionDetect) {
+-  DisableDheAndEcdheCiphers();
+-  EnableExtendedMasterSecret();
+-  client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(
+-      server_));
+-  auto alert_recorder = new TlsAlertRecorder();
+-  server_->SetPacketFilter(alert_recorder);
+-  ConnectExpectFail();
+-  EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+-  EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
+-}
+-
+-TEST_P(TlsConnectStream, ConnectExtendedMasterSecretStaticRSABogusPMSVersionIgnore) {
+-  DisableDheAndEcdheCiphers();
+-  EnableExtendedMasterSecret();
+-  client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(
+-      server_));
+-  server_->DisableRollbackDetection();
+-  Connect();
+-}
+-
+-TEST_P(TlsConnectGeneric, ConnectExtendedMasterSecretECDHE) {
+-  EnableExtendedMasterSecret();
+-  Connect();
+-
+-  ResetRsa();
+-  EnableExtendedMasterSecret();
+-  ExpectResumption(RESUME_SESSIONID);
+-  Connect();
+-}
+-
+-TEST_P(TlsConnectGeneric, ConnectExtendedMasterSecretTicket) {
+-  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+-  EnableExtendedMasterSecret();
+-  Connect();
+-
+-  ResetRsa();
+-  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+-
+-  EnableExtendedMasterSecret();
+-  ExpectResumption(RESUME_TICKET);
+-  Connect();
+-}
+-
+-TEST_P(TlsConnectGeneric,
+-       ConnectExtendedMasterSecretClientOnly) {
+-  client_->EnableExtendedMasterSecret();
+-  ExpectExtendedMasterSecret(false);
+-  Connect();
+-}
+-
+-TEST_P(TlsConnectGeneric,
+-       ConnectExtendedMasterSecretServerOnly) {
+-  server_->EnableExtendedMasterSecret();
+-  ExpectExtendedMasterSecret(false);
+-  Connect();
+-}
+-
+-TEST_P(TlsConnectGeneric,
+-       ConnectExtendedMasterSecretResumeWithout) {
+-  EnableExtendedMasterSecret();
+-  Connect();
+-
+-  ResetRsa();
+-  server_->EnableExtendedMasterSecret();
+-  auto alert_recorder = new TlsAlertRecorder();
+-  server_->SetPacketFilter(alert_recorder);
+-  ConnectExpectFail();
+-  EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+-  EXPECT_EQ(kTlsAlertHandshakeFailure, alert_recorder->description());
+-}
+-
+-TEST_P(TlsConnectGeneric,
+-       ConnectNormalResumeWithExtendedMasterSecret) {
+-  ConfigureSessionCache(RESUME_SESSIONID, RESUME_SESSIONID);
+-  ExpectExtendedMasterSecret(false);
+-  Connect();
+-
+-  ResetRsa();
+-  EnableExtendedMasterSecret();
+-  ExpectResumption(RESUME_NONE);
+-  Connect();
+-}
+-
+ INSTANTIATE_TEST_CASE_P(VariantsStream10, TlsConnectGeneric,
+                         ::testing::Combine(
+                           TlsConnectTestBase::kTlsModesStream,
+                           TlsConnectTestBase::kTlsV10));
+ INSTANTIATE_TEST_CASE_P(VariantsAll, TlsConnectGeneric,
+                         ::testing::Combine(
+                           TlsConnectTestBase::kTlsModesAll,
+                           TlsConnectTestBase::kTlsV11V12));
+diff --git a/external_tests/ssl_gtest/ssl_prf_unittest.cc b/external_tests/ssl_gtest/ssl_prf_unittest.cc
+--- a/external_tests/ssl_gtest/ssl_prf_unittest.cc
++++ b/external_tests/ssl_gtest/ssl_prf_unittest.cc
+@@ -201,53 +201,9 @@ TEST_F(TlsPrfTest, ExtendedMsParamErr) {
+   CheckForError(CKM_TLS_PRF, kPrfSeedSizeTlsPrf, kIncorrectSize, 0);
+ 
+   // CKM_TLS_PRF && seed length != MD5_LENGTH + SHA1_LENGTH
+   CheckForError(CKM_TLS_PRF, kIncorrectSize, kPmsSize, 0);
+ 
+   // !CKM_TLS_PRF && seed length != hash output length
+   CheckForError(CKM_SHA256, kIncorrectSize, kPmsSize, 0);
+ }
+-
+-// Test matrix:
+-//
+-//            DH  RSA
+-//  TLS_PRF   1   2
+-//  SHA256    3   4
+-TEST_F(TlsPrfTest, ExtendedMsDhTlsPrf) {
+-  Init();
+-  ComputeAndVerifyMs(CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH,
+-                     CKM_TLS_PRF,
+-                     nullptr,
+-                     kExpectedOutputEmsTlsPrf);
+-}
+-
+-TEST_F(TlsPrfTest, ExtendedMsRsaTlsPrf) {
+-  Init();
+-  ComputeAndVerifyMs(CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE,
+-                     CKM_TLS_PRF,
+-                     &pms_version_,
+-                     kExpectedOutputEmsTlsPrf);
+-  EXPECT_EQ(0, pms_version_.major);
+-  EXPECT_EQ(1, pms_version_.minor);
+-}
+-
+-
+-TEST_F(TlsPrfTest, ExtendedMsDhSha256) {
+-  Init();
+-  ComputeAndVerifyMs(CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH,
+-                     CKM_SHA256,
+-                     nullptr,
+-                     kExpectedOutputEmsSha256);
+-}
+-
+-TEST_F(TlsPrfTest, ExtendedMsRsaSha256) {
+-  Init();
+-  ComputeAndVerifyMs(CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE,
+-                     CKM_SHA256,
+-                     &pms_version_,
+-                     kExpectedOutputEmsSha256);
+-  EXPECT_EQ(0, pms_version_.major);
+-  EXPECT_EQ(1, pms_version_.minor);
+-}
+-
+ }  // namespace nss_test
+-
diff --git a/SOURCES/fix-reuse-of-session-cache-entry.patch b/SOURCES/fix-reuse-of-session-cache-entry.patch
new file mode 100644
index 0000000..7262fee
--- /dev/null
+++ b/SOURCES/fix-reuse-of-session-cache-entry.patch
@@ -0,0 +1,24 @@
+diff --git a/lib/ssl/sslnonce.c b/lib/ssl/sslnonce.c
+--- a/lib/ssl/sslnonce.c
++++ b/lib/ssl/sslnonce.c
+@@ -279,19 +279,17 @@ ssl_LookupSID(const PRIPv6Addr *addr, PR
+ 		   (((peerID == NULL) && (sid->peerID == NULL)) ||
+ 		    ((peerID != NULL) && (sid->peerID != NULL) &&
+ 		     PORT_Strcmp(sid->peerID, peerID) == 0)) &&
+ 		   /* is cacheable */
+ 		   (sid->version < SSL_LIBRARY_VERSION_3_0 ||
+ 		    sid->u.ssl3.keys.resumable) &&
+ 		   /* server hostname matches. */
+ 	           (sid->urlSvrName != NULL) &&
+-		   ((0 == PORT_Strcmp(urlSvrName, sid->urlSvrName)) ||
+-		    ((sid->peerCert != NULL) && (SECSuccess == 
+-		      CERT_VerifyCertName(sid->peerCert, urlSvrName))) )
++		   (0 == PORT_Strcmp(urlSvrName, sid->urlSvrName))
+ 		  ) {
+ 	    /* Hit */
+ 	    sid->lastAccessTime = now;
+ 	    sid->references++;
+ 	    break;
+ 	} else {
+ 	    sidp = &sid->next;
+ 	}
diff --git a/SOURCES/flexible-certverify.patch b/SOURCES/flexible-certverify.patch
new file mode 100644
index 0000000..481a07f
--- /dev/null
+++ b/SOURCES/flexible-certverify.patch
@@ -0,0 +1,1136 @@
+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)
diff --git a/SOURCES/nss-ssl-delete-duplicates.patch b/SOURCES/nss-ssl-delete-duplicates.patch
new file mode 100644
index 0000000..cd92b25
--- /dev/null
+++ b/SOURCES/nss-ssl-delete-duplicates.patch
@@ -0,0 +1,63 @@
+diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c
+--- a/lib/ssl/ssl3con.c
++++ b/lib/ssl/ssl3con.c
+@@ -426,36 +426,30 @@ static const ssl3CipherSuiteDef cipher_s
+                                     cipher_rc4_56, mac_sha,kea_rsa_export_1024, 0},
+ 
+     {SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa_fips, 0},
+     {SSL_RSA_FIPS_WITH_DES_CBC_SHA, cipher_des,    mac_sha, kea_rsa_fips, 0},
+ 
+     {TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_rsa, prf_256},
+     {TLS_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_rsa, prf_256},
+ #ifndef NSS_DISABLE_ECC
+-    {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_rsa},
+-    {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_ecdsa},
+     {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_rsa, prf_256},
+     {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_ecdsa, prf_256},
+     {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_ecdhe_ecdsa, prf_384},
+     {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_ecdhe_rsa, prf_384},
+     {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, cipher_aes_256, hmac_sha384, kea_ecdhe_ecdsa, prf_384},
+     {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, cipher_aes_256, hmac_sha384, kea_ecdhe_rsa, prf_384},
+ #endif /* NSS_DISABLE_ECC */
+     {TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_dhe_rsa, prf_384},
+     {TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_dss, prf_256},
+     {TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_dhe_dss, prf_384},
+     {TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_dss, prf_256},
+     {TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_dss, prf_256},
+     {TLS_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_rsa, prf_384},
+ 
+-    {TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_dss, 0},
+-    {TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_dss, 0},
+-    {TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_dss, 0},
+-
+ #ifndef NSS_DISABLE_ECC
+     {TLS_ECDH_ECDSA_WITH_NULL_SHA,        cipher_null, mac_sha, kea_ecdh_ecdsa, 0},
+     {TLS_ECDH_ECDSA_WITH_RC4_128_SHA,      cipher_rc4, mac_sha, kea_ecdh_ecdsa, 0},
+     {TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_ecdsa, 0},
+     {TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_ecdsa, 0},
+     {TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_ecdsa, 0},
+ 
+     {TLS_ECDHE_ECDSA_WITH_NULL_SHA,        cipher_null, mac_sha, kea_ecdhe_ecdsa, 0},
+diff --git a/lib/ssl/sslinfo.c b/lib/ssl/sslinfo.c
+--- a/lib/ssl/sslinfo.c
++++ b/lib/ssl/sslinfo.c
+@@ -248,19 +248,16 @@ static const SSLCipherSuiteInfo suiteInf
+ {0,CS(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384),    S_RSA,   K_ECDHE, C_AESGCM, B_256, M_AEAD_128, 1, 0, 0, },
+ {0,CS(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384),  S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA384, 1, 0, 0, },
+ {0,CS(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384),    S_RSA,   K_ECDHE, C_AES, B_256, M_SHA384, 1, 0, 0, },
+ 
+ #endif /* NSS_DISABLE_ECC */
+ 
+ {0,CS(TLS_DHE_DSS_WITH_AES_256_GCM_SHA384), S_DSA, K_DHE, C_AESGCM, B_256, M_AEAD_128, 1, 0, 0, },
+ {0,CS(TLS_DHE_RSA_WITH_AES_256_GCM_SHA384), S_RSA, K_DHE, C_AESGCM, B_256, M_AEAD_128, 1, 0, 0, },
+-{0,CS(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256), S_DSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0, },
+-{0,CS(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256), S_DSA, K_DHE, C_AES, B_128, M_SHA256, 1, 0, 0, },
+-{0,CS(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256), S_DSA, K_DHE, C_AES, B_256, M_SHA256, 1, 0, 0, },
+ {0,CS(TLS_RSA_WITH_AES_256_GCM_SHA384),     S_RSA, K_RSA, C_AESGCM, B_256, M_AEAD_128, 1, 0, 0, },
+ 
+ /* SSL 2 table */
+ {0,CK(SSL_CK_RC4_128_WITH_MD5),               S_RSA, K_RSA, C_RC4, B_128, M_MD5, 0, 0, 0, },
+ {0,CK(SSL_CK_RC2_128_CBC_WITH_MD5),           S_RSA, K_RSA, C_RC2, B_128, M_MD5, 0, 0, 0, },
+ {0,CK(SSL_CK_DES_192_EDE3_CBC_WITH_MD5),      S_RSA, K_RSA, C_3DES,B_3DES,M_MD5, 0, 0, 0, },
+ {0,CK(SSL_CK_DES_64_CBC_WITH_MD5),            S_RSA, K_RSA, C_DES, B_DES, M_MD5, 0, 0, 0, },
+ {0,CK(SSL_CK_RC4_128_EXPORT40_WITH_MD5),      S_RSA, K_RSA, C_RC4, B_40,  M_MD5, 0, 1, 0, },
diff --git a/SOURCES/nss-ssl-ssl3con-delete-duplicates.patch b/SOURCES/nss-ssl-ssl3con-delete-duplicates.patch
deleted file mode 100644
index fc0b697..0000000
--- a/SOURCES/nss-ssl-ssl3con-delete-duplicates.patch
+++ /dev/null
@@ -1,21 +0,0 @@
---- ./nss/lib/ssl/ssl3con.c.delete_duplicates	2016-04-04 10:13:34.310883577 -0700
-+++ ./nss/lib/ssl/ssl3con.c	2016-04-04 10:18:32.544936462 -0700
-@@ -426,18 +426,16 @@
-                                     cipher_rc4_56, mac_sha,kea_rsa_export_1024, 0},
- 
-     {SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa_fips, 0},
-     {SSL_RSA_FIPS_WITH_DES_CBC_SHA, cipher_des,    mac_sha, kea_rsa_fips, 0},
- 
-     {TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_rsa, prf_256},
-     {TLS_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_rsa, prf_256},
- #ifndef NSS_DISABLE_ECC
--    {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_rsa},
--    {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_ecdsa},
-     {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_rsa, prf_256},
-     {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_ecdsa, prf_256},
-     {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_ecdhe_ecdsa, prf_384},
-     {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_ecdhe_rsa, prf_384},
-     {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, cipher_aes_256, hmac_sha384, kea_ecdhe_ecdsa, prf_384},
-     {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, cipher_aes_256, hmac_sha384, kea_ecdhe_rsa, prf_384},
- #endif /* NSS_DISABLE_ECC */
-     {TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_dhe_rsa, prf_384},
diff --git a/SPECS/nss.spec b/SPECS/nss.spec
index 649cf0a..21ea02d 100644
--- a/SPECS/nss.spec
+++ b/SPECS/nss.spec
@@ -27,7 +27,7 @@
 Summary:          Network Security Services
 Name:             nss
 Version:          3.21.0
-Release:          9%{?dist}
+Release:          17%{?dist}
 License:          MPLv2.0
 URL:              http://www.mozilla.org/projects/security/pki/nss/
 Group:            System Environment/Libraries
@@ -154,7 +154,13 @@ Patch115: nss-prevent-abi-issue.patch
 Patch116: nss-tests-prevent-abi-issue.patch
 Patch117: fix-nss-test-filtering.patch
 Patch118: fix-allowed-sig-alg.patch
-Patch119: nss-ssl-ssl3con-delete-duplicates.patch
+Patch119: nss-ssl-delete-duplicates.patch
+Patch120: fix-reuse-of-session-cache-entry.patch
+Patch121: flexible-certverify.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1298692
+Patch122: disable-ems-gtests.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=1317691
+Patch123: call-restartmodules-in-nssinit.patch
 
 %description
 Network Security Services (NSS) is a set of libraries designed to
@@ -277,8 +283,12 @@ popd
 %patch110 -p0 -b .no_ssl2
 pushd nss
 %patch118 -p1 -b .allowed-sig-alg
+%patch119 -p1 -b .delete_duplicates
+%patch120 -p1 -b .session_cache
+%patch121 -p1 -b .flexible_certverify
+%patch122 -p1 -b .disable_ems_gtests
+%patch123 -p1 -b .restartmodules_in_init
 popd
-%patch119 -p0 -b .delete_duplicates
 
 #########################################################
 # Higher-level libraries and test tools need access to
@@ -543,7 +553,7 @@ pushd ./nss/tests/
 
 #  don't need to run all the tests when testing packaging
 #  nss_cycles: standard pkix upgradedb sharedb
-%global nss_tests "libpkix cert dbtests tools fips sdr crmf smime ssl ocsp merge pkits chains"
+%global nss_tests "libpkix cert dbtests tools fips sdr crmf smime ssl ocsp merge pkits chains ssl_gtests"
 #  nss_ssl_tests: crl bypass_normal normal_bypass normal_fips fips_normal iopr
 #  nss_ssl_run: cov auth stress
 #
@@ -572,8 +582,11 @@ TEST_FAILURES=$(grep -c FAILED ./tests_results/security/localhost.1/output.log) 
 if [ ${GREP_EXIT_STATUS:-0} -eq 1 ]; then
   echo "okay: test suite detected no failures"
 else
-# test suite is failing on arm and has for a while let's run the test suite but make it non fatal on arm
-%ifnarch %{arm}
+  %ifarch %{arm}
+    :
+    # do nothing on arm where the test suite is failing and has been
+    # for while, do run the test suite but make it non fatal on arm
+  %else
   if [ ${GREP_EXIT_STATUS:-0} -eq 0 ]; then
     # while a situation in which grep return status is 0 and it doesn't output
     # anything shouldn't happen, set the default to something that is
@@ -723,24 +736,6 @@ else
 fi
 /sbin/ldconfig
 
-%posttrans
-# An earlier version of this package had an incorrect %%postun script (3.14.3-9).
-# (The incorrect %%postun always called "update-alternatives --remove",
-# because it incorrectly assumed that test -f returns false for symbolic links.)
-# The only possible remedy to fix the mistake that "always removes on upgrade"
-# made by the older %%postun script, is to repair it in %%posttrans of the new package.
-# Strategy:
-# %%posttrans is never called when uninstalling.
-# %%posttrans is only called when installing or upgrading a package.
-# Because %%posttrans is the very last action of a package install,
-# %%{_libdir}/libnssckbi.so must exist.
-# If it does not, it's the result of the incorrect removal from a broken %%postun.
-# In this case, we repeat installation of the alternatives link.
-if ! test -e %{_libdir}/libnssckbi.so; then
-  %{_sbindir}/update-alternatives --install %{_libdir}/libnssckbi.so \
-    %{alt_ckbi} %{_libdir}/nss/libnssckbi.so 10
-fi
-
 
 %files
 %defattr(-,root,root)
@@ -885,6 +880,37 @@ fi
 
 
 %changelog
+* Thu Jun 30 2016 Kai Engert <kaie@redhat.com> - 3.21.0-17
+- remove additional false duplicates from sha384 downstream patches
+
+* Tue Jun 28 2016 Kai Engert <kaie@redhat.com> - 3.21.0-16
+- enable ssl_gtests (without extended master secret tests), Bug 1298692
+- call SECMOD_RestartModules in nss_Init, Bug 1317691
+
+* Fri Jun 17 2016 Kai Engert <kaie@redhat.com> - 3.21.0-15
+- escape all percent characters in all changelog comments
+
+* Fri Jun 17 2016 Kai Engert <kaie@redhat.com> - 3.21.0-14
+- Support TLS 1.2 certificate_verify hashes other than PRF,
+  backported fix from NSS 3.25 (upstream bug 1179338).
+
+* Mon May 23 2016 Elio Maldonado <emaldona@redhat.com> - 3.21.0-13
+- Fix reuse of session cache entry
+- Resolves: Bug 1241172 - Certificate verification fails with multiple https urls
+
+* Wed Apr 20 2016 Elio Maldonado <emaldona@redhat.com> - 3.21.0-12
+- Fix a flaw in %%check for nss not building on arm
+- Resolves: Bug 1200856
+
+* Wed Apr 20 2016 Elio Maldonado <emaldona@redhat.com> - 3.21.0-11
+- Cleanup: Remove unnecessary %%posttrans script from nss.spec
+- Resolves: Bug 1174201
+
+* Wed Apr 20 2016 Elio Maldonado <emaldona@redhat.com> - 3.21.0-10
+- Merge fixes from the rhel-7.2 branch
+- Fix a bogus %%changelog entry
+- Resolves: Bug 1297941
+
 * Fri Apr 15 2016 Kai Engert <kaie@redhat.com> - 3.21.0-9
 - Rebuild to require the latest nss-util build and nss-softokn build.
 
@@ -898,22 +924,22 @@ fi
 - Fix missing support for sha384/dsa in certificate_request
 
 * Wed Mar 23 2016 Kai Engert <kaie@redhat.com> - 3.21.0-5
+- Merge fixes from the rhel-7.2 branch
 - Fix the SigAlgs sent in certificate_request
-
-* Tue Mar 22 2016 Elio Maldonado <emaldona@redhat.com> - 3.21.0-4
 - Ensure all ssl.sh tests are executed
 - Update sslauth test patch to run additional tests
 
-* Thu Feb 25 2016 Elio Maldonado <emaldona@redhat.com> - 3.21.0-2
+* Fri Feb 26 2016 Elio Maldonado <emaldona@redhat.com> - 3.21.0-2
 - Fix sha384 support and testing patches
 
-* Mon Feb 22 2016 Elio Maldonado <emaldona@redhat.com> - 3.21.0-1
+* Wed Feb 17 2016 Elio Maldonado <emaldona@redhat.com> - 3.21.0-1
 - Rebase to NSS-3.21
-- Resolves: Bug 1310581
 
 * Tue Dec 15 2015 Elio Maldonado <emaldona@redhat.com> - 3.19.1-19
 - Prevent TLS 1.2 Transcript Collision attacks against MD5 in key exchange protocol
-- Resolves: Bug 1289883
+- Fix a mockbuild reported bad %%if condition when using the __isa_bits macro instead of list of 64-bit architectures
+- Change the test to %%if 0%%{__isa_bits} == 64 as required for building the srpm which is noarch
+- Resolves: Bug 1289884
 
 * Wed Oct 21 2015 Kai Engert <kaie@redhat.com> - 3.19.1-18
 - Rebuild against updated NSPR
@@ -1531,7 +1557,7 @@ fi
 - Move triggerpostun -n nss-sysinit script ahead of the other ones (#639248)
 
 * Tue Oct 05 2010 Elio Maldonado <emaldona@redhat.com> - 3.12.8-4
-- Fix invalid %postun scriptlet (#639248)
+- Fix invalid %%postun scriptlet (#639248)
 
 * Wed Sep 29 2010 Elio Maldonado <emaldona@redhat.com> - 3.12.8-3
 - Replace posttrans sysinit scriptlet with a triggerpostun one (#636787)