nss/nss-3.79-fips-review.patches
Bob Relyea 2ed3d453e9 Related: rhbz#2174613
Fix regression issue in FIPS mode. We need to return a non-locking return
code if the user supplied DH parameters are invalid, rather than a blocking
code we return if the underlying NSS math engine blows up.
2023-03-16 12:53:52 -07:00

321 lines
14 KiB
Plaintext

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) {