Bug 1577822 - land NSS NSS_3_47_BETA1 UPGRADE_NSS_RELEASE, r=kjacobs
authorJ.C. Jones <jc@mozilla.com>
Sat, 12 Oct 2019 00:01:25 +0000
changeset 497337 becf56f3cc37db3fc96b4689ac3afe70987b614a
parent 497336 0cf9f22a8c4d84e70f6c6e9006fb9f3d844e53aa
child 497338 1102d533350abd512fe7f424c275664b0e68cb92
push id36682
push userncsoregi@mozilla.com
push dateSat, 12 Oct 2019 09:52:03 +0000
treeherdermozilla-central@06ea2371f897 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskjacobs
bugs1577822, 1583068, 1152625, 1549225, 1586947, 1586456
milestone71.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 1577822 - land NSS NSS_3_47_BETA1 UPGRADE_NSS_RELEASE, r=kjacobs 2019-10-11 Kai Engert <kaie@kuix.de> * automation/release/nspr-version.txt: Bug 1583068 - Require NSPR version 4.23 r=jcj [93245f5733b3] [NSS_3_47_BETA1] 2019-10-11 Kevin Jacobs <kjacobs@mozilla.com> * coreconf/config.gypi, lib/freebl/freebl.gyp: Bug 1152625 - Add gyp flag for disabling ARM HW AES r=jcj Adds an option to disable ARMv8 HW AES, if `-Ddisable_arm_hw_aes=1` is passed to build.sh. Depends on D34473 [9abcea09fdd4] 2019-10-11 Makoto Kato <m_kato@ga2.so-net.ne.jp> * lib/freebl/aes-armv8.c: Bug 1152625 - Part 2. Remove __builtin_assume to avoid crash on PGO. r=kjacobs,mt `AESContext->iv` doesn't align to 16 bytes on PGO build, so we should remove __builtin_assume. Also, I guess that `expandedKey` has same problem. [1b0f5c5335ee] * lib/freebl/Makefile, lib/freebl/aes-armv8.c, lib/freebl/aes-armv8.h, lib/freebl/freebl.gyp, lib/freebl/intel-aes.h, lib/freebl/rijndael.c: Bug 1152625 - Support AES HW acceleration on ARMv8. r=kjacobs,jcj [efb895a43899] 2019-09-06 Martin Thomson <mt@lowentropy.net> * gtests/ssl_gtest/ssl_auth_unittest.cc, gtests/ssl_gtest/ssl_ciphersuite_unittest.cc, gtests/ssl_gtest/ssl_extension_unittest.cc, gtests/ssl_gtest/ssl_fuzz_unittest.cc, gtests/ssl_gtest/tls_esni_unittest.cc, lib/ssl/ssl3con.c, lib/ssl/ssl3exthandle.c, lib/ssl/sslimpl.h, lib/ssl/tls13con.c: Bug 1549225 - Up front Signature Scheme validation, r=ueno Summary: This patch started as an attempt to ensure that a DSA signature scheme would not be advertised if we weren't willing to negotiate versions less than TLS 1.3. Then I realized that we didn't do the same for PKCS#1 RSA. Then I realized that we were still willing to try to establish connections when we had a certificate that we couldn't use. Then I realized that ssl3_config_match_init() wasn't being run consistently. On resumption, we only ran it when we were PARANOID. That's silly because we weren't checking policies. Then I realized that we were allowing ECDSA certificates to be used when the named group in the certificate was disabled. We weren't enforcing that consistently either. However, I also discovered that the check we have wouldn't work without a tweak because in TLS 1.3 the named group is part of the signature scheme; the configured named groups are only used prior to TLS 1.3 when selecting ECDSA/ECDH certificates. So that sounds like a lot of changes but what it boils down to is more robust checking of the configuration prior to starting a connection. As a result, we should be offering fewer options that we're unwilling or unable to follow through on. A good number of tests needed tweaking as a result because we were relying on getting past the checks in those tests. No real problems were found as a result; this just moves failures that might arise from misconfiguration a little earlier in the process. [9b418f0a4912] 2019-10-08 Kevin Jacobs <kjacobs@mozilla.com> * gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc, lib/pk11wrap/pk11pk12.c: Bug 1586947 - Store nickname during EC key import. r=jcj This patch stores the nickname (if specified) during EC key import. This was already done for all other key types. [c319019aee75] 2019-10-08 Marcus Burghardt <mburghardt@mozilla.com> * lib/certdb/stanpcertdb.c, lib/pk11wrap/pk11load.c, lib/pki/pki3hack.c: Bug 1586456 - Unnecessary conditional in pki3hack, pk11load and stanpcertdb. r=jcj Some conditionals that are always true were removed. [b34061c3a377] Differential Revision: https://phabricator.services.mozilla.com/D49030
security/nss/TAG-INFO
security/nss/automation/release/nspr-version.txt
security/nss/coreconf/config.gypi
security/nss/coreconf/coreconf.dep
security/nss/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc
security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
security/nss/gtests/ssl_gtest/tls_esni_unittest.cc
security/nss/lib/certdb/stanpcertdb.c
security/nss/lib/freebl/Makefile
security/nss/lib/freebl/aes-armv8.c
security/nss/lib/freebl/aes-armv8.h
security/nss/lib/freebl/freebl.gyp
security/nss/lib/freebl/intel-aes.h
security/nss/lib/freebl/rijndael.c
security/nss/lib/pk11wrap/pk11load.c
security/nss/lib/pk11wrap/pk11pk12.c
security/nss/lib/pki/pki3hack.c
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3exthandle.c
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/tls13con.c
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-dc86215aea17
\ No newline at end of file
+NSS_3_47_BETA1
\ No newline at end of file
--- a/security/nss/automation/release/nspr-version.txt
+++ b/security/nss/automation/release/nspr-version.txt
@@ -1,9 +1,9 @@
-4.22
+4.23
 
 # The first line of this file must contain the human readable NSPR
 # version number, which is the minimum required version of NSPR
 # that is supported by this version of NSS.
 #
 # This information is used by release automation,
 # when creating an NSS source archive.
 #
--- a/security/nss/coreconf/config.gypi
+++ b/security/nss/coreconf/config.gypi
@@ -91,16 +91,17 @@
     'sqlite_libs%': ['-lsqlite3'],
     'dll_prefix': '<(dll_prefix)',
     'dll_suffix': '<(dll_suffix)',
     'freebl_name': '<(freebl_name)',
     'cc_is_clang%': '<(cc_is_clang)',
     'cc_is_gcc%': '<(cc_is_gcc)',
     'cc_use_gnu_ld%': '<(cc_use_gnu_ld)',
     # Some defaults
+    'disable_arm_hw_aes%': 0,
     'disable_tests%': 0,
     'disable_chachapoly%': 0,
     'disable_dbm%': 0,
     'disable_libpkix%': 1,
     'disable_werror%': 0,
     'mozilla_client%': 0,
     'comm_client%': 0,
     'moz_fold_libs%': 0,
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * 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/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc
@@ -10,16 +10,30 @@
 #include "pk11pub.h"
 #include "secutil.h"
 
 #include "gtest/gtest.h"
 #include "nss_scoped_ptrs.h"
 
 namespace nss_test {
 
+const std::vector<uint8_t> kValidP256Key = {
+    0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
+    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+    0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20,
+    0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57,
+    0x67, 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12,
+    0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21, 0xa1, 0x44, 0x03, 0x42,
+    0x00, 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, 0x61,
+    0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, 0x61,
+    0xfa, 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, 0x03,
+    0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, 0x28,
+    0xbc, 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, 0xa3,
+    0xc2, 0x94, 0xd4, 0x46, 0x22, 0x99};
+
 const std::vector<uint8_t> kValidRSAKey = {
     // 512-bit RSA private key (PKCS#8)
     0x30, 0x82, 0x01, 0x54, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
     0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
     0x01, 0x3e, 0x30, 0x82, 0x01, 0x3a, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00,
     0xa2, 0x40, 0xce, 0xb5, 0x4e, 0x70, 0xdc, 0x14, 0x82, 0x5b, 0x58, 0x7d,
     0x2f, 0x5d, 0xfd, 0x46, 0x3c, 0x4b, 0x82, 0x50, 0xb6, 0x96, 0x00, 0x4a,
     0x1a, 0xca, 0xaf, 0xe4, 0x9b, 0xcf, 0x38, 0x4a, 0x46, 0xaa, 0x9f, 0xb4,
@@ -68,43 +82,81 @@ const std::vector<uint8_t> kInvalidZeroL
     0x2a, 0x86, 0x48, 0xce, 0x3e, 0x02, 0x01, 0x06, 0x08,  // OID(len=8)
     // prime256v1 (1.2.840.10045.3.1.7) */
     0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04,
     0x00  // OCTET STRING(len=0)
 };
 
 class DERPrivateKeyImportTest : public ::testing::Test {
  public:
-  bool ParsePrivateKey(const std::vector<uint8_t>& data) {
-    ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
-    EXPECT_TRUE(slot);
-
+  bool ParsePrivateKey(const std::vector<uint8_t>& data, bool expect_success) {
     SECKEYPrivateKey* key = nullptr;
+    SECStatus rv = SECFailure;
+    std::string nick_str =
+        ::testing::UnitTest::GetInstance()->current_test_info()->name() +
+        std::to_string(rand());
     SECItem item = {siBuffer, const_cast<unsigned char*>(data.data()),
-                    (unsigned int)data.size()};
+                    static_cast<unsigned int>(data.size())};
+    SECItem nick = {siBuffer, reinterpret_cast<unsigned char*>(
+                                  const_cast<char*>(nick_str.data())),
+                    static_cast<unsigned int>(nick_str.length())};
+
+    ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+    EXPECT_TRUE(slot);
+    if (!slot) {
+      return false;
+    }
+
+    if (PK11_NeedUserInit(slot.get())) {
+      if (PK11_InitPin(slot.get(), nullptr, nullptr) != SECSuccess) {
+        EXPECT_EQ(rv, SECSuccess) << "PK11_InitPin failed";
+      }
+    }
+    rv = PK11_Authenticate(slot.get(), PR_TRUE, nullptr);
+    EXPECT_EQ(rv, SECSuccess);
 
-    SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
-        slot.get(), &item, nullptr, nullptr, false, false, KU_ALL, &key,
-        nullptr);
+    rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
+        slot.get(), &item, &nick, nullptr, true, false, KU_ALL, &key, nullptr);
+    EXPECT_EQ(rv == SECSuccess, key != nullptr);
+
+    if (expect_success) {
+      // Try to find the key via its label
+      ScopedSECKEYPrivateKeyList list(PK11_ListPrivKeysInSlot(
+          slot.get(), const_cast<char*>(nick_str.c_str()), nullptr));
+      EXPECT_FALSE(!list);
+    }
 
-    EXPECT_EQ(rv == SECSuccess, key != nullptr);
-    SECKEY_DestroyPrivateKey(key);
+    if (key) {
+      rv = PK11_DeleteTokenPrivateKey(key, true);
+      EXPECT_EQ(SECSuccess, rv);
+
+      // PK11_DeleteTokenPrivateKey leaves an errorCode set when there's
+      // no cert. This is expected, so clear it.
+      if (PORT_GetError() == SSL_ERROR_NO_CERTIFICATE) {
+        PORT_SetError(0);
+      }
+    }
 
     return rv == SECSuccess;
   }
 };
 
 TEST_F(DERPrivateKeyImportTest, ImportPrivateRSAKey) {
-  EXPECT_TRUE(ParsePrivateKey(kValidRSAKey));
-  EXPECT_FALSE(PORT_GetError());
+  EXPECT_TRUE(ParsePrivateKey(kValidRSAKey, true));
+  EXPECT_FALSE(PORT_GetError()) << PORT_GetError();
+}
+
+TEST_F(DERPrivateKeyImportTest, ImportEcdsaKey) {
+  EXPECT_TRUE(ParsePrivateKey(kValidP256Key, true));
+  EXPECT_FALSE(PORT_GetError()) << PORT_GetError();
 }
 
 TEST_F(DERPrivateKeyImportTest, ImportInvalidPrivateKey) {
-  EXPECT_FALSE(ParsePrivateKey(kInvalidLengthKey));
-  EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_DER);
+  EXPECT_FALSE(ParsePrivateKey(kInvalidLengthKey, false));
+  EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_DER) << PORT_GetError();
 }
 
 TEST_F(DERPrivateKeyImportTest, ImportZeroLengthPrivateKey) {
-  EXPECT_FALSE(ParsePrivateKey(kInvalidZeroLengthKey));
-  EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_KEY);
+  EXPECT_FALSE(ParsePrivateKey(kInvalidZeroLengthKey, false));
+  EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_KEY) << PORT_GetError();
 }
 
 }  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
@@ -778,24 +778,39 @@ TEST_P(TlsConnectTls13, ClientAuthPkcs1S
       client_, kTlsHandshakeCertificateVerify);
   capture_cert_verify->EnableDecryption();
 
   Connect();
   CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pss_rsae_sha256,
                  1024);
 }
 
