Bug 1539227 - land NSS 56826bedabba UPGRADE_NSS_RELEASE, r=KevinJacobs
authorJ.C. Jones <jc@mozilla.com>
Tue, 30 Apr 2019 18:22:11 +0000
changeset 530848 3c032a4347fa713fbb0565ca78fd3038c5edd95a
parent 530847 96a1f7afe8ae7bef2ab0b9968d940987616d639f
child 530849 54d6029f69a58769752692246ae768701580defb
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersKevinJacobs
bugs1539227
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1539227 - land NSS 56826bedabba UPGRADE_NSS_RELEASE, r=KevinJacobs NSS uplift, 30 April 2019. Commit log: https://hg.mozilla.org/projects/nss/log?rev=e5e10a46b9ad..56826bedabba Differential Revision: https://phabricator.services.mozilla.com/D29382
security/nss/TAG-INFO
security/nss/automation/taskcluster/graph/src/try_syntax.js
security/nss/cmd/certutil/certutil.c
security/nss/cmd/selfserv/selfserv.c
security/nss/cmd/tstclnt/tstclnt.c
security/nss/coreconf/coreconf.dep
security/nss/cpputil/tls_parser.h
security/nss/gtests/pk11_gtest/pk11_chacha20poly1305_unittest.cc
security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
security/nss/lib/freebl/blapi.h
security/nss/lib/freebl/chacha20poly1305.c
security/nss/lib/freebl/crypto_primitives.c
security/nss/lib/freebl/crypto_primitives.h
security/nss/lib/freebl/ldvector.c
security/nss/lib/freebl/loader.c
security/nss/lib/freebl/loader.h
security/nss/lib/pk11wrap/pk11mech.c
security/nss/lib/softoken/pkcs11.c
security/nss/lib/softoken/pkcs11c.c
security/nss/lib/softoken/pkcs11i.h
security/nss/lib/softoken/sdb.c
security/nss/lib/ssl/SSLerrs.h
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3prot.h
security/nss/lib/ssl/sslencode.c
security/nss/lib/ssl/sslerr.h
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslsecur.c
security/nss/lib/ssl/tls13con.c
security/nss/lib/ssl/tls13con.h
security/nss/lib/ssl/tls13hashstate.c
security/nss/lib/util/pkcs11n.h
security/nss/tests/ssl/ssl.sh
security/nss/tests/ssl/sslauth.txt
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-e5e10a46b9ad
+56826bedabba
--- a/security/nss/automation/taskcluster/graph/src/try_syntax.js
+++ b/security/nss/automation/taskcluster/graph/src/try_syntax.js
@@ -162,15 +162,15 @@ async function getCommitComment() {
   const res = await execFile('hg', ['log', '-r', '.', '-T', '{desc}']);
   return res.stdout;
 };
 
 export async function initFilter() {
   let comment = await getCommitComment();
 
   // Check for try syntax in changeset comment.
-  let match = comment.match(/^\s*try:\s*(.*)\s*$/);
+  let match = comment.match(/\btry:\s*(.*)\s*$/m);
 
   // Add try syntax filter.
   if (match) {
     queue.filter(filter(parseOptions(match[1])));
   }
 }
--- a/security/nss/cmd/certutil/certutil.c
+++ b/security/nss/cmd/certutil/certutil.c
@@ -3115,17 +3115,17 @@ certutil_main(int argc, char **argv, PRB
     }
 
     /* Delete needs a nickname or a key ID */
     if (certutil.commands[cmd_DeleteKey].activated &&
         !(certutil.options[opt_Nickname].activated || keysource)) {
         PR_fprintf(PR_STDERR,
                    "%s -%c: specify a nickname (-n) or\n"
                    "   a key ID (-k).\n",
-                   commandToRun, progName);
+                   progName, commandToRun);
         return 255;
     }
 
     /* Upgrade/Merge needs a source database and a upgrade id. */
     if (certutil.commands[cmd_UpgradeMerge].activated &&
         !(certutil.options[opt_SourceDir].activated &&
           certutil.options[opt_UpgradeID].activated)) {
 
--- a/security/nss/cmd/selfserv/selfserv.c
+++ b/security/nss/cmd/selfserv/selfserv.c
@@ -228,17 +228,19 @@ PrintParameterUsage()
         "   P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n"
         "-J comma separated list of enabled signature schemes in preference order.\n"
         "   The following values are valid:\n"
         "     rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n"
         "     ecdsa_sha1, ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,\n"
         "     ecdsa_secp521r1_sha512,\n"
         "     rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512,\n"
         "     rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512,\n"
-        "-Z enable 0-RTT (for TLS 1.3; also use -u)\n",
+        "-Z enable 0-RTT (for TLS 1.3; also use -u)\n"
+        "-E enable post-handshake authentication\n"
+        "   (for TLS 1.3; only has an effect with 3 or more -r options)\n",
         stderr);
 }
 
 static void
 Usage(const char *progName)
 {
     PrintUsageHeader(progName);
     PrintParameterUsage();
@@ -799,16 +801,17 @@ PRBool disableRollBack = PR_FALSE;
 PRBool NoReuse = PR_FALSE;
 PRBool hasSidCache = PR_FALSE;
 PRBool disableLocking = PR_FALSE;
 PRBool enableSessionTickets = PR_FALSE;
 PRBool failedToNegotiateName = PR_FALSE;
 PRBool enableExtendedMasterSecret = PR_FALSE;
 PRBool zeroRTT = PR_FALSE;
 PRBool enableALPN = PR_FALSE;
+PRBool enablePostHandshakeAuth = PR_FALSE;
 SSLNamedGroup *enabledGroups = NULL;
 unsigned int enabledGroupsCount = 0;
 const SSLSignatureScheme *enabledSigSchemes = NULL;
 unsigned int enabledSigSchemeCount = 0;
 
 static char *virtServerNameArray[MAX_VIRT_SERVER_NAME_ARRAY_INDEX];
 static int virtServerNameIndex = 1;
 
@@ -1426,25 +1429,38 @@ handle_connection(PRFileDesc *tcp_sock, 
                         break;
                     }
                     rv = SSL_OptionSet(ssl_sock, SSL_REQUIRE_CERTIFICATE,
                                        (requestCert == 4));
                     if (rv < 0) {
                         errWarn("second SSL_OptionSet SSL_REQUIRE_CERTIFICATE");
                         break;
                     }
-                    rv = SSL_ReHandshake(ssl_sock, PR_TRUE);
-                    if (rv != 0) {
-                        errWarn("SSL_ReHandshake");
-                        break;
-                    }
-                    rv = SSL_ForceHandshake(ssl_sock);
-                    if (rv < 0) {
-                        errWarn("SSL_ForceHandshake");
-                        break;
+                    if (enablePostHandshakeAuth) {
+                        rv = SSL_SendCertificateRequest(ssl_sock);
+                        if (rv != SECSuccess) {
+                            errWarn("SSL_SendCertificateRequest");
+                            break;
+                        }
+                        rv = SSL_ForceHandshake(ssl_sock);
+                        if (rv != SECSuccess) {
+                            errWarn("SSL_ForceHandshake");
+                            break;
+                        }
+                    } else {
+                        rv = SSL_ReHandshake(ssl_sock, PR_TRUE);
+                        if (rv != 0) {
+                            errWarn("SSL_ReHandshake");
+                            break;
+                        }
+                        rv = SSL_ForceHandshake(ssl_sock);
+                        if (rv < 0) {
+                            errWarn("SSL_ForceHandshake");
+                            break;
+                        }
                     }
                 }
             }
 
             numIOVs = 0;
 
             iovs[numIOVs].iov_base = (char *)outHeader;
             iovs[numIOVs].iov_len = (sizeof(outHeader)) - 1;
@@ -1943,16 +1959,26 @@ server_main(
             errExit("error configuring anti-replay ");
         }
         rv = SSL_OptionSet(model_sock, SSL_ENABLE_0RTT_DATA, PR_TRUE);
         if (rv != SECSuccess) {
             errExit("error enabling 0RTT ");
         }
     }
 
+    if (enablePostHandshakeAuth) {
+        if (enabledVersions.max < SSL_LIBRARY_VERSION_TLS_1_3) {
+            errExit("You tried enabling post-handshake auth without enabling TLS 1.3!");
+        }
+        rv = SSL_OptionSet(model_sock, SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE);
+        if (rv != SECSuccess) {
+            errExit("error enabling post-handshake auth");
+        }
+    }
+
     if (enableALPN) {
         PRUint8 alpnVal[] = { 0x08,
                               0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31 };
         rv = SSL_OptionSet(model_sock, SSL_ENABLE_ALPN, PR_TRUE);
         if (rv != SECSuccess) {
             errExit("error enabling ALPN");
         }
 
@@ -2218,17 +2244,17 @@ main(int argc, char **argv)
     SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
 
     /* please keep this list of options in ASCII collating sequence.
     ** numbers, then capital letters, then lower case, alphabetical.
     ** XXX: 'B', 'E', 'q', and 'x' were used in the past but removed
     **      in 3.28, please leave some time before resuing those.
     **      'z' was removed in 3.39. */
     optstate = PL_CreateOptState(argc, argv,
-                                 "2:A:C:DGH:I:J:L:M:NP:QRS:T:U:V:W:YZa:bc:d:e:f:g:hi:jk:lmn:op:rst:uvw:y");
+                                 "2:A:C:DEGH:I:J:L:M:NP:QRS:T:U:V:W:YZa:bc:d:e:f:g:hi:jk:lmn:op:rst:uvw:y");
     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
         ++optionsFound;
         switch (optstate->option) {
             case '2':
                 fileName = optstate->value;
                 break;
 
             case 'A':
@@ -2238,16 +2264,21 @@ main(int argc, char **argv)
             case 'C':
                 if (optstate->value)
                     NumSidCacheEntries = PORT_Atoi(optstate->value);
                 break;
 
             case 'D':
                 noDelay = PR_TRUE;
                 break;
+
+            case 'E':
+                enablePostHandshakeAuth = PR_TRUE;
+                break;
+
             case 'H':
                 configureDHE = (PORT_Atoi(optstate->value) != 0);
                 break;
 
             case 'G':
                 enableExtendedMasterSecret = PR_TRUE;
                 break;
 
--- a/security/nss/cmd/tstclnt/tstclnt.c
+++ b/security/nss/cmd/tstclnt/tstclnt.c
@@ -216,17 +216,17 @@ printSecurityInfo(PRFileDesc *fd)
 }
 
 static void
 PrintUsageHeader()
 {
     fprintf(stderr,
             "Usage:  %s -h host [-a 1st_hs_name ] [-a 2nd_hs_name ] [-p port]\n"
             "  [-D | -d certdir] [-C] [-b | -R root-module] \n"
-            "  [-n nickname] [-Bafosvx] [-c ciphers] [-Y] [-Z]\n"
+            "  [-n nickname] [-Bafosvx] [-c ciphers] [-Y] [-Z] [-E]\n"
             "  [-V [min-version]:[max-version]] [-K] [-T] [-U]\n"
             "  [-r N] [-w passwd] [-W pwfile] [-q [-t seconds]]\n"
             "  [-I groups] [-J signatureschemes]\n"
             "  [-A requestfile] [-L totalconnections] [-P {client,server}]\n"
             "  [-N encryptedSniKeys] [-Q]\n"
             "\n",
             progName);
 }
@@ -306,16 +306,19 @@ PrintParameterUsage()
                     "%-20s rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512,\n"
                     "%-20s rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512,\n"
                     "%-20s dsa_sha1, dsa_sha256, dsa_sha384, dsa_sha512\n",
             "-J", "", "", "", "", "", "", "");
     fprintf(stderr, "%-20s Enable alternative TLS 1.3 handshake\n", "-X alt-server-hello");
     fprintf(stderr, "%-20s Use DTLS\n", "-P {client, server}");
     fprintf(stderr, "%-20s Exit after handshake\n", "-Q");
     fprintf(stderr, "%-20s Encrypted SNI Keys\n", "-N");
