diff -up ./lib/softoken/pkcs11c.c.fips_2 ./lib/softoken/pkcs11c.c
--- ./lib/softoken/pkcs11c.c.fips_2	2024-01-19 09:21:19.632889660 -0800
+++ ./lib/softoken/pkcs11c.c	2024-01-19 09:22:18.541471306 -0800
@@ -7090,7 +7090,7 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
                     mech.ulParameterLen = sizeof(*params);
                     key->isFIPS = sftk_operationIsFIPS(saltKey->slot, &mech,
                                                        CKA_DERIVE, saltKey,
-                                                       keySize);
+                                                       keySize*PR_BITS_PER_BYTE);
                 }
                 saltKeySource = saltKey->source;
                 saltKey_att = sftk_FindAttribute(saltKey, CKA_VALUE);
@@ -7404,7 +7404,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
         }
     }
     key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_DERIVE, sourceKey,
-                                       keySize);
+                                       keySize*PR_BITS_PER_BYTE);
 
     switch (mechanism) {
         /* get a public key from a private key. nsslowkey_ConvertToPublickey()
diff -up ./lib/softoken/pkcs11u.c.fips_2 ./lib/softoken/pkcs11u.c
--- ./lib/softoken/pkcs11u.c.fips_2	2024-01-19 09:21:19.633889670 -0800
+++ ./lib/softoken/pkcs11u.c	2024-01-19 09:28:00.082843565 -0800
@@ -2393,20 +2393,43 @@ sftk_getKeyLength(SFTKObject *source)
 }
 
 PRBool
-sftk_CheckFIPSHash(CK_MECHANISM_TYPE hash)
+sftk_checkFIPSHash(CK_MECHANISM_TYPE hash, PRBool allowSmall, PRBool allowCMAC)
 {
     switch (hash) {
+        case CKM_AES_CMAC:
+            return allowCMAC;
+        case CKM_SHA_1:
+        case CKM_SHA_1_HMAC:
+        case CKM_SHA224:
+        case CKM_SHA224_HMAC:
+            return allowSmall;
         case CKM_SHA256:
-        case CKG_MGF1_SHA256:
+        case CKM_SHA256_HMAC:
         case CKM_SHA384:
-        case CKG_MGF1_SHA384:
+        case CKM_SHA384_HMAC:
         case CKM_SHA512:
-        case CKG_MGF1_SHA512:
+        case CKM_SHA512_HMAC:
             return PR_TRUE;
     }
     return PR_FALSE;
 }
 
+PRBool
+sftk_checkKeyLength(CK_ULONG keyLength, CK_ULONG min,
+                    CK_ULONG max, CK_ULONG step)
+{
+     if (keyLength > max) {
+         return PR_FALSE;
+     }
+     if (keyLength < min ) {
+         return PR_FALSE;
+     }
+     if (((keyLength - min) % step) != 0) {
+         return PR_FALSE;
+     }
+     return PR_TRUE;
+}
+
 /*
  * handle specialized FIPS semantics that are too complicated to
  * handle with just a table. NOTE: this means any additional semantics
@@ -2416,6 +2439,8 @@ sftk_handleSpecial(SFTKSlot *slot, CK_ME
                    SFTKFIPSAlgorithmList *mechInfo, SFTKObject *source,
                    CK_ULONG keyLength, CK_ULONG targetKeyLength)
 {
+    PRBool allowSmall = PR_FALSE;
+    PRBool allowCMAC = PR_FALSE;
     switch (mechInfo->special) {
         case SFTKFIPSDH: {
             SECItem dhPrime;
@@ -2482,7 +2507,11 @@ sftk_handleSpecial(SFTKSlot *slot, CK_ME
             if (pss->sLen > hashObj->length) {
                 return PR_FALSE;
             }
-            return sftk_CheckFIPSHash(pss->hashAlg);
+            /* Our code makes sure pss->hashAlg matches the explicit
+             * hash in the mechanism, and only mechanisms with approved
+             * hashes are included, so no need to check pss->hashAlg
+             * here */
+            return PR_TRUE;
         }
         case SFTKFIPSPBKDF2: {
             /* PBKDF2 must have the following addition restrictions
@@ -2508,12 +2537,28 @@ sftk_handleSpecial(SFTKSlot *slot, CK_ME
              return PR_TRUE;
         }
         /* check the hash mechanisms to make sure they themselves are FIPS */
+        case SFTKFIPSChkHashSp800:
+             allowCMAC = PR_TRUE;
         case SFTKFIPSChkHash:
+             allowSmall = PR_TRUE;
+        case SFTKFIPSChkHashTls:
             if (mech->ulParameterLen < mechInfo->offset +sizeof(CK_ULONG)) {
                 return PR_FALSE;
             }
-            return sftk_CheckFIPSHash(*(CK_ULONG *)(((char *)mech->pParameter)
-                        + mechInfo->offset));
+            return sftk_checkFIPSHash(*(CK_ULONG *)(((char *)mech->pParameter)
+                        + mechInfo->offset), allowSmall, allowCMAC);
+        case SFTKFIPSTlsKeyCheck:
+            if (mech->mechanism != CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256) {
+                /* unless the mechnism has a built-in hash, check the hash */
+                if (mech->ulParameterLen < mechInfo->offset +sizeof(CK_ULONG)) {
+                    return PR_FALSE;
+                }
+                if (!sftk_checkFIPSHash(*(CK_ULONG *)(((char *)mech->pParameter)
+                        + mechInfo->offset), PR_FALSE, PR_FALSE)) {
+                    return PR_FALSE;
+                }
+            }
+            return sftk_checkKeyLength(targetKeyLength, 112, 512, 1);
         default:
             break;
     }
