diff --git a/SOURCES/cve-2023-0767.patch b/SOURCES/cve-2023-0767.patch
new file mode 100644
index 0000000..fc5d4fa
--- /dev/null
+++ b/SOURCES/cve-2023-0767.patch
@@ -0,0 +1,92 @@
+diff --git a/lib/pkcs12/p12d.c b/lib/pkcs12/p12d.c
+--- a/lib/pkcs12/p12d.c
++++ b/lib/pkcs12/p12d.c
+@@ -335,35 +335,42 @@
+     sec_PKCS12SafeContentsContext *safeContentsCtx =
+         (sec_PKCS12SafeContentsContext *)arg;
+     SEC_PKCS12DecoderContext *p12dcx;
+     SECStatus rv;
+ 
+-    /* make sure that we are not skipping the current safeBag,
+-     * and that there are no errors.  If so, just return rather
+-     * than continuing to process.
+-     */
+-    if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
+-        safeContentsCtx->p12dcx->error || safeContentsCtx->skipCurrentSafeBag) {
++    if (!safeContentsCtx || !safeContentsCtx->p12dcx || !safeContentsCtx->currentSafeBagA1Dcx) {
+         return;
+     }
+     p12dcx = safeContentsCtx->p12dcx;
+ 
++    /* make sure that there are no errors and we are not skipping the current safeBag */
++    if (p12dcx->error || safeContentsCtx->skipCurrentSafeBag) {
++        goto loser;
++    }
++
+     rv = SEC_ASN1DecoderUpdate(safeContentsCtx->currentSafeBagA1Dcx, data, len);
+     if (rv != SECSuccess) {
+         p12dcx->errorValue = PORT_GetError();
++        p12dcx->error = PR_TRUE;
++        goto loser;
++    }
++
++    /* The update may have set safeContentsCtx->skipCurrentSafeBag, and we
++     * may not get another opportunity to clean up the decoder context.
++     */
++    if (safeContentsCtx->skipCurrentSafeBag) {
+         goto loser;
+     }
+ 
+     return;
+ 
+ loser:
+-    /* set the error, and finish the decoder context.  because there
++    /* Finish the decoder context. Because there
+      * is not a way of returning an error message, it may be worth
+      * while to do a check higher up and finish any decoding contexts
+      * that are still open.
+      */
+-    p12dcx->error = PR_TRUE;
+     SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
+     safeContentsCtx->currentSafeBagA1Dcx = NULL;
+     return;
+ }
+ 
+diff --git a/lib/pkcs12/p12t.h b/lib/pkcs12/p12t.h
+--- a/lib/pkcs12/p12t.h
++++ b/lib/pkcs12/p12t.h
+@@ -71,10 +71,11 @@
+         SECKEYEncryptedPrivateKeyInfo *pkcs8ShroudedKeyBag;
+         sec_PKCS12CertBag *certBag;
+         sec_PKCS12CRLBag *crlBag;
+         sec_PKCS12SecretBag *secretBag;
+         sec_PKCS12SafeContents *safeContents;
++        SECItem *unknownBag;
+     } safeBagContent;
+ 
+     sec_PKCS12Attribute **attribs;
+ 
+     /* used locally */
+diff --git a/lib/pkcs12/p12tmpl.c b/lib/pkcs12/p12tmpl.c
+--- a/lib/pkcs12/p12tmpl.c
++++ b/lib/pkcs12/p12tmpl.c
+@@ -28,16 +28,16 @@
+ 
+     safeBag = (sec_PKCS12SafeBag *)src_or_dest;
+ 
+     oiddata = SECOID_FindOID(&safeBag->safeBagType);
+     if (oiddata == NULL) {
+-        return SEC_ASN1_GET(SEC_AnyTemplate);
++        return SEC_ASN1_GET(SEC_PointerToAnyTemplate);
+     }
+ 
+     switch (oiddata->offset) {
+         default:
+-            theTemplate = SEC_ASN1_GET(SEC_AnyTemplate);
++            theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate);
+             break;
+         case SEC_OID_PKCS12_V1_KEY_BAG_ID:
+             theTemplate = SEC_ASN1_GET(SECKEY_PointerToPrivateKeyInfoTemplate);
+             break;
+         case SEC_OID_PKCS12_V1_CERT_BAG_ID:
+
diff --git a/SOURCES/fips_algorithms.h b/SOURCES/fips_algorithms.h
index 5f6dbe3..6526ec7 100644
--- a/SOURCES/fips_algorithms.h
+++ b/SOURCES/fips_algorithms.h
@@ -13,7 +13,8 @@ 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 */
+    SFTKFIPSAEAD, /* single shot AEAD functions not allowed in FIPS mode */
+    SFTKFIPSRSAPSS
 } SFTKFIPSSpecialClass;
 
 typedef struct SFTKFIPSAlgorithmListStr SFTKFIPSAlgorithmList;