+    fprintf(stderr, "%-20s Enable post-handshake authentication\n"
+                    "%-20s for TLS 1.3; need to specify -n\n",
+            "-E", "");
 }
 
 static void
 Usage()
 {
     PrintUsageHeader();
     PrintParameterUsage();
     exit(1);
@@ -984,16 +987,17 @@ unsigned int zeroRttLen = 0;
 PRBool enableAltServerHello = PR_FALSE;
 PRBool useDTLS = PR_FALSE;
 PRBool actAsServer = PR_FALSE;
 PRBool stopAfterHandshake = PR_FALSE;
 PRBool requestToExit = PR_FALSE;
 char *versionString = NULL;
 PRBool handshakeComplete = PR_FALSE;
 char *encryptedSNIKeys = NULL;
+PRBool enablePostHandshakeAuth = PR_FALSE;
 
 static int
 writeBytesToServer(PRFileDesc *s, const PRUint8 *buf, int nb)
 {
     SECStatus rv;
     const PRUint8 *bufp = buf;
     PRPollDesc pollDesc;
 
@@ -1405,16 +1409,25 @@ run()
     rv = SSL_OptionSet(s, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
                        enableSignedCertTimestamps);
     if (rv != SECSuccess) {
         SECU_PrintError(progName, "error enabling signed cert timestamps");
         error = 1;
         goto done;
     }
 
+    if (enablePostHandshakeAuth) {
+        rv = SSL_OptionSet(s, SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE);
+        if (rv != SECSuccess) {
+            SECU_PrintError(progName, "error enabling post-handshake auth");
+            error = 1;
+            goto done;
+        }
+    }
+
     if (enabledGroups) {
         rv = SSL_NamedGroupConfig(s, enabledGroups, enabledGroupsCount);
         if (rv < 0) {
             SECU_PrintError(progName, "SSL_NamedGroupConfig failed");
             error = 1;
             goto done;
         }
     }
@@ -1702,17 +1715,17 @@ main(int argc, char **argv)
         }
     }
 
     /* Note: 'B' was used in the past but removed in 3.28
      *       'z' was removed in 3.39
      * Please leave some time before reusing these.
      */
     optstate = PL_CreateOptState(argc, argv,
-                                 "46A:CDFGHI:J:KL:M:N:OP:QR:STUV:W:X:YZa:bc:d:fgh:m:n:op:qr:st:uvw:");
+                                 "46A:CDEFGHI:J:KL:M:N:OP:QR:STUV:W:X:YZa:bc:d:fgh:m:n:op:qr:st:uvw:");
     while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
         switch (optstate->option) {
             case '?':
             default:
                 Usage();
                 break;
 
             case '4':
@@ -1733,16 +1746,20 @@ main(int argc, char **argv)
             case 'C':
                 ++dumpServerChain;
                 break;
 
             case 'D':
                 openDB = PR_FALSE;
                 break;
 
+            case 'E':
+                enablePostHandshakeAuth = PR_TRUE;
+                break;
+
             case 'F':
                 if (serverCertAuth.testFreshStatusFromSideChannel) {
                     /* parameter given twice or more */
                     serverCertAuth.requireDataForIntermediates = PR_TRUE;
                 }
                 serverCertAuth.testFreshStatusFromSideChannel = PR_TRUE;
                 break;
 
@@ -1983,16 +2000,21 @@ main(int argc, char **argv)
         exit(1);
     }
 
     if (rootModule && loadDefaultRootCAs) {
         fprintf(stderr, "%s: Cannot combine parameters -b and -R\n", progName);
         exit(1);
     }
 
+    if (enablePostHandshakeAuth && !nickname) {
+        fprintf(stderr, "%s: -E requires the use of -n\n", progName);
+        exit(1);
+    }
+
     PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
 
     PK11_SetPasswordFunc(SECU_GetModulePassword);
     memset(&addr, 0, sizeof(addr));
     status = PR_StringToNetAddr(host, &addr);
     if (status == PR_SUCCESS) {
         addr.inet.port = PR_htons(portno);
     } else {
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/security/nss/cpputil/tls_parser.h
+++ b/security/nss/cpputil/tls_parser.h
@@ -47,16 +47,17 @@ const uint8_t kTlsAlertIllegalParameter 
 const uint8_t kTlsAlertDecodeError = 50;
 const uint8_t kTlsAlertDecryptError = 51;
 const uint8_t kTlsAlertProtocolVersion = 70;
 const uint8_t kTlsAlertInternalError = 80;
 const uint8_t kTlsAlertInappropriateFallback = 86;
 const uint8_t kTlsAlertMissingExtension = 109;
 const uint8_t kTlsAlertUnsupportedExtension = 110;
 const uint8_t kTlsAlertUnrecognizedName = 112;
+const uint8_t kTlsAlertCertificateRequired = 116;
 const uint8_t kTlsAlertNoApplicationProtocol = 120;
 
 const uint8_t kTlsFakeChangeCipherSpec[] = {
     ssl_ct_change_cipher_spec,  // Type
     0xfe,
     0xff,  // Version
     0x00,
     0x00,
--- a/security/nss/gtests/pk11_gtest/pk11_chacha20poly1305_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_chacha20poly1305_unittest.cc
@@ -3,29 +3,37 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <memory>
 #include "nss.h"
 #include "pk11pub.h"
 #include "sechash.h"
+#include "secerr.h"
 
 #include "cpputil.h"
 #include "nss_scoped_ptrs.h"
 
 #include "testvectors/chachapoly-vectors.h"
 #include "gtest/gtest.h"
 
 namespace nss_test {
 
+static const CK_MECHANISM_TYPE kMech = CKM_NSS_CHACHA20_POLY1305;
+static const CK_MECHANISM_TYPE kMechXor = CKM_NSS_CHACHA20_CTR;
+// Some test data for simple tests.
+static const uint8_t kKeyData[32] = {'k'};
+static const uint8_t kCtrNonce[16] = {'c', 0, 0, 0, 'n'};
+static const uint8_t kData[16] = {'d'};
+
 class Pkcs11ChaCha20Poly1305Test
     : public ::testing::TestWithParam<chacha_testvector> {
  public:
-  void EncryptDecrypt(PK11SymKey* symKey, const bool invalid_iv,
+  void EncryptDecrypt(const ScopedPK11SymKey& key, const bool invalid_iv,
                       const bool invalid_tag, const uint8_t* data,
                       size_t data_len, const uint8_t* aad, size_t aad_len,
                       const uint8_t* iv, size_t iv_len,
                       const uint8_t* ct = nullptr, size_t ct_len = 0) {
     // Prepare AEAD params.
     CK_NSS_AEAD_PARAMS aead_params;
     aead_params.pNonce = toUcharPtr(iv);
     aead_params.ulNonceLen = iv_len;
@@ -34,17 +42,17 @@ class Pkcs11ChaCha20Poly1305Test
     aead_params.ulTagLen = 16;
 
     SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&aead_params),
                       sizeof(aead_params)};
 
     // Encrypt.
     unsigned int outputLen = 0;
     std::vector<uint8_t> output(data_len + aead_params.ulTagLen);
-    SECStatus rv = PK11_Encrypt(symKey, mech, &params, output.data(),
+    SECStatus rv = PK11_Encrypt(key.get(), kMech, &params, output.data(),
                                 &outputLen, output.size(), data, data_len);
 
     // Return if encryption failure was expected due to invalid IV.
     // Without valid ciphertext, all further tests can be skipped.
     if (invalid_iv) {
       EXPECT_EQ(rv, SECFailure);
       return;
     } else {
@@ -55,106 +63,108 @@ class Pkcs11ChaCha20Poly1305Test
     if (ct) {
       ASSERT_EQ(ct_len, outputLen);
       EXPECT_TRUE(!memcmp(ct, output.data(), outputLen) != invalid_tag);
     }
 
     // Decrypt.
     unsigned int decryptedLen = 0;
     std::vector<uint8_t> decrypted(data_len);
-    rv = PK11_Decrypt(symKey, mech, &params, decrypted.data(), &decryptedLen,
-                      decrypted.size(), output.data(), outputLen);
+    rv =
+        PK11_Decrypt(key.get(), kMech, &params, decrypted.data(), &decryptedLen,
+                     decrypted.size(), output.data(), outputLen);
     EXPECT_EQ(rv, SECSuccess);
 
     // Check the plaintext.
     ASSERT_EQ(data_len, decryptedLen);
     EXPECT_TRUE(!memcmp(data, decrypted.data(), decryptedLen));
 
     // Decrypt with bogus data.
     // Skip if there's no data to modify.
     if (outputLen != 0) {
       std::vector<uint8_t> bogusCiphertext(output);
       bogusCiphertext[0] ^= 0xff;
-      rv = PK11_Decrypt(symKey, mech, &params, decrypted.data(), &decryptedLen,
-                        decrypted.size(), bogusCiphertext.data(), outputLen);
+      rv = PK11_Decrypt(key.get(), kMech, &params, decrypted.data(),
+                        &decryptedLen, decrypted.size(), bogusCiphertext.data(),
+                        outputLen);
       EXPECT_NE(rv, SECSuccess);
     }
 
     // Decrypt with bogus tag.
     // Skip if there's no tag to modify.
     if (outputLen != 0) {
       std::vector<uint8_t> bogusTag(output);
       bogusTag[outputLen - 1] ^= 0xff;
-      rv = PK11_Decrypt(symKey, mech, &params, decrypted.data(), &decryptedLen,
-                        decrypted.size(), bogusTag.data(), outputLen);
+      rv = PK11_Decrypt(key.get(), kMech, &params, decrypted.data(),
+                        &decryptedLen, decrypted.size(), bogusTag.data(),
+                        outputLen);
       EXPECT_NE(rv, SECSuccess);
     }
 
     // Decrypt with bogus IV.
     // iv_len == 0 is invalid and should be caught earlier.
     // Still skip, if there's no IV to modify.
     if (iv_len != 0) {
       SECItem bogusParams(params);
       CK_NSS_AEAD_PARAMS bogusAeadParams(aead_params);
       bogusParams.data = reinterpret_cast<unsigned char*>(&bogusAeadParams);
 
       std::vector<uint8_t> bogusIV(iv, iv + iv_len);
       bogusAeadParams.pNonce = toUcharPtr(bogusIV.data());
       bogusIV[0] ^= 0xff;
 
-      rv = PK11_Decrypt(symKey, mech, &bogusParams, decrypted.data(),
+      rv = PK11_Decrypt(key.get(), kMech, &bogusParams, decrypted.data(),
                         &decryptedLen, data_len, output.data(), outputLen);
       EXPECT_NE(rv, SECSuccess);
     }
 
     // Decrypt with bogus additional data.
     // Skip when AAD was empty and can't be modified.
     // Alternatively we could generate random aad.
     if (aad_len != 0) {
       SECItem bogusParams(params);
       CK_NSS_AEAD_PARAMS bogusAeadParams(aead_params);
       bogusParams.data = reinterpret_cast<unsigned char*>(&bogusAeadParams);
 
       std::vector<uint8_t> bogusAAD(aad, aad + aad_len);
       bogusAeadParams.pAAD = toUcharPtr(bogusAAD.data());
       bogusAAD[0] ^= 0xff;
 
-      rv = PK11_Decrypt(symKey, mech, &bogusParams, decrypted.data(),
+      rv = PK11_Decrypt(key.get(), kMech, &bogusParams, decrypted.data(),
                         &decryptedLen, data_len, output.data(), outputLen);
       EXPECT_NE(rv, SECSuccess);
     }
   }
 
   void EncryptDecrypt(const chacha_testvector testvector) {
     ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
-    SECItem keyItem = {siBuffer, toUcharPtr(testvector.Key.data()),
-                       static_cast<unsigned int>(testvector.Key.size())};
+    SECItem key_item = {siBuffer, toUcharPtr(testvector.Key.data()),
+                        static_cast<unsigned int>(testvector.Key.size())};
 
     // Import key.
-    ScopedPK11SymKey symKey(PK11_ImportSymKey(
-        slot.get(), mech, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr));
-    EXPECT_TRUE(!!symKey);
+    ScopedPK11SymKey key(PK11_ImportSymKey(slot.get(), kMech, PK11_OriginUnwrap,
+                                           CKA_ENCRYPT, &key_item, nullptr));
+    EXPECT_TRUE(!!key);
 
     // Check.
-    EncryptDecrypt(symKey.get(), testvector.invalid_iv, testvector.invalid_tag,
+    EncryptDecrypt(key, testvector.invalid_iv, testvector.invalid_tag,
                    testvector.Data.data(), testvector.Data.size(),
                    testvector.AAD.data(), testvector.AAD.size(),
                    testvector.IV.data(), testvector.IV.size(),
                    testvector.CT.data(), testvector.CT.size());
   }
 
  protected:
-  CK_MECHANISM_TYPE mech = CKM_NSS_CHACHA20_POLY1305;
 };
 
 TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateEncryptDecrypt) {
   // Generate a random key.
   ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
-  ScopedPK11SymKey symKey(PK11_KeyGen(slot.get(), mech, nullptr, 32, nullptr));
-  EXPECT_TRUE(!!symKey);
+  ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr));
+  EXPECT_TRUE(!!key);
 
   // Generate random data.
   std::vector<uint8_t> data(512);
   SECStatus rv =
       PK11_GenerateRandomOnSlot(slot.get(), data.data(), data.size());
   EXPECT_EQ(rv, SECSuccess);
 
   // Generate random AAD.
@@ -163,18 +173,95 @@ TEST_F(Pkcs11ChaCha20Poly1305Test, Gener
   EXPECT_EQ(rv, SECSuccess);
 
   // Generate random IV.
   std::vector<uint8_t> iv(12);
   rv = PK11_GenerateRandomOnSlot(slot.get(), iv.data(), iv.size());
   EXPECT_EQ(rv, SECSuccess);
 
   // Check.
-  EncryptDecrypt(symKey.get(), false, false, data.data(), data.size(),
-                 aad.data(), aad.size(), iv.data(), iv.size());
+  EncryptDecrypt(key, false, false, data.data(), data.size(), aad.data(),
+                 aad.size(), iv.data(), iv.size());
+}
+
+TEST_F(Pkcs11ChaCha20Poly1305Test, Xor) {
+  static const uint8_t kExpected[sizeof(kData)] = {
+      0xd8, 0x15, 0xd3, 0xb3, 0xe9, 0x34, 0x3b, 0x7a,
+      0x24, 0xf6, 0x5f, 0xd7, 0x95, 0x3d, 0xd3, 0x51};
+
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  SECItem keyItem = {siBuffer, toUcharPtr(kKeyData),
+                     static_cast<unsigned int>(sizeof(kKeyData))};
+  ScopedPK11SymKey key(PK11_ImportSymKey(
+      slot.get(), kMechXor, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr));
+  EXPECT_TRUE(!!key);
+
+  SECItem ctr_nonce_item = {siBuffer, toUcharPtr(kCtrNonce),
+                            static_cast<unsigned int>(sizeof(kCtrNonce))};
+  uint8_t output[sizeof(kData)];
+  unsigned int output_len = 88;  // This should be overwritten.
+  SECStatus rv =
+      PK11_Encrypt(key.get(), kMechXor, &ctr_nonce_item, output, &output_len,
+                   sizeof(output), kData, sizeof(kData));
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_EQ(sizeof(kExpected), static_cast<size_t>(output_len));
+  EXPECT_EQ(0, memcmp(kExpected, output, sizeof(kExpected)));
+
+  // Decrypting has the same effect.
+  rv = PK11_Decrypt(key.get(), kMechXor, &ctr_nonce_item, output, &output_len,
+                    sizeof(output), kData, sizeof(kData));
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_EQ(sizeof(kData), static_cast<size_t>(output_len));
+  EXPECT_EQ(0, memcmp(kExpected, output, sizeof(kExpected)));
+
+  // Operating in reverse too.
+  rv = PK11_Encrypt(key.get(), kMechXor, &ctr_nonce_item, output, &output_len,
+                    sizeof(output), kExpected, sizeof(kExpected));
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_EQ(sizeof(kExpected), static_cast<size_t>(output_len));
+  EXPECT_EQ(0, memcmp(kData, output, sizeof(kData)));
+}
+
+// This test just ensures that a key can be generated for use with the XOR
+// function.  The result is random and therefore cannot be checked.
+TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateXor) {
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr));
+  EXPECT_TRUE(!!key);
+
+  SECItem ctr_nonce_item = {siBuffer, toUcharPtr(kCtrNonce),
+                            static_cast<unsigned int>(sizeof(kCtrNonce))};
+  uint8_t output[sizeof(kData)];
+  unsigned int output_len = 88;  // This should be overwritten.
+  SECStatus rv =
+      PK11_Encrypt(key.get(), kMechXor, &ctr_nonce_item, output, &output_len,
+                   sizeof(output), kData, sizeof(kData));
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_EQ(sizeof(kData), static_cast<size_t>(output_len));
+}
+
+TEST_F(Pkcs11ChaCha20Poly1305Test, XorInvalidParams) {
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr));
+  EXPECT_TRUE(!!key);
+
+  SECItem ctr_nonce_item = {siBuffer, toUcharPtr(kCtrNonce),
+                            static_cast<unsigned int>(sizeof(kCtrNonce)) - 1};
+  uint8_t output[sizeof(kData)];
+  unsigned int output_len = 88;
+  SECStatus rv =
+      PK11_Encrypt(key.get(), kMechXor, &ctr_nonce_item, output, &output_len,
+                   sizeof(output), kData, sizeof(kData));
+  EXPECT_EQ(SECFailure, rv);
+
+  ctr_nonce_item.data = nullptr;
+  rv = PK11_Encrypt(key.get(), kMechXor, &ctr_nonce_item, output, &output_len,
+                    sizeof(output), kData, sizeof(kData));
+  EXPECT_EQ(SECFailure, rv);
+  EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
 }
 
 TEST_P(Pkcs11ChaCha20Poly1305Test, TestVectors) { EncryptDecrypt(GetParam()); }
 
 INSTANTIATE_TEST_CASE_P(NSSTestVector, Pkcs11ChaCha20Poly1305Test,
                         ::testing::ValuesIn(kChaCha20Vectors));
 
 INSTANTIATE_TEST_CASE_P(WycheproofTestVector, Pkcs11ChaCha20Poly1305Test,
--- a/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
@@ -315,16 +315,56 @@ TEST_F(TlsConnectStreamTls13, PostHandsh
   // Send 1st CertificateRequest.
   EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
       << "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
   // Send 2nd CertificateRequest.
   EXPECT_EQ(SECFailure, SSL_SendCertificateRequest(server_->ssl_fd()));
   EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
 }
 
+TEST_F(TlsConnectStreamTls13, PostHandshakeAuthBeforeKeyUpdate) {
+  client_->SetupClientAuth();
+  EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
+                                      SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
+  Connect();
+  // Send CertificateRequest.
+  EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
+      << "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
+  // Send KeyUpdate.
+  EXPECT_EQ(SECFailure, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
+  EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+}
+
+TEST_F(TlsConnectStreamTls13, PostHandshakeAuthDuringClientKeyUpdate) {
+  client_->SetupClientAuth();
+  EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
+                                      SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
+  Connect();
+  CheckEpochs(3, 3);
+  // Send CertificateRequest from server.
+  EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
+      << "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
+  // Send KeyUpdate from client.
+  EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_TRUE));
+  server_->SendData(50);   // server sends CertificateRequest
+  client_->SendData(50);   // client sends KeyUpdate
+  server_->ReadBytes(50);  // server receives KeyUpdate and defers response
+  CheckEpochs(4, 3);
+  client_->ReadBytes(50);  // client receives CertificateRequest
+  client_->SendData(
+      50);  // client sends Certificate, CertificateVerify, Finished
+  server_->ReadBytes(
+      50);  // server receives Certificate, CertificateVerify, Finished
+  client_->CheckEpochs(3, 4);
+  server_->CheckEpochs(4, 4);
+  server_->SendData(50);   // server sends KeyUpdate
+  client_->ReadBytes(50);  // client receives KeyUpdate
+  client_->CheckEpochs(4, 4);
+}
+
 TEST_F(TlsConnectStreamTls13, PostHandshakeAuthMissingExtension) {
   client_->SetupClientAuth();
   Connect();
   // Send CertificateRequest, should fail due to missing
   // post_handshake_auth extension.
   EXPECT_EQ(SECFailure, SSL_SendCertificateRequest(server_->ssl_fd()));
   EXPECT_EQ(SSL_ERROR_MISSING_POST_HANDSHAKE_AUTH_EXTENSION, PORT_GetError());
 }