+// Client should refuse to connect without a usable signature scheme.
 TEST_P(TlsConnectTls13, ClientAuthPkcs1SignatureSchemeOnly) {
   static const SSLSignatureScheme kSignatureScheme[] = {
       ssl_sig_rsa_pkcs1_sha256};
 
   Reset(TlsAgent::kServerRsa, "rsa");
   client_->SetSignatureSchemes(kSignatureScheme,
                                PR_ARRAY_SIZE(kSignatureScheme));
-  server_->SetSignatureSchemes(kSignatureScheme,
+  client_->SetupClientAuth();
+  client_->StartConnect();
+  client_->Handshake();
+  EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
+  client_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
+}
+
+// Though the client has a usable signature scheme, when a certificate is
+// requested, it can't produce one.
+TEST_P(TlsConnectTls13, ClientAuthPkcs1AndEcdsaScheme) {
+  static const SSLSignatureScheme kSignatureScheme[] = {
+      ssl_sig_rsa_pkcs1_sha256, ssl_sig_ecdsa_secp256r1_sha256};
+
+  Reset(TlsAgent::kServerRsa, "rsa");
+  client_->SetSignatureSchemes(kSignatureScheme,
                                PR_ARRAY_SIZE(kSignatureScheme));
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
 
   ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
   server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
   client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
 }
@@ -1428,16 +1443,119 @@ TEST_F(TlsAgentStreamTestServer, Configu
   EXPECT_FALSE(agent_->ConfigServerCert(TlsAgent::kServerRsaPss, false,
                                         &ServerCertDataRsaPkcs1Decrypt));
 
   // Configuring for only rsa_pss should work.
   EXPECT_TRUE(agent_->ConfigServerCert(TlsAgent::kServerRsaPss, false,
                                        &ServerCertDataRsaPss));
 }
 
+// A server should refuse to even start a handshake with
+// misconfigured certificate and signature scheme.
+TEST_P(TlsConnectTls12Plus, MisconfiguredCertScheme) {
+  Reset(TlsAgent::kServerDsa);
+  static const SSLSignatureScheme kScheme[] = {ssl_sig_ecdsa_secp256r1_sha256};
+  server_->SetSignatureSchemes(kScheme, PR_ARRAY_SIZE(kScheme));
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
+  if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
+    // TLS 1.2 disables cipher suites, which leads to a different error.
+    server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+  } else {
+    server_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
+  }
+  client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+}
+
+// In TLS 1.2, disabling an EC group causes ECDSA to be invalid.
+TEST_P(TlsConnectTls12, Tls12CertDisabledGroup) {
+  Reset(TlsAgent::kServerEcdsa256);
+  static const std::vector<SSLNamedGroup> k25519 = {ssl_grp_ec_curve25519};
+  server_->ConfigNamedGroups(k25519);
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
+  server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+  client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+}
+
+// In TLS 1.3, ECDSA configuration only depends on the signature scheme.
+TEST_P(TlsConnectTls13, Tls13CertDisabledGroup) {
+  Reset(TlsAgent::kServerEcdsa256);
+  static const std::vector<SSLNamedGroup> k25519 = {ssl_grp_ec_curve25519};
+  server_->ConfigNamedGroups(k25519);
+  Connect();
+}
+
+// A client should refuse to even start a handshake with only DSA.
+TEST_P(TlsConnectTls13, Tls13DsaOnlyClient) {
+  static const SSLSignatureScheme kDsa[] = {ssl_sig_dsa_sha256};
+  client_->SetSignatureSchemes(kDsa, PR_ARRAY_SIZE(kDsa));
+  client_->StartConnect();
+  client_->Handshake();
+  EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
+  client_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
+}
+
+TEST_P(TlsConnectTls13, Tls13DsaOnlyServer) {
+  Reset(TlsAgent::kServerDsa);
+  static const SSLSignatureScheme kDsa[] = {ssl_sig_dsa_sha256};
+  server_->SetSignatureSchemes(kDsa, PR_ARRAY_SIZE(kDsa));
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
+  server_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
+  client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+}
+
+TEST_P(TlsConnectTls13, Tls13Pkcs1OnlyClient) {
+  static const SSLSignatureScheme kPkcs1[] = {ssl_sig_rsa_pkcs1_sha256};
+  client_->SetSignatureSchemes(kPkcs1, PR_ARRAY_SIZE(kPkcs1));
+  client_->StartConnect();
+  client_->Handshake();
+  EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
+  client_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
+}
+
+TEST_P(TlsConnectTls13, Tls13Pkcs1OnlyServer) {
+  static const SSLSignatureScheme kPkcs1[] = {ssl_sig_rsa_pkcs1_sha256};
+  server_->SetSignatureSchemes(kPkcs1, PR_ARRAY_SIZE(kPkcs1));
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
+  server_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
+  client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+}
+
+TEST_P(TlsConnectTls13, Tls13DsaIsNotAdvertisedClient) {
+  EnsureTlsSetup();
+  static const SSLSignatureScheme kSchemes[] = {ssl_sig_dsa_sha256,
+                                                ssl_sig_rsa_pss_rsae_sha256};
+  client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
+  auto capture =
+      MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
+  Connect();
+  // We should only have the one signature algorithm advertised.
+  static const uint8_t kExpectedExt[] = {0, 2, ssl_sig_rsa_pss_rsae_sha256 >> 8,
+                                         ssl_sig_rsa_pss_rsae_sha256 & 0xff};
+  ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
+            capture->extension());
+}
+
+TEST_P(TlsConnectTls13, Tls13DsaIsNotAdvertisedServer) {
+  EnsureTlsSetup();
+  static const SSLSignatureScheme kSchemes[] = {ssl_sig_dsa_sha256,
+                                                ssl_sig_rsa_pss_rsae_sha256};
+  server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
+  auto capture = MakeTlsFilter<TlsExtensionCapture>(
+      server_, ssl_signature_algorithms_xtn, true);
+  capture->SetHandshakeTypes({kTlsHandshakeCertificateRequest});
+  capture->EnableDecryption();
+  server_->RequestClientAuth(false);  // So we get a CertificateRequest.
+  Connect();
+  // We should only have the one signature algorithm advertised.
+  static const uint8_t kExpectedExt[] = {0, 2, ssl_sig_rsa_pss_rsae_sha256 >> 8,
+                                         ssl_sig_rsa_pss_rsae_sha256 & 0xff};
+  ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
+            capture->extension());
+}
+
 // variant, version, certificate, auth type, signature scheme
 typedef std::tuple<SSLProtocolVariant, uint16_t, std::string, SSLAuthType,
                    SSLSignatureScheme>
     SignatureSchemeProfile;
 
 class TlsSignatureSchemeConfiguration
     : public TlsConnectTestBase,
       public ::testing::WithParamInterface<SignatureSchemeProfile> {
--- a/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
@@ -51,75 +51,93 @@ class TlsCipherSuiteTestBase : public Tl
   void EnableSingleCipher() {
     EnsureTlsSetup();
     // It doesn't matter which does this, but the test is better if both do it.
     client_->EnableSingleCipher(cipher_suite_);
     server_->EnableSingleCipher(cipher_suite_);
 
     if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
       std::vector<SSLNamedGroup> groups = {group_};
+      if (cert_group_ != ssl_grp_none) {
+        groups.push_back(cert_group_);
+      }
       client_->ConfigNamedGroups(groups);
       server_->ConfigNamedGroups(groups);
       kea_type_ = SSLInt_GetKEAType(group_);
 
       client_->SetSignatureSchemes(&sig_scheme_, 1);
       server_->SetSignatureSchemes(&sig_scheme_, 1);
     }
   }
 
   virtual void SetupCertificate() {
     if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
       switch (sig_scheme_) {
         case ssl_sig_rsa_pss_rsae_sha256:
+          std::cerr << "Signature scheme: rsa_pss_rsae_sha256" << std::endl;
+          Reset(TlsAgent::kServerRsaSign);
+          auth_type_ = ssl_auth_rsa_sign;
+          break;
         case ssl_sig_rsa_pss_rsae_sha384:
+          std::cerr << "Signature scheme: rsa_pss_rsae_sha384" << std::endl;
           Reset(TlsAgent::kServerRsaSign);
           auth_type_ = ssl_auth_rsa_sign;
           break;
         case ssl_sig_rsa_pss_rsae_sha512:
           // You can't fit SHA-512 PSS in a 1024-bit key.
+          std::cerr << "Signature scheme: rsa_pss_rsae_sha512" << std::endl;
           Reset(TlsAgent::kRsa2048);
           auth_type_ = ssl_auth_rsa_sign;
           break;
         case ssl_sig_rsa_pss_pss_sha256:
+          std::cerr << "Signature scheme: rsa_pss_pss_sha256" << std::endl;
           Reset(TlsAgent::kServerRsaPss);
           auth_type_ = ssl_auth_rsa_pss;
           break;
         case ssl_sig_rsa_pss_pss_sha384:
+          std::cerr << "Signature scheme: rsa_pss_pss_sha384" << std::endl;
           Reset("rsa_pss384");
           auth_type_ = ssl_auth_rsa_pss;
           break;
         case ssl_sig_rsa_pss_pss_sha512:
+          std::cerr << "Signature scheme: rsa_pss_pss_sha512" << std::endl;
           Reset("rsa_pss512");
           auth_type_ = ssl_auth_rsa_pss;
           break;
         case ssl_sig_ecdsa_secp256r1_sha256:
+          std::cerr << "Signature scheme: ecdsa_secp256r1_sha256" << std::endl;
           Reset(TlsAgent::kServerEcdsa256);
           auth_type_ = ssl_auth_ecdsa;
+          cert_group_ = ssl_grp_ec_secp256r1;
           break;
         case ssl_sig_ecdsa_secp384r1_sha384:
+          std::cerr << "Signature scheme: ecdsa_secp384r1_sha384" << std::endl;
           Reset(TlsAgent::kServerEcdsa384);
           auth_type_ = ssl_auth_ecdsa;
+          cert_group_ = ssl_grp_ec_secp384r1;
           break;
         default:
           ADD_FAILURE() << "Unsupported signature scheme: " << sig_scheme_;
           break;
       }
     } else {
       switch (csinfo_.authType) {
         case ssl_auth_rsa_sign:
           Reset(TlsAgent::kServerRsaSign);
           break;
         case ssl_auth_rsa_decrypt:
           Reset(TlsAgent::kServerRsaDecrypt);
           break;
         case ssl_auth_ecdsa:
           Reset(TlsAgent::kServerEcdsa256);
+          cert_group_ = ssl_grp_ec_secp256r1;
           break;
         case ssl_auth_ecdh_ecdsa:
           Reset(TlsAgent::kServerEcdhEcdsa);
+          cert_group_ = ssl_grp_ec_secp256r1;
           break;
         case ssl_auth_ecdh_rsa:
           Reset(TlsAgent::kServerEcdhRsa);
           break;
         case ssl_auth_dsa:
           Reset(TlsAgent::kServerDsa);
           break;
         default:
@@ -187,16 +205,17 @@ class TlsCipherSuiteTestBase : public Tl
     return limit;
   }
 
  protected:
   uint16_t cipher_suite_;
   SSLAuthType auth_type_;
   SSLKEAType kea_type_;
   SSLNamedGroup group_;
+  SSLNamedGroup cert_group_ = ssl_grp_none;
   SSLSignatureScheme sig_scheme_;
   SSLCipherSuiteInfo csinfo_;
 };
 
 class TlsCipherSuiteTest
     : public TlsCipherSuiteTestBase,
       public ::testing::WithParamInterface<CipherSuiteProfile> {
  public:
--- a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -647,17 +647,17 @@ TEST_P(TlsExtensionTest12, SignatureAlgo
                               0);
   ASSERT_EQ(SECSuccess, rv);
 
   Reset(TlsAgent::kServerDsa);
   auto capture2 =
       MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
   client_->SetSignatureSchemes(schemes.data(), schemes.size());
   ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
-  server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
+  server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
   client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
 
   // Check if no DSA algorithms are advertised.
   EXPECT_TRUE(capture2->captured());
   const DataBuffer& ext2 = capture2->extension();
   EXPECT_EQ(2U + 2U, ext2.len());
   uint32_t v = 0;
   EXPECT_TRUE(ext2.Read(2, 2, &v));
--- a/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
@@ -247,9 +247,9 @@ FUZZ_P(TlsFuzzTest, UnencryptedSessionTi
 INSTANTIATE_TEST_CASE_P(
     FuzzStream, TlsFuzzTest,
     ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
                        TlsConnectTestBase::kTlsVAll));
 INSTANTIATE_TEST_CASE_P(
     FuzzDatagram, TlsFuzzTest,
     ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
                        TlsConnectTestBase::kTlsV11Plus));
-}
+}  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/tls_esni_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/tls_esni_unittest.cc
@@ -467,9 +467,9 @@ TEST_P(TlsConnectTls13, EsniButTLS12Serv
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_2);
   ConnectExpectAlert(client_, kTlsAlertProtocolVersion);
   client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_VERSION);
   server_->CheckErrorCode(SSL_ERROR_PROTOCOL_VERSION_ALERT);
   ASSERT_FALSE(SSLInt_ExtensionNegotiated(server_->ssl_fd(),
                                           ssl_tls13_encrypted_sni_xtn));
 }
