# HG changeset patch # User Robert Relyea # Date 1780434653 25200 # Tue Jun 02 14:10:53 2026 -0700 # Branch NSS_3_124_BRANCH # Node ID 19e655733f3af71e3d517ada0d31ad0697d40f3f # Parent 567ea70a139936a15e80b0c88104ea44936dfc30 nss-3.124-indicators-prf.patch diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c --- a/lib/softoken/pkcs11u.c +++ b/lib/softoken/pkcs11u.c @@ -16,37 +16,47 @@ #include "secoid.h" #include "softkver.h" #if !defined(NSS_FIPS_DISABLED) && defined(NSS_ENABLE_FIPS_INDICATORS) /* 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, - SFTKFIPSTlsKeyCheck + 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 */ + SFTKFIPSTlsKeyCheck, /* check the output of TLS prf functions */ + SFTKFIPSChkHash, /* make sure the base hash of KDF functions is FIPS */ + SFTKFIPSChkHashTls, /* make sure the base hash of TLS KDF functions is FIPS */ + SFTKFIPSChkHashSp800, /* make sure the base hash of SP-800-108 KDF functions is FIPS */ + SFTKFIPSRSAOAEP, /* make sure that both hashes use the same FIPS compliant algorithm */ } SFTKFIPSSpecialClass; typedef struct SFTKFIPSAlgorithmListStr SFTKFIPSAlgorithmList; struct SFTKFIPSAlgorithmListStr { CK_MECHANISM_TYPE type; CK_MECHANISM_INFO info; CK_ULONG step; SFTKFIPSSpecialClass special; + size_t offset; }; /* this file should be supplied by the vendor and include all the * algorithms which have Algorithm certs and have been reviewed by * the lab. A blank file is included for the base so that FIPS mode * will still be compiled and run, but FIPS indicators will always * return PR_FALSE */ #include "fips_algorithms.h" + +#ifndef SFTKFIPS_PBKDF2_MIN_PW_LEN /* allow fips_algorithms.h to override */ +#define SFTKFIPS_PBKDF2_MIN_PW_LEN 8 +#endif #define NSS_HAS_FIPS_INDICATORS 1 #endif /* * ******************** Error mapping ******************************* */ /* * map all the SEC_ERROR_xxx error codes that may be returned by freebl @@ -2566,25 +2576,49 @@ sftk_checkKeyLength(CK_ULONG keyLength, return PR_TRUE; } if (((keyLength - min) % step) != 0) { return PR_FALSE; } return PR_TRUE; } +PRBool +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 CKM_SHA256_HMAC: + case CKM_SHA384: + case CKM_SHA384_HMAC: + case CKM_SHA512: + case CKM_SHA512_HMAC: + return PR_TRUE; + } + return PR_FALSE; +} + /* * handle specialized FIPS semantics that are too complicated to * handle with just a table. NOTE: this means any additional semantics * would have to be coded here before they can be added to the table */ static PRBool sftk_handleSpecial(SFTKSlot *slot, CK_MECHANISM *mech, 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; SECItem dhBase; SECItem dhGenerator; PRBool fipsOk = PR_FALSE; const SECItem *dhSubPrime; CK_RV crv = sftk_Attribute2SecItem(NULL, &dhPrime, @@ -2644,18 +2678,72 @@ sftk_handleSpecial(SFTKSlot *slot, CK_ME return PR_FALSE; } /* cap the salt based on the hash */ if (pss->sLen > hashObj->length) { return PR_FALSE; } return PR_TRUE; } + case SFTKFIPSPBKDF2: { + /* from NIST SP 800-132 + * 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_PARAMS2 *pbkdf2 = (CK_PKCS5_PBKD2_PARAMS2 *) + 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; + } + /* 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_MECHANISM_TYPE *)(((char *)mech->pParameter) + mechInfo->offset), allowSmall, allowCMAC); case SFTKFIPSTlsKeyCheck: - return sftk_checkKeyLength(targetKeyLength, 112, 512, 1); + 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_MECHANISM_TYPE *)(((char *)mech->pParameter) + mechInfo->offset), PR_FALSE, PR_FALSE)) { + return PR_FALSE; + } + } + return PR_TRUE; + case SFTKFIPSRSAOAEP: + CK_RSA_PKCS_OAEP_PARAMS *rsaoaep = (CK_RSA_PKCS_OAEP_PARAMS *) + mech->pParameter; + + HASH_HashType hash_msg = sftk_GetHashTypeFromMechanism(rsaoaep->hashAlg); + HASH_HashType hash_pad = sftk_GetHashTypeFromMechanism(rsaoaep->mgf); + /* message hash and mask generation function must be the same */ + if (hash_pad != hash_msg) + return PR_FALSE; + + return sftk_checkFIPSHash(rsaoaep->hashAlg, PR_FALSE, PR_FALSE); default: break; } /* if we didn't understand the special processing, mark it non-fips */ return PR_FALSE; } #endif