889 lines
32 KiB
Diff
889 lines
32 KiB
Diff
diff --git a/lib/freebl/stubs.c b/lib/freebl/stubs.c
|
|
--- a/lib/freebl/stubs.c
|
|
+++ b/lib/freebl/stubs.c
|
|
@@ -485,17 +485,17 @@ PR_GetLibraryFilePathname_stub(const cha
|
|
extern int
|
|
PORT_GetError_stub(void)
|
|
{
|
|
STUB_SAFE_CALL0(PORT_GetError_Util);
|
|
return errno;
|
|
}
|
|
|
|
extern void
|
|
-PORT_SafeZero(void *p, size_t n)
|
|
+PORT_SafeZero_stub(void *p, size_t n)
|
|
{
|
|
STUB_SAFE_CALL2(PORT_SafeZero, p, n);
|
|
/* just use a generic call in the case where we are running
|
|
* standalone freebl */
|
|
if (p != NULL) {
|
|
volatile unsigned char *__vl = (unsigned char *)p;
|
|
size_t __nl = n;
|
|
while (__nl--)
|
|
diff --git a/lib/freebl/stubs.h b/lib/freebl/stubs.h
|
|
--- a/lib/freebl/stubs.h
|
|
+++ b/lib/freebl/stubs.h
|
|
@@ -22,17 +22,17 @@
|
|
|
|
#define PORT_Alloc PORT_Alloc_stub
|
|
#define PORT_ArenaAlloc PORT_ArenaAlloc_stub
|
|
#define PORT_ArenaZAlloc PORT_ArenaZAlloc_stub
|
|
#define PORT_Free PORT_Free_stub
|
|
#define PORT_FreeArena PORT_FreeArena_stub
|
|
#define PORT_GetError PORT_GetError_stub
|
|
#define PORT_NewArena PORT_NewArena_stub
|
|
-#define PORT_SaveZero PORT_SaveZero_stub
|
|
+#define PORT_SafeZero PORT_SafeZero_stub
|
|
#define PORT_SetError PORT_SetError_stub
|
|
#define PORT_ZAlloc PORT_ZAlloc_stub
|
|
#define PORT_ZFree PORT_ZFree_stub
|
|
#define PORT_ZAllocAligned PORT_ZAllocAligned_stub
|
|
#define PORT_ZAllocAlignedOffset PORT_ZAllocAlignedOffset_stub
|
|
|
|
#define SECITEM_AllocItem SECITEM_AllocItem_stub
|
|
#define SECITEM_CompareItem SECITEM_CompareItem_stub
|
|
diff --git a/lib/freebl/unix_fips140_3.c b/lib/freebl/unix_fips140_3.c
|
|
--- a/lib/freebl/unix_fips140_3.c
|
|
+++ b/lib/freebl/unix_fips140_3.c
|
|
@@ -25,17 +25,17 @@ RNG_SystemInfoForRNG(void)
|
|
{
|
|
PRUint8 bytes[SYSTEM_RNG_SEED_COUNT];
|
|
size_t numBytes = RNG_SystemRNG(bytes, SYSTEM_RNG_SEED_COUNT);
|
|
if (!numBytes) {
|
|
/* error is set */
|
|
return;
|
|
}
|
|
RNG_RandomUpdate(bytes, numBytes);
|
|
- PORT_SaveZero(bytes, sizeof(bytes));
|
|
+ PORT_SafeZero(bytes, sizeof(bytes));
|
|
}
|
|
|
|
static unsigned int rng_grndFlags = 0;
|
|
static PRCallOnceType rng_KernelFips;
|
|
|
|
static PRStatus
|
|
rng_getKernelFips()
|
|
{
|
|
diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
|
|
--- a/lib/softoken/pkcs11c.c
|
|
+++ b/lib/softoken/pkcs11c.c
|
|
@@ -535,17 +535,17 @@ sftk_InitGeneric(SFTKSession *session, C
|
|
context->cipherInfo = NULL;
|
|
context->hashInfo = NULL;
|
|
context->doPad = PR_FALSE;
|
|
context->padDataLength = 0;
|
|
context->key = key;
|
|
context->blockSize = 0;
|
|
context->maxLen = 0;
|
|
context->isFIPS = sftk_operationIsFIPS(session->slot, pMechanism,
|
|
- operation, key);
|
|
+ operation, key, 0);
|
|
*contextPtr = context;
|
|
return CKR_OK;
|
|
}
|
|
|
|
static int
|
|
sftk_aes_mode(CK_MECHANISM_TYPE mechanism)
|
|
{
|
|
switch (mechanism) {
|
|
@@ -4794,16 +4794,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;
|
|
@@ -4990,16 +4991,20 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSessi
|
|
crv = CKR_SESSION_HANDLE_INVALID;
|
|
goto loser;
|
|
}
|
|
|
|
/*
|
|
* 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, 0);
|
|
+ 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));
|
|
}
|
|
if (crv == CKR_OK && !sftk_isTrue(key, CKA_EXTRACTABLE)) {
|
|
crv = sftk_forceAttribute(key, CKA_NEVER_EXTRACTABLE, &cktrue, sizeof(CK_BBOOL));
|
|
}
|
|
if (crv == CKR_OK) {
|
|
@@ -6077,18 +6082,18 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
|
|
}
|
|
|
|
/*
|
|
* handle the base object cleanup for the private Key
|
|
* If we have any problems, we destroy the public Key we've
|
|
* 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);
|
|
return crv;
|
|
}
|
|
if (sftk_isTrue(privateKey, CKA_SENSITIVE)) {
|
|
crv = sftk_forceAttribute(privateKey, CKA_ALWAYS_SENSITIVE,
|
|
&cktrue, sizeof(CK_BBOOL));
|
|
@@ -6120,22 +6125,29 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
|
|
(PRUint32)hSession, (PRUint32)pMechanism->mechanism,
|
|
(PRUint32)crv);
|
|
sftk_LogAuditMessage(NSS_AUDIT_ERROR, NSS_AUDIT_SELF_TEST, msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (crv != CKR_OK) {
|
|
+ sftk_FreeSession(session);
|
|
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, 0);
|
|
+ publicKey->isFIPS = privateKey->isFIPS;
|
|
+ session->lastOpWasFIPS = privateKey->isFIPS;
|
|
+
|
|
+ sftk_FreeSession(session);
|
|
*phPrivateKey = privateKey->handle;
|
|
*phPublicKey = publicKey->handle;
|
|
sftk_FreeObject(publicKey);
|
|
sftk_FreeObject(privateKey);
|
|
|
|
return CKR_OK;
|
|
}
|
|
|
|
@@ -7321,30 +7333,35 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
|
|
return CKR_MECHANISM_PARAM_INVALID;
|
|
}
|
|
if ((params->bExpand && keySize == 0) ||
|
|
(!params->bExpand && keySize > hashLen) ||
|
|
(params->bExpand && keySize > 255 * hashLen)) {
|
|
return CKR_TEMPLATE_INCONSISTENT;
|
|
}
|
|
|
|
+ if (!params->bExpand) {
|
|
+ keySize = hashLen;
|
|
+ }
|
|
+
|
|
/* sourceKey is NULL if we are called from the POST, skip the
|
|
* sensitiveCheck */
|
|
if (sourceKey != NULL) {
|
|
crv = sftk_DeriveSensitiveCheck(sourceKey, key, canBeData);
|
|
if (crv != CKR_OK)
|
|
return crv;
|
|
}
|
|
|
|
/* 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:
|
|
@@ -7369,31 +7386,57 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
|
|
/* if the base key is not fips, but the salt key is, the
|
|
* resulting key can be fips */
|
|
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);
|
|
+ CKA_DERIVE, saltKey,
|
|
+ keySize*PR_BITS_PER_BYTE);
|
|
}
|
|
+ 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);
|
|
}
|
|
@@ -7411,26 +7454,50 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
|
|
/* PRK = base key value */
|
|
prk = sourceKeyBytes;
|
|
prkLen = sourceKeyLen;
|
|
}
|
|
|
|
/* HKDF-Expand */
|
|
if (!params->bExpand) {
|
|
okm = prk;
|
|
- keySize = genLen = hashLen;
|
|
+ genLen = hashLen;
|
|
} else {
|
|
/* 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=¶ms->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;
|
|
}
|
|
@@ -7635,17 +7702,18 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
|
|
/* get the value of the base key */
|
|
att = sftk_FindAttribute(sourceKey, CKA_VALUE);
|
|
if (att == NULL) {
|
|
sftk_FreeObject(key);
|
|
sftk_FreeObject(sourceKey);
|
|
return CKR_KEY_HANDLE_INVALID;
|
|
}
|
|
}
|
|
- key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_DERIVE, sourceKey);
|
|
+ key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_DERIVE, sourceKey,
|
|
+ keySize*PR_BITS_PER_BYTE);
|
|
|
|
switch (mechanism) {
|
|
/* get a public key from a private key. nsslowkey_ConvertToPublickey()
|
|
* will generate the public portion if it doesn't already exist. */
|
|
case CKM_NSS_PUB_FROM_PRIV: {
|
|
NSSLOWKEYPrivateKey *privKey;
|
|
NSSLOWKEYPublicKey *pubKey;
|
|
int error;
|
|
@@ -8797,16 +8865,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;
|
|
}
|
|
@@ -8894,16 +8963,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
|
|
* tmp is the raw data created by ECDH_Derive,
|
|
* secret and secretlen are the values we will
|
|
* eventually pass as our generated key.
|
|
*/
|
|
secret = tmp.data;
|
|
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);
|
|
PORT_ZFree(tmp.data, tmp.len);
|
|
if (crv != CKR_OK) {
|
|
break;
|
|
}
|
|
tmp.data = secret;
|
|
@@ -8927,16 +8997,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 {
|
|
@@ -963,15 +974,16 @@ char **NSC_ModuleDBFunc(unsigned long fu
|
|
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 */
|
|
CK_FLAGS sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE op);
|
|
/* check the FIPS table to determine if this current operation is allowed by
|
|
* FIPS security policy */
|
|
PRBool sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech,
|
|
- CK_ATTRIBUTE_TYPE op, SFTKObject *source);
|
|
+ CK_ATTRIBUTE_TYPE op, SFTKObject *source,
|
|
+ CK_ULONG targetKeySize);
|
|
/* add validation objects to the slot */
|
|
CK_RV sftk_CreateValidationObjects(SFTKSlot *slot);
|
|
|
|
SEC_END_PROTOS
|
|
|
|
#endif /* _PKCS11I_H_ */
|
|
diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c
|
|
--- a/lib/softoken/pkcs11u.c
|
|
+++ b/lib/softoken/pkcs11u.c
|
|
@@ -1098,16 +1098,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)
|
|
@@ -1683,16 +1684,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 {
|
|
@@ -2068,16 +2070,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;
|
|
}
|
|
@@ -2234,16 +2237,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;
|
|
@@ -2319,20 +2331,20 @@ 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_KEY_TYPE keyType = CKK_INVALID_KEY_TYPE;
|
|
CK_ATTRIBUTE_TYPE keyAttribute;
|
|
CK_ULONG keyLength = 0;
|
|
SFTKAttribute *attribute;
|
|
CK_RV crv;
|
|
|
|
/* If we don't have a key, then it doesn't have a length.
|
|
* this may be OK (say we are hashing). The mech info will
|
|
* sort this out because algorithms which expect no keys
|
|
@@ -2342,17 +2354,17 @@ sftk_getKeyLength(SFTKObject *source)
|
|
}
|
|
|
|
crv = sftk_GetULongAttribute(source, CKA_KEY_TYPE, &keyType);
|
|
if (crv != CKR_OK) {
|
|
/* sometimes we're passed a data object, in that case the
|
|
* key length is CKA_VALUE, which is the default */
|
|
keyType = CKK_INVALID_KEY_TYPE;
|
|
}
|
|
- if (keyType == CKK_EC) {
|
|
+ if (keyType == CKK_EC || keyType == CKK_EC_EDWARDS || keyType == CKK_EC_MONTGOMERY) {
|
|
SECOidTag curve = sftk_quickGetECCCurveOid(source);
|
|
switch (curve) {
|
|
case SEC_OID_CURVE25519:
|
|
/* change when we start algorithm testing on curve25519 */
|
|
return 0;
|
|
case SEC_OID_SECG_EC_SECP256R1:
|
|
return 256;
|
|
case SEC_OID_SECG_EC_SECP384R1:
|
|
@@ -2384,24 +2396,65 @@ sftk_getKeyLength(SFTKObject *source)
|
|
attribute = sftk_FindAttribute(source, keyAttribute);
|
|
if (attribute) {
|
|
keyLength = attribute->attrib.ulValueLen * 8;
|
|
sftk_FreeAttribute(attribute);
|
|
}
|
|
return keyLength;
|
|
}
|
|
|
|
+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;
|
|
+}
|
|
+
|
|
+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
|
|
* 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)
|
|
+ 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,
|
|
@@ -2451,32 +2504,97 @@ sftk_handleSpecial(SFTKSlot *slot, CK_ME
|
|
}
|
|
/* 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;
|
|
}
|
|
+ /* cap the salt for legacy keys */
|
|
+ if ((keyLength <= 1024) && (pss->sLen > 63)) {
|
|
+ return PR_FALSE;
|
|
+ }
|
|
+ /* cap the salt for based on the hash */
|
|
if (pss->sLen > hashObj->length) {
|
|
return PR_FALSE;
|
|
}
|
|
+ /* 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
|
|
+ * (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;
|
|
}
|
|
+ /* 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), 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);
|
|
+ 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
|
|
|
|
PRBool
|
|
sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech, CK_ATTRIBUTE_TYPE op,
|
|
- SFTKObject *source)
|
|
+ SFTKObject *source, CK_ULONG targetKeyLength)
|
|
{
|
|
#ifndef NSS_HAS_FIPS_INDICATORS
|
|
return PR_FALSE;
|
|
#else
|
|
int i;
|
|
CK_FLAGS opFlags;
|
|
CK_ULONG keyLength;
|
|
|
|
@@ -2498,23 +2616,25 @@ sftk_operationIsFIPS(SFTKSlot *slot, CK_
|
|
}
|
|
keyLength = sftk_getKeyLength(source);
|
|
|
|
/* check against our algorithm array */
|
|
for (i = 0; i < SFTK_NUMBER_FIPS_ALGORITHMS; i++) {
|
|
SFTKFIPSAlgorithmList *mechs = &sftk_fips_mechs[i];
|
|
/* if we match the number of records exactly, then we are an
|
|
* 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) &&
|
|
- ((mechs->special == SFTKFIPSNone) ||
|
|
- sftk_handleSpecial(slot, mech, mechs, source))) {
|
|
+ if ((mech->mechanism == mechs->type) &&
|
|
+ (opFlags == (mechs->info.flags & opFlags)) &&
|
|
+ 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;
|
|
}
|
|
}
|
|
return PR_FALSE;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
diff --git a/lib/softoken/sftkike.c b/lib/softoken/sftkike.c
|
|
--- a/lib/softoken/sftkike.c
|
|
+++ b/lib/softoken/sftkike.c
|
|
@@ -511,16 +511,22 @@ sftk_ike_prf(CK_SESSION_HANDLE hSession,
|
|
}
|
|
/* key as the data */
|
|
crv = prf_update(&context, inKey->attrib.pValue,
|
|
inKey->attrib.ulValueLen);
|
|
if (crv != CKR_OK) {
|
|
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) {
|
|
goto fail;
|
|
}
|
|
if (newKeyValue) {
|
|
crv = prf_update(&context, newKeyValue->attrib.pValue,
|
|
newKeyValue->attrib.ulValueLen);
|
|
diff --git a/lib/softoken/sftkmessage.c b/lib/softoken/sftkmessage.c
|
|
--- a/lib/softoken/sftkmessage.c
|
|
+++ b/lib/softoken/sftkmessage.c
|
|
@@ -178,16 +178,48 @@ sftk_CryptMessage(CK_SESSION_HANDLE hSes
|
|
|
|
CHECK_FORK();
|
|
|
|
/* make sure we're legal */
|
|
crv = sftk_GetContext(hSession, &context, contextType, PR_TRUE, NULL);
|
|
if (crv != CKR_OK)
|
|
return crv;
|
|
|
|
+ if (context->isFIPS && (contextType == SFTK_MESSAGE_ENCRYPT)) {
|
|
+ if ((pParameter == NULL) || (ulParameterLen != sizeof(CK_GCM_MESSAGE_PARAMS))) {
|
|
+ context->isFIPS = PR_FALSE;
|
|
+ } 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 < 96/PR_BITS_PER_BYTE) ||
|
|
+ (p->ulIvFixedBits != 0)) {
|
|
+ context->isFIPS = PR_FALSE;
|
|
+ }
|
|
+ break;
|
|
+ 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;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
if (!pOuttext) {
|
|
*pulOuttextLen = ulIntextLen;
|
|
return CKR_OK;
|
|
}
|
|
rv = (*context->aeadUpdate)(context->cipherInfo, pOuttext, &outlen,
|
|
maxout, pIntext, ulIntextLen,
|
|
pParameter, ulParameterLen,
|
|
pAssociatedData, ulAssociatedDataLen);
|
|
diff --git a/lib/util/pkcs11n.h b/lib/util/pkcs11n.h
|
|
--- a/lib/util/pkcs11n.h
|
|
+++ b/lib/util/pkcs11n.h
|
|
@@ -148,16 +148,18 @@
|
|
/*
|
|
* NSS-defined certificate types
|
|
*
|
|
*/
|
|
#define CKC_NSS (CKC_VENDOR_DEFINED | NSSCK_VENDOR_NSS)
|
|
|
|
/* FAKE PKCS #11 defines */
|
|
#define CKA_DIGEST 0x81000000L
|
|
+#define CKA_NSS_GENERATE 0x81000001L
|
|
+#define CKA_NSS_GENERATE_KEY_PAIR 0x81000002L
|
|
#define CKA_NSS_MESSAGE 0x82000000L
|
|
#define CKA_NSS_MESSAGE_MASK 0xff000000L
|
|
#define CKA_FLAGS_ONLY 0 /* CKA_CLASS */
|
|
|
|
/*
|
|
* NSS-defined object attributes
|
|
*
|
|
*/
|