@@ -449,16 +489,19 @@ TEST_F(TlsConnectStreamTls13, PostHandsh
   auto capture_cert_req = MakeTlsFilter<TlsCertificateRequestContextRecorder>(
       server_, kTlsHandshakeCertificateRequest);
   auto capture_certificate =
       MakeTlsFilter<TlsCertificateRequestContextRecorder>(
           client_, kTlsHandshakeCertificate);
   client_->SetupClientAuth();
   EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
                                       SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
+  EXPECT_EQ(SECSuccess,
+            SSL_OptionSet(server_->ssl_fd(), SSL_REQUIRE_CERTIFICATE,
+                          SSL_REQUIRE_ALWAYS));
   // Client to decline the certificate request.
   EXPECT_EQ(SECSuccess,
             SSL_GetClientAuthDataHook(
                 client_->ssl_fd(),
                 [](void*, PRFileDesc*, CERTDistNames*, CERTCertificate**,
                    SECKEYPrivateKey**) -> SECStatus { return SECFailure; },
                 nullptr));
   size_t called = 0;
@@ -467,20 +510,23 @@ TEST_F(TlsConnectStreamTls13, PostHandsh
         called++;
         return SECSuccess;
       });
   Connect();
   EXPECT_EQ(0U, called);
   // Send CertificateRequest.
   EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
       << "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
-  server_->SendData(50);
-  client_->ReadBytes(50);
-  client_->SendData(50);
-  server_->ReadBytes(50);
+  server_->SendData(50);   // send Certificate Request
+  client_->ReadBytes(50);  // read Certificate Request
+  client_->SendData(50);   // send empty Certificate+Finished
+  server_->ExpectSendAlert(kTlsAlertCertificateRequired);
+  server_->ReadBytes(50);  // read empty Certificate+Finished
+  server_->ExpectReadWriteError();
+  server_->SendData(50);  // send alert
   // AuthCertificateCallback is not called, because the client sends
   // an empty certificate_list.
   EXPECT_EQ(0U, called);
   EXPECT_TRUE(capture_cert_req->filtered());
   EXPECT_TRUE(capture_certificate->filtered());
   // Check if a non-empty request context is generated and it is
   // properly sent back.
   EXPECT_LT(0U, capture_cert_req->buffer().len());
--- a/security/nss/lib/freebl/blapi.h
+++ b/security/nss/lib/freebl/blapi.h
@@ -1008,16 +1008,20 @@ extern SECStatus ChaCha20Poly1305_Seal(
 
 extern SECStatus ChaCha20Poly1305_Open(
     const ChaCha20Poly1305Context *ctx, unsigned char *output,
     unsigned int *outputLen, unsigned int maxOutputLen,
     const unsigned char *input, unsigned int inputLen,
     const unsigned char *nonce, unsigned int nonceLen,
     const unsigned char *ad, unsigned int adLen);
 
+extern SECStatus ChaCha20_Xor(
+    unsigned char *output, const unsigned char *block, unsigned int len,
+    const unsigned char *k, const unsigned char *nonce, PRUint32 ctr);
+
 /******************************************/
 /*
 ** MD5 secure hash function
 */
 
 /*
 ** Hash a null terminated string "src" into "dest" using MD5
 */
--- a/security/nss/lib/freebl/chacha20poly1305.c
+++ b/security/nss/lib/freebl/chacha20poly1305.c
@@ -166,32 +166,55 @@ ChaCha20Xor(uint8_t *output, uint8_t *bl
         Hacl_Chacha20_Vec128_chacha20(output, block, len, k, nonce, ctr);
     } else {
         Hacl_Chacha20_chacha20(output, block, len, k, nonce, ctr);
     }
 }
 #endif /* NSS_DISABLE_CHACHAPOLY */
 
 SECStatus