@@ -77,21 +78,20 @@ SFTKFIPSAlgorithmList sftk_fips_mechs[] = {
     { 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, SFTKFIPSNone },
-    { CKM_SHA256_RSA_PKCS_PSS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone },
-    { CKM_SHA384_RSA_PKCS_PSS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone },
-    { CKM_SHA512_RSA_PKCS_PSS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone },
-    { CKM_SHA224_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
-    { CKM_SHA256_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
-    { CKM_SHA384_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
-    { CKM_SHA512_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_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 --------------------- */
-    /* no diffie hellman yet */
     { 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 --------------------- */
@@ -131,18 +131,19 @@ SFTKFIPSAlgorithmList sftk_fips_mechs[] = {
     /* --------------------- Secret Key Operations ------------------------ */
     { CKM_GENERIC_SECRET_KEY_GEN, { 112, 256, CKF_GEN }, 1, SFTKFIPSNone },
     /* ---------------------- SSL/TLS operations ------------------------- */
-    { CKM_SHA224_KEY_DERIVATION, { 112, 224, CKF_KDF }, 1, SFTKFIPSNone },
-    { CKM_SHA256_KEY_DERIVATION, { 112, 256, CKF_KDF }, 1, SFTKFIPSNone },
-    { CKM_SHA384_KEY_DERIVATION, { 112, 284, CKF_KDF }, 1, SFTKFIPSNone },
-    { CKM_SHA512_KEY_DERIVATION, { 112, 512, CKF_KDF }, 1, SFTKFIPSNone },
     { 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 },
-    /* sigh, is this algorithm really tested. ssl doesn't seem to have a
-     * way of turning the extension off */
     { 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 },
 
@@ -159,15 +160,9 @@ SFTKFIPSAlgorithmList sftk_fips_mechs[] = {
     { 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, CKF_KDF }, 1, SFTKFIPSNone },
-    { CKM_NSS_IKE_PRF_DERIVE, { 112, 64, CKF_KDF }, 1, SFTKFIPSNone },
-    { CKM_NSS_IKE1_PRF_DERIVE, { 112, 64, CKF_KDF }, 1, SFTKFIPSNone },
-    { CKM_NSS_IKE1_APP_B_PRF_DERIVE, { 112, 255 * 64, CKF_KDF }, 1, SFTKFIPSNone },
+    { 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, SFTKFIPSNone },
-    { CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN, { 224, 224, CKF_GEN }, 1, SFTKFIPSNone },
-    { CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN, { 256, 256, CKF_GEN }, 1, SFTKFIPSNone },
-    { CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN, { 384, 384, CKF_GEN }, 1, SFTKFIPSNone },
-    { CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN, { 512, 512, CKF_GEN }, 1, SFTKFIPSNone }
 };
 const int SFTK_NUMBER_FIPS_ALGORITHMS = PR_ARRAY_SIZE(sftk_fips_mechs);
diff --git a/SOURCES/nss-3.79-fips-review.patches b/SOURCES/nss-3.79-fips-review.patches
new file mode 100644
index 0000000..9b8e875
--- /dev/null
+++ b/SOURCES/nss-3.79-fips-review.patches
@@ -0,0 +1,320 @@
+diff -up ./lib/freebl/dh.c.fips-review ./lib/freebl/dh.c
+--- ./lib/freebl/dh.c.fips-review	2022-05-26 02:54:33.000000000 -0700
++++ ./lib/freebl/dh.c	2023-03-16 11:54:37.839935303 -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-03-16 11:53:04.703068972 -0700
++++ ./lib/softoken/pkcs11c.c	2023-03-16 11:55:23.498360007 -0700
+@@ -4780,6 +4780,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));
+@@ -4787,9 +4791,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;
+     }
+@@ -5093,60 +5094,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 */
+@@ -5166,18 +5174,41 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
+             }
+             crv = sftk_Attribute2SecItem(NULL, &prime, privateKey, CKA_PRIME);
+             /* 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, 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;
++                    }
+                 }
++                subPrimePtr = &subPrime;
++            } else {
++                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 ((subPrimePtr->len != subPrimeLen) ||
++                        (PORT_Memcmp(subPrimePtr->data, subPrime.data,
++                                     subPrime.len) != 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(&subPrime, PR_FALSE);
+@@ -5185,13 +5216,9 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
+         }
+         /* 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;
+@@ -5709,8 +5736,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);
+@@ -5752,6 +5779,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);
+@@ -5761,6 +5789,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;
+@@ -8563,6 +8593,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	2022-05-26 02:54:33.000000000 -0700
++++ ./lib/softoken/pkcs11.c	2023-03-16 11:54:37.840935312 -0700
+@@ -4599,7 +4599,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/sftkike.c.fips-review ./lib/softoken/sftkike.c
+--- ./lib/softoken/sftkike.c.fips-review	2022-05-26 02:54:33.000000000 -0700
++++ ./lib/softoken/sftkike.c	2023-03-16 11:54:37.840935312 -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-rsa-pss-salt-fips.patch b/SOURCES/nss-3.79-rsa-pss-salt-fips.patch
new file mode 100644
index 0000000..660ecbc
--- /dev/null
+++ b/SOURCES/nss-3.79-rsa-pss-salt-fips.patch
@@ -0,0 +1,397 @@
+diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
+--- a/lib/softoken/pkcs11c.c
++++ b/lib/softoken/pkcs11c.c
+@@ -232,57 +232,26 @@ NSC_DestroyObject(CK_SESSION_HANDLE hSes
+      * be in the data base.
+      */
+     status = sftk_FreeObject(object);
+ 
+     return (status != SFTK_DestroyFailure) ? CKR_OK : CKR_DEVICE_ERROR;
+ }
+ 
+ /*
+- ************** Crypto Functions:     Utilities ************************
+- */
+-/*
+- * Utility function for converting PSS/OAEP parameter types into
+- * HASH_HashTypes. Note: Only SHA family functions are defined in RFC 3447.
+- */
+-static HASH_HashType
+-GetHashTypeFromMechanism(CK_MECHANISM_TYPE mech)
+-{
+-    switch (mech) {
+-        case CKM_SHA_1:
+-        case CKG_MGF1_SHA1:
+-            return HASH_AlgSHA1;
+-        case CKM_SHA224:
+-        case CKG_MGF1_SHA224:
+-            return HASH_AlgSHA224;
+-        case CKM_SHA256:
+-        case CKG_MGF1_SHA256:
+-            return HASH_AlgSHA256;
+-        case CKM_SHA384:
+-        case CKG_MGF1_SHA384:
+-            return HASH_AlgSHA384;
+-        case CKM_SHA512:
+-        case CKG_MGF1_SHA512:
+-            return HASH_AlgSHA512;
+-        default:
+-            return HASH_AlgNULL;
+-    }
+-}
+-
+-/*
+  * Returns true if "params" contains a valid set of PSS parameters
+  */
+ static PRBool
+ sftk_ValidatePssParams(const CK_RSA_PKCS_PSS_PARAMS *params)
+ {
+     if (!params) {
+         return PR_FALSE;
+     }
+-    if (GetHashTypeFromMechanism(params->hashAlg) == HASH_AlgNULL ||
+-        GetHashTypeFromMechanism(params->mgf) == HASH_AlgNULL) {
++    if (sftk_GetHashTypeFromMechanism(params->hashAlg) == HASH_AlgNULL ||
++        sftk_GetHashTypeFromMechanism(params->mgf) == HASH_AlgNULL) {
+         return PR_FALSE;
+     }
+     return PR_TRUE;
+ }
+ 
+ /*
+  * Returns true if "params" contains a valid set of OAEP parameters
+  */
+@@ -293,18 +262,18 @@ sftk_ValidateOaepParams(const CK_RSA_PKC
+         return PR_FALSE;
+     }
+     /* The requirements of ulSourceLen/pSourceData come from PKCS #11, which
+      * state:
+      *   If the parameter is empty, pSourceData must be NULL and
+      *   ulSourceDataLen must be zero.
+      */
+     if (params->source != CKZ_DATA_SPECIFIED ||
+-        (GetHashTypeFromMechanism(params->hashAlg) == HASH_AlgNULL) ||
+-        (GetHashTypeFromMechanism(params->mgf) == HASH_AlgNULL) ||
++        (sftk_GetHashTypeFromMechanism(params->hashAlg) == HASH_AlgNULL) ||
++        (sftk_GetHashTypeFromMechanism(params->mgf) == HASH_AlgNULL) ||
+         (params->ulSourceDataLen == 0 && params->pSourceData != NULL) ||
+         (params->ulSourceDataLen != 0 && params->pSourceData == NULL)) {
+         return PR_FALSE;
+     }
+     return PR_TRUE;
+ }
+ 
+ /*
+@@ -606,18 +575,18 @@ sftk_RSAEncryptOAEP(SFTKOAEPInfo *info, 
+     HASH_HashType maskHashAlg;
+ 
+     PORT_Assert(info->key.pub->keyType == NSSLOWKEYRSAKey);
+     if (info->key.pub->keyType != NSSLOWKEYRSAKey) {
+         PORT_SetError(SEC_ERROR_INVALID_KEY);
+         return SECFailure;
+     }
+ 
+-    hashAlg = GetHashTypeFromMechanism(info->params.hashAlg);
+-    maskHashAlg = GetHashTypeFromMechanism(info->params.mgf);
++    hashAlg = sftk_GetHashTypeFromMechanism(info->params.hashAlg);
++    maskHashAlg = sftk_GetHashTypeFromMechanism(info->params.mgf);
+ 
+     return RSA_EncryptOAEP(&info->key.pub->u.rsa, hashAlg, maskHashAlg,
+                            (const unsigned char *)info->params.pSourceData,
+                            info->params.ulSourceDataLen, NULL, 0,
+                            output, outputLen, maxLen, input, inputLen);
+ }
+ 
+ static SECStatus
+@@ -630,18 +599,18 @@ sftk_RSADecryptOAEP(SFTKOAEPInfo *info, 
+     HASH_HashType maskHashAlg;
+ 
+     PORT_Assert(info->key.priv->keyType == NSSLOWKEYRSAKey);
+     if (info->key.priv->keyType != NSSLOWKEYRSAKey) {
+         PORT_SetError(SEC_ERROR_INVALID_KEY);
+         return SECFailure;
+     }
+ 
+-    hashAlg = GetHashTypeFromMechanism(info->params.hashAlg);
+-    maskHashAlg = GetHashTypeFromMechanism(info->params.mgf);
++    hashAlg = sftk_GetHashTypeFromMechanism(info->params.hashAlg);
++    maskHashAlg = sftk_GetHashTypeFromMechanism(info->params.mgf);
+ 
+     rv = RSA_DecryptOAEP(&info->key.priv->u.rsa, hashAlg, maskHashAlg,
+                          (const unsigned char *)info->params.pSourceData,
+                          info->params.ulSourceDataLen,
+                          output, outputLen, maxLen, input, inputLen);
+     if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+         sftk_fatalError = PR_TRUE;
+     }
+@@ -2646,18 +2615,18 @@ sftk_RSASignPSS(SFTKPSSSignInfo *info, u
+     CK_RSA_PKCS_PSS_PARAMS *params = &info->params;
+ 
+     PORT_Assert(info->key->keyType == NSSLOWKEYRSAKey);
+     if (info->key->keyType != NSSLOWKEYRSAKey) {
+         PORT_SetError(SEC_ERROR_INVALID_KEY);
+         return SECFailure;
+     }
+ 
+-    hashAlg = GetHashTypeFromMechanism(params->hashAlg);
+-    maskHashAlg = GetHashTypeFromMechanism(params->mgf);
++    hashAlg = sftk_GetHashTypeFromMechanism(params->hashAlg);
++    maskHashAlg = sftk_GetHashTypeFromMechanism(params->mgf);
+ 
+     rv = RSA_SignPSS(&info->key->u.rsa, hashAlg, maskHashAlg, NULL,
+                      params->sLen, sig, sigLen, maxLen, hash, hashLen);
+     if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
+         sftk_fatalError = PR_TRUE;
+     }
+     return rv;
+ }
+@@ -3021,17 +2990,17 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
+                 tlsPrfHash = HASH_AlgNULL;
+                 if (tls12_mac_params->ulMacLength != 12) {
+                     crv = CKR_MECHANISM_PARAM_INVALID;
+                     break;
+                 }
+             } else {
+                 /* The hash function for the TLS 1.2 PRF */
+                 tlsPrfHash =
+-                    GetHashTypeFromMechanism(tls12_mac_params->prfHashMechanism);
++                    sftk_GetHashTypeFromMechanism(tls12_mac_params->prfHashMechanism);
+                 if (tlsPrfHash == HASH_AlgNULL ||
+                     tls12_mac_params->ulMacLength < 12) {
+                     crv = CKR_MECHANISM_PARAM_INVALID;
+                     break;
+                 }
+             }
+             if (tls12_mac_params->ulServerOrClient == 1) {
+                 label = "server finished";
+@@ -3539,18 +3508,18 @@ sftk_RSACheckSignPSS(SFTKPSSVerifyInfo *
+     CK_RSA_PKCS_PSS_PARAMS *params = &info->params;
+ 
+     PORT_Assert(info->key->keyType == NSSLOWKEYRSAKey);
+     if (info->key->keyType != NSSLOWKEYRSAKey) {
+         PORT_SetError(SEC_ERROR_INVALID_KEY);
+         return SECFailure;
+     }
+ 
+-    hashAlg = GetHashTypeFromMechanism(params->hashAlg);
+-    maskHashAlg = GetHashTypeFromMechanism(params->mgf);
++    hashAlg = sftk_GetHashTypeFromMechanism(params->hashAlg);
++    maskHashAlg = sftk_GetHashTypeFromMechanism(params->mgf);
+ 
+     return RSA_CheckSignPSS(&info->key->u.rsa, hashAlg, maskHashAlg,
+                             params->sLen, sig, sigLen, digest, digestLen);
+ }
+ 
+ /* NSC_VerifyInit initializes a verification operation,
+  * where the signature is an appendix to the data,
+  * and plaintext cannot be recovered from the signature (e.g. DSA) */
+@@ -6951,17 +6920,17 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
+     unsigned genLen = 0;
+     unsigned char hashbuf[HASH_LENGTH_MAX];
+     unsigned char keyBlock[9 * SFTK_MAX_MAC_LENGTH];
+     unsigned char *keyBlockAlloc = NULL;    /* allocated keyBlock */
+     unsigned char *keyBlockData = keyBlock; /* pointer to current keyBlock */
+     const unsigned char *prk;               /* psuedo-random key */
+     CK_ULONG prkLen;
+     const unsigned char *okm; /* output keying material */
+-    HASH_HashType hashType = GetHashTypeFromMechanism(params->prfHashMechanism);
++    HASH_HashType hashType = sftk_GetHashTypeFromMechanism(params->prfHashMechanism);
+     SFTKObject *saltKey = NULL;
+     CK_RV crv = CKR_OK;
+ 
+     /* Spec says it should be the base hash, but also accept the HMAC */
+     if (hashType == HASH_AlgNULL) {
+         hashType = sftk_HMACMechanismToHash(params->prfHashMechanism);
+     }
+     rawHash = HASH_GetRawHashObject(hashType);
+@@ -7389,17 +7358,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
+             if ((mechanism == CKM_TLS12_MASTER_KEY_DERIVE) ||
+                 (mechanism == CKM_TLS12_MASTER_KEY_DERIVE_DH)) {
+                 if (BAD_PARAM_CAST(pMechanism, sizeof(CK_TLS12_MASTER_KEY_DERIVE_PARAMS))) {
+                     crv = CKR_MECHANISM_PARAM_INVALID;
+                     break;
+                 }
+                 CK_TLS12_MASTER_KEY_DERIVE_PARAMS *tls12_master =
+                     (CK_TLS12_MASTER_KEY_DERIVE_PARAMS *)pMechanism->pParameter;
+-                tlsPrfHash = GetHashTypeFromMechanism(tls12_master->prfHashMechanism);
++                tlsPrfHash = sftk_GetHashTypeFromMechanism(tls12_master->prfHashMechanism);
+                 if (tlsPrfHash == HASH_AlgNULL) {
+                     crv = CKR_MECHANISM_PARAM_INVALID;
+                     break;
+                 }
+             } else if ((mechanism == CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256) ||
+                        (mechanism == CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256)) {
+                 tlsPrfHash = HASH_AlgSHA256;
+             }
+@@ -7607,17 +7576,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
+                     break;
+                 }
+ 
+                 status = TLS_PRF(&pms, "extended master secret",
+                                  &seed, &master, isFIPS);
+             } else {
+                 const SECHashObject *hashObj;
+ 
+-                tlsPrfHash = GetHashTypeFromMechanism(ems_params->prfHashMechanism);
++                tlsPrfHash = sftk_GetHashTypeFromMechanism(ems_params->prfHashMechanism);
+                 if (tlsPrfHash == HASH_AlgNULL) {
+                     crv = CKR_MECHANISM_PARAM_INVALID;
+                     break;
+                 }
+ 
+                 hashObj = HASH_GetRawHashObject(tlsPrfHash);
+                 if (seed.len != hashObj->length) {
+                     crv = CKR_TEMPLATE_INCONSISTENT;
+@@ -7665,17 +7634,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
+ 
+             if (mechanism == CKM_TLS12_KEY_AND_MAC_DERIVE) {
+                 if (BAD_PARAM_CAST(pMechanism, sizeof(CK_TLS12_KEY_MAT_PARAMS))) {
+                     crv = CKR_MECHANISM_PARAM_INVALID;
+                     break;
+                 }
+                 CK_TLS12_KEY_MAT_PARAMS *tls12_keys =
+                     (CK_TLS12_KEY_MAT_PARAMS *)pMechanism->pParameter;
+-                tlsPrfHash = GetHashTypeFromMechanism(tls12_keys->prfHashMechanism);
++                tlsPrfHash = sftk_GetHashTypeFromMechanism(tls12_keys->prfHashMechanism);
+                 if (tlsPrfHash == HASH_AlgNULL) {
+                     crv = CKR_MECHANISM_PARAM_INVALID;
+                     break;
+                 }
+             } else if (mechanism == CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256) {
+                 tlsPrfHash = HASH_AlgSHA256;
+             }
+ 
+diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h
+--- a/lib/softoken/pkcs11i.h
++++ b/lib/softoken/pkcs11i.h
+@@ -908,16 +908,19 @@ sftk_MACConstantTimeCtx *sftk_HMACConsta
+ sftk_MACConstantTimeCtx *sftk_SSLv3MACConstantTime_New(
+     CK_MECHANISM_PTR mech, SFTKObject *key);
+ void sftk_HMACConstantTime_Update(void *pctx, const void *data, unsigned int len);
+ void sftk_SSLv3MACConstantTime_Update(void *pctx, const void *data, unsigned int len);
+ void sftk_MACConstantTime_EndHash(
+     void *pctx, void *out, unsigned int *outLength, unsigned int maxLength);
+ void sftk_MACConstantTime_DestroyContext(void *pctx, PRBool);
+ 
++/* Crypto Utilities */
++HASH_HashType sftk_GetHashTypeFromMechanism(CK_MECHANISM_TYPE mech);
++
+ /****************************************
+  * implement TLS Pseudo Random Function (PRF)
+  */
+ 
+ extern CK_RV
+ sftk_TLSPRFInit(SFTKSessionContext *context,
+                 SFTKObject *key,
+                 CK_KEY_TYPE key_type,
+diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c
+--- a/lib/softoken/pkcs11u.c
++++ b/lib/softoken/pkcs11u.c
+@@ -95,16 +95,17 @@ CK_RV
+ sftk_MapVerifyError(int error)
+ {
+     CK_RV crv = sftk_MapCryptError(error);
+     if (crv == CKR_DEVICE_ERROR)
+         crv = CKR_SIGNATURE_INVALID;
+     return crv;
+ }
+ 
++
+ /*
+  * ******************** Attribute Utilities *******************************
+  */
+ 
+ /*
+  * create a new attribute with type, value, and length. Space is allocated
+  * to hold value.
+  */
+@@ -2243,17 +2244,49 @@ sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE 
+             flags = CKF_MESSAGE_VERIFY;
+             break;
+         default:
+             break;
+     }
+     return flags;
+ }
+ 
++/*
++ * ******************** Hash Utilities **************************
++ */
++/*
++ * Utility function for converting PSS/OAEP parameter types into
++ * HASH_HashTypes. Note: Only SHA family functions are defined in RFC 3447.
++ */
++HASH_HashType
++sftk_GetHashTypeFromMechanism(CK_MECHANISM_TYPE mech)
++{
++    switch (mech) {
++        case CKM_SHA_1:
++        case CKG_MGF1_SHA1:
++            return HASH_AlgSHA1;
++        case CKM_SHA224:
++        case CKG_MGF1_SHA224:
++            return HASH_AlgSHA224;
++        case CKM_SHA256:
++        case CKG_MGF1_SHA256:
++            return HASH_AlgSHA256;
++        case CKM_SHA384:
++        case CKG_MGF1_SHA384:
++            return HASH_AlgSHA384;
++        case CKM_SHA512:
++        case CKG_MGF1_SHA512:
++            return HASH_AlgSHA512;
++        default:
++            return HASH_AlgNULL;
++    }
++}
++
+ #ifdef NSS_HAS_FIPS_INDICATORS
++/**************** FIPS Indicator Utilities *************************/
+ /* sigh, we probably need a version of this in secutil so that both
+  * softoken and NSS can use it */
+ static SECOidTag
+ sftk_quickGetECCCurveOid(SFTKObject *source)
+ {
+     SFTKAttribute *attribute = sftk_FindAttribute(source, CKA_EC_PARAMS);
+     unsigned char *encoded;
+     int len;
+@@ -2379,16 +2412,39 @@ sftk_handleSpecial(SFTKSlot *slot, CK_ME
+             if (mech->ulParameterLen == 0) {
+                 /* AEAD ciphers are only in FIPS mode if we are using the
+                  * MESSAGE interface. This takes an empty parameter
+                  * in the init function */
+                 return PR_TRUE;
+             }
+             return PR_FALSE;
+         }
++        case SFTKFIPSRSAPSS: {
++            /* PSS salt must not be greater than the length of the
++             * underlying hash. We verify that the underlying hash of the
++             * parameters matches Hash of the combined hash mechanisms, so
++             * we don't need to look at the specific PSS mechanism */
++            CK_RSA_PKCS_PSS_PARAMS *pss = (CK_RSA_PKCS_PSS_PARAMS *)
++                                           mech->pParameter;
++            const SECHashObject *hashObj = NULL;
++            if (mech->ulParameterLen != sizeof(*pss)) {
++                return PR_FALSE;
++            }
++            /* we use the existing hash utilities to find the length of
++             * the hash */
++            hashObj = HASH_GetRawHashObject(sftk_GetHashTypeFromMechanism(
++                      pss->hashAlg));
++            if (hashObj == NULL) {
++                return PR_FALSE;
++            }
++            if (pss->sLen > hashObj->length) {
++                return PR_FALSE;
++            }
++            return PR_TRUE;
++        }
+         default:
+             break;
+     }
+     /* if we didn't understand the special processing, mark it non-fips */
+     return PR_FALSE;
+ }
+ #endif
+ 
diff --git a/SPECS/nss.spec b/SPECS/nss.spec
index fad31af..8dd0c18 100644
--- a/SPECS/nss.spec
+++ b/SPECS/nss.spec
@@ -1,6 +1,6 @@
 %global nss_version 3.79.0
 %global nspr_version 4.34.0
