diff --git a/.gitignore b/.gitignore
index c74a5cd..a840dca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/nss-softokn-3.79.tar.gz
+SOURCES/nss-softokn-3.90.tar.gz
diff --git a/.nss-softokn.metadata b/.nss-softokn.metadata
index 0a56480..e179dd2 100644
--- a/.nss-softokn.metadata
+++ b/.nss-softokn.metadata
@@ -1 +1 @@
-41bdca46bc56dff4c01557fe07a64cc29a10d818 SOURCES/nss-softokn-3.79.tar.gz
+9f03b3c7f1abee6b0e68c8cf2792e1062f5cf8bb SOURCES/nss-softokn-3.90.tar.gz
diff --git a/SOURCES/fips_algorithms.h b/SOURCES/fips_algorithms.h
new file mode 100644
index 0000000..80d7dcd
--- /dev/null
+++ b/SOURCES/fips_algorithms.h
@@ -0,0 +1,172 @@
+/* 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/. */
+
+/*
+ * Vendors should replace this header file with the file containing those
+ * algorithms which have NIST algorithm Certificates.
+ */
+
+/* handle special cases. Classes require existing code to already be
+ * in place for that class */
+typedef enum {
+    SFTKFIPSNone = 0,
+    SFTKFIPSDH,  /* allow only specific primes */
+    SFTKFIPSECC, /* not just keys but specific curves */
+    SFTKFIPSAEAD, /* single shot AEAD functions not allowed in FIPS mode */
+    SFTKFIPSRSAPSS, /* make sure salt isn't too big */
+    SFTKFIPSPBKDF2  /* handle pbkdf2 FIPS restrictions */
+} SFTKFIPSSpecialClass;
+
+/* set according to your security policy */
+#define SFTKFIPS_PBKDF2_MIN_PW_LEN  7
+
+typedef struct SFTKFIPSAlgorithmListStr SFTKFIPSAlgorithmList;
+struct SFTKFIPSAlgorithmListStr {
+    CK_MECHANISM_TYPE type;
+    CK_MECHANISM_INFO info;
+    CK_ULONG step;
+    SFTKFIPSSpecialClass special;
+};
+
+SFTKFIPSAlgorithmList sftk_fips_mechs[] = {
+/* A sample set of algorithms to allow basic testing in our continous
+ * testing infrastructure. The vendor version should replace this with
+ * a version that matches their algorithm testing and security policy */
+/* NOTE, This looks a lot like the PKCS #11 mechanism list in pkcs11.c, it
+ * differs in the following ways:
+ *    1) the addition of step and class elements to help restrict
+ *       the supported key sizes and types.
+ *    2) The mechanism flags are restricted to only those that map to
+ *       fips approved operations.
+ *    3) All key sizes are in bits, independent of mechanism.
+ *    4) You can add more then one entry for the same mechanism to handle
+ *       multiple descrete keys where the MIN/MAX/STEP semantics doesn't apply
+ *       or where different operations have different key requirements.
+ * This table does not encode all the modules legal FIPS semantics, only
+ * those semantics that might possibly change due to algorithms dropping
+ * of the security policy late in the process. */
+/* handy common flag types */
+#define CKF_KPG CKF_GENERATE_KEY_PAIR
+#define CKF_GEN CKF_GENERATE
+#define CKF_SGN (CKF_SIGN | CKF_VERIFY)
+#define CKF_ENC (CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP)
+#define CKF_KEK (CKF_WRAP | CKF_UNWRAP)
+#define CKF_KEA CKF_DERIVE
+#define CKF_KDF CKF_DERIVE
+#define CKF_HSH CKF_DIGEST
+#define CK_MAX 0xffffffffUL
+/* mechanisms using the same key types share the same key type
+ * limits */
+#define RSA_FB_KEY 2048, 4096 /* min, max */
+#define RSA_FB_STEP 1
+#define RSA_LEGACY_FB_KEY 1024, 1792 /* min, max */
+#define RSA_LEGACY_FB_STEP 256
+
+#define DSA_FB_KEY 2048, 4096 /* min, max */
+#define DSA_FB_STEP 1024
+#define DH_FB_KEY 2048, 8192 /* min, max */
+#define DH_FB_STEP 1024
+#define EC_FB_KEY 256, 521 /* min, max */
+#define EC_FB_STEP 1       /* key limits handled by special operation */
+#define AES_FB_KEY 128, 256
+#define AES_FB_STEP 64
+    { CKM_RSA_PKCS_KEY_PAIR_GEN, { RSA_FB_KEY, CKF_KPG }, RSA_FB_STEP, SFTKFIPSNone },
+
+    /* -------------- RSA Multipart Signing Operations -------------------- */
+    { CKM_SHA224_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA256_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA384_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA512_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA224_RSA_PKCS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA256_RSA_PKCS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA384_RSA_PKCS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA512_RSA_PKCS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA224_RSA_PKCS_PSS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSRSAPSS },
+    { CKM_SHA256_RSA_PKCS_PSS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSRSAPSS },
+    { CKM_SHA384_RSA_PKCS_PSS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSRSAPSS },
+    { CKM_SHA512_RSA_PKCS_PSS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSRSAPSS },
+    { CKM_SHA224_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSRSAPSS },
+    { CKM_SHA256_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSRSAPSS },
+    { CKM_SHA384_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSRSAPSS },
+    { CKM_SHA512_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSRSAPSS },
+    /* ------------------------- DSA Operations --------------------------- */
+    { CKM_DSA_SHA224, { DSA_FB_KEY, CKF_VERIFY }, DSA_FB_STEP, SFTKFIPSNone },
+    { CKM_DSA_SHA256, { DSA_FB_KEY, CKF_VERIFY }, DSA_FB_STEP, SFTKFIPSNone },
+    { CKM_DSA_SHA384, { DSA_FB_KEY, CKF_VERIFY }, DSA_FB_STEP, SFTKFIPSNone },
+    { CKM_DSA_SHA512, { DSA_FB_KEY, CKF_VERIFY }, DSA_FB_STEP, SFTKFIPSNone },
+    /* -------------------- Diffie Hellman Operations --------------------- */
+    { CKM_DH_PKCS_KEY_PAIR_GEN, { DH_FB_KEY, CKF_KPG }, DH_FB_STEP, SFTKFIPSDH },
+    { CKM_DH_PKCS_DERIVE, { DH_FB_KEY, CKF_KEA }, DH_FB_STEP, SFTKFIPSDH },
+    /* -------------------- Elliptic Curve Operations --------------------- */
+    { CKM_EC_KEY_PAIR_GEN, { EC_FB_KEY, CKF_KPG }, EC_FB_STEP, SFTKFIPSECC },
+    { CKM_ECDH1_DERIVE, { EC_FB_KEY, CKF_KEA }, EC_FB_STEP, SFTKFIPSECC },
+    { CKM_ECDSA_SHA224, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+    { CKM_ECDSA_SHA256, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+    { CKM_ECDSA_SHA384, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+    { CKM_ECDSA_SHA512, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+    /* ------------------------- RC2 Operations --------------------------- */
+    /* ------------------------- AES Operations --------------------------- */
+    { CKM_AES_KEY_GEN, { AES_FB_KEY, CKF_GEN }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_ECB, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_CBC, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_CMAC, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_CMAC_GENERAL, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_CBC_PAD, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_CTS, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_CTR, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_GCM, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSAEAD },
+    { CKM_AES_KEY_WRAP, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_KEY_WRAP_PAD, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_KEY_WRAP_KWP, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    /* ------------------------- Hashing Operations ----------------------- */
+    { CKM_SHA224, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone },
+    { CKM_SHA224_HMAC, { 112, 224, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA224_HMAC_GENERAL, { 112, 224, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA256, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone },
+    { CKM_SHA256_HMAC, { 112, 256, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA256_HMAC_GENERAL, { 112, 256, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA384, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone },
+    { CKM_SHA384_HMAC, { 112, 384, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA384_HMAC_GENERAL, { 112, 384, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA512, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone },
+    { CKM_SHA512_HMAC, { 112, 512, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA512_HMAC_GENERAL, { 112, 512, CKF_SGN }, 1, SFTKFIPSNone },
+    /* --------------------- Secret Key Operations ------------------------ */
+    { CKM_GENERIC_SECRET_KEY_GEN, { 112, 256, CKF_GEN }, 1, SFTKFIPSNone },
+    /* ---------------------- SSL/TLS operations ------------------------- */
+    { CKM_SSL3_PRE_MASTER_KEY_GEN, { 384, 384, CKF_GEN }, 1, SFTKFIPSNone },
+    { CKM_TLS_MASTER_KEY_DERIVE, { 384, 384, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_TLS_MASTER_KEY_DERIVE_DH, { DH_FB_KEY, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_TLS_KEY_AND_MAC_DERIVE, { 384, 384, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_TLS12_MASTER_KEY_DERIVE, { 384, 384, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_TLS12_MASTER_KEY_DERIVE_DH, { DH_FB_KEY, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_TLS12_KEY_AND_MAC_DERIVE, { 384, 384, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256, { 384, 384, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256, { DH_FB_KEY, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256, { 384, 384, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_TLS_PRF_GENERAL_SHA256, { 112, 512, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_TLS_PRF_GENERAL, { 112, 512, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_TLS_MAC, { 112, 512, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE, { 192, 1024, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH, { 192, 1024, CKF_DERIVE }, 1, SFTKFIPSNone },
+
+    /* ------------------------- HKDF Operations -------------------------- */
+    { CKM_HKDF_DERIVE, { 112, 255 * 64 * 8, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_HKDF_DATA, { 112, 255 * 64 * 8, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_HKDF_KEY_GEN, { 160, 224, CKF_GEN }, 1, SFTKFIPSNone },
+    { CKM_HKDF_KEY_GEN, { 256, 512, CKF_GEN }, 128, SFTKFIPSNone },
+    /* ------------------ NIST 800-108 Key Derivations  ------------------- */
+    { CKM_SP800_108_COUNTER_KDF, { 112, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_SP800_108_FEEDBACK_KDF, { 112, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_SP800_108_DOUBLE_PIPELINE_KDF, { 112, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_SP800_108_COUNTER_KDF_DERIVE_DATA, { 112, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA, { 112, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA, { 112, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+    /* --------------------IPSEC ----------------------- */
+    { CKM_NSS_IKE_PRF_PLUS_DERIVE, { 112, 255 * 64 * 8, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_IKE_PRF_DERIVE, { 112, 64 * 8, CKF_KDF }, 1, SFTKFIPSNone },
+    /* ------------------ PBE Key Derivations  ------------------- */
+    { CKM_PKCS5_PBKD2, { 112, 256, CKF_GEN }, 1, SFTKFIPSPBKDF2 },
+};
+const int SFTK_NUMBER_FIPS_ALGORITHMS = PR_ARRAY_SIZE(sftk_fips_mechs);
diff --git a/SOURCES/iquote.patch b/SOURCES/iquote.patch
index 3d1aa60..3ab9ea9 100644
--- a/SOURCES/iquote.patch
+++ b/SOURCES/iquote.patch
@@ -1,6 +1,6 @@
-diff -up nss/cmd/bltest/Makefile.iquote nss/cmd/bltest/Makefile
---- nss/cmd/bltest/Makefile.iquote	2013-04-04 21:56:59.329249213 -0700
-+++ nss/cmd/bltest/Makefile	2013-04-04 21:57:47.583579084 -0700
+diff -up ./nss/cmd/bltest/Makefile.iquote ./nss/cmd/bltest/Makefile
+--- ./nss/cmd/bltest/Makefile.iquote	2023-06-04 10:42:53.000000000 +0200
++++ ./nss/cmd/bltest/Makefile	2023-06-21 15:15:54.270305289 +0200
 @@ -45,6 +45,7 @@ include $(CORE_DEPTH)/coreconf/rules.mk
  # (6) Execute "component" rules. (OPTIONAL)                           #
  #######################################################################
@@ -9,10 +9,20 @@ diff -up nss/cmd/bltest/Makefile.iquote nss/cmd/bltest/Makefile
  
  
  #######################################################################
-diff -up nss/coreconf/location.mk.iquote nss/coreconf/location.mk
---- nss/coreconf/location.mk.iquote	2013-04-04 21:54:59.710477106 -0700
-+++ nss/coreconf/location.mk	2013-04-04 21:56:21.091163121 -0700
-@@ -45,6 +45,10 @@ endif
+diff -up ./nss/cmd/shlibsign/Makefile.iquote ./nss/cmd/shlibsign/Makefile
+--- ./nss/cmd/shlibsign/Makefile.iquote	2023-06-21 15:18:56.139532867 +0200
++++ ./nss/cmd/shlibsign/Makefile	2023-06-21 15:19:53.445919672 +0200
+@@ -99,3 +99,6 @@ libs: install
+ ifdef CHECKLOC
+ 	$(MAKE) $(CHECKLOC)
+ endif
++
++INCLUDES += -iquote $(DIST)/../public/nss -iquote $(DIST)/../private/nss
++
+diff -up ./nss/coreconf/location.mk.iquote ./nss/coreconf/location.mk
+--- ./nss/coreconf/location.mk.iquote	2023-06-04 10:42:53.000000000 +0200
++++ ./nss/coreconf/location.mk	2023-06-21 15:15:54.270305289 +0200
+@@ -42,6 +42,10 @@ endif
  
  ifdef NSS_INCLUDE_DIR
      INCLUDES += -I$(NSS_INCLUDE_DIR)
@@ -24,9 +34,9 @@ diff -up nss/coreconf/location.mk.iquote nss/coreconf/location.mk
  
  ifndef NSS_LIB_DIR
 diff -up ./nss/lib/softoken/Makefile.iquote ./nss/lib/softoken/Makefile
---- ./nss/lib/softoken/Makefile.iquote	2014-01-06 20:35:19.931937299 -0800
-+++ ./nss/lib/softoken/Makefile	2014-01-06 20:36:15.336390664 -0800
-@@ -42,6 +42,8 @@ ifdef NSS_DISABLE_DBM
+--- ./nss/lib/softoken/Makefile.iquote	2023-06-04 10:42:53.000000000 +0200
++++ ./nss/lib/softoken/Makefile	2023-06-21 15:15:54.270305289 +0200
+@@ -52,6 +52,8 @@ ifdef NSS_DISABLE_DBM
  DIRS=
  endif
  
diff --git a/SOURCES/nss-3.79-fips-review.patches b/SOURCES/nss-3.79-fips-review.patches
new file mode 100644
index 0000000..14c904a
--- /dev/null
+++ b/SOURCES/nss-3.79-fips-review.patches
@@ -0,0 +1,497 @@
+diff -up ./lib/freebl/dh.c.fips-review ./lib/freebl/dh.c
+--- ./lib/freebl/dh.c.fips-review	2023-06-04 01:42:53.000000000 -0700
++++ ./lib/freebl/dh.c	2023-06-12 15:30:23.453233170 -0700
+@@ -445,7 +445,7 @@ cleanup:
+ PRBool
+ KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime)
+ {
+-    mp_int p, q, y, r;
++    mp_int p, q, y, r, psub1;
+     mp_err err;
+     int cmp = 1; /* default is false */
+     if (!Y || !prime || !subPrime) {
+@@ -456,13 +456,30 @@ KEA_Verify(SECItem *Y, SECItem *prime, S
+     MP_DIGITS(&q) = 0;
+     MP_DIGITS(&y) = 0;
+     MP_DIGITS(&r) = 0;
++    MP_DIGITS(&psub1) = 0;
+     CHECK_MPI_OK(mp_init(&p));
+     CHECK_MPI_OK(mp_init(&q));
+     CHECK_MPI_OK(mp_init(&y));
+     CHECK_MPI_OK(mp_init(&r));
++    CHECK_MPI_OK(mp_init(&psub1));
+     SECITEM_TO_MPINT(*prime, &p);
+     SECITEM_TO_MPINT(*subPrime, &q);
+     SECITEM_TO_MPINT(*Y, &y);
++    CHECK_MPI_OK(mp_sub_d(&p, 1, &psub1));
++    /*
++     * We check that the public value isn't zero (which isn't in the
++     * group), one (subgroup of order one) or p-1 (subgroup of order 2). We
++     * also check that the public value is less than p, to avoid being fooled
++     * by values like p+1 or 2*p-1.
++     * This check is required by SP-800-56Ar3. It's also done in derive,
++     * but this is only called in various FIPS cases, so put it here to help
++     * reviewers find it.
++     */
++    if (mp_cmp_d(&y, 1) <= 0 ||
++        mp_cmp(&y, &psub1) >= 0) {
++        err = MP_BADARG;
++        goto cleanup;
++    }
+     /* compute r = y**q mod p */
+     CHECK_MPI_OK(mp_exptmod(&y, &q, &p, &r));
+     /* compare to 1 */
+@@ -472,6 +489,7 @@ cleanup:
+     mp_clear(&q);
+     mp_clear(&y);
+     mp_clear(&r);
++    mp_clear(&psub1);
+     if (err) {
+         MP_TO_SEC_ERROR(err);
+         return PR_FALSE;
+diff -up ./lib/softoken/pkcs11c.c.fips-review ./lib/softoken/pkcs11c.c
+--- ./lib/softoken/pkcs11c.c.fips-review	2023-06-12 15:29:04.096403884 -0700
++++ ./lib/softoken/pkcs11c.c	2023-06-12 15:30:23.454233181 -0700
+@@ -4785,6 +4785,10 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSessi
+      * handle the base object stuff
+      */
+     crv = sftk_handleObject(key, session);
++    /* we need to do this check at the end, so we can check the generated 
++     * key length against fips requirements */
++    key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE, key);
++    session->lastOpWasFIPS = key->isFIPS;
+     sftk_FreeSession(session);
+     if (crv == CKR_OK && sftk_isTrue(key, CKA_SENSITIVE)) {
+         crv = sftk_forceAttribute(key, CKA_ALWAYS_SENSITIVE, &cktrue, sizeof(CK_BBOOL));
+@@ -4792,9 +4796,6 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSessi
+     if (crv == CKR_OK && !sftk_isTrue(key, CKA_EXTRACTABLE)) {
+         crv = sftk_forceAttribute(key, CKA_NEVER_EXTRACTABLE, &cktrue, sizeof(CK_BBOOL));
+     }
+-    /* we need to do this check at the end, so we can check the generated key length against
+-     * fips requirements */
+-    key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE, key);
+     if (crv == CKR_OK) {
+         *phKey = key->handle;
+     }
+@@ -5098,60 +5099,67 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
+ 
+     if (isDerivable) {
+         SFTKAttribute *pubAttribute = NULL;
+-        CK_OBJECT_HANDLE newKey;
+         PRBool isFIPS = sftk_isFIPS(slot->slotID);
+-        CK_RV crv2;
+-        CK_OBJECT_CLASS secret = CKO_SECRET_KEY;
+-        CK_KEY_TYPE generic = CKK_GENERIC_SECRET;
+-        CK_ULONG keyLen = 128;
+-        CK_BBOOL ckTrue = CK_TRUE;
+-        CK_ATTRIBUTE template[] = {
+-            { CKA_CLASS, &secret, sizeof(secret) },
+-            { CKA_KEY_TYPE, &generic, sizeof(generic) },
+-            { CKA_VALUE_LEN, &keyLen, sizeof(keyLen) },
+-            { CKA_DERIVE, &ckTrue, sizeof(ckTrue) }
+-        };
+-        CK_ULONG templateCount = PR_ARRAY_SIZE(template);
+-        CK_ECDH1_DERIVE_PARAMS ecParams;
++        NSSLOWKEYPrivateKey *lowPrivKey = NULL;
++        ECPrivateKey *ecPriv;
++        SECItem *lowPubValue = NULL;
++        SECItem item;
++        SECStatus rv;
+ 
+         crv = CKR_OK; /*paranoia, already get's set before we drop to the end */
+-        /* FIPS 140-2 requires we verify that the resulting key is a valid key.
+-         * The easiest way to do this is to do a derive operation, which checks
+-         * the validity of the key */
+-
++        /* FIPS 140-3 requires we verify that the resulting key is a valid key
++         * by recalculating the public can an compare it to our own public
++         * key. */
++        lowPrivKey = sftk_GetPrivKey(privateKey, keyType, &crv);
++        if (lowPrivKey == NULL) {
++            return sftk_MapCryptError(PORT_GetError());
++        }
++        /* recalculate the public key from the private key */
+         switch (keyType) {
+-            case CKK_DH:
+-                mech.mechanism = CKM_DH_PKCS_DERIVE;
+-                pubAttribute = sftk_FindAttribute(publicKey, CKA_VALUE);
+-                if (pubAttribute == NULL) {
+-                    return CKR_DEVICE_ERROR;
+-                }
+-                mech.pParameter = pubAttribute->attrib.pValue;
+-                mech.ulParameterLen = pubAttribute->attrib.ulValueLen;
+-                break;
+-            case CKK_EC:
+-                mech.mechanism = CKM_ECDH1_DERIVE;
+-                pubAttribute = sftk_FindAttribute(publicKey, CKA_EC_POINT);
+-                if (pubAttribute == NULL) {
+-                    return CKR_DEVICE_ERROR;
+-                }
+-                ecParams.kdf = CKD_NULL;
+-                ecParams.ulSharedDataLen = 0;
+-                ecParams.pSharedData = NULL;
+-                ecParams.ulPublicDataLen = pubAttribute->attrib.ulValueLen;
+-                ecParams.pPublicData = pubAttribute->attrib.pValue;
+-                mech.pParameter = &ecParams;
+-                mech.ulParameterLen = sizeof(ecParams);
+-                break;
+-            default:
+-                return CKR_DEVICE_ERROR;
++        case CKK_DH:
++            rv = DH_Derive(&lowPrivKey->u.dh.base, &lowPrivKey->u.dh.prime,
++                           &lowPrivKey->u.dh.privateValue, &item, 0);
++            if (rv != SECSuccess) {
++                return CKR_GENERAL_ERROR;
++            }
++            lowPubValue = SECITEM_DupItem(&item);
++            SECITEM_ZfreeItem(&item, PR_FALSE);
++            pubAttribute = sftk_FindAttribute(publicKey, CKA_VALUE);
++            break;
++        case CKK_EC:
++            rv = EC_NewKeyFromSeed(&lowPrivKey->u.ec.ecParams, &ecPriv,
++                                   lowPrivKey->u.ec.privateValue.data,
++                                   lowPrivKey->u.ec.privateValue.len);
++            if (rv != SECSuccess) {
++                return CKR_GENERAL_ERROR;
++            }
++            /* make sure it has the same encoding */
++            if (PR_GetEnvSecure("NSS_USE_DECODED_CKA_EC_POINT") ||
++                lowPrivKey->u.ec.ecParams.fieldID.type == ec_field_plain) {
++              lowPubValue = SECITEM_DupItem(&ecPriv->publicValue);
++            } else {
++              lowPubValue = SEC_ASN1EncodeItem(NULL, NULL, &ecPriv->publicValue,
++                                               SEC_ASN1_GET(SEC_OctetStringTemplate));;
++            }
++            pubAttribute = sftk_FindAttribute(publicKey, CKA_EC_POINT);
++            /* clear out our generated private key */
++            PORT_FreeArena(ecPriv->ecParams.arena, PR_TRUE);
++            break;
++        default:
++            return CKR_DEVICE_ERROR;
+         }
+-
+-        crv = NSC_DeriveKey(hSession, &mech, privateKey->handle, template, templateCount, &newKey);
+-        if (crv != CKR_OK) {
+-            sftk_FreeAttribute(pubAttribute);
+-            return crv;
++        /* now compare new public key with our already generated key */
++        if ((pubAttribute == NULL) || (lowPubValue == NULL) ||
++            (pubAttribute->attrib.ulValueLen != lowPubValue->len) ||
++            (PORT_Memcmp(pubAttribute->attrib.pValue, lowPubValue->data,
++                        lowPubValue->len) != 0)) {
++            if (pubAttribute) sftk_FreeAttribute(pubAttribute);
++            if (lowPubValue) SECITEM_ZfreeItem(lowPubValue, PR_TRUE);
++            PORT_SetError(SEC_ERROR_BAD_KEY);
++            return CKR_GENERAL_ERROR;
+         }
++        SECITEM_ZfreeItem(lowPubValue, PR_TRUE);
++
+         /* FIPS requires full validation, but in fipx mode NSC_Derive
+          * only does partial validation with approved primes, now handle
+          * full validation */
+@@ -5159,44 +5167,78 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
+             SECItem pubKey;
+             SECItem prime;
+             SECItem subPrime;
++            SECItem base;
++            SECItem generator;
+             const SECItem *subPrimePtr = &subPrime;
+ 
+             pubKey.data = pubAttribute->attrib.pValue;
+             pubKey.len = pubAttribute->attrib.ulValueLen;
+-            prime.data = subPrime.data = NULL;
+-            prime.len = subPrime.len = 0;
++            base.data = prime.data = subPrime.data = NULL;
++            base.len = prime.len = subPrime.len = 0;
+             crv = sftk_Attribute2SecItem(NULL, &prime, privateKey, CKA_PRIME);
+             if (crv != CKR_OK) {
+                 goto done;
+             }
+-            crv = sftk_Attribute2SecItem(NULL, &prime, privateKey, CKA_PRIME);
++            crv = sftk_Attribute2SecItem(NULL, &base, privateKey, CKA_BASE);
++            if (crv != CKR_OK) {
++                goto done;
++            }
+             /* we ignore the return code an only look at the length */
+-            if (subPrime.len == 0) {
+-                /* subprime not supplied, In this case look it up.
+-                 * This only works with approved primes, but in FIPS mode
+-                 * that's the only kine of prime that will get here */
+-                subPrimePtr = sftk_VerifyDH_Prime(&prime, isFIPS);
+-                if (subPrimePtr == NULL) {
+-                    crv = CKR_GENERAL_ERROR;
++            /* do we have a known prime ? */
++            subPrimePtr = sftk_VerifyDH_Prime(&prime, &generator, isFIPS);
++            if (subPrimePtr == NULL) {
++                if (subPrime.len == 0) {
++                    /* if not a known prime, subprime must be supplied */
++                    crv = CKR_ATTRIBUTE_VALUE_INVALID;
++                    goto done;
++                } else {
++                    /* not a known prime, check for primality of prime
++                     * and subPrime */
++                    if (!KEA_PrimeCheck(&prime)) {
++                        crv = CKR_ATTRIBUTE_VALUE_INVALID;
++                        goto done;
++                    }
++                    if (!KEA_PrimeCheck(&subPrime)) {
++                        crv = CKR_ATTRIBUTE_VALUE_INVALID;
++                        goto done;
++                    }
++                    /* if we aren't using a defined group, make sure base is in the
++                     * subgroup. If it's not, then our key could fail or succeed sometimes.
++                     * This makes the failure reliable */
++                    if (!KEA_Verify(&base, &prime, (SECItem *)subPrimePtr)) {
++                        crv = CKR_ATTRIBUTE_VALUE_INVALID;
++                    }
++                }
++                subPrimePtr = &subPrime;
++            } else {
++                /* we're using a known group, make sure we are using the known generator for that group */
++                if (SECITEM_CompareItem(&generator, &base) != 0) {
++                    crv = CKR_ATTRIBUTE_VALUE_INVALID;
+                     goto done;
+                 }
++                if (subPrime.len != 0) {
++                    /* we have a known prime and a supplied subPrime,
++                     * make sure the subPrime matches the subPrime for
++                     * the known Prime */
++                     if (SECITEM_CompareItem(subPrimePtr, &subPrime) != 0) {
++                        crv = CKR_ATTRIBUTE_VALUE_INVALID;
++                        goto done;
++                     }
++                 }
+             }
+             if (!KEA_Verify(&pubKey, &prime, (SECItem *)subPrimePtr)) {
+-                crv = CKR_GENERAL_ERROR;
++                crv = CKR_ATTRIBUTE_VALUE_INVALID;
+             }
+         done:
++            SECITEM_ZfreeItem(&base, PR_FALSE);
+             SECITEM_ZfreeItem(&subPrime, PR_FALSE);
+             SECITEM_ZfreeItem(&prime, PR_FALSE);
+         }
+         /* clean up before we return */
+         sftk_FreeAttribute(pubAttribute);
+-        crv2 = NSC_DestroyObject(hSession, newKey);
+         if (crv != CKR_OK) {
+             return crv;
+         }
+-        if (crv2 != CKR_OK) {
+-            return crv2;
+-        }
+     }
+ 
+     return CKR_OK;
+@@ -5714,8 +5756,8 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
+      * created and linked.
+      */
+     crv = sftk_handleObject(publicKey, session);
+-    sftk_FreeSession(session);
+     if (crv != CKR_OK) {
++        sftk_FreeSession(session);
+         sftk_FreeObject(publicKey);
+         NSC_DestroyObject(hSession, privateKey->handle);
+         sftk_FreeObject(privateKey);
+@@ -5757,6 +5799,7 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
+     }
+ 
+     if (crv != CKR_OK) {
++        sftk_FreeSession(session);
+         NSC_DestroyObject(hSession, publicKey->handle);
+         sftk_FreeObject(publicKey);
+         NSC_DestroyObject(hSession, privateKey->handle);
+@@ -5766,6 +5809,8 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
+     /* we need to do this check at the end to make sure the generated key meets the key length requirements */
+     privateKey->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE_KEY_PAIR, privateKey);
+     publicKey->isFIPS = privateKey->isFIPS;
++    session->lastOpWasFIPS = privateKey->isFIPS;
++    sftk_FreeSession(session);
+ 
+     *phPrivateKey = privateKey->handle;
+     *phPublicKey = publicKey->handle;
+@@ -8386,7 +8431,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
+ 
+             /* if the prime is an approved prime, we can skip all the other
+              * checks. */
+-            subPrime = sftk_VerifyDH_Prime(&dhPrime, isFIPS);
++            subPrime = sftk_VerifyDH_Prime(&dhPrime, NULL, isFIPS);
+             if (subPrime == NULL) {
+                 SECItem dhSubPrime;
+                 /* If the caller set the subprime value, it means that
+@@ -8568,6 +8613,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
+                 secretlen = tmp.len;
+             } else {
+                 secretlen = keySize;
++                key->isFIPS = PR_FALSE;
+                 crv = sftk_ANSI_X9_63_kdf(&secret, keySize,
+                                           &tmp, mechParams->pSharedData,
+                                           mechParams->ulSharedDataLen, mechParams->kdf);
+diff -up ./lib/softoken/pkcs11.c.fips-review ./lib/softoken/pkcs11.c
+--- ./lib/softoken/pkcs11.c.fips-review	2023-06-04 01:42:53.000000000 -0700
++++ ./lib/softoken/pkcs11.c	2023-06-12 15:30:23.454233181 -0700
+@@ -4625,7 +4625,10 @@ NSC_CreateObject(CK_SESSION_HANDLE hSess
+     if (object == NULL) {
+         return CKR_HOST_MEMORY;
+     }
+-    object->isFIPS = PR_FALSE; /* if we created the object on the fly,
++    /* object types that we aren't allowed to create in FIPS mode are
++     * already rejected explicitly. If we get here, then the object is
++     * FIPS OK (most notably public key objects )*/
++    /* object->isFIPS = PR_FALSE;  if we created the object on the fly,
+                                 * it's not a FIPS object */
+ 
+     /*
+diff -up ./lib/softoken/pkcs11i.h.fips-review ./lib/softoken/pkcs11i.h
+--- ./lib/softoken/pkcs11i.h.fips-review	2023-06-12 15:29:04.097403894 -0700
++++ ./lib/softoken/pkcs11i.h	2023-06-12 15:30:23.454233181 -0700
+@@ -971,7 +971,7 @@ char **NSC_ModuleDBFunc(unsigned long fu
+ /* dh verify functions */
+ /* verify that dhPrime matches one of our known primes, and if so return
+  * it's subprime value */
+-const SECItem *sftk_VerifyDH_Prime(SECItem *dhPrime, PRBool isFIPS);
++const SECItem *sftk_VerifyDH_Prime(SECItem *dhPrime, SECItem *generator, PRBool isFIPS);
+ /* check if dhSubPrime claims dhPrime is a safe prime. */
+ SECStatus sftk_IsSafePrime(SECItem *dhPrime, SECItem *dhSubPrime, PRBool *isSafe);
+ /* map an operation Attribute to a Mechanism flag */
+diff -up ./lib/softoken/pkcs11u.c.fips-review ./lib/softoken/pkcs11u.c
+--- ./lib/softoken/pkcs11u.c.fips-review	2023-06-12 15:29:04.097403894 -0700
++++ ./lib/softoken/pkcs11u.c	2023-06-12 15:30:23.454233181 -0700
+@@ -2403,15 +2403,27 @@ sftk_handleSpecial(SFTKSlot *slot, CK_ME
+     switch (mechInfo->special) {
+         case SFTKFIPSDH: {
+             SECItem dhPrime;
++            SECItem dhBase;
++            SECItem dhGenerator;
++            PRBool val = PR_FALSE;
+             const SECItem *dhSubPrime;
+             CK_RV crv = sftk_Attribute2SecItem(NULL, &dhPrime,
+                                                source, CKA_PRIME);
+             if (crv != CKR_OK) {
+                 return PR_FALSE;
+             }
+-            dhSubPrime = sftk_VerifyDH_Prime(&dhPrime, PR_TRUE);
++            crv = sftk_Attribute2SecItem(NULL, &dhBase, source, CKA_BASE);
++            if (crv != CKR_OK) {
++                return PR_FALSE;
++            }
++            dhSubPrime = sftk_VerifyDH_Prime(&dhPrime, &dhGenerator, PR_TRUE);
++            val = (dhSubPrime) ? PR_TRUE : PR_FALSE;
++            if (val && (SECITEM_CompareItem(&dhBase, &dhGenerator) != 0)) {
++                val = PR_FALSE;
++            }
+             SECITEM_ZfreeItem(&dhPrime, PR_FALSE);
+-            return (dhSubPrime) ? PR_TRUE : PR_FALSE;
++            SECITEM_ZfreeItem(&dhBase, PR_FALSE);
++            return val;
+         }
+         case SFTKFIPSNone:
+             return PR_FALSE;
+diff -up ./lib/softoken/sftkdhverify.c.fips-review ./lib/softoken/sftkdhverify.c
+--- ./lib/softoken/sftkdhverify.c.fips-review	2023-06-04 01:42:53.000000000 -0700
++++ ./lib/softoken/sftkdhverify.c	2023-06-12 15:30:23.455233191 -0700
+@@ -6726,11 +6726,20 @@ static const SECItem subprime_tls_8192 =
+                                            (unsigned char *)subprime_tls_8192_data,
+                                            sizeof(subprime_tls_8192_data) };
+ 
++/* generator for all the groups is 2 */
++static const unsigned char generator_2_data[] = { 2 };
++
++
++static const SECItem generator_2 =
++    { siBuffer,
++      (unsigned char *)generator_2_data,
++      sizeof(generator_2_data) };
++
+ /*
+  * verify that dhPrime matches one of our known primes
+  */
+ const SECItem *
+-sftk_VerifyDH_Prime(SECItem *dhPrime, PRBool isFIPS)
++sftk_VerifyDH_Prime(SECItem *dhPrime, SECItem *g, PRBool isFIPS)
+ {
+     /* use the length to decide which primes to check */
+     switch (dhPrime->len) {
+@@ -6741,56 +6750,67 @@ sftk_VerifyDH_Prime(SECItem *dhPrime, PR
+             }
+             if (PORT_Memcmp(dhPrime->data, prime_ike_1536,
+                             sizeof(prime_ike_1536)) == 0) {
++                if (g) *g = generator_2;
+                 return &subprime_ike_1536;
+             }
+             break;
+         case 2048 / PR_BITS_PER_BYTE:
+             if (PORT_Memcmp(dhPrime->data, prime_tls_2048,
+                             sizeof(prime_tls_2048)) == 0) {
++                if (g) *g = generator_2;
+                 return &subprime_tls_2048;
+             }
+             if (PORT_Memcmp(dhPrime->data, prime_ike_2048,
+                             sizeof(prime_ike_2048)) == 0) {
++                if (g) *g = generator_2;
+                 return &subprime_ike_2048;
+             }
+             break;
+         case 3072 / PR_BITS_PER_BYTE:
+             if (PORT_Memcmp(dhPrime->data, prime_tls_3072,
+                             sizeof(prime_tls_3072)) == 0) {
++                if (g) *g = generator_2;
+                 return &subprime_tls_3072;
+             }
+             if (PORT_Memcmp(dhPrime->data, prime_ike_3072,
+                             sizeof(prime_ike_3072)) == 0) {
++                if (g) *g = generator_2;
+                 return &subprime_ike_3072;
+             }
+             break;
+         case 4096 / PR_BITS_PER_BYTE:
+             if (PORT_Memcmp(dhPrime->data, prime_tls_4096,
+                             sizeof(prime_tls_4096)) == 0) {
++                if (g) *g = generator_2;
+                 return &subprime_tls_4096;
+             }
+             if (PORT_Memcmp(dhPrime->data, prime_ike_4096,
+                             sizeof(prime_ike_4096)) == 0) {
++                if (g) *g = generator_2;
+                 return &subprime_ike_4096;
+             }
+             break;
+         case 6144 / PR_BITS_PER_BYTE:
+             if (PORT_Memcmp(dhPrime->data, prime_tls_6144,
+                             sizeof(prime_tls_6144)) == 0) {
++                if (g) *g = generator_2;
+                 return &subprime_tls_6144;
+             }
+             if (PORT_Memcmp(dhPrime->data, prime_ike_6144,
+                             sizeof(prime_ike_6144)) == 0) {
++                if (g) *g = generator_2;
+                 return &subprime_ike_6144;
+             }
+             break;
+         case 8192 / PR_BITS_PER_BYTE:
+             if (PORT_Memcmp(dhPrime->data, prime_tls_8192,
+                             sizeof(prime_tls_8192)) == 0) {
++                if (g) *g = generator_2;
+                 return &subprime_tls_8192;
+             }
+             if (PORT_Memcmp(dhPrime->data, prime_ike_8192,
+                             sizeof(prime_ike_8192)) == 0) {
++                if (g) *g = generator_2;
+                 return &subprime_ike_8192;
+             }
+             break;
+diff -up ./lib/softoken/sftkike.c.fips-review ./lib/softoken/sftkike.c
+--- ./lib/softoken/sftkike.c.fips-review	2023-06-04 01:42:53.000000000 -0700
++++ ./lib/softoken/sftkike.c	2023-06-12 15:30:23.455233191 -0700
+@@ -516,6 +516,11 @@ sftk_ike_prf(CK_SESSION_HANDLE hSession,
+             goto fail;
+         }
+     } else {
++        /* ikev1 isn't validated, if we use this function in ikev1 mode,
++         * mark the resulting key as not FIPS */
++        if (!params->bRekey) {
++            outKey->isFIPS = PR_FALSE;
++        }
+         crv = prf_init(&context, inKey->attrib.pValue,
+                        inKey->attrib.ulValueLen);
+         if (crv != CKR_OK) {
diff --git a/SOURCES/nss-3.79-increase-pbe-cache.patch b/SOURCES/nss-3.79-increase-pbe-cache.patch
deleted file mode 100644
index e175766..0000000
--- a/SOURCES/nss-3.79-increase-pbe-cache.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-diff --git a/lib/softoken/lowpbe.c b/lib/softoken/lowpbe.c
---- a/lib/softoken/lowpbe.c
-+++ b/lib/softoken/lowpbe.c
-@@ -565,17 +565,17 @@ struct KDFCacheItemStr {
-     int iterations;
-     int keyLen;
- };
- typedef struct KDFCacheItemStr KDFCacheItem;
- 
- /* Bug 1606992 - Cache the hash result for the common case that we're
-  * asked to repeatedly compute the key for the same password item,
-  * hash, iterations and salt. */
--#define KDF2_CACHE_COUNT 3
-+#define KDF2_CACHE_COUNT 150
- static struct {
-     PZLock *lock;
-     struct {
-         KDFCacheItem common;
-         int ivLen;
-         PRBool faulty3DES;
-     } cacheKDF1;
-     struct {
diff --git a/SOURCES/nss-3.90-DisablingASM.patch b/SOURCES/nss-3.90-DisablingASM.patch
new file mode 100644
index 0000000..7d1a17f
--- /dev/null
+++ b/SOURCES/nss-3.90-DisablingASM.patch
@@ -0,0 +1,57 @@
+diff --git a/lib/freebl/Makefile b/lib/freebl/Makefile
+index 74e8e65..8995752 100644
+--- a/lib/freebl/Makefile
++++ b/lib/freebl/Makefile
+@@ -568,7 +568,6 @@ ifneq ($(shell $(CC) -? 2>&1 >/dev/null </dev/null | sed -e 's/:.*//;1q'),lcc)
+             HAVE_INT128_SUPPORT = 1
+             DEFINES += -DHAVE_INT128_SUPPORT
+     else ifeq (1,$(CC_IS_GCC))
+-        SUPPORTS_VALE_CURVE25519 = 1
+         ifneq (,$(filter 4.6 4.7 4.8 4.9,$(word 1,$(GCC_VERSION)).$(word 2,$(GCC_VERSION))))
+             HAVE_INT128_SUPPORT = 1
+             DEFINES += -DHAVE_INT128_SUPPORT
+diff --git a/lib/freebl/freebl.gyp b/lib/freebl/freebl.gyp
+index 65f9a80..23940ef 100644
+--- a/lib/freebl/freebl.gyp
++++ b/lib/freebl/freebl.gyp
+@@ -866,12 +866,6 @@
+           }],
+         ],
+       }],
+-      [ 'supports_vale_curve25519==1', {
+-        'defines': [
+-          # The Makefile does version-tests on GCC, but we're not doing that here.
+-          'HACL_CAN_COMPILE_INLINE_ASM',
+-        ],
+-      }],
+       [ 'OS=="linux" or OS=="android"', {
+         'conditions': [
+           [ 'target_arch=="x64"', {
+@@ -934,11 +928,6 @@
+   'variables': {
+     'module': 'nss',
+     'conditions': [
+-      [ 'target_arch=="x64" and cc_is_gcc==1', {
+-        'supports_vale_curve25519%': 1,
+-      }, {
+-        'supports_vale_curve25519%': 0,
+-      }],
+       [ 'target_arch=="x64" or target_arch=="arm64" or target_arch=="aarch64"', {
+         'have_int128_support%': 1,
+       }, {
+diff --git a/lib/freebl/freebl_base.gypi b/lib/freebl/freebl_base.gypi
+index d198c44..34b6b3c 100644
+--- a/lib/freebl/freebl_base.gypi
++++ b/lib/freebl/freebl_base.gypi
+@@ -151,11 +151,6 @@
+         'ecl/curve25519_32.c',
+       ],
+     }],
+-    ['supports_vale_curve25519==1', {
+-      'sources': [
+-        'verified/Hacl_Curve25519_64.c',
+-      ],
+-    }],
+     ['(target_arch!="ppc64" and target_arch!="ppc64le") or disable_altivec==1', {
+       'sources': [
+         # Gyp does not support per-file cflags, so working around like this.
diff --git a/SOURCES/nss-3.90-pbkdf2-indicator.patch b/SOURCES/nss-3.90-pbkdf2-indicator.patch
new file mode 100644
index 0000000..dbb7765
--- /dev/null
+++ b/SOURCES/nss-3.90-pbkdf2-indicator.patch
@@ -0,0 +1,42 @@
+diff -up ./lib/softoken/pkcs11u.c.pkcs12_indicator ./lib/softoken/pkcs11u.c
+--- ./lib/softoken/pkcs11u.c.pkcs12_indicator	2023-08-03 10:50:37.067109367 -0700
++++ ./lib/softoken/pkcs11u.c	2023-08-03 11:41:55.641541953 -0700
+@@ -2429,7 +2429,7 @@ sftk_handleSpecial(SFTKSlot *slot, CK_ME
+             return PR_FALSE;
+         case SFTKFIPSECC:
+             /* we've already handled the curve selection in the 'getlength'
+-          * function */
++             * function */
+             return PR_TRUE;
+         case SFTKFIPSAEAD: {
+             if (mech->ulParameterLen == 0) {
+@@ -2463,6 +2463,29 @@ sftk_handleSpecial(SFTKSlot *slot, CK_ME
+             }
+             return PR_TRUE;
+         }
++        case SFTKFIPSPBKDF2: {
++            /* PBKDF2 must have the following addition restrictions
++             * (independent of keysize).
++             *    1. iteration count must be at least 1000.
++             *    2. salt must be at least 128 bits (16 bytes).
++             *    3. password must match the length specified in the SP
++             */
++             CK_PKCS5_PBKD2_PARAMS *pbkdf2 = (CK_PKCS5_PBKD2_PARAMS *)
++                                                    mech->pParameter;
++             if (mech->ulParameterLen != sizeof(*pbkdf2)) {
++                 return PR_FALSE;
++             }
++             if (pbkdf2->iterations < 1000) {
++                 return PR_FALSE;
++             }
++             if (pbkdf2->ulSaltSourceDataLen < 16) {
++                 return PR_FALSE;
++             }
++             if (*(pbkdf2->ulPasswordLen) < SFTKFIPS_PBKDF2_MIN_PW_LEN) {
++                 return PR_FALSE;
++             }
++             return PR_TRUE;
++        }
+         default:
+             break;
+     }
diff --git a/SOURCES/nss-softokn-3.67-read-write-db-locks.patch b/SOURCES/nss-softokn-3.67-read-write-db-locks.patch
index 68e5c66..1f1e7b3 100644
--- a/SOURCES/nss-softokn-3.67-read-write-db-locks.patch
+++ b/SOURCES/nss-softokn-3.67-read-write-db-locks.patch
@@ -1,12 +1,7 @@
-diff --git a/lib/softoken/lgglue.c b/lib/softoken/lgglue.c
---- a/lib/softoken/lgglue.c
-+++ b/lib/softoken/lgglue.c
-@@ -179,23 +179,23 @@ sftkdb_encrypt_stub(PLArenaPool *arena, 
-     }
- 
-     /* if we aren't the key handle, try the other handle */
-     if (handle->type != SFTK_KEYDB_TYPE) {
-         handle = handle->peerDB;
+diff -up ./lib/softoken/lgglue.c.read-write-db-locks ./lib/softoken/lgglue.c
+--- ./lib/softoken/lgglue.c.read-write-db-locks	2023-06-04 10:42:53.000000000 +0200
++++ ./lib/softoken/lgglue.c	2023-06-21 10:59:44.940835332 +0200
+@@ -184,13 +184,13 @@ sftkdb_encrypt_stub(PLArenaPool *arena,
      }
  
      /* not a key handle */
@@ -23,17 +18,7 @@ diff --git a/lib/softoken/lgglue.c b/lib/softoken/lgglue.c
          /* PORT_SetError */
          return SECFailure;
      }
-     key = handle->newKey ? handle->newKey : &handle->passwordKey;
-     if (sftk_isLegacyIterationCountAllowed()) {
-         if (handle->newKey) {
-             iterationCount = handle->newDefaultIterationCount;
-         } else {
-@@ -203,17 +203,17 @@ sftkdb_encrypt_stub(PLArenaPool *arena, 
-         }
-     } else {
-         iterationCount = 1;
-     }
- 
+@@ -208,7 +208,7 @@ sftkdb_encrypt_stub(PLArenaPool *arena,
      rv = sftkdb_EncryptAttribute(arena, handle, sdb, key, iterationCount,
                                   CK_INVALID_HANDLE, CKT_INVALID_TYPE,
                                   plainText, cipherText);
@@ -42,17 +27,7 @@ diff --git a/lib/softoken/lgglue.c b/lib/softoken/lgglue.c
  
      return rv;
  }
- 
- /*
-  * stub files for legacy db's to be able to encrypt and decrypt
-  * various keys and attributes.
-  */
-@@ -230,31 +230,31 @@ sftkdb_decrypt_stub(SDB *sdb, SECItem *c
- 
-     /* if we aren't the key handle, try the other handle */
-     oldKey = handle->oldKey;
-     if (handle->type != SFTK_KEYDB_TYPE) {
-         handle = handle->peerDB;
+@@ -235,13 +235,13 @@ sftkdb_decrypt_stub(SDB *sdb, SECItem *c
      }
  
      /* not a key handle */
@@ -69,7 +44,7 @@ diff --git a/lib/softoken/lgglue.c b/lib/softoken/lgglue.c
          /* PORT_SetError */
          return SECFailure;
      }
-     rv = sftkdb_DecryptAttribute(NULL, oldKey ? oldKey : &handle->passwordKey,
+@@ -249,7 +249,7 @@ sftkdb_decrypt_stub(SDB *sdb, SECItem *c
                                   CK_INVALID_HANDLE,
                                   CKT_INVALID_TYPE,
                                   cipherText, plainText);
@@ -78,20 +53,10 @@ diff --git a/lib/softoken/lgglue.c b/lib/softoken/lgglue.c
  
      return rv;
  }
- 
- static const char *LEGACY_LIB_NAME =
-     SHLIB_PREFIX "nssdbm" SHLIB_VERSION "." SHLIB_SUFFIX;
- /*
-  * 2 bools to tell us if we've check the legacy library successfully or
-diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
---- a/lib/softoken/sftkdb.c
-+++ b/lib/softoken/sftkdb.c
-@@ -376,29 +376,29 @@ sftkdb_fixupTemplateOut(CK_ATTRIBUTE *te
-             /* This code depends on the fact that the cipherText is bigger
-              * than the plain text */
-             SECItem cipherText;
-             SECItem *plainText;
-             SECStatus rv;
+diff -up ./lib/softoken/sftkdb.c.read-write-db-locks ./lib/softoken/sftkdb.c
+--- ./lib/softoken/sftkdb.c.read-write-db-locks	2023-06-04 10:42:53.000000000 +0200
++++ ./lib/softoken/sftkdb.c	2023-06-21 12:54:41.007208477 +0200
+@@ -413,9 +413,9 @@ sftkdb_fixupTemplateOut(CK_ATTRIBUTE *te
  
              cipherText.data = ntemplate[i].pValue;
              cipherText.len = ntemplate[i].ulValueLen;
@@ -103,9 +68,7 @@ diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
                  template[i].ulValueLen = -1;
                  crv = CKR_USER_NOT_LOGGED_IN;
                  continue;
-             }
-             rv = sftkdb_DecryptAttribute(handle,
-                                          &handle->passwordKey,
+@@ -425,7 +425,7 @@ sftkdb_fixupTemplateOut(CK_ATTRIBUTE *te
                                           objectID,
                                           ntemplate[i].type,
                                           &cipherText, &plainText);
@@ -114,17 +77,7 @@ diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
              if (rv != SECSuccess) {
                  PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
                  template[i].ulValueLen = -1;
-                 crv = CKR_GENERAL_ERROR;
-                 continue;
-             }
-             PORT_Assert(template[i].ulValueLen >= plainText->len);
-             if (template[i].ulValueLen < plainText->len) {
-@@ -441,30 +441,30 @@ sftkdb_fixupTemplateOut(CK_ATTRIBUTE *te
- 
-             plainText.data = ntemplate[i].pValue;
-             plainText.len = ntemplate[i].ulValueLen;
- 
-             /*
+@@ -478,12 +478,12 @@ sftkdb_fixupTemplateOut(CK_ATTRIBUTE *te
               * we do a second check holding the lock just in case the user
               * loggout while we were trying to get the signature.
               */
@@ -139,7 +92,7 @@ diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
                  continue;
              }
  
-             rv = sftkdb_VerifyAttribute(keyHandle,
+@@ -491,7 +491,7 @@ sftkdb_fixupTemplateOut(CK_ATTRIBUTE *te
                                          &keyHandle->passwordKey,
                                          objectID, ntemplate[i].type,
                                          &plainText, &signText);
@@ -148,17 +101,7 @@ diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
              if (rv != SECSuccess) {
                  PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
                  template[i].ulValueLen = -1;
-                 crv = CKR_SIGNATURE_INVALID; /* better error code? */
-             }
-             /* This Attribute is fine */
-         }
-     }
-@@ -553,28 +553,28 @@ sftk_signTemplate(PLArenaPool *arena, SF
-     for (i = 0; i < count; i++) {
-         if (sftkdb_isAuthenticatedAttribute(template[i].type)) {
-             SECStatus rv;
-             SECItem *signText;
-             SECItem plainText;
+@@ -590,9 +590,9 @@ sftk_signTemplate(PLArenaPool *arena, SF
  
              plainText.data = template[i].pValue;
              plainText.len = template[i].ulValueLen;
@@ -170,8 +113,7 @@ diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
                  crv = CKR_USER_NOT_LOGGED_IN;
                  goto loser;
              }
-             rv = sftkdb_SignAttribute(arena, keyHandle, keyTarget,
-                                       &keyHandle->passwordKey,
+@@ -601,7 +601,7 @@ sftk_signTemplate(PLArenaPool *arena, SF
                                        keyHandle->defaultIterationCount,
                                        objectID, template[i].type,
                                        &plainText, &signText);
@@ -180,17 +122,7 @@ diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
              if (rv != SECSuccess) {
                  crv = CKR_GENERAL_ERROR; /* better error code here? */
                  goto loser;
-             }
-             crv = sftkdb_PutAttributeSignature(handle, keyTarget, objectID,
-                                                template[i].type, signText);
-             if (crv != CKR_OK) {
-                 goto loser;
-@@ -733,29 +733,29 @@ sftk_ExtractTemplate(PLArenaPool *arena,
-             if (doEnc && sftkdb_isPrivateAttribute(tp->type)) {
-                 /* we have a private attribute */
-                 SECItem *cipherText;
-                 SECItem plainText;
-                 SECStatus rv;
+@@ -770,9 +770,9 @@ sftk_ExtractTemplate(PLArenaPool *arena,
  
                  plainText.data = tp->pValue;
                  plainText.len = tp->ulValueLen;
@@ -202,9 +134,7 @@ diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
                      *crv = CKR_USER_NOT_LOGGED_IN;
                      break;
                  }
-                 rv = sftkdb_EncryptAttribute(arena, handle, db,
-                                              &handle->passwordKey,
-                                              handle->defaultIterationCount,
+@@ -782,7 +782,7 @@ sftk_ExtractTemplate(PLArenaPool *arena,
                                               objectID,
                                               tp->type,
                                               &plainText, &cipherText);
@@ -213,38 +143,28 @@ diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
                  if (rv == SECSuccess) {
                      tp->pValue = cipherText->data;
                      tp->ulValueLen = cipherText->len;
-                 } else {
-                     *crv = CKR_GENERAL_ERROR; /* better error code here? */
-                     break;
-                 }
-                 PORT_Memset(plainText.data, 0, plainText.len);
-@@ -1604,18 +1604,18 @@ sftkdb_CloseDB(SFTKDBHandle *handle)
-         if (handle->db->sdb_SetForkState) {
-             (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize);
+@@ -1638,15 +1638,15 @@ sftkdb_CloseDB(SFTKDBHandle *handle)
          }
          (*handle->db->sdb_Close)(handle->db);
      }
+-    if (handle->passwordLock) {
+-        PZ_Lock(handle->passwordLock);
++    if (sftkdb_passwordLockIsInited(handle)) {
++        sftkdb_passwordWriterLock(handle);
+     }
      if (handle->passwordKey.data) {
          SECITEM_ZfreeItem(&handle->passwordKey, PR_FALSE);
      }
 -    if (handle->passwordLock) {
+-        PZ_Unlock(handle->passwordLock);
 -        SKIP_AFTER_FORK(PZ_DestroyLock(handle->passwordLock));
 +    if (sftkdb_passwordLockIsInited(handle)) {
++        sftkdb_passwordWriterUnlock(handle);
 +        SKIP_AFTER_FORK(sftkdb_passwordLockDestroy(handle));
      }
      if (handle->updatePasswordKey) {
          SECITEM_ZfreeItem(handle->updatePasswordKey, PR_TRUE);
-     }
-     if (handle->updateID) {
-         PORT_Free(handle->updateID);
-     }
-     PORT_Free(handle);
-@@ -2665,18 +2665,20 @@ sftk_NewDBHandle(SDB *sdb, int type, PRB
-     handle->oldKey = NULL;
-     handle->updatePasswordKey = NULL;
-     handle->updateID = NULL;
-     handle->type = type;
-     handle->usesLegacyStorage = legacy;
+@@ -2704,8 +2704,10 @@ sftk_NewDBHandle(SDB *sdb, int type, PRB
      handle->passwordKey.data = NULL;
      handle->passwordKey.len = 0;
      handle->passwordLock = NULL;
@@ -256,18 +176,10 @@ diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
      }
      sdb->app_private = handle;
      return handle;
- }
- 
- /*
-  * reset the key database to it's uninitialized state. This call
-  * will clear all the key entried.
-diff --git a/lib/softoken/sftkdbti.h b/lib/softoken/sftkdbti.h
---- a/lib/softoken/sftkdbti.h
-+++ b/lib/softoken/sftkdbti.h
-@@ -1,29 +1,35 @@
- /* 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/. */
+diff -up ./lib/softoken/sftkdbti.h.read-write-db-locks ./lib/softoken/sftkdbti.h
+--- ./lib/softoken/sftkdbti.h.read-write-db-locks	2023-06-04 10:42:53.000000000 +0200
++++ ./lib/softoken/sftkdbti.h	2023-06-21 10:59:44.940835332 +0200
+@@ -4,6 +4,7 @@
  
  #ifndef SFTKDBTI_H
  #define SFTKDBTI_H 1
@@ -275,15 +187,7 @@ diff --git a/lib/softoken/sftkdbti.h b/lib/softoken/sftkdbti.h
  
  /*
   * private defines
-  */
- struct SFTKDBHandleStr {
-     SDB *db;
-     PRInt32 ref;
-     CK_OBJECT_HANDLE type;
-     SECItem passwordKey;
-     int defaultIterationCount;
-     SECItem *newKey;
-     int newDefaultIterationCount;
+@@ -19,6 +20,11 @@ struct SFTKDBHandleStr {
      SECItem *oldKey;
      SECItem *updatePasswordKey;
      PZLock *passwordLock;
@@ -295,17 +199,7 @@ diff --git a/lib/softoken/sftkdbti.h b/lib/softoken/sftkdbti.h
      SFTKDBHandle *peerDB;
      SDB *update;
      char *updateID;
-     PRBool updateDBIsInit;
-     PRBool usesLegacyStorage;
- };
- 
- #define SFTK_KEYDB_TYPE 0x40000000
-@@ -74,9 +80,18 @@ CK_RV sftkdb_GetAttributeSignature(SFTKD
-                                    CK_OBJECT_HANDLE objectID,
-                                    CK_ATTRIBUTE_TYPE type,
-                                    SECItem *signText);
- CK_RV
- sftkdb_DestroyAttributeSignature(SFTKDBHandle *handle, SDB *db,
+@@ -79,4 +85,13 @@ sftkdb_DestroyAttributeSignature(SFTKDBH
                                   CK_OBJECT_HANDLE objectID,
                                   CK_ATTRIBUTE_TYPE type);
  
@@ -319,15 +213,10 @@ diff --git a/lib/softoken/sftkdbti.h b/lib/softoken/sftkdbti.h
 +void sftkdb_passwordWriterUnlock(SFTKDBHandle *keydb);
 +
  #endif
-diff --git a/lib/softoken/sftkpwd.c b/lib/softoken/sftkpwd.c
---- a/lib/softoken/sftkpwd.c
-+++ b/lib/softoken/sftkpwd.c
-@@ -627,44 +627,164 @@ sftkdb_SignAttribute(PLArenaPool *arena,
- loser:
-     PORT_Memset(signData, 0, sizeof signData);
-     if (param) {
-         nsspkcs5_DestroyPBEParameter(param);
-     }
+diff -up ./lib/softoken/sftkpwd.c.read-write-db-locks ./lib/softoken/sftkpwd.c
+--- ./lib/softoken/sftkpwd.c.read-write-db-locks	2023-06-04 10:42:53.000000000 +0200
++++ ./lib/softoken/sftkpwd.c	2023-06-21 10:59:44.940835332 +0200
+@@ -632,6 +632,126 @@ loser:
      return rv;
  }
  
@@ -454,13 +343,7 @@ diff --git a/lib/softoken/sftkpwd.c b/lib/softoken/sftkpwd.c
  /*
   * safely swith the passed in key for the one caches in the keydb handle
   *
-  * A key attached to the handle tells us the the token is logged in.
-  * We can used the key attached to the handle in sftkdb_EncryptAttribute
-  *  and sftkdb_DecryptAttribute calls.
-  */
- static void
- sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey, int iterationCount)
- {
+@@ -645,13 +765,13 @@ sftkdb_switchKeys(SFTKDBHandle *keydb, S
      unsigned char *data;
      int len;
  
@@ -476,7 +359,7 @@ diff --git a/lib/softoken/sftkpwd.c b/lib/softoken/sftkpwd.c
      data = keydb->passwordKey.data;
      len = keydb->passwordKey.len;
      keydb->passwordKey.data = passKey->data;
-     keydb->passwordKey.len = passKey->len;
+@@ -659,7 +779,7 @@ sftkdb_switchKeys(SFTKDBHandle *keydb, S
      keydb->defaultIterationCount = iterationCount;
      passKey->data = data;
      passKey->len = len;
@@ -485,17 +368,7 @@ diff --git a/lib/softoken/sftkpwd.c b/lib/softoken/sftkpwd.c
  }
  
  /*
-  * returns true if we are in a middle of a merge style update.
-  */
- PRBool
- sftkdb_InUpdateMerge(SFTKDBHandle *keydb)
- {
-@@ -700,21 +820,21 @@ sftkdb_GetUpdatePasswordKey(SFTKDBHandle
-         handle = handle->peerDB;
-     }
- 
-     /* don't have one */
-     if (!handle) {
+@@ -705,11 +825,11 @@ sftkdb_GetUpdatePasswordKey(SFTKDBHandle
          return NULL;
      }
  
@@ -509,17 +382,7 @@ diff --git a/lib/softoken/sftkpwd.c b/lib/softoken/sftkpwd.c
  
      return key;
  }
- 
- /*
-  * free the update password key from a handle.
-  */
- void
-@@ -727,22 +847,22 @@ sftkdb_FreeUpdatePasswordKey(SFTKDBHandl
-         return;
-     }
- 
-     /* if we're a cert db, we don't have one */
-     if (handle->type == SFTK_CERTDB_TYPE) {
+@@ -732,12 +852,12 @@ sftkdb_FreeUpdatePasswordKey(SFTKDBHandl
          return;
      }
  
@@ -534,17 +397,7 @@ diff --git a/lib/softoken/sftkpwd.c b/lib/softoken/sftkpwd.c
  
      if (key) {
          SECITEM_ZfreeItem(key, PR_TRUE);
-     }
- 
-     return;
- }
- 
-@@ -999,25 +1119,25 @@ sftkdb_finishPasswordCheck(SFTKDBHandle 
-          *         the user. Clear our sessions out to simulate a token
-          *         removal. C_GetTokenInfo will change the token description
-          *         and the token will still appear to be logged out.
-          *   2) If we already have the source DB  password, this password is
-          *         for the target database. We can now move forward with the
+@@ -1004,7 +1124,7 @@ sftkdb_finishPasswordCheck(SFTKDBHandle
           *         update, as we now have both required passwords.
           *
           */
@@ -553,7 +406,7 @@ diff --git a/lib/softoken/sftkpwd.c b/lib/softoken/sftkpwd.c
          if (sftkdb_NeedUpdateDBPassword(keydb)) {
              /* Squirrel this special key away.
               * This has the side effect of turning sftkdb_NeedLegacyPW off,
-              * as well as changing which database is returned from
+@@ -1012,7 +1132,7 @@ sftkdb_finishPasswordCheck(SFTKDBHandle
               * SFTK_GET_PW_DB (thus effecting both sftkdb_CheckPassword()
               * and sftkdb_HasPasswordSet()) */
              keydb->updatePasswordKey = SECITEM_DupItem(key);
@@ -562,17 +415,7 @@ diff --git a/lib/softoken/sftkpwd.c b/lib/softoken/sftkpwd.c
              if (keydb->updatePasswordKey == NULL) {
                  /* PORT_Error set by SECITEM_DupItem */
                  rv = SECFailure;
-                 goto done;
-             }
- 
-             /* Simulate a token removal -- we need to do this any
-              * any case at this point so the token name is correct. */
-@@ -1072,17 +1192,17 @@ sftkdb_finishPasswordCheck(SFTKDBHandle 
-                 goto done;
-             } else {
-                 /* there is no password, just fall through to update.
-                  * update will write the source DB's password record
-                  * into the target DB just like it would in a non-merge
+@@ -1077,7 +1197,7 @@ sftkdb_finishPasswordCheck(SFTKDBHandle
                   * update case. */
              }
          } else {
@@ -581,8 +424,3 @@ diff --git a/lib/softoken/sftkpwd.c b/lib/softoken/sftkpwd.c
          }
          /* load the keys, so the keydb can parse it's key set */
          sftkdb_switchKeys(keydb, key, iterationCount);
- 
-         /* we need to update, do it now */
-         if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update) {
-             /* update the peer certdb if it exists */
-             if (keydb->peerDB) {
diff --git a/SOURCES/nss-softokn-3.79-dont-verify-default.patch b/SOURCES/nss-softokn-3.79-dont-verify-default.patch
deleted file mode 100644
index aa20713..0000000
--- a/SOURCES/nss-softokn-3.79-dont-verify-default.patch
+++ /dev/null
@@ -1,170 +0,0 @@
-diff --git a/lib/softoken/legacydb/pcertdb.c b/lib/softoken/legacydb/pcertdb.c
---- a/lib/softoken/legacydb/pcertdb.c
-+++ b/lib/softoken/legacydb/pcertdb.c
-@@ -4272,16 +4272,17 @@ CreateTrust(void)
- {
-     NSSLOWCERTTrust *trust = NULL;
- 
-     nsslowcert_LockFreeList();
-     trust = trustListHead;
-     if (trust) {
-         trustListCount--;
-         trustListHead = trust->next;
-+        trust->next = NULL;
-     }
-     PORT_Assert(trustListCount >= 0);
-     nsslowcert_UnlockFreeList();
-     if (trust) {
-         return trust;
-     }
- 
-     return PORT_ZNew(NSSLOWCERTTrust);
-@@ -5155,19 +5156,21 @@ done:
- }
- 
- PRBool
- nsslowcert_hasTrust(NSSLOWCERTCertTrust *trust)
- {
-     if (trust == NULL) {
-         return PR_FALSE;
-     }
--    return !((trust->sslFlags & CERTDB_TRUSTED_UNKNOWN) &&
--             (trust->emailFlags & CERTDB_TRUSTED_UNKNOWN) &&
--             (trust->objectSigningFlags & CERTDB_TRUSTED_UNKNOWN));
-+    /* if we only have CERTDB__USER and CERTDB_TRUSTED_UNKNOWN bits, then
-+     * we don't have a trust record. */
-+    return !(((trust->sslFlags & ~(CERTDB_USER|CERTDB_TRUSTED_UNKNOWN)) == 0) &&
-+        ((trust->emailFlags & ~(CERTDB_USER|CERTDB_TRUSTED_UNKNOWN)) == 0) &&
-+        ((trust->objectSigningFlags & ~(CERTDB_USER|CERTDB_TRUSTED_UNKNOWN)) == 0));
- }
- 
- /*
-  * This function has the logic that decides if another person's cert and
-  * email profile from an S/MIME message should be saved.  It can deal with
-  * the case when there is no profile.
-  */
- static SECStatus
-diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
---- a/lib/softoken/sftkdb.c
-+++ b/lib/softoken/sftkdb.c
-@@ -119,47 +119,79 @@ sftkdb_isAuthenticatedAttribute(CK_ATTRI
-         case CKA_TRUST_STEP_UP_APPROVED:
-         case CKA_NSS_OVERRIDE_EXTENSIONS:
-             return PR_TRUE;
-         default:
-             break;
-     }
-     return PR_FALSE;
- }
--
- /*
-  * convert a native ULONG to a database ulong. Database ulong's
-  * are all 4 byte big endian values.
-  */
- void
- sftk_ULong2SDBULong(unsigned char *data, CK_ULONG value)
- {
-     int i;
- 
-     for (i = 0; i < SDB_ULONG_SIZE; i++) {
-         data[i] = (value >> (SDB_ULONG_SIZE - 1 - i) * BBP) & 0xff;
-     }
- }
- 
- /*
-  * convert a database ulong back to a native ULONG. (reverse of the above
-- * function.
-+ * function).
-  */
- static CK_ULONG
- sftk_SDBULong2ULong(unsigned char *data)
- {
-     int i;
-     CK_ULONG value = 0;
- 
-     for (i = 0; i < SDB_ULONG_SIZE; i++) {
-         value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE - 1 - i) * BBP);
-     }
-     return value;
- }
- 
-+/* certain trust records are default values, which are the values
-+ * returned if the signature check fails anyway.
-+ * In those cases, we can skip the signature check. */
-+PRBool
-+sftkdb_isNullTrust(const CK_ATTRIBUTE *template)
-+{
-+    switch (template->type) {
-+        case CKA_TRUST_SERVER_AUTH:
-+        case CKA_TRUST_CLIENT_AUTH:
-+        case CKA_TRUST_EMAIL_PROTECTION:
-+        case CKA_TRUST_CODE_SIGNING:
-+            if (template->ulValueLen != SDB_ULONG_SIZE) {
-+                break;
-+            }
-+            if (sftk_SDBULong2ULong(template->pValue) == 
-+                CKT_NSS_TRUST_UNKNOWN) {
-+                return PR_TRUE;
-+            }
-+            break;
-+        case CKA_TRUST_STEP_UP_APPROVED:
-+            if (template->ulValueLen != 1) {
-+                break;
-+            }
-+            if (*((unsigned char *)(template->pValue)) == 0) {
-+                return PR_TRUE;
-+            }
-+            break;
-+        default:
-+            break;
-+    }
-+    return PR_FALSE;
-+}
-+
- /*
-  * fix up the input templates. Our fixed up ints are stored in data and must
-  * be freed by the caller. The new template must also be freed. If there are no
-  * CK_ULONG attributes, the orignal template is passed in as is.
-  */
- static CK_ATTRIBUTE *
- sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count,
-                        unsigned char **dataOut, int *dataOutSize)
-@@ -410,17 +442,18 @@ sftkdb_fixupTemplateOut(CK_ATTRIBUTE *te
-             }
- 
-             /* copy the plain text back into the template */
-             PORT_Memcpy(template[i].pValue, plainText->data, plainText->len);
-             template[i].ulValueLen = plainText->len;
-             SECITEM_ZfreeItem(plainText, PR_TRUE);
-         }
-         /* make sure signed attributes are valid */
--        if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type)) {
-+        if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type)
-+            && !sftkdb_isNullTrust(&ntemplate[i])) {
-             SECStatus rv;
-             CK_RV local_crv;
-             SECItem signText;
-             SECItem plainText;
-             unsigned char signData[SDB_MAX_META_DATA_LEN];
- 
-             signText.data = signData;
-             signText.len = sizeof(signData);
-@@ -2387,16 +2420,18 @@ sftkdb_mergeObject(SFTKDBHandle *handle,
-     crv = (*source->sdb_GetAttributeValue)(source, id,
-                                            ptemplate, max_attributes);
-     if (crv != CKR_OK) {
-         goto loser;
-     }
- 
-     objectType = sftkdb_getULongFromTemplate(CKA_CLASS, ptemplate,
-                                              max_attributes);
-+printf(" - merging object Type 0x%08lx id=0x%08lx updateID=%s\n", objectType, id,
-+       handle->updateID?handle->updateID: "<NULL>");
- 
-     /*
-      * Update Object updates the object template if necessary then returns
-      * whether or not we need to actually write the object out to our target
-      * database.
-      */
-     if (!handle->updateID) {
-         crv = sftkdb_CreateObject(arena, handle, target, &newID,
diff --git a/SOURCES/nss-softokn-3.79-fips.patch b/SOURCES/nss-softokn-3.79-fips.patch
new file mode 100644
index 0000000..27309dd
--- /dev/null
+++ b/SOURCES/nss-softokn-3.79-fips.patch
@@ -0,0 +1,556 @@
+diff --git a/lib/freebl/config.mk b/lib/freebl/config.mk
+--- a/lib/freebl/config.mk
++++ b/lib/freebl/config.mk
+@@ -85,9 +85,13 @@ EXTRA_SHARED_LIBS += \
+ 	$(NULL)
+ endif
+ endif
+ 
+ ifeq ($(OS_ARCH), Darwin)
+ EXTRA_SHARED_LIBS += -dylib_file @executable_path/libplc4.dylib:$(DIST)/lib/libplc4.dylib -dylib_file @executable_path/libplds4.dylib:$(DIST)/lib/libplds4.dylib
+ endif
+ 
++ifdef NSS_FIPS_140_3
++DEFINES += -DNSS_FIPS_140_3
+ endif
++
++endif
+diff --git a/lib/freebl/unix_urandom.c b/lib/freebl/unix_urandom.c
+--- a/lib/freebl/unix_urandom.c
++++ b/lib/freebl/unix_urandom.c
+@@ -20,53 +20,110 @@ RNG_SystemInfoForRNG(void)
+     if (!numBytes) {
+         /* error is set */
+         return;
+     }
+     RNG_RandomUpdate(bytes, numBytes);
+     PORT_Memset(bytes, 0, sizeof bytes);
+ }
+ 
++#ifdef NSS_FIPS_140_3
++#include <sys/random.h>
++#include "prinit.h"
++
++static int rng_grndFlags= 0;
++static PRCallOnceType rng_KernelFips;
++
++static PRStatus
++rng_getKernelFips()
++{
++#ifdef LINUX
++    FILE *f;
++    char d;
++    size_t size;
++
++    f = fopen("/proc/sys/crypto/fips_enabled", "r");
++    if (!f)
++        return PR_FAILURE;
++
++    size = fread(&d, 1, 1, f);
++    fclose(f);
++    if (size != 1)
++        return PR_SUCCESS;
++    if (d != '1')
++        return PR_SUCCESS;
++    /* if the kernel is in FIPS mode, set the GRND_RANDOM flag */
++    rng_grndFlags = GRND_RANDOM;
++#endif /* LINUX */
++    return PR_SUCCESS;
++}
++#endif
++
+ size_t
+ RNG_SystemRNG(void *dest, size_t maxLen)
+ {
++    size_t fileBytes = 0;
++    unsigned char *buffer = dest;
++#ifndef NSS_FIPS_140_3
+     int fd;
+     int bytes;
+-    size_t fileBytes = 0;
+-    unsigned char *buffer = dest;
++#else
++    PR_CallOnce(&rng_KernelFips, rng_getKernelFips);
++#endif
+ 
+ #if defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || (defined(LINUX) && defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25))))
+     int result;
+-
+     while (fileBytes < maxLen) {
+         size_t getBytes = maxLen - fileBytes;
+         if (getBytes > GETENTROPY_MAX_BYTES) {
+             getBytes = GETENTROPY_MAX_BYTES;
+         }
++#ifdef NSS_FIPS_140_3
++        /* FIP 140-3 requires full kernel reseeding for chained entropy sources
++         * so we need to use getrandom with GRND_RANDOM.
++         * getrandom returns -1 on failure, otherwise returns
++         * the number of bytes, which can be less than getBytes */
++        result = getrandom(buffer, getBytes, rng_grndFlags);
++        if (result < 0) {
++            break;
++        }
++        fileBytes += result;
++        buffer += result;
++#else
++        /* get entropy returns 0 on success and always return
++         * getBytes on success */
+         result = getentropy(buffer, getBytes);
+         if (result == 0) { /* success */
+             fileBytes += getBytes;
+             buffer += getBytes;
+         } else {
+             break;
+         }
++#endif
+     }
+     if (fileBytes == maxLen) { /* success */
+         return maxLen;
+     }
++#ifdef NSS_FIPS_140_3
++    /* in FIPS 104-3 we don't fallback, just fail */
++    PORT_SetError(SEC_ERROR_NEED_RANDOM);
++    return 0;
++#else
+     /* If we failed with an error other than ENOSYS, it means the destination
+      * buffer is not writeable. We don't need to try writing to it again. */
+     if (errno != ENOSYS) {
+         PORT_SetError(SEC_ERROR_NEED_RANDOM);
+         return 0;
+     }
++#endif /*!NSS_FIPS_140_3 */
++#endif /* platorm has getentropy */
++#ifndef NSS_FIPS_140_3
+     /* ENOSYS means the kernel doesn't support getentropy()/getrandom().
+      * Reset the number of bytes to get and fall back to /dev/urandom. */
+     fileBytes = 0;
+-#endif
+     fd = open("/dev/urandom", O_RDONLY);
+     if (fd < 0) {
+         PORT_SetError(SEC_ERROR_NEED_RANDOM);
+         return 0;
+     }
+     while (fileBytes < maxLen) {
+         bytes = read(fd, buffer, maxLen - fileBytes);
+         if (bytes <= 0) {
+@@ -76,9 +133,10 @@ RNG_SystemRNG(void *dest, size_t maxLen)
+         buffer += bytes;
+     }
+     (void)close(fd);
+     if (fileBytes != maxLen) {
+         PORT_SetError(SEC_ERROR_NEED_RANDOM);
+         return 0;
+     }
+     return fileBytes;
++#endif
+ }
+diff --git a/lib/softoken/config.mk b/lib/softoken/config.mk
+--- a/lib/softoken/config.mk
++++ b/lib/softoken/config.mk
+@@ -58,8 +58,12 @@ endif
+ ifdef NSS_ENABLE_FIPS_INDICATORS
+ DEFINES += -DNSS_ENABLE_FIPS_INDICATORS
+ endif
+ 
+ ifdef NSS_FIPS_MODULE_ID
+ DEFINES += -DNSS_FIPS_MODULE_ID=\"${NSS_FIPS_MODULE_ID}\"
+ endif
+ 
++ifdef NSS_FIPS_140_3
++DEFINES += -DNSS_FIPS_140_3
++endif
++
+diff --git a/lib/softoken/lowpbe.c b/lib/softoken/lowpbe.c
+--- a/lib/softoken/lowpbe.c
++++ b/lib/softoken/lowpbe.c
+@@ -1766,16 +1766,20 @@ sftk_fips_pbkdf_PowerUpSelfTests(void)
+     unsigned char iteration_count = 5;
+     unsigned char keyLen = 64;
+     char *inKeyData = TEST_KEY;
+-    static const unsigned char saltData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
++    static const unsigned char saltData[] = {
++        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
++    };
++
+     static const unsigned char pbkdf_known_answer[] = {
+-        0x31, 0xf0, 0xe5, 0x39, 0x9f, 0x39, 0xb9, 0x29,
+-        0x68, 0xac, 0xf2, 0xe9, 0x53, 0x9b, 0xb4, 0x9c,
+-        0x28, 0x59, 0x8b, 0x5c, 0xd8, 0xd4, 0x02, 0x37,
+-        0x18, 0x22, 0xc1, 0x92, 0xd0, 0xfa, 0x72, 0x90,
+-        0x2c, 0x8d, 0x19, 0xd4, 0x56, 0xfb, 0x16, 0xfa,
+-        0x8d, 0x5c, 0x06, 0x33, 0xd1, 0x5f, 0x17, 0xb1,
+-        0x22, 0xd9, 0x9c, 0xaf, 0x5e, 0x3f, 0xf3, 0x66,
+-        0xc6, 0x14, 0xfe, 0x83, 0xfa, 0x1a, 0x2a, 0xc5
++        0x73, 0x8c, 0xfa, 0x02, 0xe8, 0xdb, 0x43, 0xe4,
++        0x99, 0xc5, 0xfd, 0xd9, 0x4d, 0x8e, 0x3e, 0x7b,
++        0xc4, 0xda, 0x22, 0x1b, 0xe1, 0xae, 0x23, 0x7a,
++        0x21, 0x27, 0xbd, 0xcc, 0x78, 0xc4, 0xe6, 0xc5,
++        0x33, 0x38, 0x35, 0xe0, 0x68, 0x1a, 0x1e, 0x06,
++        0xad, 0xaf, 0x7f, 0xd7, 0x3f, 0x0e, 0xc0, 0x90,
++        0x17, 0x97, 0x73, 0x75, 0x7b, 0x88, 0x49, 0xd8,
++        0x6f, 0x78, 0x5a, 0xde, 0x50, 0x20, 0x55, 0x33
+     };
+
+     sftk_PBELockInit();
+diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
+--- a/lib/softoken/pkcs11c.c
++++ b/lib/softoken/pkcs11c.c
+@@ -4609,16 +4609,17 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSessi
+         goto loser;
+     }
+ 
+     /* make sure we don't have any class, key_type, or value fields */
+     sftk_DeleteAttributeType(key, CKA_CLASS);
+     sftk_DeleteAttributeType(key, CKA_KEY_TYPE);
+     sftk_DeleteAttributeType(key, CKA_VALUE);
+ 
++
+     /* Now Set up the parameters to generate the key (based on mechanism) */
+     key_gen_type = nsc_bulk; /* bulk key by default */
+     switch (pMechanism->mechanism) {
+         case CKM_CDMF_KEY_GEN:
+         case CKM_DES_KEY_GEN:
+         case CKM_DES2_KEY_GEN:
+         case CKM_DES3_KEY_GEN:
+             checkWeak = PR_TRUE;
+@@ -4812,16 +4813,19 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSessi
+     crv = sftk_handleObject(key, session);
+     sftk_FreeSession(session);
+     if (crv == CKR_OK && sftk_isTrue(key, CKA_SENSITIVE)) {
+         crv = sftk_forceAttribute(key, CKA_ALWAYS_SENSITIVE, &cktrue, sizeof(CK_BBOOL));
+     }
+     if (crv == CKR_OK && !sftk_isTrue(key, CKA_EXTRACTABLE)) {
+         crv = sftk_forceAttribute(key, CKA_NEVER_EXTRACTABLE, &cktrue, sizeof(CK_BBOOL));
+     }
++    /* we need to do this check at the end, so we can check the generated key length against
++     * fips requirements */
++    key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE, key);
+     if (crv == CKR_OK) {
+         *phKey = key->handle;
+     }
+ loser:
+     PORT_Memset(buf, 0, sizeof buf);
+     sftk_FreeObject(key);
+     return crv;
+ }
+@@ -5780,16 +5784,19 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
+ 
+     if (crv != CKR_OK) {
+         NSC_DestroyObject(hSession, publicKey->handle);
+         sftk_FreeObject(publicKey);
+         NSC_DestroyObject(hSession, privateKey->handle);
+         sftk_FreeObject(privateKey);
+         return crv;
+     }
++    /* we need to do this check at the end to make sure the generated key meets the key length requirements */
++    privateKey->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE_KEY_PAIR, privateKey);
++    publicKey->isFIPS = privateKey->isFIPS;
+ 
+     *phPrivateKey = privateKey->handle;
+     *phPublicKey = publicKey->handle;
+     sftk_FreeObject(publicKey);
+     sftk_FreeObject(privateKey);
+ 
+     return CKR_OK;
+ }
+@@ -6990,16 +6997,17 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
+     }
+ 
+     /* HKDF-Extract(salt, base key value) */
+     if (params->bExtract) {
+         CK_BYTE *salt;
+         CK_ULONG saltLen;
+         HMACContext *hmac;
+         unsigned int bufLen;
++        SFTKSource saltKeySource = SFTK_SOURCE_DEFAULT;
+ 
+         switch (params->ulSaltType) {
+             case CKF_HKDF_SALT_NULL:
+                 saltLen = hashLen;
+                 salt = hashbuf;
+                 memset(salt, 0, saltLen);
+                 break;
+             case CKF_HKDF_SALT_DATA:
+@@ -7026,29 +7034,54 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
+                 if (isFIPS && (key->isFIPS == 0) && (saltKey->isFIPS == 1)) {
+                     CK_MECHANISM mech;
+                     mech.mechanism = CKM_HKDF_DERIVE;
+                     mech.pParameter = params;
+                     mech.ulParameterLen = sizeof(*params);
+                     key->isFIPS = sftk_operationIsFIPS(saltKey->slot, &mech,
+                                                        CKA_DERIVE, saltKey);
+                 }
++                saltKeySource = saltKey->source;
+                 saltKey_att = sftk_FindAttribute(saltKey, CKA_VALUE);
+                 if (saltKey_att == NULL) {
+                     sftk_FreeObject(saltKey);
+                     return CKR_KEY_HANDLE_INVALID;
+                 }
+                 /* save the resulting salt */
+                 salt = saltKey_att->attrib.pValue;
+                 saltLen = saltKey_att->attrib.ulValueLen;
+                 break;
+             default:
+                 return CKR_MECHANISM_PARAM_INVALID;
+                 break;
+         }
++        /* only TLS style usage is FIPS approved,
++         * turn off the FIPS indicator for other usages */
++        if (isFIPS && key && sourceKey) {
++            PRBool fipsOK = PR_FALSE;
++            /* case one: mix the kea with a previous or default
++             * salt */
++            if ((sourceKey->source == SFTK_SOURCE_KEA) &&
++                (saltKeySource == SFTK_SOURCE_HKDF_EXPAND) &&
++                (saltLen == rawHash->length)) {
++                fipsOK = PR_TRUE;
++            }
++            /* case two: restart, remix the previous secret as a salt */
++            if ((sourceKey->objclass == CKO_DATA) &&
++                (NSS_SecureMemcmpZero(sourceKeyBytes, sourceKeyLen) == 0) &&
++                (sourceKeyLen == rawHash->length) &&
++                (saltKeySource == SFTK_SOURCE_HKDF_EXPAND) &&
++                (saltLen == rawHash->length)) {
++                fipsOK = PR_TRUE;
++            }
++            if (!fipsOK) {
++                key->isFIPS = PR_FALSE;
++            }
++        }
++        if (key) key->source = SFTK_SOURCE_HKDF_EXTRACT;
+ 
+         hmac = HMAC_Create(rawHash, salt, saltLen, isFIPS);
+         if (saltKey_att) {
+             sftk_FreeAttribute(saltKey_att);
+         }
+         if (saltKey) {
+             sftk_FreeObject(saltKey);
+         }
+@@ -7076,16 +7109,40 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
+         /* T(1) = HMAC-Hash(prk, "" | info | 0x01)
+          * T(n) = HMAC-Hash(prk, T(n-1) | info | n
+          * key material = T(1) | ... | T(n)
+          */
+         HMACContext *hmac;
+         CK_BYTE bi;
+         unsigned iterations;
+ 
++        /* only TLS style usage is FIPS approved,
++         * turn off the FIPS indicator for other usages */
++        if (isFIPS && key && key->isFIPS && sourceKey) {
++            unsigned char *info=&params->pInfo[3];
++            /* only one case,
++             *  1) Expand only
++             *  2) with a key whose source was
++             *  SFTK_SOURCE_HKDF_EXPAND or SFTK_SOURCE_HKDF_EXTRACT
++             *  3) source key length == rawHash->length
++             *  4) Info has tls or dtls
++             * If any of those conditions aren't met, then we turn
++             * off the fips indicator */
++            if (params->bExtract ||
++               ((sourceKey->source != SFTK_SOURCE_HKDF_EXTRACT) &&
++                (sourceKey->source != SFTK_SOURCE_HKDF_EXPAND)) ||
++               (sourceKeyLen != rawHash->length) ||
++               (params->ulInfoLen < 7) ||
++               ((PORT_Memcmp(info,"tls",3) != 0) &&
++               (PORT_Memcmp(info,"dtls",4) != 0))) {
++               key->isFIPS = PR_FALSE;
++            }
++        }
++        if (key) key->source = SFTK_SOURCE_HKDF_EXPAND;
++
+         genLen = PR_ROUNDUP(keySize, hashLen);
+         iterations = genLen / hashLen;
+ 
+         if (genLen > sizeof(keyBlock)) {
+             keyBlockAlloc = PORT_Alloc(genLen);
+             if (keyBlockAlloc == NULL) {
+                 return CKR_HOST_MEMORY;
+             }
+@@ -8434,16 +8491,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
+ 
+             /* calculate private value - oct */
+             rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize);
+ 
+             SECITEM_ZfreeItem(&dhPrime, PR_FALSE);
+             SECITEM_ZfreeItem(&dhValue, PR_FALSE);
+ 
+             if (rv == SECSuccess) {
++                key->source = SFTK_SOURCE_KEA;
+                 sftk_forceAttribute(key, CKA_VALUE, derived.data, derived.len);
+                 SECITEM_ZfreeItem(&derived, PR_FALSE);
+                 crv = CKR_OK;
+             } else
+                 crv = CKR_HOST_MEMORY;
+ 
+             break;
+         }
+@@ -8564,16 +8622,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
+                     }
+                     PORT_Memcpy(&keyData[keySize - secretlen], secret, secretlen);
+                     secret = keyData;
+                 } else {
+                     secret += (secretlen - keySize);
+                 }
+                 secretlen = keySize;
+             }
++            key->source = SFTK_SOURCE_KEA;
+ 
+             sftk_forceAttribute(key, CKA_VALUE, secret, secretlen);
+             PORT_ZFree(tmp.data, tmp.len);
+             if (keyData) {
+                 PORT_ZFree(keyData, keySize);
+             }
+             break;
+ 
+diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h
+--- a/lib/softoken/pkcs11i.h
++++ b/lib/softoken/pkcs11i.h
+@@ -147,16 +147,26 @@ typedef enum {
+  */
+ typedef enum {
+     SFTK_DestroyFailure,
+     SFTK_Destroyed,
+     SFTK_Busy
+ } SFTKFreeStatus;
+ 
+ /*
++ * Source of various objects
++ */
++typedef enum {
++    SFTK_SOURCE_DEFAULT=0,
++    SFTK_SOURCE_KEA,
++    SFTK_SOURCE_HKDF_EXPAND,
++    SFTK_SOURCE_HKDF_EXTRACT
++} SFTKSource;
++
++/*
+  * attribute values of an object.
+  */
+ struct SFTKAttributeStr {
+     SFTKAttribute *next;
+     SFTKAttribute *prev;
+     PRBool freeAttr;
+     PRBool freeData;
+     /*must be called handle to make sftkqueue_find work */
+@@ -189,16 +199,17 @@ struct SFTKObjectStr {
+     CK_OBJECT_CLASS objclass;
+     CK_OBJECT_HANDLE handle;
+     int refCount;
+     PZLock *refLock;
+     SFTKSlot *slot;
+     void *objectInfo;
+     SFTKFree infoFree;
+     PRBool isFIPS;
++    SFTKSource source;
+ };
+ 
+ struct SFTKTokenObjectStr {
+     SFTKObject obj;
+     SECItem dbKey;
+ };
+ 
+ struct SFTKSessionObjectStr {
+diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c
+--- a/lib/softoken/pkcs11u.c
++++ b/lib/softoken/pkcs11u.c
+@@ -1090,16 +1090,17 @@ sftk_NewObject(SFTKSlot *slot)
+         sessObject->attrList[i].freeData = PR_FALSE;
+     }
+     sessObject->optimizeSpace = slot->optimizeSpace;
+ 
+     object->handle = 0;
+     object->next = object->prev = NULL;
+     object->slot = slot;
+     object->isFIPS = sftk_isFIPS(slot->slotID);
++    object->source = SFTK_SOURCE_DEFAULT;
+ 
+     object->refCount = 1;
+     sessObject->sessionList.next = NULL;
+     sessObject->sessionList.prev = NULL;
+     sessObject->sessionList.parent = object;
+     sessObject->session = NULL;
+     sessObject->wasDerived = PR_FALSE;
+     if (!hasLocks)
+@@ -1674,16 +1675,17 @@ fail:
+ CK_RV
+ sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject)
+ {
+     SFTKAttribute *attribute;
+     SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);
+     unsigned int i;
+ 
+     destObject->isFIPS = srcObject->isFIPS;
++    destObject->source = srcObject->source;
+     if (src_so == NULL) {
+         return sftk_CopyTokenObject(destObject, srcObject);
+     }
+ 
+     PZ_Lock(src_so->attributeLock);
+     for (i = 0; i < src_so->hashSize; i++) {
+         attribute = src_so->head[i];
+         do {
+@@ -2059,16 +2061,17 @@ sftk_NewTokenObject(SFTKSlot *slot, SECI
+     /* every object must have a class, if we can't get it, the object
+      * doesn't exist */
+     crv = handleToClass(slot, handle, &object->objclass);
+     if (crv != CKR_OK) {
+         goto loser;
+     }
+     object->slot = slot;
+     object->isFIPS = sftk_isFIPS(slot->slotID);
++    object->source = SFTK_SOURCE_DEFAULT;
+     object->objectInfo = NULL;
+     object->infoFree = NULL;
+     if (!hasLocks) {
+         object->refLock = PZ_NewLock(nssILockRefLock);
+     }
+     if (object->refLock == NULL) {
+         goto loser;
+     }
+@@ -2225,16 +2228,25 @@ sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE 
+             break;
+         case CKA_DERIVE:
+             flags = CKF_DERIVE;
+             break;
+         /* fake attribute to select digesting */
+         case CKA_DIGEST:
+             flags = CKF_DIGEST;
+             break;
++        /* fake attribute to select key gen */
++         case CKA_NSS_GENERATE:
++            flags = CKF_GENERATE;
++            break;
++        /* fake attribute to select key pair gen */
++        case CKA_NSS_GENERATE_KEY_PAIR:
++            flags = CKF_GENERATE_KEY_PAIR;
++            break;
++        /* fake attributes to to handle MESSAGE* flags */
+         case CKA_NSS_MESSAGE | CKA_ENCRYPT:
+             flags = CKF_MESSAGE_ENCRYPT;
+             break;
+         case CKA_NSS_MESSAGE | CKA_DECRYPT:
+             flags = CKF_MESSAGE_DECRYPT;
+             break;
+         case CKA_NSS_MESSAGE | CKA_SIGN:
+             flags = CKF_MESSAGE_SIGN;
+@@ -2278,17 +2290,17 @@ sftk_quickGetECCCurveOid(SFTKObject *sou
+ }
+ 
+ /* This function currently only returns valid lengths for
+  * FIPS approved ECC curves. If we want to make this generic
+  * in the future, that Curve determination can be done in
+  * the sftk_handleSpecial. Since it's currently only used
+  * in FIPS indicators, it's currently only compiled with
+  * the FIPS indicator code */
+-static int
++static CK_ULONG
+ sftk_getKeyLength(SFTKObject *source)
+ {
+     CK_KEY_TYPE keyType = CK_INVALID_HANDLE;
+     CK_ATTRIBUTE_TYPE keyAttribute;
+     CK_ULONG keyLength = 0;
+     SFTKAttribute *attribute;
+     CK_RV crv;
+ 
diff --git a/SOURCES/nss-softokn-3.79-fix-freebl-crash.patch b/SOURCES/nss-softokn-3.79-fix-freebl-crash.patch
deleted file mode 100644
index d32cd07..0000000
--- a/SOURCES/nss-softokn-3.79-fix-freebl-crash.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-diff --git a/lib/freebl/shvfy.c b/lib/freebl/shvfy.c
---- a/lib/freebl/shvfy.c
-+++ b/lib/freebl/shvfy.c
-@@ -508,29 +508,44 @@ loser:
-         PR_Close(shFD);
-     }
-     if (hashcx != NULL) {
-         if (hashObj) {
-             hashObj->destroy(hashcx, PR_TRUE);
-         }
-     }
-     if (signature.data != NULL) {
--        SECITEM_ZfreeItem(&signature, PR_FALSE);
-+        /* can't use SECITEM_ZfreeItem on rhel7 because rhel7
-+         * supports util-free softoken for hash operations */
-+        PORT_Memset(signature.data, 0, signature.len);
-+        PORT_Free(signature.data);
-     }
-     if (key.params.prime.data != NULL) {
--        SECITEM_ZfreeItem(&key.params.prime, PR_FALSE);
-+        /* can't use SECITEM_ZfreeItem on rhel7 because rhel7
-+         * supports util-free softoken for hash operations */
-+        PORT_Memset(key.params.prime.data, 0, key.params.prime.len);
-+        PORT_Free(key.params.prime.data);
-     }
-     if (key.params.subPrime.data != NULL) {
--        SECITEM_ZfreeItem(&key.params.subPrime, PR_FALSE);
-+        /* can't use SECITEM_ZfreeItem on rhel7 because rhel7
-+         * supports util-free softoken for hash operations */
-+        PORT_Memset(key.params.subPrime.data, 0, key.params.subPrime.len);
-+        PORT_Free(key.params.subPrime.data);
-     }
-     if (key.params.base.data != NULL) {
--        SECITEM_ZfreeItem(&key.params.base, PR_FALSE);
-+        /* can't use SECITEM_ZfreeItem on rhel7 because rhel7
-+         * supports util-free softoken for hash operations */
-+        PORT_Memset(key.params.base.data, 0, key.params.base.len);
-+        PORT_Free(key.params.base.data);
-     }
-     if (key.publicValue.data != NULL) {
--        SECITEM_ZfreeItem(&key.publicValue, PR_FALSE);
-+        /* can't use SECITEM_ZfreeItem on rhel7 because rhel7
-+         * supports util-free softoken for hash operations */
-+        PORT_Memset(key.publicValue.data, 0, key.publicValue.len);
-+        PORT_Free(key.publicValue.data);
-     }
- 
-     return result;
- }
- 
- PRBool
- BLAPI_VerifySelf(const char *name)
- {
diff --git a/SOURCES/nss-softokn-3.90-fix-lowhashtest-dependency.patch b/SOURCES/nss-softokn-3.90-fix-lowhashtest-dependency.patch
new file mode 100644
index 0000000..afd5245
--- /dev/null
+++ b/SOURCES/nss-softokn-3.90-fix-lowhashtest-dependency.patch
@@ -0,0 +1,10 @@
+--- ./cmd/lowhashtest/lowhashtest.c	2023-06-04 10:42:53.000000000 +0200
++++ ./cmd/lowhashtest/lowhashtest.c.fix-lowhashtest-dependency	2023-07-27 08:52:24.085772080 +0200
+@@ -2,6 +2,7 @@
+ #include <string.h>
+ #include <assert.h>
+ 
++#include "nspr.h"
+ /* nss headers */
+ #include "hasht.h"
+ #include "nsslowhash.h"
diff --git a/SPECS/nss-softokn.spec b/SPECS/nss-softokn.spec
index 60fcb6d..00ba4d3 100644
--- a/SPECS/nss-softokn.spec
+++ b/SPECS/nss-softokn.spec
@@ -1,8 +1,8 @@
-%global nspr_version 4.34.0
+%global nspr_version 4.35.0
 %global nss_name nss
-%global nss_util_version 3.79.0
+%global nss_util_version 3.90.0
 %global nss_util_build -1
-%global nss_softokn_version 3.79.0
+%global nss_softokn_version 3.90.0
 %global unsupported_tools_directory %{_libdir}/nss/unsupported-tools
 %global saved_files_dir %{_libdir}/nss/saved
 %global prelink_conf_dir %{_sysconfdir}/prelink.conf.d/
@@ -40,7 +40,7 @@ rpm.define(string.format("nss_softokn_archive_version %s",
 Summary:          Network Security Services Softoken Module
 Name:             nss-softokn
 Version:          %{nss_softokn_version}
-Release:          4%{?dist}
+Release:          6%{?dist}
 License:          MPLv2.0
 URL:              http://www.mozilla.org/projects/security/pki/nss/
 Group:            System Environment/Libraries
@@ -74,6 +74,7 @@ Source3:          nss-softokn-config.in
 Source4:	  nss-softokn-prelink.conf
 Source5:	  nss-softokn-dracut-module-setup.sh
 Source6:	  nss-softokn-dracut.conf
+Source30:         fips_algorithms.h
 
 # Select the tests to run based on the type of build
 # This patch uses the gcc-iquote dir option documented at
@@ -93,20 +94,21 @@ Patch97:	   nss-softokn-3.16-add_encrypt_derive.patch
 
 Patch102:          nss-softokn-tls-abi-fix.patch
 
-# this patch won't likely be upstreamed
-Patch103:          nss-softokn-3.79-fix-freebl-crash.patch
-
 # To revert the upstream change in the default behavior in:
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1382736
 Patch104:         nss-softokn-fs-probe.patch
 
 
 Patch200:         nss-softokn-3.67-read-write-db-locks.patch
-# https://bugzilla.mozilla.org/show_bug.cgi?id=2084334
-Patch201:         nss-softokn-3.79-dont-verify-default.patch
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1774659
 Patch202:         nss-softokn-3.79-dbtool.patch
-Patch203:         nss-3.79-increase-pbe-cache.patch
+Patch260:         nss-softokn-3.79-fips.patch
+Patch261:         nss-3.79-fips-review.patches
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1836781
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1836925
+Patch262:         nss-3.90-DisablingASM.patch
+Patch270:	  nss-softokn-3.90-fix-lowhashtest-dependency.patch
+Patch272:	  nss-3.90-pbkdf2-indicator.patch
 
 %description
 Network Security Services Softoken Cryptographic Module
@@ -161,24 +163,31 @@ Header and library files for doing development with Network Security Services.
 %setup -q -n %{name}-%{nss_softokn_archive_version}
 
 # activate if needed when doing a major update with new apis
-%patch10 -p0 -b .iquote
+%patch -P10 -p0 -b .iquote
 
 pushd nss
-%patch97 -p1 -b .add_encrypt_derive
-%patch103 -p1 -b .fix-freebl-crash
-%patch104 -p1 -b .fs-probe
-%patch200 -p1 -b .read-write-db-locks
-%patch201 -p1 -b .dont-verify-default.patch
-%patch202 -p1 -b .dbtool
-%patch203 -p1 -b .increase-pbe-cache
+%patch -P97 -p1 -b .add_encrypt_derive
+%patch -P104 -p1 -b .fs-probe
+%patch -P200 -p1 -b .read-write-db-locks
+%patch -P202 -p1 -b .dbtool
+%patch -P260 -p1 -b .fips
+%patch -P261 -p1 -b .fips-review
+%patch -P262 -p1 -b .disable-asm
+%patch -P270 -p1 -b .fix-lowhashtest-dependency
+%patch -P272 -p1 -b .pbkdf2-indicator
 popd
 
-%patch102 -p1 -b .tls-abi-fix
+%patch -P102 -p1 -b .tls-abi-fix
+
+# copy the fips_algorithms.h for this release
+# this file is release specific and matches what
+# each vendors claim in their own FIPS certification
+cp %{SOURCE30} nss/lib/softoken/
 
 %build
 
 # partial RELRO support as a security enhancement
-LDFLAGS+=-Wl,-z,relro
+LDFLAGS+=" -Wl,-z,relro"
 export LDFLAGS
 
 FREEBL_NO_DEPEND=1
@@ -193,6 +202,13 @@ export FREEBL_LOWHASH
 
 NSS_FORCE_FIPS=1
 export NSS_FORCE_FIPS
+export NSS_FIPS_VERSION="%{name}\ %{version}-%{srpmhash}"
+eval $(sed -n 's/^\(\(NAME\|VERSION_ID\)=.*\)/OS_\1/p' /etc/os-release | sed -e 's/ /\\ /g')
+export FIPS_MODULE_OS="$OS_NAME\ ${OS_VERSION_ID%%.*}"
+export NSS_FIPS_MODULE_ID="${FIPS_MODULE_OS}\ ${NSS_FIPS_VERSION}"
+export NSS_FIPS_140_3=1
+export NSS_ENABLE_FIPS_INDICATORS=1
+
 
 #FREEBL_USE_PRELINK=1
 #export FREEBL_USE_PRELINK
@@ -509,6 +525,15 @@ done
 %{_includedir}/nss3/shsign.h
 
 %changelog
+* Tue Aug 15 2023  Bob Relyea <rrelyea@redhat.com> - 3.90.0-6
+- Fix double free issue when using dsa check files
+
+* Tue Aug 15 2023  Bob Relyea <rrelyea@redhat.com> - 3.90.0-5
+- Fix pbkdf indicators
+
+* Tue Jun 20 2023  Bob Relyea <rrelyea@redhat.com> - 3.90.0-1
+- Rebase to NSS 3.90.
+
 * Fri Jun 17 2022  Bob Relyea <rrelyea@redhat.com> - 3.79.0-4
 - increase the cache for the pbe