Bug 1564499 - land NSS 009a7163c80a UPGRADE_NSS_RELEASE, r=me
☠☠ backed out by b5f2fa86e696 ☠ ☠
authorJ.C. Jones <jc@mozilla.com>
Wed, 31 Jul 2019 20:20:02 +0000
changeset 546333 f742215abea862a82599cc6869b970d487cf8f29
parent 546332 783c0e44c713d31bdf14dd84bdded192171343d1
child 546334 2cc2e0210a28dba5566fe5e57c51a195f66bf71b
push id11848
push userffxbld-merge
push dateMon, 26 Aug 2019 19:26:25 +0000
treeherdermozilla-beta@9b31bfdfac10 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs1564499
milestone70.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 1564499 - land NSS 009a7163c80a UPGRADE_NSS_RELEASE, r=me
security/nss/TAG-INFO
security/nss/cmd/lib/secpwd.c
security/nss/cmd/pk11mode/pk11mode.c
security/nss/cmd/shlibsign/shlibsign.c
security/nss/coreconf/coreconf.dep
security/nss/gtests/softoken_gtest/softoken_gtest.cc
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/pqg.c
security/nss/lib/freebl/rijndael.c
security/nss/lib/softoken/fipstokn.c
security/nss/lib/softoken/pkcs11.c
security/nss/lib/softoken/pkcs11i.h
security/nss/mach
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-a31fc0eefc4c
+009a7163c80a
--- a/security/nss/cmd/lib/secpwd.c
+++ b/security/nss/cmd/lib/secpwd.c
@@ -61,17 +61,17 @@ SEC_GetPassword(FILE *input, FILE *outpu
 #if defined(_WINDOWS)
     int isTTY = (input == stdin);
 #define echoOn(x)
 #define echoOff(x)
 #else
     int infd = fileno(input);
     int isTTY = isatty(infd);
 #endif
-    char phrase[200] = { '\0' }; /* ensure EOF doesn't return junk */
+    char phrase[500] = { '\0' }; /* ensure EOF doesn't return junk */
 
     for (;;) {
         /* Prompt for password */
         if (isTTY) {
             fprintf(output, "%s", prompt);
             fflush(output);
             echoOff(infd);
         }
--- a/security/nss/cmd/pk11mode/pk11mode.c
+++ b/security/nss/cmd/pk11mode/pk11mode.c
@@ -5224,17 +5224,17 @@ PKM_Digest(CK_FUNCTION_LIST_PTR pFunctio
     }
 
     return crv;
 }
 
 char *
 PKM_FilePasswd(char *pwFile)
 {
-    unsigned char phrase[200];
+    unsigned char phrase[500];
     PRFileDesc *fd;
     PRInt32 nb;
     int i;
 
     if (!pwFile)
         return 0;
 
     fd = PR_Open(pwFile, PR_RDONLY, 0);
--- a/security/nss/cmd/shlibsign/shlibsign.c
+++ b/security/nss/cmd/shlibsign/shlibsign.c
@@ -609,17 +609,17 @@ cleanup:
     }
 
     return crv;
 }
 
 static char *
 filePasswd(char *pwFile)
 {
-    unsigned char phrase[200];
+    unsigned char phrase[500];
     PRFileDesc *fd;
     PRInt32 nb;
     int i;
 
     if (!pwFile)
         return 0;
 
     fd = PR_Open(pwFile, PR_RDONLY, 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/softoken_gtest/softoken_gtest.cc
+++ b/security/nss/gtests/softoken_gtest/softoken_gtest.cc
@@ -1,13 +1,14 @@
 #include "cert.h"
 #include "certdb.h"
 #include "nspr.h"
 #include "nss.h"
 #include "pk11pub.h"
+#include "secmod.h"
 #include "secerr.h"
 
 #include "nss_scoped_ptrs.h"
 #include "util.h"
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 
@@ -114,16 +115,37 @@ TEST_F(SoftokenTest, CreateObjectChangeP
   EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
   EXPECT_EQ(SECSuccess, PK11_ChangePW(slot.get(), "", "password"));
   EXPECT_EQ(SECSuccess, PK11_Logout(slot.get()));
   ScopedPK11GenericObject obj(PK11_CreateGenericObject(
       slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
   EXPECT_EQ(nullptr, obj);
 }
 
+/* The size limit for a password is 500 characters as defined in pkcs11i.h */
+TEST_F(SoftokenTest, CreateObjectChangeToBigPassword) {
+  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+  ASSERT_TRUE(slot);
+  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
+  EXPECT_EQ(
+      SECSuccess,
+      PK11_ChangePW(slot.get(), "",
+                    "rUIFIFr2bxKnbJbitsfkyqttpk6vCJzlYMNxcxXcaN37gSZKbLk763X7iR"
+                    "yeVNWZHQ02lSF69HYjzTyPW3318ZD0DBFMMbALZ8ZPZP73CIo5uIQlaowV"
+                    "IbP8eOhRYtGUqoLGlcIFNEYogV8Q3GN58VeBMs0KxrIOvPQ9s8SnYYkqvt"
+                    "zzgntmAvCgvk64x6eQf0okHwegd5wi6m0WVJytEepWXkP9J629FSa5kNT8"
+                    "FvL3jvslkiImzTNuTvl32fQDXXMSc8vVk5Q3mH7trMZM0VDdwHWYERjHbz"
+                    "kGxFgp0VhediHx7p9kkz6H6ac4et9sW4UkTnN7xhYc1Zr17wRSk2heQtcX"
+                    "oZJGwuzhiKm8A8wkuVxms6zO56P4JORIk8oaUW6lyNTLo2kWWnTA"));
+  EXPECT_EQ(SECSuccess, PK11_Logout(slot.get()));
+  ScopedPK11GenericObject obj(PK11_CreateGenericObject(
+      slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
+  EXPECT_EQ(nullptr, obj);
+}
+
 TEST_F(SoftokenTest, CreateObjectChangeToEmptyPassword) {
   ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
   ASSERT_TRUE(slot);
   EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
   EXPECT_EQ(SECSuccess, PK11_ChangePW(slot.get(), "password", ""));
   // PK11_Logout returnes an error and SEC_ERROR_TOKEN_NOT_LOGGED_IN if the user
   // is not "logged in".
   EXPECT_EQ(SECFailure, PK11_Logout(slot.get()));
@@ -260,15 +282,109 @@ TEST_F(SoftokenNoDBTest, NeedUserInitNoD
   ASSERT_TRUE(slot);
   EXPECT_EQ(PR_FALSE, PK11_NeedUserInit(slot.get()));
 
   // When shutting down in here we have to release the slot first.
   slot = nullptr;
   ASSERT_EQ(SECSuccess, NSS_Shutdown());
 }
 
+#ifndef NSS_FIPS_DISABLED
+
+class SoftokenFipsTest : public SoftokenTest {
+ protected:
+  SoftokenFipsTest() : SoftokenTest("SoftokenFipsTest.d-") {}
+
+  virtual void SetUp() {
+    SoftokenTest::SetUp();
+
+    // Turn on FIPS mode (code borrowed from FipsMode in modutil/pk11.c)
+    char *internal_name;
+    ASSERT_FALSE(PK11_IsFIPS());
+    internal_name = PR_smprintf("%s", SECMOD_GetInternalModule()->commonName);
+    ASSERT_EQ(SECSuccess, SECMOD_DeleteInternalModule(internal_name));
+    PR_smprintf_free(internal_name);
+    ASSERT_TRUE(PK11_IsFIPS());
+  }
+};
+
+const std::vector<std::string> kFipsPasswordCases[] = {
+    // FIPS level1 -> level1 -> level1
+    {"", "", ""},
+    // FIPS level1 -> level1 -> level2
+    {"", "", "strong-_123"},
+    // FIXME: this should work: FIPS level1 -> level2 -> level2
+    // {"", "strong-_123", "strong-_456"},
+    // FIPS level2 -> level2 -> level2
+    {"strong-_123", "strong-_456", "strong-_123"}};
+
+const std::vector<std::string> kFipsPasswordBadCases[] = {
+    // FIPS level1 -> level2 -> level1
+    {"", "strong-_123", ""},
+    // FIPS level2 -> level1 -> level1
+    {"strong-_123", ""},
+    // FIPS level2 -> level2 -> level1
+    {"strong-_123", "strong-_456", ""},
+    // initialize with a weak password
+    {"weak"},
+    // FIPS level1 -> weak password
+    {"", "weak"},
+    // FIPS level2 -> weak password
+    {"strong-_123", "weak"}};
+
+class SoftokenFipsPasswordTest
+    : public SoftokenFipsTest,
+      public ::testing::WithParamInterface<std::vector<std::string>> {};
+
+class SoftokenFipsBadPasswordTest
+    : public SoftokenFipsTest,
+      public ::testing::WithParamInterface<std::vector<std::string>> {};
+
+TEST_P(SoftokenFipsPasswordTest, SetPassword) {
+  const std::vector<std::string> &passwords = GetParam();
+  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+  ASSERT_TRUE(slot);
+
+  auto it = passwords.begin();
+  auto prev_it = it;
+  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, (*it).c_str()));
+  for (it++; it != passwords.end(); it++, prev_it++) {
+    EXPECT_EQ(SECSuccess,
+              PK11_ChangePW(slot.get(), (*prev_it).c_str(), (*it).c_str()));
+  }
+}
+
+TEST_P(SoftokenFipsBadPasswordTest, SetBadPassword) {
+  const std::vector<std::string> &passwords = GetParam();
+  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+  ASSERT_TRUE(slot);
+
+  auto it = passwords.begin();
+  auto prev_it = it;
+  SECStatus rv = PK11_InitPin(slot.get(), nullptr, (*it).c_str());
+  if (it + 1 == passwords.end())
+    EXPECT_EQ(SECFailure, rv);
+  else
+    EXPECT_EQ(SECSuccess, rv);
+  for (it++; it != passwords.end(); it++, prev_it++) {
+    rv = PK11_ChangePW(slot.get(), (*prev_it).c_str(), (*it).c_str());
+    if (it + 1 == passwords.end())
+      EXPECT_EQ(SECFailure, rv);
+    else
+      EXPECT_EQ(SECSuccess, rv);
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(FipsPasswordCases, SoftokenFipsPasswordTest,
+                        ::testing::ValuesIn(kFipsPasswordCases));
+
+INSTANTIATE_TEST_CASE_P(BadFipsPasswordCases, SoftokenFipsBadPasswordTest,
+                        ::testing::ValuesIn(kFipsPasswordBadCases));
+
+#endif
+
 }  // namespace nss_test
 
 int main(int argc, char **argv) {
   ::testing::InitGoogleTest(&argc, argv);
 
   return RUN_ALL_TESTS();
 }
--- a/security/nss/lib/freebl/Makefile
+++ b/security/nss/lib/freebl/Makefile
@@ -236,19 +236,34 @@ ifeq ($(CPU_ARCH),x86)
     DEFINES += -DMP_ASSEMBLY_DIV_2DX1D -DMP_USE_UINT_DIGIT
     DEFINES += -DMP_IS_LITTLE_ENDIAN
 endif
 ifeq ($(CPU_ARCH),arm)
     DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE 
     DEFINES += -DMP_USE_UINT_DIGIT
     DEFINES += -DSHA_NO_LONG_LONG # avoid 64-bit arithmetic in SHA512
     MPI_SRCS += mpi_arm.c
+    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 ($(CPU_ARCH),aarch64)
-    EXTRA_SRCS += gcm-aarch64.c
+    DEFINES += -DUSE_HW_AES
+    EXTRA_SRCS += aes-armv8.c gcm-aarch64.c
 endif
 ifeq ($(CPU_ARCH),ppc)
 ifdef USE_64
     DEFINES += -DNSS_NO_INIT_SUPPORT
 endif # USE_64
 endif # ppc
 endif # Linux
 
@@ -756,11 +771,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(__builtin_assume_aligned(key, 16));
+    key2 = vld1q_u8(__builtin_assume_aligned(key + 16, 16));
+    key3 = vld1q_u8(__builtin_assume_aligned(key + 32, 16));
+    key4 = vld1q_u8(__builtin_assume_aligned(key + 48, 16));
+    key5 = vld1q_u8(__builtin_assume_aligned(key + 64, 16));
+    key6 = vld1q_u8(__builtin_assume_aligned(key + 80, 16));
+    key7 = vld1q_u8(__builtin_assume_aligned(key + 96, 16));
+    key8 = vld1q_u8(__builtin_assume_aligned(key + 112, 16));
+    key9 = vld1q_u8(__builtin_assume_aligned(key + 128, 16));
+    key10 = vld1q_u8(__builtin_assume_aligned(key + 144, 16));
+    key11 = vld1q_u8(__builtin_assume_aligned(key + 160, 16));
+
+    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(__builtin_assume_aligned(key, 16));
+    key2 = vld1q_u8(__builtin_assume_aligned(key + 16, 16));
+    key3 = vld1q_u8(__builtin_assume_aligned(key + 32, 16));
+    key4 = vld1q_u8(__builtin_assume_aligned(key + 48, 16));
+    key5 = vld1q_u8(__builtin_assume_aligned(key + 64, 16));
+    key6 = vld1q_u8(__builtin_assume_aligned(key + 80, 16));
+    key7 = vld1q_u8(__builtin_assume_aligned(key + 96, 16));
+    key8 = vld1q_u8(__builtin_assume_aligned(key + 112, 16));
+    key9 = vld1q_u8(__builtin_assume_aligned(key + 128, 16));
+    key10 = vld1q_u8(__builtin_assume_aligned(key + 144, 16));
+    key11 = vld1q_u8(__builtin_assume_aligned(key + 160, 16));
+
+    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(__builtin_assume_aligned(cx->iv, 16));
+
+    /* expanedKey */
+    key1 = vld1q_u8(__builtin_assume_aligned(key, 16));
+    key2 = vld1q_u8(__builtin_assume_aligned(key + 16, 16));
+    key3 = vld1q_u8(__builtin_assume_aligned(key + 32, 16));
+    key4 = vld1q_u8(__builtin_assume_aligned(key + 48, 16));
+    key5 = vld1q_u8(__builtin_assume_aligned(key + 64, 16));
+    key6 = vld1q_u8(__builtin_assume_aligned(key + 80, 16));
+    key7 = vld1q_u8(__builtin_assume_aligned(key + 96, 16));
+    key8 = vld1q_u8(__builtin_assume_aligned(key + 112, 16));
+    key9 = vld1q_u8(__builtin_assume_aligned(key + 128, 16));
+    key10 = vld1q_u8(__builtin_assume_aligned(key + 144, 16));
+    key11 = vld1q_u8(__builtin_assume_aligned(key + 160, 16));
+
+    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(__builtin_assume_aligned(cx->iv, 16), 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(__builtin_assume_aligned(cx->iv, 16));
+
+    /* expanedKey */
+    key1 = vld1q_u8(__builtin_assume_aligned(key, 16));
+    key2 = vld1q_u8(__builtin_assume_aligned(key + 16, 16));
+    key3 = vld1q_u8(__builtin_assume_aligned(key + 32, 16));
+    key4 = vld1q_u8(__builtin_assume_aligned(key + 48, 16));
+    key5 = vld1q_u8(__builtin_assume_aligned(key + 64, 16));
+    key6 = vld1q_u8(__builtin_assume_aligned(key + 80, 16));
+    key7 = vld1q_u8(__builtin_assume_aligned(key + 96, 16));
+    key8 = vld1q_u8(__builtin_assume_aligned(key + 112, 16));
+    key9 = vld1q_u8(__builtin_assume_aligned(key + 128, 16));
+    key10 = vld1q_u8(__builtin_assume_aligned(key + 144, 16));
+    key11 = vld1q_u8(__builtin_assume_aligned(key + 160, 16));
+
+    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(__builtin_assume_aligned(cx->iv, 16), 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(__builtin_assume_aligned(key, 16));
+    key2 = vld1q_u8(__builtin_assume_aligned(key + 16, 16));
+    key3 = vld1q_u8(__builtin_assume_aligned(key + 32, 16));
+    key4 = vld1q_u8(__builtin_assume_aligned(key + 48, 16));
+    key5 = vld1q_u8(__builtin_assume_aligned(key + 64, 16));
+    key6 = vld1q_u8(__builtin_assume_aligned(key + 80, 16));
+    key7 = vld1q_u8(__builtin_assume_aligned(key + 96, 16));
+    key8 = vld1q_u8(__builtin_assume_aligned(key + 112, 16));
+    key9 = vld1q_u8(__builtin_assume_aligned(key + 128, 16));
+    key10 = vld1q_u8(__builtin_assume_aligned(key + 144, 16));
+    key11 = vld1q_u8(__builtin_assume_aligned(key + 160, 16));
+    key12 = vld1q_u8(__builtin_assume_aligned(key + 176, 16));
+    key13 = vld1q_u8(__builtin_assume_aligned(key + 192, 16));
+
+    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(__builtin_assume_aligned(key, 16));
+    key2 = vld1q_u8(__builtin_assume_aligned(key + 16, 16));
+    key3 = vld1q_u8(__builtin_assume_aligned(key + 32, 16));
+    key4 = vld1q_u8(__builtin_assume_aligned(key + 48, 16));
+    key5 = vld1q_u8(__builtin_assume_aligned(key + 64, 16));
+    key6 = vld1q_u8(__builtin_assume_aligned(key + 80, 16));
+    key7 = vld1q_u8(__builtin_assume_aligned(key + 96, 16));
+    key8 = vld1q_u8(__builtin_assume_aligned(key + 112, 16));
+    key9 = vld1q_u8(__builtin_assume_aligned(key + 128, 16));
+    key10 = vld1q_u8(__builtin_assume_aligned(key + 144, 16));
+    key11 = vld1q_u8(__builtin_assume_aligned(key + 160, 16));
+    key12 = vld1q_u8(__builtin_assume_aligned(key + 176, 16));
+    key13 = vld1q_u8(__builtin_assume_aligned(key + 192, 16));
+
+    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(__builtin_assume_aligned(key, 16));
+    key2 = vld1q_u8(__builtin_assume_aligned(key + 16, 16));
+    key3 = vld1q_u8(__builtin_assume_aligned(key + 32, 16));
+    key4 = vld1q_u8(__builtin_assume_aligned(key + 48, 16));
+    key5 = vld1q_u8(__builtin_assume_aligned(key + 64, 16));
+    key6 = vld1q_u8(__builtin_assume_aligned(key + 80, 16));
+    key7 = vld1q_u8(__builtin_assume_aligned(key + 96, 16));
+    key8 = vld1q_u8(__builtin_assume_aligned(key + 112, 16));
+    key9 = vld1q_u8(__builtin_assume_aligned(key + 128, 16));
+    key10 = vld1q_u8(__builtin_assume_aligned(key + 144, 16));
+    key11 = vld1q_u8(__builtin_assume_aligned(key + 160, 16));
+    key12 = vld1q_u8(__builtin_assume_aligned(key + 176, 16));
+    key13 = vld1q_u8(__builtin_assume_aligned(key + 192, 16));
+
+    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(__builtin_assume_aligned(cx->iv, 16), 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(__builtin_assume_aligned(cx->iv, 16));
+
+    /* expanedKey */
+    key1 = vld1q_u8(__builtin_assume_aligned(key, 16));
+    key2 = vld1q_u8(__builtin_assume_aligned(key + 16, 16));
+    key3 = vld1q_u8(__builtin_assume_aligned(key + 32, 16));
+    key4 = vld1q_u8(__builtin_assume_aligned(key + 48, 16));
+    key5 = vld1q_u8(__builtin_assume_aligned(key + 64, 16));
+    key6 = vld1q_u8(__builtin_assume_aligned(key + 80, 16));
+    key7 = vld1q_u8(__builtin_assume_aligned(key + 96, 16));
+    key8 = vld1q_u8(__builtin_assume_aligned(key + 112, 16));
+    key9 = vld1q_u8(__builtin_assume_aligned(key + 128, 16));
+    key10 = vld1q_u8(__builtin_assume_aligned(key + 144, 16));
+    key11 = vld1q_u8(__builtin_assume_aligned(key + 160, 16));
+    key12 = vld1q_u8(__builtin_assume_aligned(key + 176, 16));
+    key13 = vld1q_u8(__builtin_assume_aligned(key + 192, 16));
+
+    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(__builtin_assume_aligned(cx->iv, 16), 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(__builtin_assume_aligned(key, 16));
+    key2 = vld1q_u8(__builtin_assume_aligned(key + 16, 16));
+    key3 = vld1q_u8(__builtin_assume_aligned(key + 32, 16));
+    key4 = vld1q_u8(__builtin_assume_aligned(key + 48, 16));
+    key5 = vld1q_u8(__builtin_assume_aligned(key + 64, 16));
+    key6 = vld1q_u8(__builtin_assume_aligned(key + 80, 16));
+    key7 = vld1q_u8(__builtin_assume_aligned(key + 96, 16));
+    key8 = vld1q_u8(__builtin_assume_aligned(key + 112, 16));
+    key9 = vld1q_u8(__builtin_assume_aligned(key + 128, 16));
+    key10 = vld1q_u8(__builtin_assume_aligned(key + 144, 16));
+    key11 = vld1q_u8(__builtin_assume_aligned(key + 160, 16));
+    key12 = vld1q_u8(__builtin_assume_aligned(key + 176, 16));
+    key13 = vld1q_u8(__builtin_assume_aligned(key + 192, 16));
+    key14 = vld1q_u8(__builtin_assume_aligned(key + 208, 16));
+    key15 = vld1q_u8(__builtin_assume_aligned(key + 224, 16));
+
+    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(__builtin_assume_aligned(key, 16));
+    key2 = vld1q_u8(__builtin_assume_aligned(key + 16, 16));
+    key3 = vld1q_u8(__builtin_assume_aligned(key + 32, 16));
+    key4 = vld1q_u8(__builtin_assume_aligned(key + 48, 16));
+    key5 = vld1q_u8(__builtin_assume_aligned(key + 64, 16));
+    key6 = vld1q_u8(__builtin_assume_aligned(key + 80, 16));
+    key7 = vld1q_u8(__builtin_assume_aligned(key + 96, 16));
+    key8 = vld1q_u8(__builtin_assume_aligned(key + 112, 16));
+    key9 = vld1q_u8(__builtin_assume_aligned(key + 128, 16));
+    key10 = vld1q_u8(__builtin_assume_aligned(key + 144, 16));
+    key11 = vld1q_u8(__builtin_assume_aligned(key + 160, 16));
+    key12 = vld1q_u8(__builtin_assume_aligned(key + 176, 16));
+    key13 = vld1q_u8(__builtin_assume_aligned(key + 192, 16));
+    key14 = vld1q_u8(__builtin_assume_aligned(key + 208, 16));
+    key15 = vld1q_u8(__builtin_assume_aligned(key + 224, 16));
+
+    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(__builtin_assume_aligned(key, 16));
+    key2 = vld1q_u8(__builtin_assume_aligned(key + 16, 16));
+    key3 = vld1q_u8(__builtin_assume_aligned(key + 32, 16));
+    key4 = vld1q_u8(__builtin_assume_aligned(key + 48, 16));
+    key5 = vld1q_u8(__builtin_assume_aligned(key + 64, 16));
+    key6 = vld1q_u8(__builtin_assume_aligned(key + 80, 16));
+    key7 = vld1q_u8(__builtin_assume_aligned(key + 96, 16));
+    key8 = vld1q_u8(__builtin_assume_aligned(key + 112, 16));
+    key9 = vld1q_u8(__builtin_assume_aligned(key + 128, 16));
+    key10 = vld1q_u8(__builtin_assume_aligned(key + 144, 16));
+    key11 = vld1q_u8(__builtin_assume_aligned(key + 160, 16));
+    key12 = vld1q_u8(__builtin_assume_aligned(key + 176, 16));
+    key13 = vld1q_u8(__builtin_assume_aligned(key + 192, 16));
+    key14 = vld1q_u8(__builtin_assume_aligned(key + 208, 16));
+    key15 = vld1q_u8(__builtin_assume_aligned(key + 224, 16));
+
+    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(__builtin_assume_aligned(cx->iv, 16), 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(__builtin_assume_aligned(key, 16));
+    key2 = vld1q_u8(__builtin_assume_aligned(key + 16, 16));
+    key3 = vld1q_u8(__builtin_assume_aligned(key + 32, 16));
+    key4 = vld1q_u8(__builtin_assume_aligned(key + 48, 16));
+    key5 = vld1q_u8(__builtin_assume_aligned(key + 64, 16));
+    key6 = vld1q_u8(__builtin_assume_aligned(key + 80, 16));
+    key7 = vld1q_u8(__builtin_assume_aligned(key + 96, 16));
+    key8 = vld1q_u8(__builtin_assume_aligned(key + 112, 16));
+    key9 = vld1q_u8(__builtin_assume_aligned(key + 128, 16));
+    key10 = vld1q_u8(__builtin_assume_aligned(key + 144, 16));
+    key11 = vld1q_u8(__builtin_assume_aligned(key + 160, 16));
+    key12 = vld1q_u8(__builtin_assume_aligned(key + 176, 16));
+    key13 = vld1q_u8(__builtin_assume_aligned(key + 192, 16));
+    key14 = vld1q_u8(__builtin_assume_aligned(key + 208, 16));
+    key15 = vld1q_u8(__builtin_assume_aligned(key + 224, 16));
+
+    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(__builtin_assume_aligned(cx->iv, 16), 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',
           ],
+        }, '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': [
@@ -424,16 +461,22 @@
           }],
           [ 'target_arch=="arm"', {
             'defines': [
               'MP_ASSEMBLY_MULTIPLY',
               'MP_ASSEMBLY_SQUARE',
               'MP_USE_UINT_DIGIT',
               'SHA_NO_LONG_LONG',
               'ARMHF',
+              'USE_HW_AES',
+            ],
+          }],
+          [ 'target_arch=="arm64" or target_arch=="aarch64"', {
+            'defines': [
+              'USE_HW_AES',
             ],
           }],
         ],
       }],
     ],
   },
   'variables': {
     'module': 'nss',
--- 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/pqg.c
+++ b/security/nss/lib/freebl/pqg.c
@@ -885,17 +885,17 @@ findQfromSeed(
     const SECItem *seed,        /* input.  */
     mp_int *Q,                  /* input. */
     mp_int *Q_,                 /* output. */
     unsigned int *qseed_len,    /* output */
     HASH_HashType *hashtypePtr, /* output. Hash uses */
     pqgGenType *typePtr,        /* output. Generation Type used */
     unsigned int *qgen_counter) /* output. q_counter */
 {
-    HASH_HashType hashtype;
+    HASH_HashType hashtype = HASH_AlgNULL;
     SECItem firstseed = { 0, 0, 0 };
     SECItem qseed = { 0, 0, 0 };
     SECStatus rv;
 
     *qseed_len = 0; /* only set if FIPS186_3_ST_TYPE */
 
     /* handle legacy small DSA first can only be FIPS186_1_TYPE */
     if (L < 1024) {
@@ -1234,17 +1234,17 @@ pqg_ParamGen(unsigned int L, unsigned in
              unsigned int seedBytes, PQGParams **pParams, PQGVerify **pVfy)
 {
     unsigned int n;       /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */
     unsigned int seedlen; /* Per FIPS 186-3 app A.1.1.2  (was 'g' 186-1)*/
     unsigned int counter; /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */
     unsigned int offset;  /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */
     unsigned int outlen;  /* Per FIPS 186-3, appendix A.1.1.2. */
     unsigned int maxCount;
-    HASH_HashType hashtype;
+    HASH_HashType hashtype = HASH_AlgNULL;
     SECItem *seed; /* Per FIPS 186, app 2.2. 186-3 app A.1.1.2 */
     PLArenaPool *arena = NULL;
     PQGParams *params = NULL;
     PQGVerify *verify = NULL;
     PRBool passed;
     SECItem hit = { 0, 0, 0 };
     SECItem firstseed = { 0, 0, 0 };
     SECItem qseed = { 0, 0, 0 };
@@ -1625,18 +1625,18 @@ PQG_VerifyParams(const PQGParams *params
     unsigned int g, n, L, N, offset, outlen;
     mp_int p0, P, Q, G, P_, Q_, G_, r, h;
     mp_err err = MP_OKAY;
     int j;
     unsigned int counter_max = 0; /* handle legacy L < 1024 */
     unsigned int qseed_len;
     unsigned int qgen_counter_ = 0;
     SECItem pseed_ = { 0, 0, 0 };
-    HASH_HashType hashtype;
-    pqgGenType type;
+    HASH_HashType hashtype = HASH_AlgNULL;
+    pqgGenType type = FIPS186_1_TYPE;
 
 #define CHECKPARAM(cond)      \
     if (!(cond)) {            \
         *result = SECFailure; \
         goto cleanup;         \
     }
     if (!params || !vfy || !result) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
--- 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/softoken/fipstokn.c
+++ b/security/nss/lib/softoken/fipstokn.c
@@ -640,27 +640,47 @@ FC_InitPIN(CK_SESSION_HANDLE hSession,
 CK_RV
 FC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin,
           CK_ULONG usOldLen, CK_CHAR_PTR pNewPin, CK_ULONG usNewLen)
 {
     CK_RV rv;
 
     CHECK_FORK();
 
-    if ((rv = sftk_fipsCheck()) == CKR_OK &&
-        (rv = sftk_newPinCheck(pNewPin, usNewLen)) == CKR_OK) {
+    rv = sftk_fipsCheck();
+    if (rv != CKR_OK) {
+        goto loser;
+    }
+
+    if (isLevel2 || usNewLen > 0) {
+        rv = sftk_newPinCheck(pNewPin, usNewLen);
+        if (rv != CKR_OK) {
+            goto loser;
+        }
         rv = NSC_SetPIN(hSession, pOldPin, usOldLen, pNewPin, usNewLen);
-        if ((rv == CKR_OK) &&
-            (sftk_SlotIDFromSessionHandle(hSession) == FIPS_SLOT_ID)) {
+        if (rv != CKR_OK) {
+            goto loser;
+        }
+        if (sftk_SlotIDFromSessionHandle(hSession) == FIPS_SLOT_ID) {
             /* if we set the password in level1 we now go
              * to level2. NOTE: we don't allow the user to
              * go from level2 to level1 */
             isLevel2 = PR_TRUE;
         }
+    } else {
+        /* here both old and new passwords are empty, but we need to
+         * call NSC_SetPIN to force rekey the database entries */
+        PORT_Assert(usNewLen == 0);
+        rv = NSC_SetPIN(hSession, pOldPin, usOldLen, pNewPin, usNewLen);
+        if (rv != CKR_OK) {
+            goto loser;
+        }
     }
+
+loser:
     if (sftk_audit_enabled) {
         char msg[128];
         NSSAuditSeverity severity = (rv == CKR_OK) ? NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
         PR_snprintf(msg, sizeof msg,
                     "C_SetPIN(hSession=0x%08lX)=0x%08lX",
                     (PRUint32)hSession, (PRUint32)rv);
         sftk_LogAuditMessage(severity, NSS_AUDIT_SET_PIN, msg);
     }
--- a/security/nss/lib/softoken/pkcs11.c
+++ b/security/nss/lib/softoken/pkcs11.c
@@ -3895,17 +3895,20 @@ NSC_SetPIN(CK_SESSION_HANDLE hSession, C
     sftk_FreeSession(sp);
     sp = NULL;
 
     /* make sure the pins aren't too long */
     if ((ulNewLen > SFTK_MAX_PIN) || (ulOldLen > SFTK_MAX_PIN)) {
         crv = CKR_PIN_LEN_RANGE;
         goto loser;
     }
-    if (ulNewLen < (CK_ULONG)slot->minimumPinLen) {
+    /* check the length of new pin, unless both old and new passwords
+     * are empty */
+    if ((ulNewLen != 0 || ulOldLen != 0) &&
+        ulNewLen < (CK_ULONG)slot->minimumPinLen) {
         crv = CKR_PIN_LEN_RANGE;
         goto loser;
     }
 
     /* convert to null terminated string */
     PORT_Memcpy(newPinStr, pNewPin, ulNewLen);
     newPinStr[ulNewLen] = 0;
     PORT_Memcpy(oldPinStr, pOldPin, ulOldLen);
--- a/security/nss/lib/softoken/pkcs11i.h
+++ b/security/nss/lib/softoken/pkcs11i.h
@@ -454,17 +454,17 @@ struct SFTKItemTemplateStr {
 /* certdb (high bit == 1) */
 #define SFTK_TOKEN_TYPE_TRUST 0x40000000L
 #define SFTK_TOKEN_TYPE_CRL 0x50000000L
 #define SFTK_TOKEN_TYPE_SMIME 0x60000000L
 #define SFTK_TOKEN_TYPE_CERT 0x70000000L
 
 #define SFTK_TOKEN_KRL_HANDLE (SFTK_TOKEN_MAGIC | SFTK_TOKEN_TYPE_CRL | 1)
 /* how big (in bytes) a password/pin we can deal with */
-#define SFTK_MAX_PIN 255
+#define SFTK_MAX_PIN 500
 /* minimum password/pin length (in Unicode characters) in FIPS mode */
 #define FIPS_MIN_PIN 7
 
 /* slot ID's */
 #define NETSCAPE_SLOT_ID 1
 #define PRIVATE_KEY_SLOT_ID 2
 #define FIPS_SLOT_ID 3
 
--- a/security/nss/mach
+++ b/security/nss/mach
@@ -192,16 +192,23 @@ class coverityAction(argparse.Action):
 
     def cov_is_file_in_source(self, abs_path):
         if os.path.islink(abs_path):
             abs_path = os.path.realpath(abs_path)
         return abs_path
 
     def dump_cov_artifact(self, cov_results, source, output):
         import json
+
+        def relpath(path):
+            '''Build path relative to repository root'''
+            if path.startswith(cwd):
+                return os.path.relpath(path, cwd)
+            return path
+
         # Parse Coverity json into structured issues
         with open(cov_results) as f:
             result = json.load(f)
 
             # Parse the issues to a standard json format
             issues_dict = {'files': {}}
 
             files_list = issues_dict['files']
@@ -218,30 +225,31 @@ class coverityAction(argparse.Action):
                         'category': issue['checkerProperties']['category'],
                         'stateOnServer': issue['stateOnServer'],
                         'stack': []
                     }
                 }
 
                 # Embed all events into extra message
                 for event in issue['events']:
-                    dict_issue['extra']['stack'].append({'file_path': event['strippedFilePathname'],
+                    dict_issue['extra']['stack'].append({'file_path': relpath(event['strippedFilePathname']),
                                                          'line_number': event['lineNumber'],
                                                          'path_type': event['eventTag'],
                                                          'description': event['eventDescription']})
 
                 return dict_issue
 
             for issue in result['issues']:
                 path = self.cov_is_file_in_source(issue['strippedMainEventFilePathname'])
                 if path is None:
                     # Since we skip a result we should log it
                     print('Skipping CID: {0} from file: {1} since it\'s not related with the current patch.'.format(
                         issue['stateOnServer']['cid'], issue['strippedMainEventFilePathname']))
                     continue
+                path = relpath(path)
                 if path in files_list:
                     files_list[path]['warnings'].append(build_element(issue))
                 else:
                     files_list[path] = {'warnings': [build_element(issue)]}
 
             with open(output, 'w') as f:
                 json.dump(issues_dict, f)