-}
+}  // namespace nss_test
--- a/security/nss/lib/certdb/stanpcertdb.c
+++ b/security/nss/lib/certdb/stanpcertdb.c
@@ -407,28 +407,27 @@ CERT_NewTempCertificate(CERTCertDBHandle
     if (!cc) {
         CERT_MapStanError();
         goto loser;
     }
     nssItem_Create(c->object.arena, &c->issuer, cc->derIssuer.len,
                    cc->derIssuer.data);
     nssItem_Create(c->object.arena, &c->subject, cc->derSubject.len,
                    cc->derSubject.data);
-    if (PR_TRUE) {
-        /* CERTCertificate stores serial numbers decoded.  I need the DER
-        * here.  sigh.
-        */
-        SECItem derSerial = { 0 };
-        CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
-        if (!derSerial.data)
-            goto loser;
-        nssItem_Create(c->object.arena, &c->serial, derSerial.len,
-                       derSerial.data);
-        PORT_Free(derSerial.data);
-    }
+    /* CERTCertificate stores serial numbers decoded.  I need the DER
+    * here.  sigh.
+    */
+    SECItem derSerial = { 0 };
+    CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
+    if (!derSerial.data)
+        goto loser;
+    nssItem_Create(c->object.arena, &c->serial, derSerial.len,
+                   derSerial.data);
+    PORT_Free(derSerial.data);
+
     if (nickname) {
         c->object.tempName =
             nssUTF8_Create(c->object.arena, nssStringType_UTF8String,
                            (NSSUTF8 *)nickname, PORT_Strlen(nickname));
     }
     if (cc->emailAddr && cc->emailAddr[0]) {
         c->email = nssUTF8_Create(
             c->object.arena, nssStringType_PrintableString,
--- a/security/nss/lib/freebl/Makefile
+++ b/security/nss/lib/freebl/Makefile
@@ -115,17 +115,34 @@ ifeq (,$(filter-out i386 x386 x86 x86_64
 $(OBJDIR)/aes-x86.o: CFLAGS += -mpclmul -maes
 ifneq (,$(USE_64)$(USE_X32))
         DEFINES += -DNSS_X64
 else
         DEFINES += -DNSS_X86
 endif
 endif
 ifeq ($(CPU_ARCH),aarch64)
-    EXTRA_SRCS += gcm-aarch64.c
+    DEFINES += -DUSE_HW_AES
+    EXTRA_SRCS += aes-armv8.c gcm-aarch64.c
+endif
+ifeq ($(CPU_ARCH),arm)
+    ifdef CC_IS_CLANG
+        DEFINES += -DUSE_HW_AES
+        EXTRA_SRCS += aes-armv8.c
+    else ifeq (1,$(CC_IS_GCC))
+        # Old compiler doesn't support ARM AES.
+        ifneq (,$(filter 4.9,$(word 1,$(GCC_VERSION)).$(word 2,$(GCC_VERSION))))
+            DEFINES += -DUSE_HW_AES
+            EXTRA_SRCS += aes-armv8.c
+        endif
+        ifeq (,$(filter 0 1 2 3 4,$(word 1,$(GCC_VERSION))))
+            DEFINES += -DUSE_HW_AES
+            EXTRA_SRCS += aes-armv8.c
+        endif
+    endif
 endif
 
 ifeq ($(OS_TARGET),OSF1)
     DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_NO_MP_WORD
     MPI_SRCS += mpvalpha.c
 endif
 
 ifeq (OS2,$(OS_TARGET))
@@ -756,11 +773,15 @@ endif
 
 ifdef INTEL_GCM_CLANG_CL
 #
 # clang-cl needs -mssse3
 #
 $(OBJDIR)/$(PROG_PREFIX)intel-gcm-wrap$(OBJ_SUFFIX): CFLAGS += -mssse3
 endif
 
+ifeq ($(CPU_ARCH),arm)
+$(OBJDIR)/$(PROG_PREFIX)aes-armv8$(OBJ_SUFFIX): CFLAGS += -march=armv8-a -mfpu=crypto-neon-fp-armv8
+endif
 ifeq ($(CPU_ARCH),aarch64)
+$(OBJDIR)/$(PROG_PREFIX)aes-armv8$(OBJ_SUFFIX): CFLAGS += -march=armv8-a+crypto
 $(OBJDIR)/$(PROG_PREFIX)gcm-aarch64$(OBJ_SUFFIX): CFLAGS += -march=armv8-a+crypto
 endif
new file mode 100644
--- /dev/null
+++ b/security/nss/lib/freebl/aes-armv8.c
@@ -0,0 +1,1168 @@
+/* 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 "secerr.h"
+#include "rijndael.h"
+
+#if (defined(__clang__) ||                            \
+     (defined(__GNUC__) && defined(__GNUC_MINOR__) && \
+      (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 8))))
+
+#ifndef __ARM_FEATURE_CRYPTO
+#error "Compiler option is invalid"
+#endif
+
+#include <arm_neon.h>
+
+SECStatus
+arm_aes_encrypt_ecb_128(AESContext *cx, unsigned char *output,
+                        unsigned int *outputLen,
+                        unsigned int maxOutputLen,
+                        const unsigned char *input,
+                        unsigned int inputLen,
+                        unsigned int blocksize)
+{
+#if !defined(HAVE_UNALIGNED_ACCESS)
+    pre_align unsigned char buf[16] post_align;
+#endif
+    uint8x16_t key1, key2, key3, key4, key5, key6, key7, key8, key9, key10;
+    uint8x16_t key11;
+    const PRUint8 *key = (const PRUint8 *)cx->expandedKey;
+
+    if (!inputLen) {
+        return SECSuccess;
+    }
+
+    key1 = vld1q_u8(key);
+    key2 = vld1q_u8(key + 16);
+    key3 = vld1q_u8(key + 32);
+    key4 = vld1q_u8(key + 48);
+    key5 = vld1q_u8(key + 64);
+    key6 = vld1q_u8(key + 80);
+    key7 = vld1q_u8(key + 96);
+    key8 = vld1q_u8(key + 112);
+    key9 = vld1q_u8(key + 128);
+    key10 = vld1q_u8(key + 144);
+    key11 = vld1q_u8(key + 160);
+
+    while (inputLen > 0) {
+        uint8x16_t state;
+#if defined(HAVE_UNALIGNED_ACCESS)
+        state = vld1q_u8(input);
+#else
+        if ((uintptr_t)input & 0x7) {
+            memcpy(buf, input, 16);
+            state = vld1q_u8(__builtin_assume_aligned(buf, 16));
+        } else {
+            state = vld1q_u8(__builtin_assume_aligned(input, 8));
+        }
+#endif
+        input += 16;
+        inputLen -= 16;
+
+        /* Rounds */
+        state = vaeseq_u8(state, key1);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key2);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key3);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key4);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key5);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key6);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key7);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key8);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key9);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key10);
+        /* AddRoundKey */
+        state = veorq_u8(state, key11);
+
+#if defined(HAVE_UNALIGNED_ACCESS)
+        vst1q_u8(output, state);
+#else
+        if ((uintptr_t)output & 0x7) {
+            vst1q_u8(__builtin_assume_aligned(buf, 16), state);
+            memcpy(output, buf, 16);
+        } else {
+            vst1q_u8(__builtin_assume_aligned(output, 8), state);
+        }
+#endif
+        output += 16;
+    }
+
+    return SECSuccess;
+}
+
+SECStatus
+arm_aes_decrypt_ecb_128(AESContext *cx, unsigned char *output,
+                        unsigned int *outputLen,
+                        unsigned int maxOutputLen,
+                        const unsigned char *input,
+                        unsigned int inputLen,
+                        unsigned int blocksize)
+{
+#if !defined(HAVE_UNALIGNED_ACCESS)
+    pre_align unsigned char buf[16] post_align;
+#endif
+    uint8x16_t key1, key2, key3, key4, key5, key6, key7, key8, key9, key10;
+    uint8x16_t key11;
+    const PRUint8 *key = (const PRUint8 *)cx->expandedKey;
+
+    if (inputLen == 0) {
+        return SECSuccess;
+    }
+
+    key1 = vld1q_u8(key);
+    key2 = vld1q_u8(key + 16);
+    key3 = vld1q_u8(key + 32);
+    key4 = vld1q_u8(key + 48);
+    key5 = vld1q_u8(key + 64);
+    key6 = vld1q_u8(key + 80);
+    key7 = vld1q_u8(key + 96);
+    key8 = vld1q_u8(key + 112);
+    key9 = vld1q_u8(key + 128);
+    key10 = vld1q_u8(key + 144);
+    key11 = vld1q_u8(key + 160);
+
+    while (inputLen > 0) {
+        uint8x16_t state;
+#if defined(HAVE_UNALIGNED_ACCESS)
+        state = vld1q_u8(input);
+#else
+        if ((uintptr_t)input & 0x7) {
+            memcpy(buf, input, 16);
+            state = vld1q_u8(__builtin_assume_aligned(buf, 16));
+        } else {
+            state = vld1q_u8(__builtin_assume_aligned(input, 8));
+        }
+#endif
+        input += 16;
+        inputLen -= 16;
+
+        /* Rounds */
+        state = vaesdq_u8(state, key11);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key10);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key9);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key8);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key7);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key6);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key5);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key4);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key3);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key2);
+        /* AddRoundKey */
+        state = veorq_u8(state, key1);
+
+#if defined(HAVE_UNALIGNED_ACCESS)
+        vst1q_u8(output, state);
+#else
+        if ((uintptr_t)output & 0x7) {
+            vst1q_u8(__builtin_assume_aligned(buf, 16), state);
+            memcpy(output, buf, 16);
+        } else {
+            vst1q_u8(__builtin_assume_aligned(output, 8), state);
+        }
+#endif
+        output += 16;
+    }
+
+    return SECSuccess;
+}
+
+SECStatus
+arm_aes_encrypt_cbc_128(AESContext *cx, unsigned char *output,
+                        unsigned int *outputLen,
+                        unsigned int maxOutputLen,
+                        const unsigned char *input,
+                        unsigned int inputLen,
+                        unsigned int blocksize)
+{
+#if !defined(HAVE_UNALIGNED_ACCESS)
+    pre_align unsigned char buf[16] post_align;
+#endif
+    uint8x16_t key1, key2, key3, key4, key5, key6, key7, key8, key9, key10;
+    uint8x16_t key11;
+    uint8x16_t iv;
+    const PRUint8 *key = (const PRUint8 *)cx->expandedKey;
+
+    if (!inputLen) {
+        return SECSuccess;
+    }
+
+    /* iv */
+    iv = vld1q_u8(cx->iv);
+
+    /* expanedKey */
+    key1 = vld1q_u8(key);
+    key2 = vld1q_u8(key + 16);
+    key3 = vld1q_u8(key + 32);
+    key4 = vld1q_u8(key + 48);
+    key5 = vld1q_u8(key + 64);
+    key6 = vld1q_u8(key + 80);
+    key7 = vld1q_u8(key + 96);
+    key8 = vld1q_u8(key + 112);
+    key9 = vld1q_u8(key + 128);
+    key10 = vld1q_u8(key + 144);
+    key11 = vld1q_u8(key + 160);
+
+    while (inputLen > 0) {
+        uint8x16_t state;
+#if defined(HAVE_UNALIGNED_ACCESS)
+        state = vld1q_u8(input);
+#else
+        if ((uintptr_t)input & 0x7) {
+            memcpy(buf, input, 16);
+            state = vld1q_u8(__builtin_assume_aligned(buf, 16));
+        } else {
+            state = vld1q_u8(__builtin_assume_aligned(input, 8));
+        }
+#endif
+        input += 16;
+        inputLen -= 16;
+
+        state = veorq_u8(state, iv);
+
+        /* Rounds */
+        state = vaeseq_u8(state, key1);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key2);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key3);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key4);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key5);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key6);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key7);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key8);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key9);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key10);
+        /* AddRoundKey */
+        state = veorq_u8(state, key11);
+
+#if defined(HAVE_UNALIGNED_ACCESS)
+        vst1q_u8(output, state);
+#else
+        if ((uintptr_t)output & 0x7) {
+            vst1q_u8(__builtin_assume_aligned(buf, 16), state);
+            memcpy(output, buf, 16);
+        } else {
+            vst1q_u8(__builtin_assume_aligned(output, 8), state);
+        }
+#endif
+        output += 16;
+        iv = state;
+    }
+    vst1q_u8(cx->iv, iv);
+
+    return SECSuccess;
+}
+
+SECStatus
+arm_aes_decrypt_cbc_128(AESContext *cx, unsigned char *output,
+                        unsigned int *outputLen,
+                        unsigned int maxOutputLen,
+                        const unsigned char *input,
+                        unsigned int inputLen,
+                        unsigned int blocksize)
+{
+#if !defined(HAVE_UNALIGNED_ACCESS)
+    pre_align unsigned char buf[16] post_align;
+#endif
+    uint8x16_t iv;
+    uint8x16_t key1, key2, key3, key4, key5, key6, key7, key8, key9, key10;
+    uint8x16_t key11;
+    const PRUint8 *key = (const PRUint8 *)cx->expandedKey;
+
+    if (!inputLen) {
+        return SECSuccess;
+    }
+
+    /* iv */
+    iv = vld1q_u8(cx->iv);
+
+    /* expanedKey */
+    key1 = vld1q_u8(key);
+    key2 = vld1q_u8(key + 16);
+    key3 = vld1q_u8(key + 32);
+    key4 = vld1q_u8(key + 48);
+    key5 = vld1q_u8(key + 64);
+    key6 = vld1q_u8(key + 80);
+    key7 = vld1q_u8(key + 96);
+    key8 = vld1q_u8(key + 112);
+    key9 = vld1q_u8(key + 128);
+    key10 = vld1q_u8(key + 144);
+    key11 = vld1q_u8(key + 160);
+
+    while (inputLen > 0) {
+        uint8x16_t state, old_state;
+#if defined(HAVE_UNALIGNED_ACCESS)
+        state = vld1q_u8(input);
+#else
+        if ((uintptr_t)input & 0x7) {
+            memcpy(buf, input, 16);
+            state = vld1q_u8(__builtin_assume_aligned(buf, 16));
+        } else {
+            state = vld1q_u8(__builtin_assume_aligned(input, 8));
+        }
+#endif
+        old_state = state;
+        input += 16;
+        inputLen -= 16;
+
+        /* Rounds */
+        state = vaesdq_u8(state, key11);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key10);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key9);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key8);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key7);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key6);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key5);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key4);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key3);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key2);
+        /* AddRoundKey */
+        state = veorq_u8(state, key1);
+
+        state = veorq_u8(state, iv);
+
+#if defined(HAVE_UNALIGNED_ACCESS)
+        vst1q_u8(output, state);
+#else
+        if ((uintptr_t)output & 0x7) {
+            vst1q_u8(__builtin_assume_aligned(buf, 16), state);
+            memcpy(output, buf, 16);
+        } else {
+            vst1q_u8(__builtin_assume_aligned(output, 8), state);
+        }
+#endif
+        output += 16;
+
+        iv = old_state;
+    }
+    vst1q_u8(cx->iv, iv);
+
+    return SECSuccess;
+}
+
+SECStatus
+arm_aes_encrypt_ecb_192(AESContext *cx, unsigned char *output,
+                        unsigned int *outputLen,
+                        unsigned int maxOutputLen,
+                        const unsigned char *input,
+                        unsigned int inputLen,
+                        unsigned int blocksize)
+{
+#if !defined(HAVE_UNALIGNED_ACCESS)
+    pre_align unsigned char buf[16] post_align;
+#endif
+    uint8x16_t key1, key2, key3, key4, key5, key6, key7, key8, key9, key10;
+    uint8x16_t key11, key12, key13;
+    PRUint8 *key = (PRUint8 *)cx->expandedKey;
+
+    if (!inputLen) {
+        return SECSuccess;
+    }
+
+    key1 = vld1q_u8(key);
+    key2 = vld1q_u8(key + 16);
+    key3 = vld1q_u8(key + 32);
+    key4 = vld1q_u8(key + 48);
+    key5 = vld1q_u8(key + 64);
+    key6 = vld1q_u8(key + 80);
+    key7 = vld1q_u8(key + 96);
+    key8 = vld1q_u8(key + 112);
+    key9 = vld1q_u8(key + 128);
+    key10 = vld1q_u8(key + 144);
+    key11 = vld1q_u8(key + 160);
+    key12 = vld1q_u8(key + 176);
+    key13 = vld1q_u8(key + 192);
+
+    while (inputLen > 0) {
+        uint8x16_t state;
+#if defined(HAVE_UNALIGNED_ACCESS)
+        state = vld1q_u8(input);
+#else
+        if ((uintptr_t)input & 0x7) {
+            memcpy(buf, input, 16);
+            state = vld1q_u8(__builtin_assume_aligned(buf, 16));
+        } else {
+            state = vld1q_u8(__builtin_assume_aligned(input, 8));
+        }
+#endif
+        input += 16;
+        inputLen -= 16;
+
+        /* Rounds */
+        state = vaeseq_u8(state, key1);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key2);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key3);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key4);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key5);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key6);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key7);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key8);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key9);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key10);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key11);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key12);
+        /* AddRoundKey */
+        state = veorq_u8(state, key13);
+
+#if defined(HAVE_UNALIGNED_ACCESS)
+        vst1q_u8(output, state);
+#else
+        if ((uintptr_t)output & 0x7) {
+            vst1q_u8(__builtin_assume_aligned(buf, 16), state);
+            memcpy(output, buf, 16);
+        } else {
+            vst1q_u8(__builtin_assume_aligned(output, 8), state);
+        }
+#endif
+        output += 16;
+    }
+
+    return SECSuccess;
+}
+
+SECStatus
+arm_aes_decrypt_ecb_192(AESContext *cx, unsigned char *output,
+                        unsigned int *outputLen,
+                        unsigned int maxOutputLen,
+                        const unsigned char *input,
+                        unsigned int inputLen,
+                        unsigned int blocksize)
+{
+#if !defined(HAVE_UNALIGNED_ACCESS)
+    pre_align unsigned char buf[16] post_align;
+#endif
+    uint8x16_t key1, key2, key3, key4, key5, key6, key7, key8, key9, key10;
+    uint8x16_t key11, key12, key13;
+    const PRUint8 *key = (const PRUint8 *)cx->expandedKey;
+
+    if (!inputLen) {
+        return SECSuccess;
+    }
+
+    key1 = vld1q_u8(key);
+    key2 = vld1q_u8(key + 16);
+    key3 = vld1q_u8(key + 32);
+    key4 = vld1q_u8(key + 48);
+    key5 = vld1q_u8(key + 64);
+    key6 = vld1q_u8(key + 80);
+    key7 = vld1q_u8(key + 96);
+    key8 = vld1q_u8(key + 112);
+    key9 = vld1q_u8(key + 128);
+    key10 = vld1q_u8(key + 144);
+    key11 = vld1q_u8(key + 160);
+    key12 = vld1q_u8(key + 176);
+    key13 = vld1q_u8(key + 192);
+
+    while (inputLen > 0) {
+        uint8x16_t state;
+#if defined(HAVE_UNALIGNED_ACCESS)
+        state = vld1q_u8(input);
+#else
+        if ((uintptr_t)input & 0x7) {
+            memcpy(buf, input, 16);
+            state = vld1q_u8(__builtin_assume_aligned(buf, 16));
+        } else {
+            state = vld1q_u8(__builtin_assume_aligned(input, 8));
+        }
+#endif
+        input += 16;
+        inputLen -= 16;
+
+        /* Rounds */
+        state = vaesdq_u8(state, key13);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key12);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key11);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key10);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key9);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key8);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key7);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key6);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key5);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key4);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key3);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key2);
+        /* AddRoundKey */
+        state = veorq_u8(state, key1);
+
+#if defined(HAVE_UNALIGNED_ACCESS)
+        vst1q_u8(output, state);
+#else
+        if ((uintptr_t)output & 0x7) {
+            vst1q_u8(__builtin_assume_aligned(buf, 16), state);
+            memcpy(output, buf, 16);
+        } else {
+            vst1q_u8(__builtin_assume_aligned(output, 8), state);
+        }
+#endif
+        output += 16;
+    }
+
+    return SECSuccess;
+}
+
+SECStatus
+arm_aes_encrypt_cbc_192(AESContext *cx, unsigned char *output,
+                        unsigned int *outputLen,
+                        unsigned int maxOutputLen,
+                        const unsigned char *input,
+                        unsigned int inputLen,
+                        unsigned int blocksize)
+{
+#if !defined(HAVE_UNALIGNED_ACCESS)
+    pre_align unsigned char buf[16] post_align;
+#endif
+    uint8x16_t key1, key2, key3, key4, key5, key6, key7, key8, key9, key10;
+    uint8x16_t key11, key12, key13;
+    uint8x16_t iv;
+    PRUint8 *key = (PRUint8 *)cx->expandedKey;
+
+    if (!inputLen) {
+        return SECSuccess;
+    }
+
+    /* iv */
+    iv = vld1q_u8(cx->iv);
+
+    /* expanedKey */
+    key1 = vld1q_u8(key);
+    key2 = vld1q_u8(key + 16);
+    key3 = vld1q_u8(key + 32);
+    key4 = vld1q_u8(key + 48);
+    key5 = vld1q_u8(key + 64);
+    key6 = vld1q_u8(key + 80);
+    key7 = vld1q_u8(key + 96);
+    key8 = vld1q_u8(key + 112);
+    key9 = vld1q_u8(key + 128);
+    key10 = vld1q_u8(key + 144);
+    key11 = vld1q_u8(key + 160);
+    key12 = vld1q_u8(key + 176);
+    key13 = vld1q_u8(key + 192);
+
+    while (inputLen > 0) {
+        uint8x16_t state;
+#if defined(HAVE_UNALIGNED_ACCESS)
+        state = vld1q_u8(input);
+#else
+        if ((uintptr_t)input & 0x7) {
+            memcpy(buf, input, 16);
+            state = vld1q_u8(__builtin_assume_aligned(buf, 16));
+        } else {
+            state = vld1q_u8(__builtin_assume_aligned(input, 8));
+        }
+#endif
+        input += 16;
+        inputLen -= 16;
+
+        state = veorq_u8(state, iv);
+
+        /* Rounds */
+        state = vaeseq_u8(state, key1);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key2);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key3);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key4);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key5);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key6);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key7);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key8);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key9);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key10);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key11);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key12);
+        state = veorq_u8(state, key13);
+
+#if defined(HAVE_UNALIGNED_ACCESS)
+        vst1q_u8(output, state);
+#else
+        if ((uintptr_t)output & 0x7) {
+            vst1q_u8(__builtin_assume_aligned(buf, 16), state);
+            memcpy(output, buf, 16);
+        } else {
+            vst1q_u8(__builtin_assume_aligned(output, 8), state);
+        }
+#endif
+        output += 16;
+        iv = state;
+    }
+    vst1q_u8(cx->iv, iv);
+
+    return SECSuccess;
+}
+
+SECStatus
+arm_aes_decrypt_cbc_192(AESContext *cx, unsigned char *output,
+                        unsigned int *outputLen,
+                        unsigned int maxOutputLen,
+                        const unsigned char *input,
+                        unsigned int inputLen,
+                        unsigned int blocksize)
+{
+#if !defined(HAVE_UNALIGNED_ACCESS)
+    pre_align unsigned char buf[16] post_align;
+#endif
+    uint8x16_t iv;
+    uint8x16_t key1, key2, key3, key4, key5, key6, key7, key8, key9, key10;
+    uint8x16_t key11, key12, key13;
+    const PRUint8 *key = (const PRUint8 *)cx->expandedKey;
+
+    if (!inputLen) {
+        return SECSuccess;
+    }
+
+    /* iv */
+    iv = vld1q_u8(cx->iv);
+
+    /* expanedKey */
+    key1 = vld1q_u8(key);
+    key2 = vld1q_u8(key + 16);
+    key3 = vld1q_u8(key + 32);
+    key4 = vld1q_u8(key + 48);
+    key5 = vld1q_u8(key + 64);
+    key6 = vld1q_u8(key + 80);
+    key7 = vld1q_u8(key + 96);
+    key8 = vld1q_u8(key + 112);
+    key9 = vld1q_u8(key + 128);
+    key10 = vld1q_u8(key + 144);
+    key11 = vld1q_u8(key + 160);
+    key12 = vld1q_u8(key + 176);
+    key13 = vld1q_u8(key + 192);
+
+    while (inputLen > 0) {
+        uint8x16_t state, old_state;
+#if defined(HAVE_UNALIGNED_ACCESS)
+        state = vld1q_u8(input);
+#else
+        if ((uintptr_t)input & 0x7) {
+            memcpy(buf, input, 16);
+            state = vld1q_u8(__builtin_assume_aligned(buf, 16));
+        } else {
+            state = vld1q_u8(__builtin_assume_aligned(input, 8));
+        }
+#endif
+        old_state = state;
+        input += 16;
+        inputLen -= 16;
+
+        /* Rounds */
+        state = vaesdq_u8(state, key13);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key12);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key11);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key10);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key9);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key8);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key7);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key6);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key5);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key4);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key3);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key2);
+        /* AddRoundKey */
+        state = veorq_u8(state, key1);
+
+        state = veorq_u8(state, iv);
+
+#if defined(HAVE_UNALIGNED_ACCESS)
+        vst1q_u8(output, state);
+#else
+        if ((uintptr_t)output & 0x7) {
+            vst1q_u8(__builtin_assume_aligned(buf, 16), state);
+            memcpy(output, buf, 16);
+        } else {
+            vst1q_u8(__builtin_assume_aligned(output, 8), state);
+        }
+#endif
+        output += 16;
+
+        iv = old_state;
+    }
+    vst1q_u8(cx->iv, iv);
+
+    return SECSuccess;
+}
+
+SECStatus
+arm_aes_encrypt_ecb_256(AESContext *cx, unsigned char *output,
+                        unsigned int *outputLen,
+                        unsigned int maxOutputLen,
+                        const unsigned char *input,
+                        unsigned int inputLen,
+                        unsigned int blocksize)
+{
+#if !defined(HAVE_UNALIGNED_ACCESS)
+    pre_align unsigned char buf[16] post_align;
+#endif
+    uint8x16_t key1, key2, key3, key4, key5, key6, key7, key8, key9, key10;
+    uint8x16_t key11, key12, key13, key14, key15;
+    PRUint8 *key = (PRUint8 *)cx->expandedKey;
+
+    if (inputLen == 0) {
+        return SECSuccess;
+    }
+
+    key1 = vld1q_u8(key);
+    key2 = vld1q_u8(key + 16);
+    key3 = vld1q_u8(key + 32);
+    key4 = vld1q_u8(key + 48);
+    key5 = vld1q_u8(key + 64);
+    key6 = vld1q_u8(key + 80);
+    key7 = vld1q_u8(key + 96);
+    key8 = vld1q_u8(key + 112);
+    key9 = vld1q_u8(key + 128);
+    key10 = vld1q_u8(key + 144);
+    key11 = vld1q_u8(key + 160);
+    key12 = vld1q_u8(key + 176);
+    key13 = vld1q_u8(key + 192);
+    key14 = vld1q_u8(key + 208);
+    key15 = vld1q_u8(key + 224);
+
+    while (inputLen > 0) {
+        uint8x16_t state;
+#if defined(HAVE_UNALIGNED_ACCESS)
+        state = vld1q_u8(input);
+#else
+        if ((uintptr_t)input & 0x7) {
+            memcpy(buf, input, 16);
+            state = vld1q_u8(__builtin_assume_aligned(buf, 16));
+        } else {
+            state = vld1q_u8(__builtin_assume_aligned(input, 8));
+        }
+#endif
+        input += 16;
+        inputLen -= 16;
+
+        /* Rounds */
+        state = vaeseq_u8(state, key1);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key2);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key3);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key4);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key5);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key6);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key7);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key8);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key9);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key10);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key11);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key12);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key13);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key14);
+        /* AddRoundKey */
+        state = veorq_u8(state, key15);
+
+#if defined(HAVE_UNALIGNED_ACCESS)
+        vst1q_u8(output, state);
+#else
+        if ((uintptr_t)output & 0x7) {
+            vst1q_u8(__builtin_assume_aligned(buf, 16), state);
+            memcpy(output, buf, 16);
+        } else {
+            vst1q_u8(__builtin_assume_aligned(output, 8), state);
+        }
+#endif
+        output += 16;
+    }
+    return SECSuccess;
+}
+
+SECStatus
+arm_aes_decrypt_ecb_256(AESContext *cx, unsigned char *output,
+                        unsigned int *outputLen,
+                        unsigned int maxOutputLen,
+                        const unsigned char *input,
+                        unsigned int inputLen,
+                        unsigned int blocksize)
+{
+#if !defined(HAVE_UNALIGNED_ACCESS)
+    pre_align unsigned char buf[16] post_align;
+#endif
+    uint8x16_t key1, key2, key3, key4, key5, key6, key7, key8, key9, key10;
+    uint8x16_t key11, key12, key13, key14, key15;
+    const PRUint8 *key = (const PRUint8 *)cx->expandedKey;
+
+    if (!inputLen) {
+        return SECSuccess;
+    }
+
+    key1 = vld1q_u8(key);
+    key2 = vld1q_u8(key + 16);
+    key3 = vld1q_u8(key + 32);
+    key4 = vld1q_u8(key + 48);
+    key5 = vld1q_u8(key + 64);
+    key6 = vld1q_u8(key + 80);
+    key7 = vld1q_u8(key + 96);
+    key8 = vld1q_u8(key + 112);
+    key9 = vld1q_u8(key + 128);
+    key10 = vld1q_u8(key + 144);
+    key11 = vld1q_u8(key + 160);
+    key12 = vld1q_u8(key + 176);
+    key13 = vld1q_u8(key + 192);
+    key14 = vld1q_u8(key + 208);
+    key15 = vld1q_u8(key + 224);
+
+    while (inputLen > 0) {
+        uint8x16_t state;
+#if defined(HAVE_UNALIGNED_ACCESS)
+        state = vld1q_u8(input);
+#else
+        if ((uintptr_t)input & 0x7) {
+            memcpy(buf, input, 16);
+            state = vld1q_u8(__builtin_assume_aligned(buf, 16));
+        } else {
+            state = vld1q_u8(__builtin_assume_aligned(input, 8));
+        }
+#endif
+        input += 16;
+        inputLen -= 16;
+
+        /* Rounds */
+        state = vaesdq_u8(state, key15);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key14);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key13);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key12);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key11);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key10);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key9);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key8);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key7);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key6);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key5);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key4);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key3);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key2);
+        /* AddRoundKey */
+        state = veorq_u8(state, key1);
+
+#if defined(HAVE_UNALIGNED_ACCESS)
+        vst1q_u8(output, state);
+#else
+        if ((uintptr_t)output & 0x7) {
+            vst1q_u8(__builtin_assume_aligned(buf, 16), state);
+            memcpy(output, buf, 16);
+        } else {
+            vst1q_u8(__builtin_assume_aligned(output, 8), state);
+        }
+#endif
+        output += 16;
+    }
+
+    return SECSuccess;
+}
+
+SECStatus
+arm_aes_encrypt_cbc_256(AESContext *cx, unsigned char *output,
+                        unsigned int *outputLen,
+                        unsigned int maxOutputLen,
+                        const unsigned char *input,
+                        unsigned int inputLen,
+                        unsigned int blocksize)
+{
+#if !defined(HAVE_UNALIGNED_ACCESS)
+    pre_align unsigned char buf[16] post_align;
+#endif
+    uint8x16_t key1, key2, key3, key4, key5, key6, key7, key8, key9, key10;
+    uint8x16_t key11, key12, key13, key14, key15;
+    uint8x16_t iv;
+    const PRUint8 *key = (const PRUint8 *)cx->expandedKey;
+
+    if (!inputLen) {
+        return SECSuccess;
+    }
+
+    /* iv */
+    iv = vld1q_u8(cx->iv);
+
+    /* expanedKey */
+    key1 = vld1q_u8(key);
+    key2 = vld1q_u8(key + 16);
+    key3 = vld1q_u8(key + 32);
+    key4 = vld1q_u8(key + 48);
+    key5 = vld1q_u8(key + 64);
+    key6 = vld1q_u8(key + 80);
+    key7 = vld1q_u8(key + 96);
+    key8 = vld1q_u8(key + 112);
+    key9 = vld1q_u8(key + 128);
+    key10 = vld1q_u8(key + 144);
+    key11 = vld1q_u8(key + 160);
+    key12 = vld1q_u8(key + 176);
+    key13 = vld1q_u8(key + 192);
+    key14 = vld1q_u8(key + 208);
+    key15 = vld1q_u8(key + 224);
+
+    while (inputLen > 0) {
+        uint8x16_t state;
+#if defined(HAVE_UNALIGNED_ACCESS)
+        state = vld1q_u8(input);
+#else
+        if ((uintptr_t)input & 0x7) {
+            memcpy(buf, input, 16);
+            state = vld1q_u8(__builtin_assume_aligned(buf, 16));
+        } else {
+            state = vld1q_u8(__builtin_assume_aligned(input, 8));
+        }
+#endif
+        input += 16;
+        inputLen -= 16;
+
+        state = veorq_u8(state, iv);
+
+        /* Rounds */
+        state = vaeseq_u8(state, key1);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key2);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key3);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key4);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key5);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key6);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key7);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key8);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key9);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key10);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key11);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key12);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key13);
+        state = vaesmcq_u8(state);
+        state = vaeseq_u8(state, key14);
+        /* AddRoundKey */
+        state = veorq_u8(state, key15);
+
+#if defined(HAVE_UNALIGNED_ACCESS)
+        vst1q_u8(output, state);
+#else
+        if ((uintptr_t)output & 0x7) {
+            vst1q_u8(__builtin_assume_aligned(buf, 16), state);
+            memcpy(output, buf, 16);
+        } else {
+            vst1q_u8(__builtin_assume_aligned(output, 8), state);
+        }
+#endif
+        output += 16;
+        iv = state;
+    }
+    vst1q_u8(cx->iv, iv);
+
+    return SECSuccess;
+}
+
+SECStatus
+arm_aes_decrypt_cbc_256(AESContext *cx, unsigned char *output,
+                        unsigned int *outputLen,
+                        unsigned int maxOutputLen,
+                        const unsigned char *input,
+                        unsigned int inputLen,
+                        unsigned int blocksize)
+{
+#if !defined(HAVE_UNALIGNED_ACCESS)
+    pre_align unsigned char buf[16] post_align;
+#endif
+    uint8x16_t iv;
+    uint8x16_t key1, key2, key3, key4, key5, key6, key7, key8, key9, key10;
+    uint8x16_t key11, key12, key13, key14, key15;
+    const PRUint8 *key = (const PRUint8 *)cx->expandedKey;
+
+    if (!inputLen) {
+        return SECSuccess;
+    }
+
+    /* iv */
+    iv = vld1q_u8(cx->iv);
+
+    /* expanedKey */
+    key1 = vld1q_u8(key);
+    key2 = vld1q_u8(key + 16);
+    key3 = vld1q_u8(key + 32);
+    key4 = vld1q_u8(key + 48);
+    key5 = vld1q_u8(key + 64);
+    key6 = vld1q_u8(key + 80);
+    key7 = vld1q_u8(key + 96);
+    key8 = vld1q_u8(key + 112);
+    key9 = vld1q_u8(key + 128);
+    key10 = vld1q_u8(key + 144);
+    key11 = vld1q_u8(key + 160);
+    key12 = vld1q_u8(key + 176);
+    key13 = vld1q_u8(key + 192);
+    key14 = vld1q_u8(key + 208);
+    key15 = vld1q_u8(key + 224);
+
+    while (inputLen > 0) {
+        uint8x16_t state, old_state;
+#if defined(HAVE_UNALIGNED_ACCESS)
+        state = vld1q_u8(input);
+#else
+        if ((uintptr_t)input & 0x7) {
+            memcpy(buf, input, 16);
+            state = vld1q_u8(__builtin_assume_aligned(buf, 16));
+        } else {
+            state = vld1q_u8(__builtin_assume_aligned(input, 8));
+        }
+#endif
+        old_state = state;
+        input += 16;
+        inputLen -= 16;
+
+        /* Rounds */
+        state = vaesdq_u8(state, key15);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key14);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key13);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key12);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key11);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key10);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key9);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key8);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key7);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key6);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key5);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key4);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key3);
+        state = vaesimcq_u8(state);
+        state = vaesdq_u8(state, key2);
+        /* AddRoundKey */
+        state = veorq_u8(state, key1);
+
+        state = veorq_u8(state, iv);
+
+#if defined(HAVE_UNALIGNED_ACCESS)
+        vst1q_u8(output, state);
+#else
+        if ((uintptr_t)output & 0x7) {
+            vst1q_u8(__builtin_assume_aligned(buf, 16), state);
+            memcpy(output, buf, 16);
+        } else {
+            vst1q_u8(__builtin_assume_aligned(output, 8), state);
+        }
+#endif
+        output += 16;
+
+        iv = old_state;
+    }
+    vst1q_u8(cx->iv, iv);
+
+    return SECSuccess;
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/security/nss/lib/freebl/aes-armv8.h
@@ -0,0 +1,103 @@
+/* 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/. */
+
+SECStatus arm_aes_encrypt_ecb_128(AESContext *cx, unsigned char *output,
+                                  unsigned int *outputLen,
+                                  unsigned int maxOutputLen,
+                                  const unsigned char *input,
+                                  unsigned int inputLen,
+                                  unsigned int blocksize);
+SECStatus arm_aes_decrypt_ecb_128(AESContext *cx, unsigned char *output,
+                                  unsigned int *outputLen,
+                                  unsigned int maxOutputLen,
+                                  const unsigned char *input,
+                                  unsigned int inputLen,
+                                  unsigned int blocksize);
+SECStatus arm_aes_encrypt_cbc_128(AESContext *cx, unsigned char *output,
+                                  unsigned int *outputLen,
+                                  unsigned int maxOutputLen,
+                                  const unsigned char *input,
+                                  unsigned int inputLen,
+                                  unsigned int blocksize);
+SECStatus arm_aes_decrypt_cbc_128(AESContext *cx, unsigned char *output,
+                                  unsigned int *outputLen,
+                                  unsigned int maxOutputLen,
+                                  const unsigned char *input,
+                                  unsigned int inputLen,
+                                  unsigned int blocksize);
+SECStatus arm_aes_encrypt_ecb_192(AESContext *cx, unsigned char *output,
+                                  unsigned int *outputLen,
+                                  unsigned int maxOutputLen,
+                                  const unsigned char *input,
+                                  unsigned int inputLen,
+                                  unsigned int blocksize);
+SECStatus arm_aes_decrypt_ecb_192(AESContext *cx, unsigned char *output,
+                                  unsigned int *outputLen,
+                                  unsigned int maxOutputLen,
+                                  const unsigned char *input,
+                                  unsigned int inputLen,
+                                  unsigned int blocksize);
+SECStatus arm_aes_encrypt_cbc_192(AESContext *cx, unsigned char *output,
+                                  unsigned int *outputLen,
+                                  unsigned int maxOutputLen,
+                                  const unsigned char *input,
+                                  unsigned int inputLen,
+                                  unsigned int blocksize);
+SECStatus arm_aes_decrypt_cbc_192(AESContext *cx, unsigned char *output,
+                                  unsigned int *outputLen,
+                                  unsigned int maxOutputLen,
+                                  const unsigned char *input,
+                                  unsigned int inputLen,
+                                  unsigned int blocksize);
+SECStatus arm_aes_encrypt_ecb_256(AESContext *cx, unsigned char *output,
+                                  unsigned int *outputLen,
+                                  unsigned int maxOutputLen,
+                                  const unsigned char *input,
+                                  unsigned int inputLen,
+                                  unsigned int blocksize);
+SECStatus arm_aes_decrypt_ecb_256(AESContext *cx, unsigned char *output,
+                                  unsigned int *outputLen,
+                                  unsigned int maxOutputLen,
+                                  const unsigned char *input,
+                                  unsigned int inputLen,
+                                  unsigned int blocksize);
+SECStatus arm_aes_encrypt_cbc_256(AESContext *cx, unsigned char *output,
+                                  unsigned int *outputLen,
+                                  unsigned int maxOutputLen,
+                                  const unsigned char *input,
+                                  unsigned int inputLen,
+                                  unsigned int blocksize);
+SECStatus arm_aes_decrypt_cbc_256(AESContext *cx, unsigned char *output,
+                                  unsigned int *outputLen,
+                                  unsigned int maxOutputLen,
+                                  const unsigned char *input,
+                                  unsigned int inputLen,
+                                  unsigned int blocksize);
+
+#define native_aes_ecb_worker(encrypt, keysize)                          \
+    ((encrypt)                                                           \
+         ? ((keysize) == 16 ? arm_aes_encrypt_ecb_128                    \
+                            : (keysize) == 24 ? arm_aes_encrypt_ecb_192  \
+                                              : arm_aes_encrypt_ecb_256) \
+         : ((keysize) == 16 ? arm_aes_decrypt_ecb_128                    \
+                            : (keysize) == 24 ? arm_aes_decrypt_ecb_192  \
+                                              : arm_aes_decrypt_ecb_256))
+
+#define native_aes_cbc_worker(encrypt, keysize)                          \
+    ((encrypt)                                                           \
+         ? ((keysize) == 16 ? arm_aes_encrypt_cbc_128                    \
+                            : (keysize) == 24 ? arm_aes_encrypt_cbc_192  \
+                                              : arm_aes_encrypt_cbc_256) \
+         : ((keysize) == 16 ? arm_aes_decrypt_cbc_128                    \
+                            : (keysize) == 24 ? arm_aes_decrypt_cbc_192  \
+                                              : arm_aes_decrypt_cbc_256))
+
+#define native_aes_init(encrypt, keysize)           \
+    do {                                            \
+        if (encrypt) {                              \
+            rijndael_key_expansion(cx, key, Nk);    \
+        } else {                                    \
+            rijndael_invkey_expansion(cx, key, Nk); \
+        }                                           \
+    } while (0)
--- a/security/nss/lib/freebl/freebl.gyp
+++ b/security/nss/lib/freebl/freebl.gyp
@@ -128,16 +128,45 @@
       'cflags': [
         '-march=armv8-a+crypto'
       ],
       'cflags_mozilla': [
         '-march=armv8-a+crypto'
       ]
     },
     {
+      'target_name': 'armv8_c_lib',
+      'type': 'static_library',
+      'sources': [
+        'aes-armv8.c',
+      ],
+      'dependencies': [
+        '<(DEPTH)/exports.gyp:nss_exports'
+      ],
+      'conditions': [
+        [ 'target_arch=="arm"', {
+          'cflags': [
+            '-march=armv8-a',
+            '-mfpu=crypto-neon-fp-armv8'
+          ],
+          'cflags_mozilla': [
+            '-march=armv8-a',
+            '-mfpu=crypto-neon-fp-armv8'
+          ],
+        }, 'target_arch=="arm64" or target_arch=="aarch64"', {
+          'cflags': [
+            '-march=armv8-a+crypto'
+          ],
+          'cflags_mozilla': [
+            '-march=armv8-a+crypto'
+          ],
+        }]
+      ]
+    },
+    {
       'target_name': 'freebl',
       'type': 'static_library',
       'sources': [
         'loader.c'
       ],
       'dependencies': [
         '<(DEPTH)/exports.gyp:nss_exports'
       ]
@@ -155,16 +184,20 @@
         '<(DEPTH)/exports.gyp:nss_exports',
         'hw-acc-crypto',
       ],
       'conditions': [
         [ 'target_arch=="ia32" or target_arch=="x64"', {
           'dependencies': [
             'gcm-aes-x86_c_lib',
           ],
+        }, 'disable_arm_hw_aes==0 and (target_arch=="arm" or target_arch=="arm64" or target_arch=="aarch64")', {
+          'dependencies': [
+            'armv8_c_lib'
+          ],
         }],
         [ 'target_arch=="arm64" or target_arch=="aarch64"', {
           'dependencies': [
             'gcm-aes-aarch64_c_lib',
           ],
         }],
         [ 'OS=="linux"', {
           'defines!': [
@@ -197,16 +230,20 @@
         '<(DEPTH)/exports.gyp:nss_exports',
         'hw-acc-crypto',
       ],
       'conditions': [
         [ 'target_arch=="ia32" or target_arch=="x64"', {
           'dependencies': [
             'gcm-aes-x86_c_lib',
           ]
+        }, 'target_arch=="arm" or target_arch=="arm64" or target_arch=="aarch64"', {
+          'dependencies': [
+            'armv8_c_lib',
+          ],
         }],
         [ 'target_arch=="arm64" or target_arch=="aarch64"', {
           'dependencies': [
             'gcm-aes-aarch64_c_lib',
           ],
         }],
         [ 'OS!="linux"', {
           'conditions': [
@@ -426,16 +463,21 @@
             'defines': [
               'MP_ASSEMBLY_MULTIPLY',
               'MP_ASSEMBLY_SQUARE',
               'MP_USE_UINT_DIGIT',
               'SHA_NO_LONG_LONG',
               'ARMHF',
             ],
           }],
+          [ 'disable_arm_hw_aes==0 and (target_arch=="arm" or target_arch=="arm64" or target_arch=="aarch64")', {
+            'defines': [
+              'USE_HW_AES',
+            ],
+          }],
         ],
       }],
     ],
   },
   'variables': {
     'module': 'nss',
     'conditions': [
       [ 'OS!="win"', {
--- a/security/nss/lib/freebl/intel-aes.h
+++ b/security/nss/lib/freebl/intel-aes.h
@@ -95,40 +95,40 @@ SECStatus intel_aes_decrypt_cbc_256(AESC
                                     unsigned int blocksize);
 SECStatus intel_aes_encrypt_ctr_256(CTRContext *cx, unsigned char *output,
                                     unsigned int *outputLen,
                                     unsigned int maxOutputLen,
                                     const unsigned char *input,
                                     unsigned int inputLen,
                                     unsigned int blocksize);
 
-#define intel_aes_ecb_worker(encrypt, keysize)                             \
+#define native_aes_ecb_worker(encrypt, keysize)                            \
     ((encrypt)                                                             \
          ? ((keysize) == 16 ? intel_aes_encrypt_ecb_128                    \
                             : (keysize) == 24 ? intel_aes_encrypt_ecb_192  \
                                               : intel_aes_encrypt_ecb_256) \
          : ((keysize) == 16 ? intel_aes_decrypt_ecb_128                    \
                             : (keysize) == 24 ? intel_aes_decrypt_ecb_192  \
                                               : intel_aes_decrypt_ecb_256))
 
-#define intel_aes_cbc_worker(encrypt, keysize)                             \
+#define native_aes_cbc_worker(encrypt, keysize)                            \
     ((encrypt)                                                             \
          ? ((keysize) == 16 ? intel_aes_encrypt_cbc_128                    \
                             : (keysize) == 24 ? intel_aes_encrypt_cbc_192  \
                                               : intel_aes_encrypt_cbc_256) \
          : ((keysize) == 16 ? intel_aes_decrypt_cbc_128                    \
                             : (keysize) == 24 ? intel_aes_decrypt_cbc_192  \
                                               : intel_aes_decrypt_cbc_256))
 
 #define intel_aes_ctr_worker(nr)                         \
     ((nr) == 10 ? intel_aes_encrypt_ctr_128              \
                 : (nr) == 12 ? intel_aes_encrypt_ctr_192 \
                              : intel_aes_encrypt_ctr_256)
 
-#define intel_aes_init(encrypt, keysize)                          \
+#define native_aes_init(encrypt, keysize)                         \
     do {                                                          \
         if (encrypt) {                                            \
             if (keysize == 16)                                    \
                 intel_aes_encrypt_init_128(key, cx->expandedKey); \
             else if (keysize == 24)                               \
                 intel_aes_encrypt_init_192(key, cx->expandedKey); \
             else                                                  \
                 intel_aes_encrypt_init_256(key, cx->expandedKey); \
--- a/security/nss/lib/freebl/rijndael.c
+++ b/security/nss/lib/freebl/rijndael.c
@@ -15,19 +15,28 @@
 #include "blapi.h"
 #include "rijndael.h"
 
 #include "cts.h"
 #include "ctr.h"
 #include "gcm.h"
 #include "mpi.h"
 
+#if !defined(IS_LITTLE_ENDIAN) && !defined(NSS_X86_OR_X64)
+// not test yet on big endian platform of arm
+#undef USE_HW_AES
+#endif
+
 #ifdef USE_HW_AES
+#ifdef NSS_X86_OR_X64
 #include "intel-aes.h"
+#else
+#include "aes-armv8.h"
 #endif
+#endif /* USE_HW_AES */
 #ifdef INTEL_GCM
 #include "intel-gcm.h"
 #endif /* INTEL_GCM */
 
 /* Forward declarations */
 void rijndael_native_key_expansion(AESContext *cx, const unsigned char *key,
                                    unsigned int Nk);
 void rijndael_native_encryptBlock(AESContext *cx,
@@ -842,58 +851,62 @@ aes_InitContext(AESContext *cx, const un
     if (mode == NSS_AES_CBC && iv == NULL) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
     if (!cx) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
-    use_hw_aes = aesni_support() && (keysize % 8) == 0;
+#if defined(NSS_X86_OR_X64) || defined(USE_HW_AES)
+    use_hw_aes = (aesni_support() || arm_aes_support()) && (keysize % 8) == 0;
+#else
+    use_hw_aes = PR_FALSE;
+#endif
     /* Nb = (block size in bits) / 32 */
     cx->Nb = AES_BLOCK_SIZE / 4;
     /* Nk = (key size in bits) / 32 */
     Nk = keysize / 4;
     /* Obtain number of rounds from "table" */
     cx->Nr = RIJNDAEL_NUM_ROUNDS(Nk, cx->Nb);
     /* copy in the iv, if neccessary */
     if (mode == NSS_AES_CBC) {
         memcpy(cx->iv, iv, AES_BLOCK_SIZE);
 #ifdef USE_HW_AES
         if (use_hw_aes) {
             cx->worker = (freeblCipherFunc)
-                intel_aes_cbc_worker(encrypt, keysize);
+                native_aes_cbc_worker(encrypt, keysize);
         } else
 #endif
         {
             cx->worker = (freeblCipherFunc)(encrypt
                                                 ? &rijndael_encryptCBC
                                                 : &rijndael_decryptCBC);
         }
     } else {
 #ifdef USE_HW_AES
         if (use_hw_aes) {
             cx->worker = (freeblCipherFunc)
-                intel_aes_ecb_worker(encrypt, keysize);
+                native_aes_ecb_worker(encrypt, keysize);
         } else
 #endif
         {
             cx->worker = (freeblCipherFunc)(encrypt
                                                 ? &rijndael_encryptECB
                                                 : &rijndael_decryptECB);
         }
     }
     PORT_Assert((cx->Nb * (cx->Nr + 1)) <= RIJNDAEL_MAX_EXP_KEY_SIZE);
     if ((cx->Nb * (cx->Nr + 1)) > RIJNDAEL_MAX_EXP_KEY_SIZE) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 #ifdef USE_HW_AES
     if (use_hw_aes) {
-        intel_aes_init(encrypt, keysize);
+        native_aes_init(encrypt, keysize);
     } else
 #endif
     {
         /* Generate expanded key */
         if (encrypt) {
             if (use_hw_aes && (cx->mode == NSS_AES_GCM || cx->mode == NSS_AES ||
                                cx->mode == NSS_AES_CTR)) {
                 PORT_Assert(keysize == 16 || keysize == 24 || keysize == 32);
--- a/security/nss/lib/pk11wrap/pk11load.c
+++ b/security/nss/lib/pk11wrap/pk11load.c
@@ -483,22 +483,20 @@ secmod_LoadPKCS11Module(SECMODModule *mo
 
     /*
      * We need to get the function list
      */
     if ((*entry)((CK_FUNCTION_LIST_PTR *)&mod->functionList) != CKR_OK)
         goto fail;
 
 #ifdef DEBUG_MODULE
-    if (PR_TRUE) {
-        modToDBG = PR_GetEnvSecure("NSS_DEBUG_PKCS11_MODULE");
-        if (modToDBG && strcmp(mod->commonName, modToDBG) == 0) {
-            mod->functionList = (void *)nss_InsertDeviceLog(
-                (CK_FUNCTION_LIST_PTR)mod->functionList);
-        }
+    modToDBG = PR_GetEnvSecure("NSS_DEBUG_PKCS11_MODULE");
+    if (modToDBG && strcmp(mod->commonName, modToDBG) == 0) {
+        mod->functionList = (void *)nss_InsertDeviceLog(
+            (CK_FUNCTION_LIST_PTR)mod->functionList);
     }
 #endif
 
     mod->isThreadSafe = PR_TRUE;
 
     /* Now we initialize the module */
     rv = secmod_ModuleInit(mod, oldModule, &alreadyLoaded);
     if (rv != SECSuccess) {
--- a/security/nss/lib/pk11wrap/pk11pk12.c
+++ b/security/nss/lib/pk11wrap/pk11pk12.c
@@ -494,16 +494,20 @@ PK11_ImportAndReturnPrivateKey(PK11SlotI
             PK11_SETATTRS(attrs, CKA_SIGN_RECOVER,
                           (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue
                                                             : &ckfalse,
                           sizeof(CK_BBOOL));
             attrs++;
             PK11_SETATTRS(attrs, CKA_DERIVE, (keyUsage & KU_KEY_AGREEMENT) ? &cktrue : &ckfalse,
                           sizeof(CK_BBOOL));
             attrs++;
+            if (nickname) {
+                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
+                attrs++;
+            }
             ck_id = PK11_MakeIDFromPubKey(&lpk->u.ec.publicValue);
             if (ck_id == NULL) {
                 goto loser;
             }
             PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
             attrs++;
             /* No signed attrs for EC */
             /* curveOID always is a copy of AlgorithmID.parameters. */
--- a/security/nss/lib/pki/pki3hack.c
+++ b/security/nss/lib/pki/pki3hack.c
@@ -997,30 +997,29 @@ STAN_GetNSSCertificate(CERTCertificate *
         nssArena_Destroy(arena);
         return NULL;
     }
     c->object = *pkiob;
     nssItem_Create(arena,
                    &c->issuer, cc->derIssuer.len, cc->derIssuer.data);
     nssItem_Create(arena,
                    &c->subject, cc->derSubject.len, cc->derSubject.data);
-    if (PR_TRUE) {
-        /* CERTCertificate stores serial numbers decoded.  I need the DER
-        * here.  sigh.
-        */
-        SECItem derSerial;
-        SECStatus secrv;
-        secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
-        if (secrv == SECFailure) {
-            nssArena_Destroy(arena);
-            return NULL;
-        }
-        nssItem_Create(arena, &c->serial, derSerial.len, derSerial.data);
-        PORT_Free(derSerial.data);
+    /* CERTCertificate stores serial numbers decoded.  I need the DER
+    * here.  sigh.
+    */
+    SECItem derSerial;
+    SECStatus secrv;
+    secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
+    if (secrv == SECFailure) {
+        nssArena_Destroy(arena);
+        return NULL;
     }
+    nssItem_Create(arena, &c->serial, derSerial.len, derSerial.data);
+    PORT_Free(derSerial.data);
+
     if (cc->emailAddr && cc->emailAddr[0]) {
         c->email = nssUTF8_Create(arena,
                                   nssStringType_PrintableString,
                                   (NSSUTF8 *)cc->emailAddr,
                                   PORT_Strlen(cc->emailAddr));
     }
     if (cc->slot) {
         instance = nss_ZNEW(arena, nssCryptokiInstance);
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -732,17 +732,17 @@ ssl_KEAEnabled(const sslSocket *ss, SSLK
         case ssl_kea_fortezza:
         default:
             PORT_Assert(0);
     }
     return PR_FALSE;
 }
 
 static PRBool
-ssl_HasCert(const sslSocket *ss, SSLAuthType authType)
+ssl_HasCert(const sslSocket *ss, PRUint16 maxVersion, SSLAuthType authType)
 {
     PRCList *cursor;
     if (authType == ssl_auth_null || authType == ssl_auth_psk || authType == ssl_auth_tls13_any) {
         return PR_TRUE;
     }
     for (cursor = PR_NEXT_LINK(&ss->serverCerts);
          cursor != &ss->serverCerts;
          cursor = PR_NEXT_LINK(cursor)) {
@@ -752,27 +752,139 @@ ssl_HasCert(const sslSocket *ss, SSLAuth
             !cert->serverCertChain ||
             !SSL_CERT_IS(cert, authType)) {
             continue;
         }
         /* When called from ssl3_config_match_init(), all the EC curves will be
          * enabled, so this will essentially do nothing (unless we implement
          * curve configuration).  However, once we have seen the
          * supported_groups extension and this is called from config_match(),
-         * this will filter out certificates with an unsupported curve. */
-        if ((authType == ssl_auth_ecdsa ||
+         * this will filter out certificates with an unsupported curve.
+         *
+         * If we might negotiate TLS 1.3, skip this test as group configuration
+         * doesn't affect choices in TLS 1.3.
+         */
+        if (maxVersion < SSL_LIBRARY_VERSION_TLS_1_3 &&
+            (authType == ssl_auth_ecdsa ||
              authType == ssl_auth_ecdh_ecdsa ||
              authType == ssl_auth_ecdh_rsa) &&
             !ssl_NamedGroupEnabled(ss, cert->namedCurve)) {
             continue;
         }
         return PR_TRUE;
     }
     if (authType == ssl_auth_rsa_sign) {
-        return ssl_HasCert(ss, ssl_auth_rsa_pss);
+        return ssl_HasCert(ss, maxVersion, ssl_auth_rsa_pss);
+    }
+    return PR_FALSE;
+}
+
+/* Check that a signature scheme is accepted.
+ * Both by policy and by having a token that supports it. */
+static PRBool
+ssl_SignatureSchemeAccepted(PRUint16 minVersion,
+                            SSLSignatureScheme scheme)
+{
+    /* Disable RSA-PSS schemes if there are no tokens to verify them. */
+    if (ssl_IsRsaPssSignatureScheme(scheme)) {
+        if (!PK11_TokenExists(auth_alg_defs[ssl_auth_rsa_pss])) {
+            return PR_FALSE;
+        }
+    } else if (ssl_IsRsaPkcs1SignatureScheme(scheme)) {
+        /* Disable PKCS#1 signatures if we are limited to TLS 1.3. */
+        if (minVersion >= SSL_LIBRARY_VERSION_TLS_1_3) {
+            return PR_FALSE;
+        }
+    } else if (ssl_IsDsaSignatureScheme(scheme)) {
+        /* DSA: not in TLS 1.3, and check policy. */
+        if (minVersion >= SSL_LIBRARY_VERSION_TLS_1_3) {
+            return PR_FALSE;
+        }
+        PRUint32 dsaPolicy;
+        SECStatus rv = NSS_GetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE,
+                                              &dsaPolicy);
+        if (rv == SECSuccess && (dsaPolicy & NSS_USE_ALG_IN_SSL_KX) == 0) {
+            return PR_FALSE;
+        }
+    }
+
+    /* Hash policy. */
+    PRUint32 hashPolicy;
+    SSLHashType hashType = ssl_SignatureSchemeToHashType(scheme);
+    SECOidTag hashOID = ssl3_HashTypeToOID(hashType);
+    SECStatus rv = NSS_GetAlgorithmPolicy(hashOID, &hashPolicy);
+    if (rv == SECSuccess && (hashPolicy & NSS_USE_ALG_IN_SSL_KX) == 0) {
+        return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+
+static SECStatus
+ssl_CheckSignatureSchemes(sslSocket *ss)
+{
+    if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_2) {
+        return SECSuccess;
+    }
+
+    /* If this is a server using TLS 1.3, we just need to have one signature
+     * scheme for which we have a usable certificate.
+     *
+     * Note: Certificates for earlier TLS versions are checked along with the
+     * cipher suite in ssl3_config_match_init. */
+    if (ss->sec.isServer && ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) {
+        PRBool foundCert = PR_FALSE;
+        for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
+            SSLAuthType authType =
+                ssl_SignatureSchemeToAuthType(ss->ssl3.signatureSchemes[i]);
+            if (ssl_HasCert(ss, ss->vrange.max, authType)) {
+                foundCert = PR_TRUE;
+                break;
+            }
+        }
+        if (!foundCert) {
+            PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
+            return SECFailure;
+        }
+    }
+
+    /* Ensure that there is a signature scheme that can be accepted.*/
+    for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
+        if (ssl_SignatureSchemeAccepted(ss->vrange.min,
+                                        ss->ssl3.signatureSchemes[i])) {
+            return SECSuccess;
+        }
+    }
+    PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
+    return SECFailure;
+}
+
+/* For a server, check that a signature scheme that can be used with the
+ * provided authType is both enabled and usable. */
+static PRBool
+ssl_HasSignatureScheme(const sslSocket *ss, SSLAuthType authType)
+{
+    PORT_Assert(ss->sec.isServer);
+    PORT_Assert(ss->ssl3.hs.preliminaryInfo & ssl_preinfo_version);
+    PORT_Assert(authType != ssl_auth_null);
+    PORT_Assert(authType != ssl_auth_tls13_any);
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2 ||
+        authType == ssl_auth_rsa_decrypt ||
+        authType == ssl_auth_ecdh_rsa ||
+        authType == ssl_auth_ecdh_ecdsa) {
+        return PR_TRUE;
+    }
+    for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
+        SSLSignatureScheme scheme = ss->ssl3.signatureSchemes[i];
+        SSLAuthType schemeAuthType = ssl_SignatureSchemeToAuthType(scheme);
+        PRBool acceptable = authType == schemeAuthType ||
+                            (schemeAuthType == ssl_auth_rsa_pss &&
+                             authType == ssl_auth_rsa_sign);
+        if (acceptable && ssl_SignatureSchemeAccepted(ss->version, scheme)) {
+            return PR_TRUE;
+        }
     }
     return PR_FALSE;
 }
 
 /* Initialize the suite->isPresent value for config_match
  * Returns count of enabled ciphers supported by extant tokens,
  * regardless of policy or user preference.
  * If this returns zero, the user cannot do SSL v3.
@@ -793,16 +905,19 @@ ssl3_config_match_init(sslSocket *ss)
     PORT_Assert(ss);
     if (!ss) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return 0;
     }
     if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) {
         return 0;
     }
+    if (ssl_CheckSignatureSchemes(ss) != SECSuccess) {
+        return 0; /* Code already set. */
+    }
 
     ssl_FilterSupportedGroups(ss);
     for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
         suite = &ss->cipherSuites[i];
         if (suite->enabled) {
             ++numEnabled;
             /* We need the cipher defs to see if we have a token that can handle
              * this cipher.  It isn't part of the static definition.
@@ -815,20 +930,21 @@ ssl3_config_match_init(sslSocket *ss)
             cipher_alg = ssl_GetBulkCipherDef(cipher_def)->calg;
             cipher_mech = ssl3_Alg2Mech(cipher_alg);
 
             /* Mark the suites that are backed by real tokens, certs and keys */
             suite->isPresent = PR_TRUE;
 
             authType = kea_defs[cipher_def->key_exchange_alg].authKeyType;
             if (authType != ssl_auth_null && authType != ssl_auth_tls13_any) {
-                if (ss->sec.isServer && !ssl_HasCert(ss, authType)) {
+                if (ss->sec.isServer &&
+                    !(ssl_HasCert(ss, ss->vrange.max, authType) &&
+                      ssl_HasSignatureScheme(ss, authType))) {
                     suite->isPresent = PR_FALSE;
-                }
-                if (!PK11_TokenExists(auth_alg_defs[authType])) {
+                } else if (!PK11_TokenExists(auth_alg_defs[authType])) {
                     suite->isPresent = PR_FALSE;
                 }
             }
 
             keaType = kea_defs[cipher_def->key_exchange_alg].exchKeyType;
             if (keaType != ssl_kea_null &&
                 keaType != ssl_kea_tls13_any &&
                 !PK11_TokenExists(kea_alg_defs[keaType])) {
@@ -882,17 +998,17 @@ ssl3_config_match(const ssl3CipherSuiteC
     cipher_def = ssl_LookupCipherSuiteDef(suite->cipher_suite);
     PORT_Assert(cipher_def != NULL);
     kea_def = &kea_defs[cipher_def->key_exchange_alg];
     PORT_Assert(kea_def != NULL);
     if (!ssl_KEAEnabled(ss, kea_def->exchKeyType)) {
         return PR_FALSE;
     }
 
-    if (ss->sec.isServer && !ssl_HasCert(ss, kea_def->authKeyType)) {
+    if (ss->sec.isServer && !ssl_HasCert(ss, vrange->max, kea_def->authKeyType)) {
         return PR_FALSE;
     }
 
     return ssl3_CipherSuiteAllowedForVersionRange(suite->cipher_suite, vrange);
 }
 
 /* Return the number of cipher suites that are usable. */
 /* called from ssl3_SendClientHello */
@@ -4151,16 +4267,19 @@ ssl_SignatureSchemeValid(SSLSignatureSch
     }
     if (isTls13) {
         if (ssl_SignatureSchemeToHashType(scheme) == ssl_hash_sha1) {
             return PR_FALSE;
         }
         if (ssl_IsRsaPkcs1SignatureScheme(scheme)) {
             return PR_FALSE;
         }
+        if (ssl_IsDsaSignatureScheme(scheme)) {
+            return PR_FALSE;
+        }
         /* With TLS 1.3, EC keys should have been selected based on calling
          * ssl_SignatureSchemeFromSpki(), reject them otherwise. */
         return spkiOid != SEC_OID_ANSIX962_EC_PUBLIC_KEY;
     }
     return PR_TRUE;
 }
 
 static SECStatus
@@ -4265,16 +4384,17 @@ ssl_SignatureSchemeFromSpki(const CERTSu
     if (isTls13 && spkiOid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
         return ssl_SignatureSchemeFromEcSpki(spki, scheme);
     }
 
     *scheme = ssl_sig_none;
     return SECSuccess;
 }
 
+/* Check that a signature scheme is enabled by configuration. */
 PRBool
 ssl_SignatureSchemeEnabled(const sslSocket *ss, SSLSignatureScheme scheme)
 {
     unsigned int i;
     for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
         if (scheme == ss->ssl3.signatureSchemes[i]) {
             return PR_TRUE;
         }
@@ -8047,16 +8167,17 @@ ssl3_NegotiateCipherSuiteInner(sslSocket
         for (i = 0; i + 1 < suites->len; i += 2) {
             PRUint16 suite_i = (suites->data[i] << 8) | suites->data[i + 1];
             if (suite_i == suite->cipher_suite) {
                 *suitep = suite_i;
                 return SECSuccess;
             }
         }
     }
+    PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
     return SECFailure;
 }
 
 /* Select a cipher suite.
 **
 ** NOTE: This suite selection algorithm should be the same as the one in
 ** ssl3_HandleV2ClientHello().
 **
@@ -8071,16 +8192,24 @@ ssl3_NegotiateCipherSuiteInner(sslSocket
 */
 SECStatus
 ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites,
                           PRBool initHashes)
 {
     PRUint16 selected;
     SECStatus rv;
 
+    /* Ensure that only valid cipher suites are enabled. */
+    if (ssl3_config_match_init(ss) == 0) {
+        /* No configured cipher is both supported by PK11 and allowed.
+         * This is a configuration error, so report handshake failure.*/
+        FATAL_ERROR(ss, PORT_GetError(), handshake_failure);
+        return SECFailure;
+    }
+
     rv = ssl3_NegotiateCipherSuiteInner(ss, suites, ss->version, &selected);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     ss->ssl3.hs.cipher_suite = selected;
     return ssl3_SetupCipherSuite(ss, initHashes);
 }
@@ -8200,23 +8329,16 @@ ssl3_ServerCallSNICallback(sslSocket *ss
                 rv = SECITEM_CopyItem(NULL, pwsName, name);
                 ssl_ReleaseSpecWriteLock(ss); /***************************/
                 if (rv != SECSuccess) {
                     errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
                     desc = internal_error;
                     ret = SSL_SNI_SEND_ALERT;
                     break;
                 }
-                if (ssl3_config_match_init(ss) == 0) {
-                    /* no ciphers are working/supported */
-                    errCode = PORT_GetError();
-                    desc = handshake_failure;
-                    ret = SSL_SNI_SEND_ALERT;
-                    break;
-                }
                 /* Need to tell the client that application has picked
                  * the name from the offered list and reconfigured the socket.
                  * Don't do this if we negotiated ESNI.
                  */
                 if (!ssl3_ExtensionNegotiated(ss, ssl_tls13_encrypted_sni_xtn)) {
                     ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_server_name_xtn,
                                                  ssl_SendEmptyExtension);
                 }
@@ -8840,41 +8962,39 @@ ssl3_HandleClientHelloPart2(sslSocket *s
     }
 
     /* If we already have a session for this client, be sure to pick the same
     ** cipher suite we picked before.  This is not a loop, despite appearances.
     */
     if (sid)
         do {
             ssl3CipherSuiteCfg *suite;
-#ifdef PARANOID
             SSLVersionRange vrange = { ss->version, ss->version };
-#endif
 
             suite = ss->cipherSuites;
             /* Find the entry for the cipher suite used in the cached session. */
             for (j = ssl_V3_SUITES_IMPLEMENTED; j > 0; --j, ++suite) {
                 if (suite->cipher_suite == sid->u.ssl3.cipherSuite)
                     break;
             }
             PORT_Assert(j > 0);
             if (j == 0)
                 break;
-#ifdef PARANOID
+
             /* Double check that the cached cipher suite is still enabled,
              * implemented, and allowed by policy.  Might have been disabled.
-             * The product policy won't change during the process lifetime.
-             * Implemented ("isPresent") shouldn't change for servers.
              */
+            if (ssl3_config_match_init(ss) == 0) {
+                desc = handshake_failure;
+                errCode = PORT_GetError();
+                goto alert_loser;
+            }
             if (!ssl3_config_match(suite, ss->ssl3.policy, &vrange, ss))
                 break;
-#else
-            if (!suite->enabled)
-                break;
-#endif
+
             /* Double check that the cached cipher suite is in the client's
              * list.  If it isn't, fall through and start a new session. */
             for (i = 0; i + 1 < suites->len; i += 2) {
                 PRUint16 suite_i = (suites->data[i] << 8) | suites->data[i + 1];
                 if (suite_i == suite->cipher_suite) {
                     ss->ssl3.hs.cipher_suite = suite_i;
                     rv = ssl3_SetupCipherSuite(ss, PR_TRUE);
                     if (rv != SECSuccess) {
@@ -8882,31 +9002,22 @@ ssl3_HandleClientHelloPart2(sslSocket *s
                         errCode = PORT_GetError();
                         goto alert_loser;
                     }
 
                     goto cipher_found;
                 }
             }
         } while (0);
-/* START A NEW SESSION */
-
-#ifndef PARANOID
-    /* Look for a matching cipher suite. */
-    if (ssl3_config_match_init(ss) == 0) {
-        desc = internal_error;
-        errCode = PORT_GetError(); /* error code is already set. */
-        goto alert_loser;
-    }
-#endif
+    /* START A NEW SESSION */
 
     rv = ssl3_NegotiateCipherSuite(ss, suites, PR_TRUE);
     if (rv != SECSuccess) {
         desc = handshake_failure;
-        errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
+        errCode = PORT_GetError();
         goto alert_loser;
     }
 
 cipher_found:
     suites->data = NULL;
 
     /* If there are any failures while processing the old sid,
      * we don't consider them to be errors.  Instead, We just behave
@@ -9664,55 +9775,34 @@ ssl3_SendServerKeyExchange(sslSocket *ss
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             break;
     }
 
     return SECFailure;
 }
 
 SECStatus
-ssl3_EncodeSigAlgs(const sslSocket *ss, sslBuffer *buf)
+ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, sslBuffer *buf)
 {
     unsigned int lengthOffset;
-    unsigned int i;
     PRBool found = PR_FALSE;
     SECStatus rv;
 
     rv = sslBuffer_Skip(buf, 2, &lengthOffset);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
-    for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
-        PRUint32 policy = 0;
-        SSLHashType hashType = ssl_SignatureSchemeToHashType(
-            ss->ssl3.signatureSchemes[i]);
-        SECOidTag hashOID = ssl3_HashTypeToOID(hashType);
-
-        /* Skip RSA-PSS schemes if there are no tokens to verify them. */
-        if (ssl_IsRsaPssSignatureScheme(ss->ssl3.signatureSchemes[i]) &&
-            !PK11_TokenExists(auth_alg_defs[ssl_auth_rsa_pss])) {
-            continue;
-        }
-
-        /* Skip DSA scheme if it is disabled by policy. */
-        if (ssl_IsDsaSignatureScheme(ss->ssl3.signatureSchemes[i]) &&
-            (NSS_GetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE, &policy) ==
-             SECSuccess) &&
-            !(policy & NSS_USE_ALG_IN_SSL_KX)) {
-            continue;
-        }
-
-        if ((NSS_GetAlgorithmPolicy(hashOID, &policy) != SECSuccess) ||
-            (policy & NSS_USE_ALG_IN_SSL_KX)) {
+    for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
+        if (ssl_SignatureSchemeAccepted(minVersion,
+                                        ss->ssl3.signatureSchemes[i])) {
             rv = sslBuffer_AppendNumber(buf, ss->ssl3.signatureSchemes[i], 2);
             if (rv != SECSuccess) {
                 return SECFailure;
             }
-
             found = PR_TRUE;
         }
     }
 
     if (!found) {
         PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
         return SECFailure;
     }
@@ -9748,17 +9838,17 @@ ssl3_SendCertificateRequest(sslSocket *s
     if (rv != SECSuccess) {
         return rv;
     }
     certTypes = certificate_types;
     certTypesLength = sizeof certificate_types;
 
     length = 1 + certTypesLength + 2 + calen;
     if (isTLS12) {
-        rv = ssl3_EncodeSigAlgs(ss, &sigAlgsBuf);
+        rv = ssl3_EncodeSigAlgs(ss, ss->version, &sigAlgsBuf);
         if (rv != SECSuccess) {
             return rv;
         }
         length += SSL_BUFFER_LEN(&sigAlgsBuf);
     }
 
     rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request, length);
     if (rv != SECSuccess) {
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -1631,23 +1631,28 @@ ssl3_HandleSigAlgsXtn(const sslSocket *s
 }
 
 /* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS
  * 1.2 ClientHellos. */
 SECStatus
 ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                     sslBuffer *buf, PRBool *added)
 {
-    SECStatus rv;
-
     if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_2) {
         return SECSuccess;
     }
 
-    rv = ssl3_EncodeSigAlgs(ss, buf);
+    PRUint16 minVersion;
+    if (ss->sec.isServer) {
+        minVersion = ss->version; /* CertificateRequest */
+    } else {
+        minVersion = ss->vrange.min; /* ClientHello */
+    }
+
+    SECStatus rv = ssl3_EncodeSigAlgs(ss, minVersion, buf);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     *added = PR_TRUE;
     return SECSuccess;
 }
 
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -1676,17 +1676,18 @@ void ssl3_SendAlertForCertError(sslSocke
 SECStatus ssl3_HandleNoCertificate(sslSocket *ss);
 SECStatus ssl3_SendEmptyCertificate(sslSocket *ss);
 void ssl3_CleanupPeerCerts(sslSocket *ss);
 SECStatus ssl3_SendCertificateStatus(sslSocket *ss);
 SECStatus ssl_SetAuthKeyBits(sslSocket *ss, const SECKEYPublicKey *pubKey);
 SECStatus ssl3_AuthCertificate(sslSocket *ss);
 SECStatus ssl_ReadCertificateStatus(sslSocket *ss, PRUint8 *b,
                                     PRUint32 length);
-SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, sslBuffer *buf);
+SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion,
+                             sslBuffer *buf);
 SECStatus ssl_GetCertificateRequestCAs(const sslSocket *ss,
                                        unsigned int *calenp,
                                        const SECItem **namesp,
                                        unsigned int *nnamesp);
 SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b,
                                           PRUint32 *length, CERTDistNames *ca_list);
 SECStatus ssl3_CompleteHandleCertificateRequest(
     sslSocket *ss, const SSLSignatureScheme *signatureSchemes,
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -1726,28 +1726,20 @@ tls13_HandleClientHelloPart2(sslSocket *
     }
 
     ss->ssl3.hs.endOfFlight = PR_TRUE;
 
     if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) {
         ss->ssl3.hs.zeroRttState = ssl_0rtt_sent;
     }
 
-#ifndef PARANOID
-    /* Look for a matching cipher suite. */
-    if (ssl3_config_match_init(ss) == 0) { /* no ciphers are working/supported by PK11 */
-        FATAL_ERROR(ss, PORT_GetError(), internal_error);
-        goto loser;
-    }
-#endif
-
     /* Negotiate cipher suite. */
     rv = ssl3_NegotiateCipherSuite(ss, suites, PR_FALSE);
     if (rv != SECSuccess) {
-        FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP, handshake_failure);
+        FATAL_ERROR(ss, PORT_GetError(), handshake_failure);
         goto loser;
     }
 
     /* If we are going around again, then we should make sure that the cipher
      * suite selection doesn't change. That's a sign of client shennanigans. */
     if (ss->ssl3.hs.helloRetry) {
 
         /* Update sequence numbers before checking the cookie so that any alerts