-%global baserelease 14
+%global baserelease 17
 %global nss_release %baserelease
 # NOTE: To avoid NVR clashes of nspr* packages:
 # use "%%global nspr_release %%[%%baserelease+n]" to handle offsets when
@@ -175,6 +175,12 @@ Patch55:          nss-3.79-enable-POST-rerun.patch
 Patch56:          nss-3.79-increase-pbe-cache.patch
 Patch57:          nss-3.79-pkcs12-fix-null-password.patch
 Patch58:          nss-3.79-fips.patch
+Patch60:          nss-3.79-rsa-pss-salt-fips.patch
+Patch61:          nss-3.79-fips-review.patches
+
+# cve 2023-0767, remove on rebase to nss 3.88.1 or later
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1804640
+Patch70:          cve-2023-0767.patch
 
 Patch100:         nspr-config-pc.patch
 Patch101:         nspr-gcc-atomics.patch
@@ -1165,6 +1171,18 @@ update-crypto-policies &> /dev/null || :
 
 
 %changelog
+* Thu Mar 16 2023 Bob Relyea <rrelyea@redhat.com> - 3.79.0-17
+- fix consistency return errors. We shouldn't lock the FIPS
+  token if the application asked for invalid DH parameters on
+  on keygen.
+
+* Mon Mar 13 2023 Bob Relyea <rrelyea@redhat.com> - 3.79.0-16
+- Add check for RSA PSS Salt required by FIPS
+- Update fips_algorithms.sh according to the review.
+
+* Thu Mar 2 2023 Bob Relyea <rrelyea@redhat.com> - 3.79.0-15
+- Fix CVE-2023-0767
+
 * Wed Aug 24 2022 Bob Relyea <rrelyea@redhat.com> - 3.79.0-14
 - Update fips_algorithms.h to match the final FIPS requirements
 - Disable delegated credentials