+ChaCha20_Xor(unsigned char *output, const unsigned char *block, unsigned int len,
+             const unsigned char *k, const unsigned char *nonce, PRUint32 ctr)
+{
+#ifdef NSS_DISABLE_CHACHAPOLY
+    return SECFailure;
+#else
+    // ChaCha has a 64 octet block, with a 32-bit block counter.
+    if (sizeof(len) > 4 && len >= (1ULL << (6 + 32))) {
+        PORT_SetError(SEC_ERROR_INPUT_LEN);
+        return SECFailure;
+    }
+    ChaCha20Xor(output, (uint8_t *)block, len, (uint8_t *)k,
+                (uint8_t *)nonce, ctr);
+    return SECSuccess;
+#endif
+}
+
+SECStatus
 ChaCha20Poly1305_Seal(const ChaCha20Poly1305Context *ctx, unsigned char *output,
                       unsigned int *outputLen, unsigned int maxOutputLen,
                       const unsigned char *input, unsigned int inputLen,
                       const unsigned char *nonce, unsigned int nonceLen,
                       const unsigned char *ad, unsigned int adLen)
 {
 #ifdef NSS_DISABLE_CHACHAPOLY
     return SECFailure;
 #else
     unsigned char block[64];
     unsigned char tag[16];
 
     if (nonceLen != 12) {
         PORT_SetError(SEC_ERROR_INPUT_LEN);
         return SECFailure;
     }
+    // ChaCha has a 64 octet block, with a 32-bit block counter.
+    if (sizeof(inputLen) > 4 && inputLen >= (1ULL << (6 + 32))) {
+        PORT_SetError(SEC_ERROR_INPUT_LEN);
+        return SECFailure;
+    }
     *outputLen = inputLen + ctx->tagLen;
     if (maxOutputLen < *outputLen) {
         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
         return SECFailure;
     }
 
     PORT_Memset(block, 0, sizeof(block));
     // Generate a block of keystream. The first 32 bytes will be the poly1305
--- a/security/nss/lib/freebl/crypto_primitives.c
+++ b/security/nss/lib/freebl/crypto_primitives.c
@@ -17,17 +17,17 @@
 __inline__ PRUint64
 swap8b(PRUint64 value)
 {
     __asm__("bswapq %0"
             : "+r"(value));
     return (value);
 }
 
-#elif !defined(_MSC_VER) && !__has_builtin(__builtin_bswap64)
+#elif !defined(_MSC_VER) && !__has_builtin(__builtin_bswap64) && !((defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))))
 
 PRUint64
 swap8b(PRUint64 x)
 {
     PRUint64 t1 = x;
     t1 = ((t1 & SHA_MASK8) << 8) | ((t1 >> 8) & SHA_MASK8);
     t1 = ((t1 & SHA_MASK16) << 16) | ((t1 >> 16) & SHA_MASK16);
     return (t1 >> 32) | (t1 << 32);
--- a/security/nss/lib/freebl/crypto_primitives.h
+++ b/security/nss/lib/freebl/crypto_primitives.h
@@ -35,17 +35,18 @@
  * FREEBL_HTONLL(x): swap bytes in a 64-bit integer.
  */
 #if defined(IS_LITTLE_ENDIAN)
 #if defined(_MSC_VER)
 
 #pragma intrinsic(_byteswap_uint64)
 #define FREEBL_HTONLL(x) _byteswap_uint64(x)
 
-#elif __has_builtin(__builtin_bswap64)
+/* gcc doesn't have __has_builtin, but it does have __builtin_bswap64 */
+#elif __has_builtin(__builtin_bswap64) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
 
 #define FREEBL_HTONLL(x) __builtin_bswap64(x)
 
 #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__x86_64))
 
 PRUint64 swap8b(PRUint64 value);
 #define FREEBL_HTONLL(x) swap8b(x)
 
--- a/security/nss/lib/freebl/ldvector.c
+++ b/security/nss/lib/freebl/ldvector.c
@@ -308,20 +308,24 @@ static const struct FREEBLVectorStr vect
       BLAKE2B_NewContext,
       BLAKE2B_DestroyContext,
       BLAKE2B_Begin,
       BLAKE2B_MAC_Begin,
       BLAKE2B_Update,
       BLAKE2B_End,
       BLAKE2B_FlattenSize,
       BLAKE2B_Flatten,
-      BLAKE2B_Resurrect
+      BLAKE2B_Resurrect,
 
       /* End of Version 3.020 */
 
+      ChaCha20_Xor
+
+      /* End of version 3.021 */
+
     };
 
 const FREEBLVector*
 FREEBL_GetVector(void)
 {
 #ifdef FREEBL_NO_DEPEND
     SECStatus rv;
 #endif
--- a/security/nss/lib/freebl/loader.c
+++ b/security/nss/lib/freebl/loader.c
@@ -2056,16 +2056,26 @@ EC_CopyParams(PLArenaPool *arena, ECPara
               const ECParams *srcParams)
 {
     if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
         return SECFailure;
     return (vector->p_EC_CopyParams)(arena, dstParams, srcParams);
 }
 
 SECStatus
+ChaCha20_Xor(unsigned char *output, const unsigned char *block, unsigned int len,
+             const unsigned char *k, const unsigned char *nonce, PRUint32 ctr)
+{
+    if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) {
+        return SECFailure;
+    }
+    return (vector->p_ChaCha20_Xor)(output, block, len, k, nonce, ctr);
+}
+
+SECStatus
 ChaCha20Poly1305_InitContext(ChaCha20Poly1305Context *ctx,
                              const unsigned char *key, unsigned int keyLen,
                              unsigned int tagLen)
 {
     if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
         return SECFailure;
     return (vector->p_ChaCha20Poly1305_InitContext)(ctx, key, keyLen, tagLen);
 }
--- a/security/nss/lib/freebl/loader.h
+++ b/security/nss/lib/freebl/loader.h
@@ -5,17 +5,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _LOADER_H_
 #define _LOADER_H_ 1
 
 #include "blapi.h"
 
-#define FREEBL_VERSION 0x0314
+#define FREEBL_VERSION 0x0315
 
 struct FREEBLVectorStr {
 
     unsigned short length;  /* of this struct in bytes */
     unsigned short version; /* of this struct. */
 
     RSAPrivateKey *(*p_RSA_NewKey)(int keySizeInBits,
                                    SECItem *publicExponent);
@@ -754,16 +754,22 @@ struct FREEBLVectorStr {
     SECStatus (*p_BLAKE2B_End)(BLAKE2BContext *ctx, unsigned char *out,
                                unsigned int *digestLen, size_t maxDigestLen);
     unsigned int (*p_BLAKE2B_FlattenSize)(BLAKE2BContext *ctx);
     SECStatus (*p_BLAKE2B_Flatten)(BLAKE2BContext *ctx, unsigned char *space);
     BLAKE2BContext *(*p_BLAKE2B_Resurrect)(unsigned char *space, void *arg);
 
     /* Version 3.020 came to here */
 
+    SECStatus (*p_ChaCha20_Xor)(unsigned char *output, const unsigned char *block,
+                                unsigned int len, const unsigned char *k,
+                                const unsigned char *nonce, PRUint32 ctr);
+
+    /* Version 3.021 came to here */
+
     /* Add new function pointers at the end of this struct and bump
      * FREEBL_VERSION at the beginning of this file. */
 };
 
 typedef struct FREEBLVectorStr FREEBLVector;
 
 #ifdef FREEBL_LOWHASH
 #include "nsslowhash.h"
--- a/security/nss/lib/pk11wrap/pk11mech.c
+++ b/security/nss/lib/pk11wrap/pk11mech.c
@@ -221,16 +221,17 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type, 
         case CKM_CAMELLIA_CBC:
         case CKM_CAMELLIA_MAC:
         case CKM_CAMELLIA_MAC_GENERAL:
         case CKM_CAMELLIA_CBC_PAD:
         case CKM_CAMELLIA_KEY_GEN:
             return CKK_CAMELLIA;
         case CKM_NSS_CHACHA20_POLY1305:
         case CKM_NSS_CHACHA20_KEY_GEN:
+        case CKM_NSS_CHACHA20_CTR:
             return CKK_NSS_CHACHA20;
         case CKM_AES_ECB:
         case CKM_AES_CBC:
         case CKM_AES_CCM:
         case CKM_AES_CTR:
         case CKM_AES_CTS:
         case CKM_AES_GCM:
         case CKM_AES_MAC:
@@ -435,16 +436,17 @@ PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE
         case CKM_CAMELLIA_ECB:
         case CKM_CAMELLIA_CBC:
         case CKM_CAMELLIA_MAC:
         case CKM_CAMELLIA_MAC_GENERAL:
         case CKM_CAMELLIA_CBC_PAD:
         case CKM_CAMELLIA_KEY_GEN:
             return CKM_CAMELLIA_KEY_GEN;
         case CKM_NSS_CHACHA20_POLY1305:
+        case CKM_NSS_CHACHA20_CTR:
             return CKM_NSS_CHACHA20_KEY_GEN;
         case CKM_AES_ECB:
         case CKM_AES_CBC:
         case CKM_AES_CCM:
         case CKM_AES_CTR:
         case CKM_AES_CTS:
         case CKM_AES_GCM:
         case CKM_AES_MAC:
@@ -725,16 +727,19 @@ PK11_GetBlockSize(CK_MECHANISM_TYPE type
         case CKM_PBE_SHA1_RC4_40:
         case CKM_PBE_SHA1_RC4_128:
             return 0;
         case CKM_RSA_PKCS:
         case CKM_RSA_9796:
         case CKM_RSA_X_509:
             /*actually it's the modulus length of the key!*/
             return -1; /* failure */
+        case CKM_NSS_CHACHA20_POLY1305:
+        case CKM_NSS_CHACHA20_CTR:
+            return 64;
         default:
             return pk11_lookup(type)->blockSize;
     }
 }
 
 /*
  * get the iv length
  */
@@ -779,22 +784,26 @@ PK11_GetIVLength(CK_MECHANISM_TYPE type)
         case CKM_DES_CBC_PAD:
         case CKM_DES3_CBC_PAD:
         case CKM_IDEA_CBC_PAD:
         case CKM_RC5_CBC_PAD:
         case CKM_CAST_CBC_PAD:
         case CKM_CAST3_CBC_PAD:
         case CKM_CAST5_CBC_PAD:
             return 8;
+        case CKM_AES_GCM:
+        case CKM_NSS_CHACHA20_POLY1305:
+            return 12;
         case CKM_SEED_CBC:
         case CKM_SEED_CBC_PAD:
         case CKM_CAMELLIA_CBC:
         case CKM_CAMELLIA_CBC_PAD:
         case CKM_AES_CBC:
         case CKM_AES_CBC_PAD:
+        case CKM_NSS_CHACHA20_CTR:
             return 16;
         case CKM_SKIPJACK_CBC64:
         case CKM_SKIPJACK_ECB64:
         case CKM_SKIPJACK_OFB64:
         case CKM_SKIPJACK_CFB64:
         case CKM_SKIPJACK_CFB32:
         case CKM_SKIPJACK_CFB16:
         case CKM_SKIPJACK_CFB8:
--- a/security/nss/lib/softoken/pkcs11.c
+++ b/security/nss/lib/softoken/pkcs11.c
@@ -341,16 +341,17 @@ static const struct mechanismList mechan
     { CKM_SEED_CBC, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
     { CKM_SEED_MAC, { 16, 16, CKF_SN_VR }, PR_TRUE },
     { CKM_SEED_MAC_GENERAL, { 16, 16, CKF_SN_VR }, PR_TRUE },
     { CKM_SEED_CBC_PAD, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
 #ifndef NSS_DISABLE_CHACHAPOLY
     /* ------------------------- ChaCha20 Operations ---------------------- */
     { CKM_NSS_CHACHA20_KEY_GEN, { 32, 32, CKF_GENERATE }, PR_TRUE },
     { CKM_NSS_CHACHA20_POLY1305, { 32, 32, CKF_EN_DE }, PR_TRUE },
+    { CKM_NSS_CHACHA20_CTR, { 32, 32, CKF_EN_DE }, PR_TRUE },
 #endif /* NSS_DISABLE_CHACHAPOLY */
     /* ------------------------- Hashing Operations ----------------------- */
     { CKM_MD2, { 0, 0, CKF_DIGEST }, PR_FALSE },
     { CKM_MD2_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
     { CKM_MD2_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
     { CKM_MD5, { 0, 0, CKF_DIGEST }, PR_FALSE },
     { CKM_MD5_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
     { CKM_MD5_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -755,16 +755,42 @@ sftk_ChaCha20Poly1305_Decrypt(const SFTK
         ad = ctx->ad;
     }
 
     return ChaCha20Poly1305_Open(&ctx->freeblCtx, output, outputLen,
                                  maxOutputLen, input, inputLen, ctx->nonce,
                                  sizeof(ctx->nonce), ad, ctx->adLen);
 }
 
+static SECStatus
+sftk_ChaCha20Ctr(const SFTKChaCha20CtrInfo *ctx,
+                 unsigned char *output, unsigned int *outputLen,
+                 unsigned int maxOutputLen,
+                 const unsigned char *input, unsigned int inputLen)
+{
+    if (maxOutputLen < inputLen) {
+        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+        return SECFailure;
+    }
+    ChaCha20_Xor(output, input, inputLen, ctx->key,
+                 ctx->nonce, ctx->counter);
+    *outputLen = inputLen;
+    return SECSuccess;
+}
+
+static void
+sftk_ChaCha20Ctr_DestroyContext(SFTKChaCha20CtrInfo *ctx,
+                                PRBool freeit)
+{
+    memset(ctx, 0, sizeof(*ctx));
+    if (freeit) {
+        PORT_Free(ctx);
+    }
+}
+
 /** NSC_CryptInit initializes an encryption/Decryption operation.
  *
  * Always called by NSC_EncryptInit, NSC_DecryptInit, NSC_WrapKey,NSC_UnwrapKey.
  * Called by NSC_SignInit, NSC_VerifyInit (via sftk_InitCBCMac) only for block
  *  ciphers MAC'ing.
  */
 static CK_RV
 sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
@@ -1175,16 +1201,57 @@ sftk_CryptInit(CK_SESSION_HANDLE hSessio
             if (context->cipherInfo == NULL) {
                 crv = sftk_MapCryptError(PORT_GetError());
                 break;
             }
             context->update = (SFTKCipher)(isEncrypt ? sftk_ChaCha20Poly1305_Encrypt : sftk_ChaCha20Poly1305_Decrypt);
             context->destroy = (SFTKDestroy)sftk_ChaCha20Poly1305_DestroyContext;
             break;
 
+        case CKM_NSS_CHACHA20_CTR:
+            if (key_type != CKK_NSS_CHACHA20) {
+                crv = CKR_KEY_TYPE_INCONSISTENT;
+                break;
+            }
+            if (pMechanism->pParameter == NULL || pMechanism->ulParameterLen != 16) {
+                crv = CKR_MECHANISM_PARAM_INVALID;
+                break;
+            }
+
+            att = sftk_FindAttribute(key, CKA_VALUE);
+            if (att == NULL) {
+                crv = CKR_KEY_HANDLE_INVALID;
+                break;
+            }
+            SFTKChaCha20CtrInfo *ctx = PORT_ZNew(SFTKChaCha20CtrInfo);
+            if (!ctx) {
+                sftk_FreeAttribute(att);
+                crv = CKR_HOST_MEMORY;
+                break;
+            }
+            if (att->attrib.ulValueLen != sizeof(ctx->key)) {
+                sftk_FreeAttribute(att);
+                crv = CKR_KEY_HANDLE_INVALID;
+                break;
+            }
+            memcpy(ctx->key, att->attrib.pValue, att->attrib.ulValueLen);
+            sftk_FreeAttribute(att);
+
+            /* The counter is little endian. */
+            PRUint8 *param = pMechanism->pParameter;
+            int i = 0;
+            for (; i < 4; ++i) {
+                ctx->counter |= param[i] << (i * 8);
+            }
+            memcpy(ctx->nonce, param + 4, 12);
+            context->cipherInfo = ctx;
+            context->update = (SFTKCipher)sftk_ChaCha20Ctr;
+            context->destroy = (SFTKDestroy)sftk_ChaCha20Ctr_DestroyContext;
+            break;
+
         case CKM_NSS_AES_KEY_WRAP_PAD:
             context->doPad = PR_TRUE;
         /* fall thru */
         case CKM_NSS_AES_KEY_WRAP:
             context->multi = PR_FALSE;
             context->blockSize = 8;
             if (key_type != CKK_AES) {
                 crv = CKR_KEY_TYPE_INCONSISTENT;
--- a/security/nss/lib/softoken/pkcs11i.h
+++ b/security/nss/lib/softoken/pkcs11i.h
@@ -101,16 +101,17 @@ typedef struct SFTKSlotStr SFTKSlot;
 typedef struct SFTKSessionContextStr SFTKSessionContext;
 typedef struct SFTKSearchResultsStr SFTKSearchResults;
 typedef struct SFTKHashVerifyInfoStr SFTKHashVerifyInfo;
 typedef struct SFTKHashSignInfoStr SFTKHashSignInfo;
 typedef struct SFTKOAEPEncryptInfoStr SFTKOAEPEncryptInfo;
 typedef struct SFTKOAEPDecryptInfoStr SFTKOAEPDecryptInfo;
 typedef struct SFTKSSLMACInfoStr SFTKSSLMACInfo;
 typedef struct SFTKChaCha20Poly1305InfoStr SFTKChaCha20Poly1305Info;
+typedef struct SFTKChaCha20CtrInfoStr SFTKChaCha20CtrInfo;
 typedef struct SFTKItemTemplateStr SFTKItemTemplate;
 
 /* define function pointer typdefs for pointer tables */
 typedef void (*SFTKDestroy)(void *, PRBool);
 typedef void (*SFTKBegin)(void *);
 typedef SECStatus (*SFTKCipher)(void *, void *, unsigned int *, unsigned int,
                                 void *, unsigned int);
 typedef SECStatus (*SFTKVerify)(void *, void *, unsigned int, void *, unsigned int);
@@ -404,16 +405,24 @@ struct SFTKSSLMACInfoStr {
 struct SFTKChaCha20Poly1305InfoStr {
     ChaCha20Poly1305Context freeblCtx;
     unsigned char nonce[12];
     unsigned char ad[16];
     unsigned char *adOverflow;
     unsigned int adLen;
 };
 
+/* SFTKChaCha20BlockInfoStr the key, nonce and counter for a
+ * ChaCha20 block operation. */
+struct SFTKChaCha20CtrInfoStr {
+    PRUint8 key[32];
+    PRUint8 nonce[12];
+    PRUint32 counter;
+};
+
 /*
  * Template based on SECItems, suitable for passing as arrays
  */
 struct SFTKItemTemplateStr {
     CK_ATTRIBUTE_TYPE type;
     SECItem *item;
 };
 
--- a/security/nss/lib/softoken/sdb.c
+++ b/security/nss/lib/softoken/sdb.c
@@ -936,32 +936,36 @@ sdb_GetAttributeValueNoLock(SDB *sdb, CK
             for (i = 0; i < count; i++) {
                 unsigned int blobSize;
                 const char *blobData;
 
                 // NB: indices in sqlite_column_{bytes,blob} are 0-indexed
                 blobSize = sqlite3_column_bytes(stmt, i);
                 blobData = sqlite3_column_blob(stmt, i);
                 if (blobData == NULL) {
+                    /* PKCS 11 requires that get attributes process all the
+                     * attributes in the template, marking the attributes with
+                     * issues with -1. Mark the error but continue */
                     template[i].ulValueLen = -1;
                     error = CKR_ATTRIBUTE_TYPE_INVALID;
-                    break;
+                    continue;
                 }
                 /* If the blob equals our explicit NULL value, then the
                  * attribute is a NULL. */
                 if ((blobSize == SQLITE_EXPLICIT_NULL_LEN) &&
                     (PORT_Memcmp(blobData, SQLITE_EXPLICIT_NULL,
                                  SQLITE_EXPLICIT_NULL_LEN) == 0)) {
                     blobSize = 0;
                 }
                 if (template[i].pValue) {
                     if (template[i].ulValueLen < blobSize) {
+                        /* like CKR_ATTRIBUTE_TYPE_INVALID, continue processing */
                         template[i].ulValueLen = -1;
                         error = CKR_BUFFER_TOO_SMALL;
-                        break;
+                        continue;
                     }
                     PORT_Memcpy(template[i].pValue, blobData, blobSize);
                 }
                 template[i].ulValueLen = blobSize;
             }
             found = 1;
         }
     } while (!sdb_done(sqlerr, &retry));
--- a/security/nss/lib/ssl/SSLerrs.h
+++ b/security/nss/lib/ssl/SSLerrs.h
@@ -559,8 +559,11 @@ ER3(SSL_ERROR_RX_MALFORMED_ESNI_KEYS, (S
 ER3(SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, (SSL_ERROR_BASE + 177),
     "SSL received a malformed ESNI extension")
 
 ER3(SSL_ERROR_MISSING_ESNI_EXTENSION, (SSL_ERROR_BASE + 178),
     "SSL did not receive an ESNI extension")
 
 ER3(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, (SSL_ERROR_BASE + 179),
     "SSL received an unexpected record type.")
+
+ER3(SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT, (SSL_ERROR_BASE + 181),
+    "SSL received a certificate_required alert.")
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -2678,17 +2678,22 @@ ssl3_HandleNoCertificate(sslSocket *ss)
      * know the server is paying attention to the certificate.
      */
     if ((ss->opt.requireCertificate == SSL_REQUIRE_ALWAYS) ||
         (!ss->firstHsDone &&
          (ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE))) {
         PRFileDesc *lower;
 
         ssl_UncacheSessionID(ss);
-        SSL3_SendAlert(ss, alert_fatal, bad_certificate);
+
+        if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+            SSL3_SendAlert(ss, alert_fatal, certificate_required);
+        } else {
+            SSL3_SendAlert(ss, alert_fatal, bad_certificate);
+        }
 
         lower = ss->fd->lower;
 #ifdef _WIN32
         lower->methods->shutdown(lower, PR_SHUTDOWN_SEND);
 #else
         lower->methods->shutdown(lower, PR_SHUTDOWN_BOTH);
 #endif
         PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
@@ -2914,16 +2919,19 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffe
             error = SSL_ERROR_DECOMPRESSION_FAILURE_ALERT;
             break;
         case handshake_failure:
             error = SSL_ERROR_HANDSHAKE_FAILURE_ALERT;
             break;
         case no_certificate:
             error = SSL_ERROR_NO_CERTIFICATE;
             break;
+        case certificate_required:
+            error = SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT;
+            break;
         case bad_certificate:
             error = SSL_ERROR_BAD_CERT_ALERT;
             break;
         case unsupported_certificate:
             error = SSL_ERROR_UNSUPPORTED_CERT_ALERT;
             break;
         case certificate_revoked:
             error = SSL_ERROR_REVOKED_CERT_ALERT;
@@ -3714,16 +3722,20 @@ ssl3_RestartHandshakeHashes(sslSocket *s
     if (ss->ssl3.hs.md5) {
         PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE);
         ss->ssl3.hs.md5 = NULL;
     }
     if (ss->ssl3.hs.sha) {
         PK11_DestroyContext(ss->ssl3.hs.sha, PR_TRUE);
         ss->ssl3.hs.sha = NULL;
     }
+    if (ss->ssl3.hs.shaPostHandshake) {
+        PK11_DestroyContext(ss->ssl3.hs.shaPostHandshake, PR_TRUE);
+        ss->ssl3.hs.shaPostHandshake = NULL;
+    }
 }
 
 /*
  * Handshake messages
  */
 /* Called from  ssl3_InitHandshakeHashes()
 **      ssl3_AppendHandshake()
 **      ssl3_HandleV2ClientHello()
@@ -3774,16 +3786,34 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss
             ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
             return rv;
         }
     }
     return rv;
 }
 
 SECStatus
+ssl3_UpdatePostHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l)
+{
+    SECStatus rv = SECSuccess;
+
+    PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+    PRINT_BUF(90, (ss, "post handshake hash input:", b, l));
+
+    PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_single);
+    PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+    rv = PK11_DigestOp(ss->ssl3.hs.shaPostHandshake, b, l);
+    if (rv != SECSuccess) {
+        PORT_SetError(SSL_ERROR_DIGEST_FAILURE);
+    }
+    return rv;
+}
+
+SECStatus
 ssl3_AppendHandshakeHeader(sslSocket *ss, SSLHandshakeType t, PRUint32 length)
 {
     SECStatus rv;
 
     /* If we already have a message in place, we need to enqueue it.
      * This empties the buffer. This is a convenient place to call
      * dtls_StageHandshakeMessage to mark the message boundary.
      */
@@ -11618,30 +11648,31 @@ ssl3_FinishHandshake(sslSocket *ss)
     ssl_FinishHandshake(ss);
 
     return SECSuccess;
 }
 
 SECStatus
 ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType ct,
                             PRUint32 dtlsSeq,
-                            const PRUint8 *b, PRUint32 length)
+                            const PRUint8 *b, PRUint32 length,
+                            sslUpdateHandshakeHashes updateHashes)
 {
     PRUint8 hdr[4];
     PRUint8 dtlsData[8];
     SECStatus rv;
 
     PRINT_BUF(50, (ss, "Hash handshake message:", b, length));
 
     hdr[0] = (PRUint8)ct;
     hdr[1] = (PRUint8)(length >> 16);
     hdr[2] = (PRUint8)(length >> 8);
     hdr[3] = (PRUint8)(length);
 
-    rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)hdr, 4);
+    rv = updateHashes(ss, (unsigned char *)hdr, 4);
     if (rv != SECSuccess)
         return rv; /* err code already set. */
 
     /* Extra data to simulate a complete DTLS handshake fragment */
     if (IS_DTLS(ss)) {
         /* Sequence number */
         dtlsData[0] = MSB(dtlsSeq);
         dtlsData[1] = LSB(dtlsSeq);
@@ -11651,36 +11682,43 @@ ssl_HashHandshakeMessageInt(sslSocket *s
         dtlsData[3] = 0;
         dtlsData[4] = 0;
 
         /* Fragment length */
         dtlsData[5] = (PRUint8)(length >> 16);
         dtlsData[6] = (PRUint8)(length >> 8);
         dtlsData[7] = (PRUint8)(length);
 
-        rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)dtlsData,
-                                        sizeof(dtlsData));
+        rv = updateHashes(ss, (unsigned char *)dtlsData, sizeof(dtlsData));
         if (rv != SECSuccess)
             return rv; /* err code already set. */
     }
 
     /* The message body */
-    rv = ssl3_UpdateHandshakeHashes(ss, b, length);
+    rv = updateHashes(ss, b, length);
     if (rv != SECSuccess)
         return rv; /* err code already set. */
 
     return SECSuccess;
 }
 
 SECStatus
 ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType ct,
                          const PRUint8 *b, PRUint32 length)
 {
     return ssl_HashHandshakeMessageInt(ss, ct, ss->ssl3.hs.recvMessageSeq,
-                                       b, length);
+                                       b, length, ssl3_UpdateHandshakeHashes);
+}
+
+SECStatus
+ssl_HashPostHandshakeMessage(sslSocket *ss, SSLHandshakeType ct,
+                             const PRUint8 *b, PRUint32 length)
+{
+    return ssl_HashHandshakeMessageInt(ss, ct, ss->ssl3.hs.recvMessageSeq,
+                                       b, length, ssl3_UpdatePostHandshakeHashes);
 }
 
 /* Called from ssl3_HandleHandshake() when it has gathered a complete ssl3
  * handshake message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 SECStatus
 ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length,
@@ -11709,19 +11747,21 @@ ssl3_HandleHandshakeMessage(sslSocket *s
         /* Defer hashing of these messages until the message handlers. */
         case ssl_hs_client_hello:
         case ssl_hs_server_hello:
         case ssl_hs_certificate_verify:
         case ssl_hs_finished:
             break;
 
         default:
-            rv = ssl_HashHandshakeMessage(ss, ss->ssl3.hs.msg_type, b, length);
-            if (rv != SECSuccess) {
-                return SECFailure;
+            if (!tls13_IsPostHandshake(ss)) {
+                rv = ssl_HashHandshakeMessage(ss, ss->ssl3.hs.msg_type, b, length);
+                if (rv != SECSuccess) {
+                    return SECFailure;
+                }
             }
     }
 
     PORT_SetError(0); /* each message starts with no error. */
 
     if (ss->ssl3.hs.ws == wait_certificate_status &&
         ss->ssl3.hs.msg_type != ssl_hs_certificate_status) {
         /* If we negotiated the certificate_status extension then we deferred
@@ -13124,16 +13164,19 @@ ssl3_DestroySSL3Info(sslSocket *ss)
 
     /* clean up handshake */
     if (ss->ssl3.hs.md5) {
         PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE);
     }
     if (ss->ssl3.hs.sha) {
         PK11_DestroyContext(ss->ssl3.hs.sha, PR_TRUE);
     }
+    if (ss->ssl3.hs.shaPostHandshake) {
+        PK11_DestroyContext(ss->ssl3.hs.shaPostHandshake, PR_TRUE);
+    }
     if (ss->ssl3.hs.messages.buf) {
         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);
--- a/security/nss/lib/ssl/ssl3prot.h
+++ b/security/nss/lib/ssl/ssl3prot.h
@@ -69,16 +69,17 @@ typedef enum {
 
     /* Alerts for client hello extensions */
     missing_extension = 109,
     unsupported_extension = 110,
     certificate_unobtainable = 111,
     unrecognized_name = 112,
     bad_certificate_status_response = 113,
     bad_certificate_hash_value = 114,
+    certificate_required = 116,
     no_application_protocol = 120,
 
     /* invalid alert */
     no_alert = 256
 } SSL3AlertDescription;
 
 typedef PRUint8 SSL3Random[SSL3_RANDOM_LENGTH];
 
--- a/security/nss/lib/ssl/sslencode.c
+++ b/security/nss/lib/ssl/sslencode.c
@@ -5,16 +5,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nss.h"
 #include "prnetdb.h"
 #include "ssl.h"
 #include "sslimpl.h"
+#include "sslproto.h"
 
 /* Helper function to encode an unsigned integer into a buffer. */
 static void
 ssl_EncodeUintX(PRUint8 *to, PRUint64 value, unsigned int bytes)
 {
     PRUint64 encoded;
 
     PORT_Assert(bytes > 0 && bytes <= sizeof(encoded));
@@ -258,19 +259,21 @@ ssl3_AppendHandshake(sslSocket *ss, cons
         rv = sslBuffer_Grow(&ss->sec.ci.sendBuf, PR_MAX(MIN_SEND_BUF_LENGTH,
                                                         PR_MIN(MAX_SEND_BUF_LENGTH, ss->sec.ci.sendBuf.len + bytes)));
         if (rv != SECSuccess)
             return SECFailure; /* sslBuffer_Grow sets a memory error code. */
         room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len;
     }
 
     PRINT_BUF(60, (ss, "Append to Handshake", (unsigned char *)void_src, bytes));
-    rv = ssl3_UpdateHandshakeHashes(ss, src, bytes);
-    if (rv != SECSuccess)
-        return SECFailure; /* error code set by ssl3_UpdateHandshakeHashes */
+    if (!ss->firstHsDone || ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        rv = ssl3_UpdateHandshakeHashes(ss, src, bytes);
+        if (rv != SECSuccess)
+            return SECFailure; /* error code set by ssl3_UpdateHandshakeHashes */
+    }
 
     while (bytes > room) {
         if (room > 0)
             PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src,
                         room);
         ss->sec.ci.sendBuf.len += room;
         rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
         if (rv != SECSuccess) {
--- a/security/nss/lib/ssl/sslerr.h
+++ b/security/nss/lib/ssl/sslerr.h
@@ -264,15 +264,16 @@ typedef enum {
     SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR = (SSL_ERROR_BASE + 173),
     SSL_ERROR_RX_MALFORMED_DTLS_ACK = (SSL_ERROR_BASE + 174),
     SSL_ERROR_DH_KEY_TOO_LONG = (SSL_ERROR_BASE + 175),
     SSL_ERROR_RX_MALFORMED_ESNI_KEYS = (SSL_ERROR_BASE + 176),
     SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION = (SSL_ERROR_BASE + 177),
     SSL_ERROR_MISSING_ESNI_EXTENSION = (SSL_ERROR_BASE + 178),
     SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE = (SSL_ERROR_BASE + 179),
     SSL_ERROR_MISSING_POST_HANDSHAKE_AUTH_EXTENSION = (SSL_ERROR_BASE + 180),
+    SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT = (SSL_ERROR_BASE + 181),
     SSL_ERROR_END_OF_LIST   /* let the c compiler determine the value of this. */
 } SSLErrorCodes;
 #endif /* NO_SECURITY_ERROR_ENUM */
 
 /* clang-format on */
 
 #endif /* __SSL_ERR_H_ */
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -139,16 +139,21 @@ typedef enum {
 typedef enum {
     ticket_allow_early_data = 1,
     ticket_allow_psk_ke = 2,
     ticket_allow_psk_dhe_ke = 4,
     ticket_allow_psk_auth = 8,
     ticket_allow_psk_sign_auth = 16
 } TLS13SessionTicketFlags;
 
+typedef enum {
+    update_not_requested = 0,
+    update_requested = 1
+} tls13KeyUpdateRequest;
+
 struct sslNamedGroupDefStr {
     /* The name is the value that is encoded on the wire in TLS. */
     SSLNamedGroup name;
     /* The number of bits in the group. */
     unsigned int bits;
     /* The key exchange algorithm this group provides. */
     SSLKEAType keaType;
     /* The OID that identifies the group to PKCS11.  This also determines
@@ -605,16 +610,17 @@ typedef struct SSL3HandshakeStateStr {
     SSL3HandshakeHashType hashType;
     sslBuffer messages; /* Accumulated handshake messages */
     /* 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. */
     PK11Context *md5;
     PK11Context *sha;
+    PK11Context *shaPostHandshake;
     SSLSignatureScheme signatureScheme;
     const ssl3KEADef *kea_def;
     ssl3CipherSuite cipher_suite;
     const ssl3CipherSuiteDef *suite_def;
     sslBuffer msg_body; /* protected by recvBufLock */
                         /* partial handshake message from record layer */
     unsigned int header_bytes;
     /* number of bytes consumed from handshake */
@@ -738,16 +744,21 @@ struct ssl3StateStr {
     ssl3CipherSpec *prSpec; /* pending read spec. */
     ssl3CipherSpec *cwSpec; /* current write spec. */
     ssl3CipherSpec *pwSpec; /* pending write spec. */
 
     /* This is true after the peer requests a key update; false after a key
      * update is initiated locally. */
     PRBool peerRequestedKeyUpdate;
 
+    /* This is true if we deferred sending a key update as
+     * post-handshake auth is in progress. */
+    PRBool keyUpdateDeferred;
+    tls13KeyUpdateRequest deferredKeyUpdateRequest;
+
     /* This is true after the server requests client certificate;
      * false after the client certificate is received.  Used by the
      * server. */
     PRBool clientCertRequested;
 
     CERTCertificate *clientCertificate;   /* used by client */
     SECKEYPrivateKey *clientPrivateKey;   /* used by client */
     CERTCertificateList *clientCertChain; /* used by client */
@@ -1208,25 +1219,34 @@ extern SECStatus ssl_CipherPrefSetDefaul
 
 extern SECStatus ssl3_ConstrainRangeByPolicy(void);
 
 extern SECStatus ssl3_InitState(sslSocket *ss);
 extern SECStatus Null_Cipher(void *ctx, unsigned char *output, unsigned int *outputLen,
                              unsigned int maxOutputLen, const unsigned char *input,
                              unsigned int inputLen);
 extern void ssl3_RestartHandshakeHashes(sslSocket *ss);
+typedef SECStatus (*sslUpdateHandshakeHashes)(sslSocket *ss,
+                                              const unsigned char *b,
+                                              unsigned int l);
 extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket *ss,
                                             const unsigned char *b,
                                             unsigned int l);
+extern SECStatus ssl3_UpdatePostHandshakeHashes(sslSocket *ss,
+                                                const unsigned char *b,
+                                                unsigned int l);
 SECStatus
 ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType type,
                             PRUint32 dtlsSeq,
-                            const PRUint8 *b, PRUint32 length);
+                            const PRUint8 *b, PRUint32 length,
+                            sslUpdateHandshakeHashes cb);
 SECStatus ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType type,
                                    const PRUint8 *b, PRUint32 length);
+SECStatus ssl_HashPostHandshakeMessage(sslSocket *ss, SSLHandshakeType type,
+                                       const PRUint8 *b, PRUint32 length);
 
 /* Returns PR_TRUE if we are still waiting for the server to complete its
  * response to our client second round. Once we've received the Finished from
  * the server then there is no need to check false start.
  */
 extern PRBool ssl3_WaitingForServerSecondRound(sslSocket *ss);
 
 extern PRInt32 ssl3_SendRecord(sslSocket *ss, ssl3CipherSpec *cwSpec,
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -715,17 +715,18 @@ ssl_SecureShutdown(sslSocket *ss, int ns
 
 static SECStatus
 tls13_CheckKeyUpdate(sslSocket *ss, SSLSecretDirection dir)
 {
     PRBool keyUpdate;
     ssl3CipherSpec *spec;
     sslSequenceNumber seqNum;
     sslSequenceNumber margin;
-    SECStatus rv;
+    tls13KeyUpdateRequest keyUpdateRequest;
+    SECStatus rv = SECSuccess;
 
     /* Bug 1413368: enable for DTLS */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 || IS_DTLS(ss)) {
         return SECSuccess;
     }
 
     /* If both sides update at the same number, then this will cause two updates
      * to happen at once. The problem is that the KeyUpdate itself consumes a
@@ -750,19 +751,25 @@ tls13_CheckKeyUpdate(sslSocket *ss, SSLS
     ssl_ReleaseSpecReadLock(ss);
     if (!keyUpdate) {
         return SECSuccess;
     }
 
     SSL_TRC(5, ("%d: SSL[%d]: automatic key update at %llx for %s cipher spec",
                 SSL_GETPID(), ss->fd, seqNum,
                 (dir == ssl_secret_read) ? "read" : "write"));
+    keyUpdateRequest = (dir == ssl_secret_read) ? update_requested : update_not_requested;
     ssl_GetSSL3HandshakeLock(ss);
-    rv = tls13_SendKeyUpdate(ss, (dir == ssl_secret_read) ? update_requested : update_not_requested,
-                             dir == ssl_secret_write /* buffer */);
+    if (ss->ssl3.clientCertRequested) {
+        ss->ssl3.keyUpdateDeferred = PR_TRUE;
+        ss->ssl3.deferredKeyUpdateRequest = keyUpdateRequest;
+    } else {
+        rv = tls13_SendKeyUpdate(ss, keyUpdateRequest,
+                                 dir == ssl_secret_write /* buffer */);
+    }
     ssl_ReleaseSSL3HandshakeLock(ss);
     return rv;
 }
 
 int
 ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
 {
     int rv = 0;
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -254,16 +254,22 @@ tls13_CheckHsState(sslSocket *ss, int er
                 SSL_GETPID(), ss->fd,
                 error_name,
                 tls13_HandshakeState(TLS13_BASE_WAIT_STATE(ss->ssl3.hs.ws)),
                 func, file, line));
     tls13_FatalError(ss, err, unexpected_message);
     return SECFailure;
 }
 
+PRBool
+tls13_IsPostHandshake(const sslSocket *ss)
+{
+    return ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 && ss->firstHsDone;
+}
+
 SSLHashType
 tls13_GetHashForCipherSuite(ssl3CipherSuite suite)
 {
     const ssl3CipherSuiteDef *cipherDef =
         ssl_LookupCipherSuiteDef(suite);
     PORT_Assert(cipherDef);
     if (!cipherDef) {
         return ssl_hash_none;
@@ -677,18 +683,19 @@ tls13_SendKeyUpdate(sslSocket *ss, tls13
     SECStatus rv;
 
     SSL_TRC(3, ("%d: TLS13[%d]: %s send key update, response %s",
                 SSL_GETPID(), ss->fd, SSL_ROLE(ss),
                 (request == update_requested) ? "requested"
                                               : "not requested"));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
-
-    if (!ss->firstHsDone) {
+    PORT_Assert(!ss->sec.isServer || !ss->ssl3.clientCertRequested);
+
+    if (!tls13_IsPostHandshake(ss)) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_LIBRARY_FAILURE,
                               idle_handshake);
     if (rv != SECSuccess) {
         return SECFailure;
@@ -736,21 +743,26 @@ SECStatus
 SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate)
 {
     SECStatus rv;
     sslSocket *ss = ssl_FindSocket(fd);
     if (!ss) {
         return SECFailure;
     }
 
-    if (!ss->firstHsDone) {
+    if (!tls13_IsPostHandshake(ss)) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
+    if (ss->ssl3.clientCertRequested) {
+        PORT_SetError(PR_WOULD_BLOCK_ERROR);
+        return SECFailure;
+    }
+
     rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_INVALID_ARGS,
                               idle_handshake);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     ssl_GetSSL3HandshakeLock(ss);
     rv = tls13_SendKeyUpdate(ss, requestUpdate ? update_requested : update_not_requested,
@@ -781,17 +793,17 @@ tls13_HandleKeyUpdate(sslSocket *ss, PRU
 
     SSL_TRC(3, ("%d: TLS13[%d]: %s handle key update",
                 SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     PORT_Assert(ss->firstHsDone);
-    if (!ss->firstHsDone) {
+    if (!tls13_IsPostHandshake(ss)) {
         FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE, unexpected_message);
         return SECFailure;
     }
 
     rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE,
                               idle_handshake);
     if (rv != SECSuccess) {
         /* We should never be idle_handshake prior to firstHsDone. */
@@ -815,17 +827,22 @@ tls13_HandleKeyUpdate(sslSocket *ss, PRU
 
     rv = tls13_UpdateTrafficKeys(ss, ssl_secret_read);
     if (rv != SECSuccess) {
         return SECFailure; /* Error code set by tls13_UpdateTrafficKeys. */
     }
 
     if (update == update_requested) {
         PRBool sendUpdate;
-        if (ss->ssl3.peerRequestedKeyUpdate) {
+        if (ss->ssl3.clientCertRequested) {
+            /* Post-handshake auth is in progress; defer sending a key update. */
+            ss->ssl3.keyUpdateDeferred = PR_TRUE;
+            ss->ssl3.deferredKeyUpdateRequest = update_not_requested;
+            sendUpdate = PR_FALSE;
+        } else if (ss->ssl3.peerRequestedKeyUpdate) {
             /* Only send an update if we have sent with the current spec.  This
              * prevents us from being forced to crank forward pointlessly. */
             ssl_GetSpecReadLock(ss);
             sendUpdate = ss->ssl3.cwSpec->nextSeqNum > 0;
             ssl_ReleaseSpecReadLock(ss);
         } else {
             sendUpdate = PR_TRUE;
         }
@@ -852,17 +869,17 @@ SSLExp_SendCertificateRequest(PRFileDesc
     }
 
     /* Not supported. */
     if (IS_DTLS(ss)) {
         PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION);
         return SECFailure;
     }
 
-    if (!ss->firstHsDone || ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+    if (!tls13_IsPostHandshake(ss)) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
     if (ss->ssl3.clientCertRequested) {
         PORT_SetError(PR_WOULD_BLOCK_ERROR);
         return SECFailure;
     }
@@ -2190,20 +2207,30 @@ tls13_HandleClientKeyShare(sslSocket *ss
  *         CertificateExtension certificate_extensions<0..2^16-1>;
  *     } CertificateRequest;
  */
 static SECStatus
 tls13_SendCertificateRequest(sslSocket *ss)
 {
     SECStatus rv;
     sslBuffer extensionBuf = SSL_BUFFER_EMPTY;
+    unsigned int offset = 0;
 
     SSL_TRC(3, ("%d: TLS13[%d]: begin send certificate_request",
                 SSL_GETPID(), ss->fd));
 
+    if (ss->firstHsDone) {
+        PORT_Assert(ss->ssl3.hs.shaPostHandshake == NULL);
+        ss->ssl3.hs.shaPostHandshake = PK11_CloneContext(ss->ssl3.hs.sha);
+        if (ss->ssl3.hs.shaPostHandshake == NULL) {
+            ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+            return SECFailure;
+        }
+    }
+
     rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_certificate_request);
     if (rv != SECSuccess) {
         return SECFailure; /* Code already set. */
     }
     /* We should always have at least one of these. */
     PORT_Assert(SSL_BUFFER_LEN(&extensionBuf) > 0);
 
     /* Create a new request context for post-handshake authentication */
@@ -2217,16 +2244,18 @@ tls13_SendCertificateRequest(sslSocket *
         }
 
         SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
         rv = SECITEM_CopyItem(NULL, &ss->xtnData.certReqContext, &contextItem);
         if (rv != SECSuccess) {
             FATAL_ERROR(ss, SEC_ERROR_NO_MEMORY, internal_error);
             goto loser;
         }
+
+        offset = SSL_BUFFER_LEN(&ss->sec.ci.sendBuf);
     }
 
     rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request,
                                     1 + /* request context length */
                                         ss->xtnData.certReqContext.len +
                                         2 + /* extension length */
                                         SSL_BUFFER_LEN(&extensionBuf));
     if (rv != SECSuccess) {
@@ -2240,16 +2269,25 @@ tls13_SendCertificateRequest(sslSocket *
         goto loser; /* err set by AppendHandshake. */
     }
     /* Extensions. */
     rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
 
+    if (ss->firstHsDone) {
+        rv = ssl3_UpdatePostHandshakeHashes(ss,
+                                            SSL_BUFFER_BASE(&ss->sec.ci.sendBuf) + offset,
+                                            SSL_BUFFER_LEN(&ss->sec.ci.sendBuf) - offset);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
+    }
+
     sslBuffer_Clear(&extensionBuf);
     return SECSuccess;
 
 loser:
     sslBuffer_Clear(&extensionBuf);
     return SECFailure;
 }
 
@@ -2405,17 +2443,29 @@ tls13_HandleCertificateRequest(sslSocket
     } else {
         rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST,
                                   wait_cert_request);
     }
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
-    if (ss->firstHsDone) {
+    if (tls13_IsPostHandshake(ss)) {
+        PORT_Assert(ss->ssl3.hs.shaPostHandshake == NULL);
+        ss->ssl3.hs.shaPostHandshake = PK11_CloneContext(ss->ssl3.hs.sha);
+        if (ss->ssl3.hs.shaPostHandshake == NULL) {
+            ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+            return SECFailure;
+        }
+        rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_certificate_request, b, length);
+        if (rv != SECSuccess) {
+            FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+            return SECFailure;
+        }
+
         /* clean up anything left from previous handshake. */
         if (ss->ssl3.clientCertChain != NULL) {
             CERT_DestroyCertificateList(ss->ssl3.clientCertChain);
             ss->ssl3.clientCertChain = NULL;
         }
         if (ss->ssl3.clientCertificate != NULL) {
             CERT_DestroyCertificate(ss->ssl3.clientCertificate);
             ss->ssl3.clientCertificate = NULL;
@@ -2436,17 +2486,17 @@ tls13_HandleCertificateRequest(sslSocket
 
     rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     /* Unless it is a post-handshake client auth, the certificate
      * request context must be empty. */
-    if (!ss->firstHsDone && context.len > 0) {
+    if (!tls13_IsPostHandshake(ss) && context.len > 0) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, illegal_parameter);
         return SECFailure;
     }
 
     rv = ssl3_ConsumeHandshakeVariable(ss, &extensionsData, 2, &b, &length);
     if (rv != SECSuccess) {
         return SECFailure;
     }
@@ -2496,16 +2546,19 @@ tls13_HandleCertificateRequest(sslSocket
             if (sendAlert != no_alert) {
                 FATAL_ERROR(ss, PORT_GetError(), sendAlert);
             } else {
                 LOG_ERROR(ss, PORT_GetError());
             }
             return SECFailure;
         }
         PORT_Assert(ss->ssl3.hs.ws == idle_handshake);
+        PORT_Assert(ss->ssl3.hs.shaPostHandshake != NULL);
+        PK11_DestroyContext(ss->ssl3.hs.shaPostHandshake, PR_TRUE);
+        ss->ssl3.hs.shaPostHandshake = NULL;
     } else {
         TLS13_SET_HS_STATE(ss, wait_server_cert);
     }
     return SECSuccess;
 }
 
 PRBool
 tls13_ShouldRequestClientAuth(sslSocket *ss)
@@ -3053,16 +3106,25 @@ tls13_HandleCertificate(sslSocket *ss, P
     if (rv != SECSuccess)
         return SECFailure;
 
     /* We can ignore any other cleartext from the client. */
     if (ss->sec.isServer && IS_DTLS(ss)) {
         ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read, TrafficKeyClearText);
         dtls_ReceivedFirstMessageInFlight(ss);
     }
+
+    if (ss->firstHsDone) {
+        rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_certificate, b, length);
+        if (rv != SECSuccess) {
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return SECFailure;
+        }
+    }
+
     /* Process the context string */
     rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
     if (rv != SECSuccess)
         return SECFailure;
 
     if (ss->ssl3.clientCertRequested) {
         PORT_Assert(ss->sec.isServer);
         if (SECITEM_CompareItem(&context, &ss->xtnData.certReqContext) != 0) {
@@ -3610,17 +3672,21 @@ tls13_ComputeHandshakeHashes(sslSocket *
 
         if (PK11_DigestOp(ctx,
                           ss->ssl3.hs.messages.buf,
                           ss->ssl3.hs.messages.len) != SECSuccess) {
             ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
             goto loser;
         }
     } else {
-        ctx = PK11_CloneContext(ss->ssl3.hs.sha);
+        if (ss->firstHsDone) {
+            ctx = PK11_CloneContext(ss->ssl3.hs.shaPostHandshake);
+        } else {
+            ctx = PK11_CloneContext(ss->ssl3.hs.sha);
+        }
         if (!ctx) {
             ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
             return SECFailure;
         }
     }
 
     rv = PK11_DigestFinal(ctx, hashes->u.raw,
                           &hashes->len,
@@ -4064,17 +4130,21 @@ tls13_HandleCertificateVerify(sslSocket 
         return SECFailure;
     }
 
     rv = tls13_ComputeHandshakeHashes(ss, &hashes);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
-    rv = ssl_HashHandshakeMessage(ss, ssl_hs_certificate_verify, b, length);
+    if (ss->firstHsDone) {
+        rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_certificate_verify, b, length);
+    } else {
+        rv = ssl_HashHandshakeMessage(ss, ssl_hs_certificate_verify, b, length);
+    }
     if (rv != SECSuccess) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_VERIFY, illegal_parameter);
@@ -4124,20 +4194,16 @@ tls13_HandleCertificateVerify(sslSocket 
             ss, ss->xtnData.sigSchemes, ss->xtnData.numSigSchemes,
             &ss->xtnData.certReqAuthorities);
         if (rv != SECSuccess) {
             FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
             return rv;
         }
     }
 
-    if (ss->ssl3.clientCertRequested) {
-        PORT_Assert(ss->sec.isServer);
-        ss->ssl3.clientCertRequested = PR_FALSE;
-    }
     TLS13_SET_HS_STATE(ss, wait_finished);
 
     return SECSuccess;
 }
 
 static SECStatus
 tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefixLength,
                            SSL3Hashes *hashes)
@@ -4388,17 +4454,21 @@ tls13_CommonHandleFinished(sslSocket *ss
     ss->ssl3.hs.endOfFlight = PR_TRUE;
 
     rv = tls13_ComputeHandshakeHashes(ss, &hashes);
     if (rv != SECSuccess) {
         LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
-    rv = ssl_HashHandshakeMessage(ss, ssl_hs_finished, b, length);
+    if (ss->firstHsDone) {
+        rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_finished, b, length);
+    } else {
+        rv = ssl_HashHandshakeMessage(ss, ssl_hs_finished, b, length);
+    }
     if (rv != SECSuccess) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     return tls13_VerifyFinished(ss, ssl_hs_finished,
                                 key, b, length, &hashes);
 }
@@ -4438,16 +4508,32 @@ tls13_ServerHandleFinished(sslSocket *ss
                                     ss->firstHsDone ? ss->ssl3.hs.clientTrafficSecret : ss->ssl3.hs.clientHsTrafficSecret,
                                     b, length);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     if (ss->firstHsDone) {
         TLS13_SET_HS_STATE(ss, idle_handshake);
+
+        PORT_Assert(ss->ssl3.hs.shaPostHandshake != NULL);
+        PK11_DestroyContext(ss->ssl3.hs.shaPostHandshake, PR_TRUE);
+        ss->ssl3.hs.shaPostHandshake = NULL;
+
+        ss->ssl3.clientCertRequested = PR_FALSE;
+
+        if (ss->ssl3.keyUpdateDeferred) {
+            rv = tls13_SendKeyUpdate(ss, ss->ssl3.deferredKeyUpdateRequest,
+                                     PR_FALSE);
+            if (rv != SECSuccess) {
+                return SECFailure; /* error is set. */
+            }
+            ss->ssl3.keyUpdateDeferred = PR_FALSE;
+        }
+
         return SECSuccess;
     }
 
     if (!tls13_ShouldRequestClientAuth(ss) &&
         (ss->ssl3.hs.zeroRttState != ssl_0rtt_done)) {
         dtls_ReceivedFirstMessageInFlight(ss);
     }
 
@@ -4520,52 +4606,80 @@ tls13_FinishHandshake(sslSocket *ss)
 
 /* Do the parts of sending the client's second round that require
  * the XmitBuf lock. */
 static SECStatus
 tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert,
                              SSL3AlertDescription *sendAlert)
 {
     SECStatus rv;
+    unsigned int offset = 0;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
 
     *sendAlert = internal_error;
 
+    if (ss->firstHsDone) {
+        offset = SSL_BUFFER_LEN(&ss->sec.ci.sendBuf);
+    }
+
     if (ss->ssl3.sendEmptyCert) {
         ss->ssl3.sendEmptyCert = PR_FALSE;
         rv = ssl3_SendEmptyCertificate(ss);
         /* Don't send verify */
         if (rv != SECSuccess) {
             return SECFailure; /* error code is set. */
         }
     } else if (sendClientCert) {
         rv = tls13_SendCertificate(ss);
         if (rv != SECSuccess) {
             return SECFailure; /* error code is set. */
         }
     }
+
+    if (ss->firstHsDone) {
+        rv = ssl3_UpdatePostHandshakeHashes(ss,
+                                            SSL_BUFFER_BASE(&ss->sec.ci.sendBuf) + offset,
+                                            SSL_BUFFER_LEN(&ss->sec.ci.sendBuf) - offset);
+        if (rv != SECSuccess) {
+            return SECFailure; /* error code is set. */
+        }
+    }
+
     if (ss->ssl3.hs.clientCertRequested) {
         SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
         if (ss->xtnData.certReqAuthorities.arena) {
             PORT_FreeArena(ss->xtnData.certReqAuthorities.arena, PR_FALSE);
             ss->xtnData.certReqAuthorities.arena = NULL;
         }
         PORT_Memset(&ss->xtnData.certReqAuthorities, 0,
                     sizeof(ss->xtnData.certReqAuthorities));
         ss->ssl3.hs.clientCertRequested = PR_FALSE;
     }
 
     if (sendClientCert) {
+        if (ss->firstHsDone) {
+            offset = SSL_BUFFER_LEN(&ss->sec.ci.sendBuf);
+        }
+
         rv = tls13_SendCertificateVerify(ss, ss->ssl3.clientPrivateKey);
         SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
         ss->ssl3.clientPrivateKey = NULL;
         if (rv != SECSuccess) {
             return SECFailure; /* err is set. */
         }
+
+        if (ss->firstHsDone) {
+            rv = ssl3_UpdatePostHandshakeHashes(ss,
+                                                SSL_BUFFER_BASE(&ss->sec.ci.sendBuf) + offset,
+                                                SSL_BUFFER_LEN(&ss->sec.ci.sendBuf) - offset);
+            if (rv != SECSuccess) {
+                return SECFailure; /* error is set. */
+            }
+        }
     }
 
     rv = tls13_SendFinished(ss, ss->firstHsDone ? ss->ssl3.hs.clientTrafficSecret : ss->ssl3.hs.clientHsTrafficSecret);
     if (rv != SECSuccess) {
         return SECFailure; /* err code was set. */
     }
     rv = ssl3_FlushHandshake(ss, 0);
     if (rv != SECSuccess) {
@@ -4820,18 +4934,17 @@ SSLExp_SendSessionTicket(PRFileDesc *fd,
         return SECFailure;
     }
 
     if (IS_DTLS(ss)) {
         PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION);
         return SECFailure;
     }
 
-    if (!ss->sec.isServer || !ss->firstHsDone ||
-        ss->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
+    if (!ss->sec.isServer || !tls13_IsPostHandshake(ss) ||
         tokenLen > 0xffff) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
     ssl_GetSSL3HandshakeLock(ss);
     ssl_GetXmitBufLock(ss);
     rv = tls13_SendNewSessionTicket(ss, token, tokenLen);
@@ -4857,17 +4970,17 @@ tls13_HandleNewSessionTicket(sslSocket *
     SSL_TRC(3, ("%d: TLS13[%d]: handle new session ticket message",
                 SSL_GETPID(), ss->fd));
 
     rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET,
                               idle_handshake);
     if (rv != SECSuccess) {
         return SECFailure;
     }
-    if (!ss->firstHsDone || ss->sec.isServer) {
+    if (!tls13_IsPostHandshake(ss) || ss->sec.isServer) {
         FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET,
                     unexpected_message);
         return SECFailure;
     }
 
     ticket.received_timestamp = ssl_TimeUsec();
     rv = ssl3_ConsumeHandshakeNumber(ss, &ticket.ticket_lifetime_hint, 4, &b,
                                      &length);
--- a/security/nss/lib/ssl/tls13con.h
+++ b/security/nss/lib/ssl/tls13con.h
@@ -13,21 +13,16 @@
 #include "sslspec.h"
 
 typedef enum {
     tls13_extension_allowed,
     tls13_extension_disallowed,
     tls13_extension_unknown
 } tls13ExtensionStatus;
 
-typedef enum {
-    update_not_requested = 0,
-    update_requested = 1
-} tls13KeyUpdateRequest;
-
 #define TLS13_MAX_FINISHED_SIZE 64
 
 SECStatus tls13_UnprotectRecord(
     sslSocket *ss, ssl3CipherSpec *spec,
     SSL3Ciphertext *cText, sslBuffer *plaintext,
     SSLContentType *innerType,
     SSL3AlertDescription *alert);
 
@@ -42,16 +37,18 @@ void tls13_SetHsState(sslSocket *ss, SSL
 
 /* Return PR_TRUE if the socket is in one of the given states, else return
  * PR_FALSE. Only call the macro not the function, because the trailing
  * wait_invalid is needed to terminate the argument list. */
 PRBool tls13_InHsState(sslSocket *ss, ...);
 #define TLS13_IN_HS_STATE(ss, ...) \
     tls13_InHsState(ss, __VA_ARGS__, wait_invalid)
 
+PRBool tls13_IsPostHandshake(const sslSocket *ss);
+
 SSLHashType tls13_GetHashForCipherSuite(ssl3CipherSuite suite);
 SSLHashType tls13_GetHash(const sslSocket *ss);
 unsigned int tls13_GetHashSizeForHash(SSLHashType hash);
 unsigned int tls13_GetHashSize(const sslSocket *ss);
 CK_MECHANISM_TYPE tls13_GetHkdfMechanism(sslSocket *ss);
 CK_MECHANISM_TYPE tls13_GetHkdfMechanismForHash(SSLHashType hash);
 SECStatus tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes,
                             const PRUint8 *buf, unsigned int len);
--- a/security/nss/lib/ssl/tls13hashstate.c
+++ b/security/nss/lib/ssl/tls13hashstate.c
@@ -152,33 +152,35 @@ tls13_RecoverHashState(sslSocket *ss,
     if (hashLen != tls13_GetHashSize(ss)) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
         return SECFailure;
     }
 
     /* Now reinject the message. */
     SSL_ASSERT_HASHES_EMPTY(ss);
     rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_message_hash, 0,
-                                     SSL_READER_CURRENT(&reader), hashLen);
+                                     SSL_READER_CURRENT(&reader), hashLen,
+                                     ssl3_UpdateHandshakeHashes);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     /* And finally reinject the HRR. */
     rv = tls13_ConstructHelloRetryRequest(ss, cipherSuite,
                                           selectedGroup,
                                           cookie, cookieLen,
                                           &messageBuf);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_server_hello, 0,
                                      SSL_BUFFER_BASE(&messageBuf),
-                                     SSL_BUFFER_LEN(&messageBuf));
+                                     SSL_BUFFER_LEN(&messageBuf),
+                                     ssl3_UpdateHandshakeHashes);
     sslBuffer_Clear(&messageBuf);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     *previousCipherSuite = cipherSuite;
     *previousGroup = selectedGroup;
     return SECSuccess;
--- a/security/nss/lib/util/pkcs11n.h
+++ b/security/nss/lib/util/pkcs11n.h
@@ -225,16 +225,18 @@
 #define CKM_NSS_CHACHA20_POLY1305 (CKM_NSS + 28)
 
 /* Additional PKCS #12 PBE algorithms defined in v1.1 */
 #define CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN (CKM_NSS + 29)
 #define CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN (CKM_NSS + 30)
 #define CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN (CKM_NSS + 31)
 #define CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN (CKM_NSS + 32)
 
+#define CKM_NSS_CHACHA20_CTR (CKM_NSS + 33)
+
 /*
  * HISTORICAL:
  * Do not attempt to use these. They are only used by NETSCAPE's internal
  * PKCS #11 interface. Most of these are place holders for other mechanism
  * and will change in the future.
  */
 #define CKM_NETSCAPE_PBE_SHA1_DES_CBC 0x80000002UL
 #define CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC 0x80000003UL
--- a/security/nss/tests/ssl/ssl.sh
+++ b/security/nss/tests/ssl/ssl.sh
@@ -215,28 +215,30 @@ start_selfserv()
   else
       ECC_OPTIONS=""
   fi
   if [ -z "$RSA_PSS_CERT" -o "$RSA_PSS_CERT" != "1" ] ; then
       RSA_OPTIONS="-n ${HOSTADDR}"
   else
       RSA_OPTIONS="-n ${HOSTADDR}-rsa-pss"
   fi
+  SERVER_VMIN=${SERVER_VMIN-ssl3}
+  SERVER_VMAX=${SERVER_VMAX-tls1.2}
   echo "selfserv starting at `date`"
   echo "selfserv -D -p ${PORT} -d ${P_R_SERVERDIR} ${RSA_OPTIONS} ${SERVER_OPTIONS} \\"
   echo "         ${ECC_OPTIONS} -S ${HOSTADDR}-dsa -w nss "$@" -i ${R_SERVERPID}\\"
-  echo "         -V ssl3:tls1.2 $verbose -H 1 &"
+  echo "         -V ${SERVER_VMIN}:${SERVER_VMAX} $verbose -H 1 &"
   if [ ${fileout} -eq 1 ]; then
       ${PROFTOOL} ${BINDIR}/selfserv -D -p ${PORT} -d ${P_R_SERVERDIR} ${RSA_OPTIONS} ${SERVER_OPTIONS} \
-               ${ECC_OPTIONS} -S ${HOSTADDR}-dsa -w nss "$@" -i ${R_SERVERPID} -V ssl3:tls1.2 $verbose -H 1 \
+               ${ECC_OPTIONS} -S ${HOSTADDR}-dsa -w nss "$@" -i ${R_SERVERPID} -V ${SERVER_VMIN}:${SERVER_VMAX} $verbose -H 1 \
                > ${SERVEROUTFILE} 2>&1 &
       RET=$?
   else
       ${PROFTOOL} ${BINDIR}/selfserv -D -p ${PORT} -d ${P_R_SERVERDIR} ${RSA_OPTIONS} ${SERVER_OPTIONS} \
-               ${ECC_OPTIONS} -S ${HOSTADDR}-dsa -w nss "$@" -i ${R_SERVERPID} -V ssl3:tls1.2 $verbose -H 1 &
+               ${ECC_OPTIONS} -S ${HOSTADDR}-dsa -w nss "$@" -i ${R_SERVERPID} -V ${SERVER_VMIN}:${SERVER_VMAX} $verbose -H 1 &
       RET=$?
   fi
 
   # The PID $! returned by the MKS or Cygwin shell is not the PID of
   # the real background process, but rather the PID of a helper
   # process (sh.exe).  MKS's kill command has a bug: invoking kill
   # on the helper process does not terminate the real background
   # process.  Our workaround has been to have selfserv save its PID
@@ -383,27 +385,36 @@ ssl_auth()
   #verbose="-v"
   html_head "SSL Client Authentication $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
 
   ignore_blank_lines ${SSLAUTH} | \
   while read ectype value sparam cparam testname
   do
       echo "${testname}" | grep "don't require client auth" > /dev/null
       CAUTH=$?
+      echo "${testname}" | grep "TLS 1.3" > /dev/null
+      TLS13=$?
 
       if [ "${CLIENT_MODE}" = "fips" -a "${CAUTH}" -eq 0 ] ; then
           echo "$SCRIPTNAME: skipping  $testname (non-FIPS only)"
       elif [ "$ectype" = "SNI" -a "$NORM_EXT" = "Extended Test" ] ; then
           echo "$SCRIPTNAME: skipping  $testname for $NORM_EXT"
       else
           cparam=`echo $cparam | sed -e 's;_; ;g' -e "s/TestUser/$USER_NICKNAME/g" `
           if [ "$ectype" = "SNI" ]; then
               cparam=`echo $cparam | sed -e "s/Host/$HOST/g" -e "s/Dom/$DOMSUF/g" `
               sparam=`echo $sparam | sed -e "s/Host/$HOST/g" -e "s/Dom/$DOMSUF/g" `
           fi
+	  # SSL3 cannot be used with TLS 1.3
+	  unset SERVER_VMIN
+	  unset SERVER_VMAX
+	  if [ $TLS13 -eq 0 ] ; then
+	      SERVER_VMIN=tls1.0
+	      SERVER_VMAX=tls1.3
+	  fi
           start_selfserv `echo "$sparam" | sed -e 's,_, ,g'`
 
           echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
           echo "        ${cparam}  < ${REQUEST_FILE}"
           rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
           ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${cparam} $verbose ${CLIENT_OPTIONS} \
                   -d ${P_R_CLIENTDIR} < ${REQUEST_FILE} \
                   >${TMP}/$HOST.tmp.$$  2>&1
@@ -664,19 +675,28 @@ ssl_crl_ssl()
   # Cert number $UNREVOKED_CERT_GRP_1 was not revoked
   CRL_GROUP_BEGIN=$CRL_GRP_1_BEGIN
   CRL_GROUP_RANGE=$CRL_GRP_1_RANGE
   UNREVOKED_CERT=$UNREVOKED_CERT_GRP_1
 
   ignore_blank_lines ${SSLAUTH} | \
   while read ectype value sparam cparam testname
   do
+    echo "${testname}" | grep "TLS 1.3" > /dev/null
+    TLS13=$?
     if [ "$ectype" = "SNI" ]; then
         continue
     else
+        # SSL3 cannot be used with TLS 1.3
+        unset SERVER_VMIN
+        unset SERVER_VMAX
+        if [ $TLS13 -eq 0 ] ; then
+            SERVER_VMIN=tls1.0
+            SERVER_VMAX=tls1.3
+        fi
         servarg=`echo $sparam | awk '{r=split($0,a,"-r") - 1;print r;}'`
         pwd=`echo $cparam | grep nss`
         user=`echo $cparam | grep TestUser`
         _cparam=$cparam
         case $servarg in
             1) if [ -z "$pwd" -o -z "$user" ]; then
                  rev_modvalue=0
                else
@@ -1034,17 +1054,17 @@ ssl_crl_cache()
 {
   #verbose="-v"
   html_head "Cache CRL SSL Client Tests $NORM_EXT"
   SSLAUTH_TMP=${TMP}/authin.tl.tmp
   SERV_ARG=-r_-r
   rm -f ${SSLAUTH_TMP}
   echo ${SSLAUTH_TMP}
 
-  grep -- " $SERV_ARG " ${SSLAUTH} | grep -v "^#" | grep -v none | grep -v bogus > ${SSLAUTH_TMP}
+  grep -- " $SERV_ARG " ${SSLAUTH} | grep -v "^#" | grep -v none | grep -v bogus | grep -v 'post hs' > ${SSLAUTH_TMP}
   echo $?
   while [ $? -eq 0 -a -f ${SSLAUTH_TMP} ]
     do
     start_selfserv `echo $SERV_ARG | sed -e 's,_, ,g'`
     exec < ${SSLAUTH_TMP}
     while read ectype value sparam cparam testname
       do
       [ "$ectype" = "" ] && continue
--- a/security/nss/tests/ssl/sslauth.txt
+++ b/security/nss/tests/ssl/sslauth.txt
@@ -33,16 +33,20 @@
   noECC     1       -r_-r_-r_-r  -V_ssl3:tls1.0_-w_bogus_-n_TestUser  TLS 1.0 Require client auth on 2nd hs (bad password)
   noECC     0       -r_-r_-r_-r  -V_ssl3:tls1.0_-w_nss_-n_TestUser    TLS 1.0 Require client auth on 2nd hs (client auth)
   noECC     0       -r_-r_-r     -V_ssl3:ssl3_-w_nss_-n_none     SSL3 Request don't require client auth on 2nd hs (client does not provide auth)
   noECC     0       -r_-r_-r     -V_ssl3:ssl3_-n_TestUser_-w_bogus SSL3 Request don't require client auth on 2nd hs (bad password)
   noECC     0       -r_-r_-r     -V_ssl3:ssl3_-n_TestUser_-w_nss SSL3 Request don't require client auth on 2nd hs (client auth)
   noECC     1       -r_-r_-r_-r  -V_ssl3:ssl3_-w_nss_-n_none     SSL3 Require client auth on 2nd hs (client does not provide auth)
   noECC     1       -r_-r_-r_-r  -V_ssl3:ssl3_-n_TestUser_-w_bogus SSL3 Require client auth on 2nd hs (bad password)
   noECC     0       -r_-r_-r_-r  -V_ssl3:ssl3_-n_TestUser_-w_nss SSL3 Require client auth on 2nd hs (client auth)
+  noECC     0       -r_-r_-r_-E  -V_tls1.3:tls1.3_-E_-n_TestUser_-w_nss TLS 1.3 Request don't require client auth on post hs (client auth)
+  noECC     0       -r_-r_-r_-r_-E  -V_tls1.3:tls1.3_-E_-n_TestUser_-w_nss TLS 1.3 Require client auth on post hs (client auth)
+  noECC     0       -r_-r_-r_-E  -V_tls1.3:tls1.3_-E_-n_none_-w_nss TLS 1.3 Request don't require client auth on post hs (client does not provide auth)
+  noECC     1       -r_-r_-r_-r_-E  -V_tls1.3:tls1.3_-E_-n_none_-w_nss TLS 1.3 Require client auth on post hs (client does not provide auth)
 #
 # Use EC cert for client authentication
 #
    ECC      0       -r           -V_ssl3:tls1.2_-w_bogus_-n_TestUser-ec     TLS Request don't require client auth (EC) (bad password)
    ECC      0       -r           -V_ssl3:tls1.2_-w_nss_-n_TestUser-ec       TLS Request don't require client auth (EC) (client auth)
    ECC     254      -r_-r        -V_ssl3:tls1.2_-w_bogus_-n_TestUser-ec     TLS Require client auth (EC) (bad password)
    ECC      0       -r_-r        -V_ssl3:tls1.2_-w_nss_-n_TestUser-ec_      TLS Require client auth (EC) (client auth)
    ECC      0       -r           -V_ssl3:ssl3_-n_TestUser-ec_-w_bogus  SSL3 Request don't require client auth (EC) (bad password)