@@ -2558,13 +2603,11 @@ sftk_operationIsFIPS(SFTKSlot *slot, CK_
          * approved algorithm in the approved mode with an approved key */
         if ((mech->mechanism == mechs->type) &&
             (opFlags == (mechs->info.flags & opFlags)) &&
-            (keyLength <= mechs->info.ulMaxKeySize) &&
-            (keyLength >= mechs->info.ulMinKeySize) &&
-            (((keyLength - mechs->info.ulMinKeySize) % mechs->step) == 0) &&
-            ((targetKeyLength == 0) ||
-             ((targetKeyLength <= mechs->info.ulMaxKeySize) &&
-             (targetKeyLength >= mechs->info.ulMinKeySize) &&
-             ((targetKeyLength - mechs->info.ulMinKeySize) % mechs->step) == 0)) &&
+            sftk_checkKeyLength(keyLength, mechs->info.ulMinKeySize,
+                                mechs->info.ulMaxKeySize, mechs->step) &&
+            ((targetKeyLength == 0) ||  (mechs->special == SFTKFIPSTlsKeyCheck)
+             || sftk_checkKeyLength(targetKeyLength, mechs->info.ulMinKeySize,
+                                mechs->info.ulMaxKeySize, mechs->step)) &&
             ((mechs->special == SFTKFIPSNone) ||
              sftk_handleSpecial(slot, mech, mechs, source, keyLength, targetKeyLength))) {
             return PR_TRUE;
diff -up ./lib/softoken/sftkmessage.c.fips_2 ./lib/softoken/sftkmessage.c
--- ./lib/softoken/sftkmessage.c.fips_2	2024-01-19 09:21:19.634889680 -0800
+++ ./lib/softoken/sftkmessage.c	2024-01-19 09:22:18.541471306 -0800
@@ -157,16 +157,25 @@ sftk_CryptMessage(CK_SESSION_HANDLE hSes
         } else {
             CK_GCM_MESSAGE_PARAMS *p = (CK_GCM_MESSAGE_PARAMS *)pParameter;
             switch (p->ivGenerator) {
+                default:
                 case CKG_NO_GENERATE:
                     context->isFIPS = PR_FALSE;
                     break;
                 case CKG_GENERATE_RANDOM:
-                    if ((p->ulIvLen < 12) || (p->ulIvFixedBits != 0)) {
+                    if ((p->ulIvLen < 96/PR_BITS_PER_BYTE) ||
+                        (p->ulIvFixedBits != 0)) {
                         context->isFIPS = PR_FALSE;
                     }
                     break;
-                default:
-                    if ((p->ulIvLen < 12) || (p->ulIvFixedBits < 32)) {
+                case CKG_GENERATE_COUNTER_XOR:
+                    if ((p->ulIvLen != 96/PR_BITS_PER_BYTE) ||
+                        (p->ulIvFixedBits != 32)) {
+                        context->isFIPS = PR_FALSE;
+                    }
+                    break;
+                case CKG_GENERATE_COUNTER:
+                    if ((p->ulIvFixedBits < 32) ||
+                       ((p->ulIvLen*PR_BITS_PER_BYTE - p->ulIvFixedBits) < 32)) {
                         context->isFIPS = PR_FALSE;
                     }
             }