/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* *ThisfileimplementsPKCS11ontopofourexistingsecuritymodules * *FormoreinformationaboutPKCS11SeePKCS11TokenIntefaceStandard. *Thisimplementationhastwoslots: *slot1isourgenericcryptosupport.Itdoesnotrequirelogin. *ItsupportsPublicKeyops,andalltheybulkciphersandhashes. *ItcanalsosupportPrivateKeyopsforimportedPrivatekeys.Itdoes *nothaveanytokenstorage. *slot2isourprivatekeysupport.Itrequiresaloginbeforeuse.It *canstorePrivateKeysandCertsastokenobjects.Currentlyonlyprivate *keysandtheirassociatedCertificatesaresavedonthetoken. * *Inthisimplementation,sessionobjectsareonlyvisibletothesession *thatcreatedorgeneratedthem.
*/
#include <limits.h> /* for UINT_MAX and ULONG_MAX */
#include"lowkeyti.h" #include"seccomon.h" #include"secitem.h" #include"secport.h" #include"blapi.h" /* we need to use the deprecated mechanisms values for backward compatibility */ #include"pkcs11.h" #include"pkcs11i.h" #include"pkcs1sig.h" #include"lowkeyi.h" #include"secder.h" #include"secdig.h" #include"lowpbe.h"/* We do PBE below */ #include"pkcs11t.h" #include"secoid.h" #include"cmac.h" #include"alghmac.h" #include"softoken.h" #include"secasn1.h" #include"secerr.h" #include"kem.h" #include"kyber.h"
/* create a definition of SHA1 that's consistent
* with the rest of the CKM_SHAxxx hashes*/ #define CKM_SHA1 CKM_SHA_1 #define CKM_SHA1_HMAC CKM_SHA_1_HMAC #define CKM_SHA1_HMAC_GENERAL CKM_SHA_1_HMAC_GENERAL
/* fake hash end, the hashed data is already in the signature context,
* return a NULL hash, which will be passed to the sign final and ignored */ void
sftk_NullHashEnd(void *info, unsignedchar *data, unsignedint *lenp, unsignedint maxlen)
{
*lenp = 0;
}
/* xor source with des, zero the parity bits and deprecate the key*/ for (i = 0; i < 8; i++) { if (i & 1) {
enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0xfe;
} else {
enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0x0e;
}
}
/* set the corret parity on our new des key */
sftk_FormatDESKey(deskey, 8);
done:
PORT_Memset(enc_src, 0, sizeof enc_src);
PORT_Memset(enc_dest, 0, sizeof enc_dest); return crv;
}
/* *Returnstrueif"params"containsavalidsetofOAEPparameters
*/ static PRBool
sftk_ValidateOaepParams(const CK_RSA_PKCS_OAEP_PARAMS *params)
{ if (!params) { return PR_FALSE;
} /* The requirements of ulSourceLen/pSourceData come from PKCS #11, which *state: *Iftheparameterisempty,pSourceDatamustbeNULLand *ulSourceDataLenmustbezero.
*/ if (params->source != CKZ_DATA_SPECIFIED ||
(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;
}
/* *returnacontextbasedontheSFTKContexttype.
*/
SFTKSessionContext *
sftk_ReturnContextByType(SFTKSession *session, SFTKContextType type)
{ switch (type) { case SFTK_ENCRYPT: case SFTK_DECRYPT: case SFTK_MESSAGE_ENCRYPT: case SFTK_MESSAGE_DECRYPT: return session->enc_context; case SFTK_HASH: return session->hash_context; case SFTK_SIGN: case SFTK_SIGN_RECOVER: case SFTK_VERIFY: case SFTK_VERIFY_RECOVER: case SFTK_MESSAGE_SIGN: case SFTK_MESSAGE_VERIFY: return session->hash_context;
} return NULL;
}
/* *changeacontextbasedontheSFTKContexttype.
*/ void
sftk_SetContextByType(SFTKSession *session, SFTKContextType type,
SFTKSessionContext *context)
{ switch (type) { case SFTK_ENCRYPT: case SFTK_DECRYPT: case SFTK_MESSAGE_ENCRYPT: case SFTK_MESSAGE_DECRYPT:
session->enc_context = context; break; case SFTK_HASH:
session->hash_context = context; break; case SFTK_SIGN: case SFTK_SIGN_RECOVER: case SFTK_VERIFY: case SFTK_VERIFY_RECOVER: case SFTK_MESSAGE_SIGN: case SFTK_MESSAGE_VERIFY:
session->hash_context = context; break;
} return;
}
/* Pair to sftk_InstallContext. Atomically detach whatever context is *storedonthesessionfor`type`andfreeit.Holdingthesession *bucketlockforthedetachensuresthataconcurrent *sftk_InstallContextseeseithertheoldcontextstillinplace *(yieldingCKR_OPERATION_ACTIVE)ortheslotalreadyNULL(allowing
* its install to succeed), never a transient stale pointer. */ void
sftk_UninstallContext(SFTKSession *session, SFTKContextType type)
{
SFTKSlot *slot = sftk_SlotFromSession(session);
PRLock *lock = SFTK_SESSION_LOCK(slot, session->handle);
SFTKSessionContext *context;
PR_Lock(lock);
context = sftk_ReturnContextByType(session, type);
sftk_SetContextByType(session, type, NULL); /* Read isFIPS while still under the lock so the write to *session->lastOpWasFIPSreflectsthecontextbeingtorndown,
* not one a concurrent installer might race in afterwards. */ if (context) {
session->lastOpWasFIPS = context->isFIPS;
}
PR_Unlock(lock); if (context) {
sftk_FreeContext(context);
}
}
PORT_Assert(sessionPtr != NULL);
session = sftk_SessionFromHandle(handle); if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
context = sftk_ReturnContextByType(session, type); /* make sure the context is valid */ if ((context == NULL) || (context->type != type) || (needMulti && !(context->multi))) {
sftk_FreeSession(session); return CKR_OPERATION_NOT_INITIALIZED;
}
*contextPtr = context;
*sessionPtr = session; return CKR_OK;
}
/* Terminate operation (in the PKCS#11 spec sense). Thin wrapper over *sftk_UninstallContext:theinstall/uninstallpairtakestheslot *lock,freeswhateveriscurrentlyinstalledfor`ctype`,andreads
* context->isFIPS into session->lastOpWasFIPS under the lock. */ void
sftk_TerminateOp(SFTKSession *session, SFTKContextType ctype)
{
sftk_UninstallContext(session, ctype);
}
/* make sure we don't overflow our parameters */ if ((sizeof(ctx->counter) < counter_len) ||
(sizeof(ctx->nonce) < nonce_len)) {
PORT_Free(ctx);
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
/* The counter is little endian. */ int i = 0; for (; i < counter_len; ++i) {
ctx->counter |= (PRUint32)counter[i] << (i * 8);
}
memcpy(ctx->nonce, nonce, nonce_len);
context->cipherInfo = ctx;
context->update = sftk_ChaCha20Ctr;
context->destroy = sftk_ChaCha20Ctr_DestroyContext; break;
}
case CKM_NSS_AES_KEY_WRAP_PAD: case CKM_AES_KEY_WRAP_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_NSS_AES_KEY_WRAP: case CKM_AES_KEY_WRAP:
context->blockSize = 8; case CKM_AES_KEY_WRAP_KWP:
context->multi = PR_FALSE; if (key_type != CKK_AES) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
att = sftk_FindAttribute(key, CKA_VALUE); if (att == NULL) {
crv = CKR_KEY_HANDLE_INVALID; break;
}
context->cipherInfo = AESKeyWrap_CreateContext(
(unsignedchar *)att->attrib.pValue,
(unsignedchar *)pMechanism->pParameter,
isEncrypt, att->attrib.ulValueLen);
sftk_FreeAttribute(att); if (context->cipherInfo == NULL) {
crv = CKR_HOST_MEMORY; break;
} if (pMechanism->mechanism == CKM_AES_KEY_WRAP_KWP) {
context->update = isEncrypt ? SFTKCipher_AESKeyWrap_EncryptKWP
: SFTKCipher_AESKeyWrap_DecryptKWP;
} else {
context->update = isEncrypt ? SFTKCipher_AESKeyWrap_Encrypt
: SFTKCipher_AESKeyWrap_Decrypt;
}
context->destroy = SFTKCipher_AESKeyWrap_DestroyContext; break;
/* Hold the session reference for the duration of the context deref;
* see comment on NSC_DigestUpdate. */
crv = sftk_GetContext(hSession, &context, SFTK_ENCRYPT, PR_TRUE, &session); if (crv != CKR_OK) return crv;
if (!pEncryptedPart) { if (context->doPad) {
CK_ULONG totalDataAvailable = ulPartLen + context->padDataLength;
CK_ULONG blocksToSend = totalDataAvailable / context->blockSize;
/* do padding */ if (context->doPad) { /* deal with previous buffered data */ if (context->padDataLength != 0) { /* fill in the padded to a full block size */ for (i = context->padDataLength;
(ulPartLen != 0) && i < context->blockSize; i++) {
context->padBuf[i] = *pPart++;
ulPartLen--;
context->padDataLength++;
}
/* not enough data to encrypt yet? then return */ if (context->padDataLength != context->blockSize) {
*pulEncryptedPartLen = 0; goto finish;
} /* encrypt the current padded data */
rv = (*context->update)(context->cipherInfo, pEncryptedPart,
&padoutlen, maxout, context->padBuf,
context->blockSize); if (rv != SECSuccess) {
crv = sftk_MapCryptError(PORT_GetError()); goto finish;
}
pEncryptedPart += padoutlen;
maxout -= padoutlen;
} /* save the residual */
context->padDataLength = ulPartLen % context->blockSize; if (context->padDataLength) {
PORT_Memcpy(context->padBuf,
&pPart[ulPartLen - context->padDataLength],
context->padDataLength);
ulPartLen -= context->padDataLength;
} /* if we've exhausted our new buffer, we're done */ if (ulPartLen == 0) {
*pulEncryptedPartLen = padoutlen; goto finish;
}
}
/* do it: NOTE: this assumes buf size in is >= buf size out! */
rv = (*context->update)(context->cipherInfo, pEncryptedPart,
&outlen, maxout, pPart, ulPartLen); if (rv != SECSuccess) {
crv = sftk_MapCryptError(PORT_GetError()); goto finish;
}
*pulEncryptedPartLen = (CK_ULONG)(outlen + padoutlen);
finish:
sftk_FreeSession(session); return crv;
}
/* make sure we're legal */
crv = sftk_GetContext(hSession, &context, SFTK_ENCRYPT, PR_TRUE, &session); if (crv != CKR_OK) return crv;
*pulLastEncryptedPartLen = 0; if (!pLastEncryptedPart) { /* caller is checking the amount of remaining data */ if (context->blockSize > 0 && context->doPad) {
*pulLastEncryptedPartLen = context->blockSize;
contextFinished = PR_FALSE; /* still have padding to go */
} goto finish;
}
/* do padding */ if (context->doPad) { unsignedchar padbyte = (unsignedchar)(context->blockSize - context->padDataLength); /* fill out rest of pad buffer with pad magic*/ for (i = context->padDataLength; i < context->blockSize; i++) {
context->padBuf[i] = padbyte;
}
rv = (*context->update)(context->cipherInfo, pLastEncryptedPart,
&outlen, maxout, context->padBuf, context->blockSize); if (rv == SECSuccess)
*pulLastEncryptedPartLen = (CK_ULONG)outlen;
}
/* Hold the session reference for the duration of the context deref;
* see comment on NSC_DigestUpdate. */
crv = sftk_GetContext(hSession, &context, SFTK_DECRYPT, PR_TRUE, &session); if (crv != CKR_OK) return crv;
/* this can only happen on an NSS programming error */
PORT_Assert((context->padDataLength == 0) || context->padDataLength == context->blockSize);
if (context->doPad) { /* Check the data length for block ciphers. If we are padding, *thenwemustbeusingablockcipher.Inthenon-paddingcase *theerrorwillbereturnedbytheunderlyingdecryption *functionwhenwedotheactualdecrypt.Weneedtodothe *checkheretoavoidreturninganegativelengthtothecaller *orreadingbeforethebeginningofthepEncryptedPartbuffer.
*/ if ((ulEncryptedPartLen == 0) ||
(ulEncryptedPartLen % context->blockSize) != 0) {
crv = CKR_ENCRYPTED_DATA_LEN_RANGE; goto finish;
}
}
if (!pPart) { if (context->doPad) {
*pulPartLen =
ulEncryptedPartLen + context->padDataLength - context->blockSize; goto finish;
} /* for stream ciphers there is are no constraints on ulEncryptedPartLen. *forblockciphers,itmustbeamultipleofblockSize.Theerroris *detectedwhenthisfunctioniscalledagaindodecrypttheoutput.
*/
*pulPartLen = ulEncryptedPartLen; goto finish;
}
if (context->doPad) { /* first decrypt our saved buffer */ if (context->padDataLength != 0) {
rv = (*context->update)(context->cipherInfo, pPart, &padoutlen,
maxout, context->padBuf, context->blockSize); if (rv != SECSuccess) {
crv = sftk_MapDecryptError(PORT_GetError()); goto finish;
}
pPart += padoutlen;
maxout -= padoutlen;
} /* now save the final block for the next decrypt or the final */
PORT_Memcpy(context->padBuf, &pEncryptedPart[ulEncryptedPartLen - context->blockSize],
context->blockSize);
context->padDataLength = context->blockSize;
ulEncryptedPartLen -= context->padDataLength;
}
/* do it: NOTE: this assumes buf size in is >= buf size out! */
rv = (*context->update)(context->cipherInfo, pPart, &outlen,
maxout, pEncryptedPart, ulEncryptedPartLen); if (rv != SECSuccess) {
crv = sftk_MapDecryptError(PORT_GetError()); goto finish;
}
*pulPartLen = (CK_ULONG)(outlen + padoutlen);
finish:
sftk_FreeSession(session); return crv;
}
/* make sure we're legal */
crv = sftk_GetContext(hSession, &context, SFTK_DECRYPT, PR_TRUE, &session); if (crv != CKR_OK) return crv;
*pulLastPartLen = 0; if (!pLastPart) { /* caller is checking the amount of remaining data */ if (context->padDataLength > 0) {
*pulLastPartLen = context->padDataLength;
} goto finish;
}
if (context->doPad) { /* decrypt our saved buffer */ if (context->padDataLength != 0) { /* this assumes that pLastPart is big enough to hold the *whole*
* buffer!!! */
rv = (*context->update)(context->cipherInfo, pLastPart, &outlen,
maxout, context->padBuf, context->blockSize); if (rv != SECSuccess) {
crv = sftk_MapDecryptError(PORT_GetError());
} else { unsignedint padSize = 0;
crv = sftk_CheckCBCPadding(pLastPart, outlen,
context->blockSize, &padSize); /* Update pulLastPartLen, in constant time, if crv is OK */
*pulLastPartLen = PORT_CT_SEL(sftk_CKRVToMask(crv), outlen - padSize, *pulLastPartLen);
}
}
}
#if (ULONG_MAX > UINT_MAX) /* The context->hashUpdate function takes an unsigned int for its data
* length argument, but NSC_Digest takes an unsigned long. */ while (ulDataLen > UINT_MAX) {
(*context->hashUpdate)(context->cipherInfo, pData, UINT_MAX);
pData += UINT_MAX;
ulDataLen -= UINT_MAX;
} #endif
(*context->hashUpdate)(context->cipherInfo, pData, ulDataLen);
/* NOTE: this assumes buf size is bigenough for the algorithm */
(*context->end)(context->cipherInfo, pDigest, &digestLen, maxout);
*pulDigestLen = digestLen;
/* Hold the session reference for the duration of the context deref: *withoutit,aconcurrentNSC_CloseSessioncoulddriverefCountto0 *insidesftk_GetContext,destroyingthesession(andfreeingthe
* context) before we touch context->hashUpdate. */
crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, &session); if (crv != CKR_OK) return crv;
#if (ULONG_MAX > UINT_MAX) /* The context->hashUpdate function takes an unsigned int for its data
* length argument, but NSC_DigestUpdate takes an unsigned long. */ while (ulPartLen > UINT_MAX) {
(*context->hashUpdate)(context->cipherInfo, pPart, UINT_MAX);
pPart += UINT_MAX;
ulPartLen -= UINT_MAX;
} #endif
(*context->hashUpdate)(context->cipherInfo, pPart, ulPartLen);
/* Required by FIPS 198 Section 4. Delay this check until after the MAC
* has been initialized to steal the output size of the MAC. */ if (isFIPS && (mac_size < 4 || mac_size < context->mac_size / 2)) {
sftk_MAC_DestroyContext(context, PR_TRUE); return CKR_BUFFER_TOO_SMALL;
}
/* Configure our helper functions appropriately. Note that these casts
* ignore the return values. */
session->hashUpdate = SFTKHash_sftk_MAC_Update;
session->end = SFTKHash_sftk_MAC_End;
session->hashdestroy = SFTKHash_sftk_MAC_DestroyContext;
/* Since we're only "hashing", copy the result from session->end to the
* caller using sftk_SignCopy. */
session->update = sftk_SignCopy;
session->verify = sftk_HMACCmp;
session->destroy = sftk_Space;
if (!pMechanism) { return CKR_MECHANISM_PARAM_INVALID;
}
switch (pMechanism->mechanism) { #ifndef NSS_DISABLE_DEPRECATED_RC2 case CKM_RC2_MAC_GENERAL: if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC2_MAC_GENERAL_PARAMS))) { return CKR_MECHANISM_PARAM_INVALID;
}
mac_bytes =
((CK_RC2_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength; /* fall through */ case CKM_RC2_MAC: /* this works because ulEffectiveBits is in the same place in both the
* CK_RC2_MAC_GENERAL_PARAMS and CK_RC2_CBC_PARAMS */
rc2_params.ulEffectiveBits = ((CK_RC2_MAC_GENERAL_PARAMS *)
pMechanism->pParameter)
->ulEffectiveBits;
PORT_Memset(rc2_params.iv, 0, sizeof(rc2_params.iv));
cbc_mechanism.mechanism = CKM_RC2_CBC;
cbc_mechanism.pParameter = &rc2_params;
cbc_mechanism.ulParameterLen = sizeof(rc2_params);
blockSize = 8; break; #endif/* NSS_DISABLE_DEPRECATED_RC2 */
#if NSS_SOFTOKEN_DOES_RC5 case CKM_RC5_MAC_GENERAL: if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC5_MAC_GENERAL_PARAMS))) { return CKR_MECHANISM_PARAM_INVALID;
}
mac_bytes =
((CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength; /* fall through */ case CKM_RC5_MAC: /* this works because ulEffectiveBits is in the same place in both the
* CK_RC5_MAC_GENERAL_PARAMS and CK_RC5_CBC_PARAMS */ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC5_MAC_GENERAL_PARAMS))) { return CKR_MECHANISM_PARAM_INVALID;
}
rc5_mac = (CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter;
rc5_params.ulWordsize = rc5_mac->ulWordsize;
rc5_params.ulRounds = rc5_mac->ulRounds;
rc5_params.pIv = ivBlock; if ((blockSize = rc5_mac->ulWordsize * 2) > SFTK_MAX_BLOCK_SIZE) return CKR_MECHANISM_PARAM_INVALID;
rc5_params.ulIvLen = blockSize;
PORT_Memset(ivBlock, 0, blockSize);
cbc_mechanism.mechanism = CKM_RC5_CBC;
cbc_mechanism.pParameter = &rc5_params;
cbc_mechanism.ulParameterLen = sizeof(rc5_params); break; #endif /* add cast and idea later */ case CKM_DES_MAC_GENERAL:
mac_bytes = *(CK_ULONG *)pMechanism->pParameter; /* fall through */ case CKM_DES_MAC:
blockSize = 8;
PORT_Memset(ivBlock, 0, blockSize);
cbc_mechanism.mechanism = CKM_DES_CBC;
cbc_mechanism.pParameter = &ivBlock;
cbc_mechanism.ulParameterLen = blockSize; break; case CKM_DES3_MAC_GENERAL:
mac_bytes = *(CK_ULONG *)pMechanism->pParameter; /* fall through */ case CKM_DES3_MAC:
blockSize = 8;
PORT_Memset(ivBlock, 0, blockSize);
cbc_mechanism.mechanism = CKM_DES3_CBC;
cbc_mechanism.pParameter = &ivBlock;
cbc_mechanism.ulParameterLen = blockSize; break; case CKM_CDMF_MAC_GENERAL:
mac_bytes = *(CK_ULONG *)pMechanism->pParameter; /* fall through */ case CKM_CDMF_MAC:
blockSize = 8;
PORT_Memset(ivBlock, 0, blockSize);
cbc_mechanism.mechanism = CKM_CDMF_CBC;
cbc_mechanism.pParameter = &ivBlock;
cbc_mechanism.ulParameterLen = blockSize; break; #ifndef NSS_DISABLE_DEPRECATED_SEED case CKM_SEED_MAC_GENERAL:
mac_bytes = *(CK_ULONG *)pMechanism->pParameter; /* fall through */ case CKM_SEED_MAC:
blockSize = 16;
PORT_Memset(ivBlock, 0, blockSize);
cbc_mechanism.mechanism = CKM_SEED_CBC;
cbc_mechanism.pParameter = &ivBlock;
cbc_mechanism.ulParameterLen = blockSize; break; #endif/* NSS_DISABLE_DEPRECATED_SEED */ case CKM_CAMELLIA_MAC_GENERAL:
mac_bytes = *(CK_ULONG *)pMechanism->pParameter; /* fall through */ case CKM_CAMELLIA_MAC:
blockSize = 16;
PORT_Memset(ivBlock, 0, blockSize);
cbc_mechanism.mechanism = CKM_CAMELLIA_CBC;
cbc_mechanism.pParameter = &ivBlock;
cbc_mechanism.ulParameterLen = blockSize; break; case CKM_AES_MAC_GENERAL:
mac_bytes = *(CK_ULONG *)pMechanism->pParameter; /* fall through */ case CKM_AES_MAC:
blockSize = 16;
PORT_Memset(ivBlock, 0, blockSize);
cbc_mechanism.mechanism = CKM_AES_CBC;
cbc_mechanism.pParameter = &ivBlock;
cbc_mechanism.ulParameterLen = blockSize; break; case CKM_AES_XCBC_MAC_96: case CKM_AES_XCBC_MAC: /* The only difference between CKM_AES_XCBC_MAC
* and CKM_AES_XCBC_MAC_96 is the size of the returned mac. */
mac_bytes = pMechanism->mechanism == CKM_AES_XCBC_MAC_96 ? 12 : 16;
blockSize = 16;
PORT_Memset(ivBlock, 0, blockSize);
cbc_mechanism.mechanism = CKM_AES_CBC;
cbc_mechanism.pParameter = &ivBlock;
cbc_mechanism.ulParameterLen = blockSize; /* is XCBC requires extra processing at the end of the operation */
isXCBC = PR_TRUE; /* The input key is used to generate k1, k2, and k3. k2 and k3 *areusedattheendinthepadstep.k1replacestheinput
* key in the aes cbc mac */
crv = sftk_aes_xcbc_new_keys(hSession, hKey, &hKey, k2, k3); if (crv != CKR_OK) { return crv;
} break; default: return CKR_FUNCTION_NOT_SUPPORTED;
}
/* if MAC size is externally supplied, it should be checked.
*/ if (mac_bytes == SFTK_INVALID_MAC_SIZE)
mac_bytes = blockSize >> 1; else { if (mac_bytes > blockSize) {
crv = CKR_MECHANISM_PARAM_INVALID; goto fail;
}
}
crv = sftk_CryptInit(hSession, &cbc_mechanism, hKey,
CKA_ENCRYPT, /* CBC mech is able to ENCRYPT, not SIGN/VERIFY */
keyUsage, contextType, PR_TRUE); if (crv != CKR_OK) goto fail; /* Hold the session reference for the duration of the context writes;
* see comment on NSC_DigestUpdate. */
crv = sftk_GetContext(hSession, &context, contextType, PR_TRUE, &session);
/* this shouldn't happen! */
PORT_Assert(crv == CKR_OK); if (crv != CKR_OK) goto fail;
context->blockSize = blockSize;
context->macSize = mac_bytes;
context->isXCBC = isXCBC; if (isXCBC) { /* save the xcbc specific parameters */
PORT_Memcpy(context->k2, k2, blockSize);
PORT_Memcpy(context->k3, k3, blockSize);
PORT_Memset(k2, 0, blockSize);
PORT_Memset(k3, 0, blockSize); /* get rid of the temp key now that the context has been created */
NSC_DestroyObject(hSession, hKey);
}
sftk_FreeSession(session); return CKR_OK;
fail: if (isXCBC) {
PORT_Memset(k2, 0, blockSize);
PORT_Memset(k3, 0, blockSize);
NSC_DestroyObject(hSession, hKey); /* get rid of our temp key */
} return crv;
}
if (len != 0) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure;
}
return MLDSA_VerifyFinal(ctptr, &sigIn);
}
unsignedint
sftk_MLDSAGetSigLen(CK_ML_DSA_PARAMETER_SET_TYPE paramSet)
{ switch (paramSet) { case CKP_ML_DSA_44: return ML_DSA_44_SIGNATURE_LEN; case CKP_ML_DSA_65: return ML_DSA_65_SIGNATURE_LEN; case CKP_ML_DSA_87: return ML_DSA_87_SIGNATURE_LEN;
} /* this is a programming error if we get a valid DSA key with an unknown
* parmaSet */
PORT_Assert(/* unknown param set */ 0); return0;
}
if (crv != CKR_OK) { if (info)
PORT_Free(info); if (pinfo)
PORT_ZFree(pinfo, pinfo->size);
sftk_FreeContext(context);
sftk_FreeSession(session); return crv;
} /* At this point info/pinfo (if allocated) are linked into
* context->cipherInfo and will be freed via sftk_FreeContext. */
crv = sftk_InstallContext(session, SFTK_SIGN, context); if (crv != CKR_OK) {
sftk_FreeContext(context);
}
sftk_FreeSession(session); return crv;
}
/** MAC one block of data by block cipher
*/ static CK_RV
sftk_MACBlock(SFTKSessionContext *ctx, void *blk)
{ unsignedint outlen; return (SECSuccess == (ctx->update)(ctx->cipherInfo, ctx->macBuf, &outlen,
SFTK_MAX_BLOCK_SIZE, blk, ctx->blockSize))
? CKR_OK
: sftk_MapCryptError(PORT_GetError());
}
/** MAC last (incomplete) block of data by block cipher * *Callonce,thenterminateMACingoperation.
*/ static CK_RV
sftk_MACFinal(SFTKSessionContext *ctx)
{ unsignedint padLen = ctx->padDataLength; /* pad and proceed the residual */ if (ctx->isXCBC) {
CK_RV crv = sftk_xcbc_mac_pad(ctx->padBuf, padLen, ctx->blockSize,
ctx->k2, ctx->k3); if (crv != CKR_OK) return crv; return sftk_MACBlock(ctx, ctx->padBuf);
} if (padLen) { /* shd clr ctx->padLen to make sftk_MACFinal idempotent */
PORT_Memset(ctx->padBuf + padLen, 0, ctx->blockSize - padLen); return sftk_MACBlock(ctx, ctx->padBuf);
} else return CKR_OK;
}
/** The common implementation for {Sign,Verify}Update. (S/V only vary in their *setupandfinaloperations). * *Acallwhichresultsinanerrorterminatestheoperation[PKCS#11,v2.11]
*/ static CK_RV
sftk_MACUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
CK_ULONG ulPartLen, SFTKContextType type)
{
SFTKSession *session;
SFTKSessionContext *context;
CK_RV crv;
/* make sure we're legal */
crv = sftk_GetContext(hSession, &context, type, PR_TRUE, &session); if (crv != CKR_OK) return crv;
if (context->hashInfo) { #if (ULONG_MAX > UINT_MAX) while (ulPartLen > UINT_MAX) {
(*context->hashUpdate)(context->cipherInfo, pPart, UINT_MAX);
pPart += UINT_MAX;
ulPartLen -= UINT_MAX;
} #endif
(*context->hashUpdate)(context->hashInfo, pPart, ulPartLen);
} else { /* must be block cipher MACing */
unsignedint blkSize = context->blockSize; unsignedchar *residual = /* free room in context->padBuf */
context->padBuf + context->padDataLength; unsignedint minInput = /* min input for MACing at least one block */
blkSize - context->padDataLength;
/* not enough data even for one block */ if (ulPartLen <= minInput) {
PORT_Memcpy(residual, pPart, ulPartLen);
context->padDataLength += ulPartLen; goto cleanup;
} /* MACing residual */ if (context->padDataLength) {
PORT_Memcpy(residual, pPart, minInput);
ulPartLen -= minInput;
pPart += minInput; if (CKR_OK != (crv = sftk_MACBlock(context, context->padBuf))) goto terminate;
} /* MACing full blocks */ while (ulPartLen > blkSize) { if (CKR_OK != (crv = sftk_MACBlock(context, pPart))) goto terminate;
ulPartLen -= blkSize;
pPart += blkSize;
} /* save the residual */ if ((context->padDataLength = ulPartLen))
PORT_Memcpy(context->padBuf, pPart, ulPartLen);
} /* blk cipher MACing */
/* NSC_Sign signs (encrypts with private key) data in a single part, *wherethesignatureis(willbe)anappendixtothedata,
* and plaintext cannot be recovered from the signature */
CK_RV
NSC_Sign(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
CK_ULONG_PTR pulSignatureLen)
{
SFTKSession *session;
SFTKSessionContext *context;
CK_RV crv;
CHECK_FORK();
/* make sure we're legal */
crv = sftk_GetContext(hSession, &context, SFTK_SIGN, PR_FALSE, &session); if (crv != CKR_OK) return crv;
if (!pSignature) { /* see also how C_SignUpdate implements this */
*pulSignatureLen = (!context->multi || context->hashInfo)
? context->maxLen
: context->macSize; /* must be block cipher MACing */ goto finish;
}
/* multi part Signing are completely implemented by SignUpdate and
* sign Final */ if (context->multi) { /* SignFinal can't follow failed SignUpdate */ if (CKR_OK == (crv = NSC_SignUpdate(hSession, pData, ulDataLen)))
crv = NSC_SignFinal(hSession, pSignature, pulSignatureLen);
} else { /* single-part PKC signature (e.g. CKM_ECDSA) */ unsignedint outlen; unsignedint maxoutlen = *pulSignatureLen; if (SECSuccess != (*context->update)(context->cipherInfo, pSignature,
&outlen, maxoutlen, pData, ulDataLen))
crv = sftk_MapCryptError(PORT_GetError());
*pulSignatureLen = (CK_ULONG)outlen; /* "too small" here is certainly continuable */ if (crv != CKR_BUFFER_TOO_SMALL)
sftk_TerminateOp(session, SFTK_SIGN);
} /* single-part */
finish:
sftk_FreeSession(session); return crv;
}
/* **************CryptoFunctions:SignRecover************************
*/ /* NSC_SignRecoverInit initializes a signature operation, *wherethe(digest)datacanberecoveredfromthesignature.
* E.g. encryption with the user's private key */
CK_RV
NSC_SignRecoverInit(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
{
CHECK_FORK();
switch (pMechanism->mechanism) { case CKM_RSA_PKCS: case CKM_RSA_X_509: return NSC_SignInit(hSession, pMechanism, hKey); default: break;
} return CKR_MECHANISM_INVALID;
}
/* NSC_SignRecover signs data in a single operation *wherethe(digest)datacanberecoveredfromthesignature.
* E.g. encryption with the user's private key */
CK_RV
NSC_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
{
CHECK_FORK();
/* pkcs1DigestInfo.data must be less than key->u.rsa.modulus.len */
bufferSize = key->u.rsa.modulus.len;
pkcs1DigestInfoData = PORT_ZAlloc(bufferSize); if (!pkcs1DigestInfoData) {
PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure;
}
case CKM_SSL3_MD5_MAC:
PORT_Assert(pMechanism->pParameter); if (!pMechanism->pParameter) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
crv = sftk_doSSLMACInit(context, SEC_OID_MD5, key,
*(CK_ULONG *)pMechanism->pParameter); break; case CKM_SSL3_SHA1_MAC:
PORT_Assert(pMechanism->pParameter); if (!pMechanism->pParameter) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
crv = sftk_doSSLMACInit(context, SEC_OID_SHA1, key,
*(CK_ULONG *)pMechanism->pParameter); break; case CKM_TLS_PRF_GENERAL:
crv = sftk_TLSPRFInit(context, key, key_type, HASH_AlgNULL, 0); break; case CKM_NSS_TLS_PRF_GENERAL_SHA256:
crv = sftk_TLSPRFInit(context, key, key_type, HASH_AlgSHA256, 0); break;
default:
crv = CKR_MECHANISM_INVALID; break;
}
if (crv != CKR_OK) { if (info)
PORT_Free(info); if (pinfo)
PORT_ZFree(pinfo, pinfo->size);
sftk_FreeContext(context);
sftk_FreeSession(session); return crv;
} /* At this point info/pinfo (if allocated) are linked into
* context->cipherInfo and will be freed via sftk_FreeContext. */
crv = sftk_InstallContext(session, SFTK_VERIFY, context); if (crv != CKR_OK) {
sftk_FreeContext(context);
}
sftk_FreeSession(session); return crv;
}
/* NSC_Verify verifies a signature in a single-part operation, *wherethesignatureisanappendixtothedata,
* and plaintext cannot be recovered from the signature */
CK_RV
NSC_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
{
SFTKSession *session;
SFTKSessionContext *context;
CK_RV crv;
CHECK_FORK();
/* make sure we're legal */
crv = sftk_GetContext(hSession, &context, SFTK_VERIFY, PR_FALSE, &session); if (crv != CKR_OK) return crv;
/* multi part Verifying are completely implemented by VerifyUpdate and
* VerifyFinal */ if (context->multi) { /* VerifyFinal can't follow failed VerifyUpdate */ if (CKR_OK == (crv = NSC_VerifyUpdate(hSession, pData, ulDataLen)))
crv = NSC_VerifyFinal(hSession, pSignature, ulSignatureLen);
} else { if (SECSuccess != (*context->verify)(context->cipherInfo, pSignature,
ulSignatureLen, pData, ulDataLen))
crv = sftk_MapCryptError(PORT_GetError());
/* make sure we're legal */ if (!context->signature) {
sftk_FreeSession(session); return CKR_OPERATION_NOT_INITIALIZED;
}
crv = NSC_Verify(hSession, pData, ulDataLen,
context->signature->data, context->signature->len); /* we free the signature here because the context is part of the session and has *alifetimetiedtothesession.Sowewanttoholdourreferencetothe
* session so it doesn't go away on us */
sftk_FreeSession(session); return crv;
}
/* make sure we're legal */
crv = sftk_GetContext(hSession, &context, SFTK_VERIFY, PR_TRUE, &session); if (crv != CKR_OK) return crv;
/* like verify above, we bother keeping the session to make sure the context *doesn'tgowayonuse.there'slittlechancethatitwillsincethatapplication *mustprotectagainstmultiplethreadscallingthesamesamesessionatthesame *time(nsshassessionlocksforthis),butthereareacoupleofcornercases, *(likecloseallsessions,orshuttingdownthewholemodule.Alsoifthe
* application breaks the contract, we want to just fail rather than crash */ if (!context->signature) {
sftk_FreeSession(session); return CKR_OPERATION_NOT_INITIALIZED;
}
sftk_FreeSession(session); return NSC_VerifyUpdate(hSession, pPart, ulPartLen);
}
/* NSC_VerifyRecover verifies a signature in a single-part operation, *wherethedataisrecoveredfromthesignature.
* E.g. Decryption with the user's public key */
CK_RV
NSC_VerifyRecover(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen,
CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
{
SFTKSession *session;
SFTKSessionContext *context; unsignedint outlen; unsignedint maxoutlen = *pulDataLen;
CK_RV crv;
SECStatus rv;
CHECK_FORK();
/* make sure we're legal */
crv = sftk_GetContext(hSession, &context, SFTK_VERIFY_RECOVER,
PR_FALSE, &session); if (crv != CKR_OK) return crv; if (pData == NULL) { /* to return the actual size, we need to do the decrypt, just return
* the max size, which is the size of the input signature. */
*pulDataLen = ulSignatureLen;
rv = SECSuccess; goto finish;
}
/* NSC_SeedRandom mixes additional seed material into the token's random number
* generator. */
CK_RV
NSC_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed,
CK_ULONG ulSeedLen)
{
SECStatus rv;
/* if P and Q are supplied, we want to generate a new G */
attribute = sftk_FindAttribute(key, CKA_PRIME); if (attribute != NULL) {
PLArenaPool *arena;
switch (params->encAlg) { case SEC_OID_DES_CBC:
*key_type = CKK_DES;
*key_length = params->keyLen; break; case SEC_OID_DES_EDE3_CBC:
*key_type = params->is2KeyDES ? CKK_DES2 : CKK_DES3;
*key_length = params->keyLen; break; #ifndef NSS_DISABLE_DEPRECATED_RC2 case SEC_OID_RC2_CBC:
*key_type = CKK_RC2;
*key_length = params->keyLen; break; #endif/* NSS_DISABLE_DEPRECATED_RC2 */ case SEC_OID_RC4:
*key_type = CKK_RC4;
*key_length = params->keyLen; break; case SEC_OID_PKCS5_PBKDF2: /* key type must already be set */ if (*key_type == CKK_INVALID_KEY_TYPE) {
crv = CKR_TEMPLATE_INCOMPLETE; break;
} /* PBKDF2 needs to calculate the key length from the other parameters
*/ if (*key_length == 0) {
*key_length = sftk_MapKeySize(*key_type);
} if (*key_length == 0) {
crv = CKR_TEMPLATE_INCOMPLETE; break;
}
params->keyLen = *key_length; break; default:
crv = CKR_MECHANISM_INVALID; break;
} if (crv == CKR_OK) {
*pbe = params;
} else {
nsspkcs5_DestroyPBEParameter(params);
} return crv;
}
/* NSC_GenerateKey generates a secret key, creating a new key object. */
CK_RV
NSC_GenerateKey(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
CK_OBJECT_HANDLE_PTR phKey)
{
SFTKObject *key;
SFTKSession *session;
PRBool checkWeak = PR_FALSE;
CK_ULONG key_length = 0;
CK_KEY_TYPE key_type = CKK_INVALID_KEY_TYPE;
CK_OBJECT_CLASS objclass = CKO_SECRET_KEY;
CK_RV crv = CKR_OK;
CK_BBOOL cktrue = CK_TRUE;
NSSPKCS5PBEParameter *pbe_param = NULL; int i;
SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession); unsignedchar buf[MAX_KEY_LEN]; enum { nsc_pbe,
nsc_ssl,
nsc_bulk,
nsc_param,
nsc_jpake } key_gen_type;
SSL3RSAPreMasterSecret *rsa_pms;
CK_VERSION *version; /* in very old versions of NSS, there were implementation errors with key *generationmethods.Wewanttobeabletoreadthese,butnot *producethemanymore.Theaffectedalgorithmwas3DES.
*/
PRBool faultyPBE3DES = PR_FALSE;
HASH_HashType hashType = HASH_AlgNULL;
CHECK_FORK();
if (!slot) { return CKR_SESSION_HANDLE_INVALID;
} /* *nowletscreateanobjecttohangtheattributesoffof
*/
key = sftk_NewObject(slot); /* fill in the handle later */ if (key == NULL) { return CKR_HOST_MEMORY;
}
/* *loadthetemplatevaluesintotheobject
*/ for (i = 0; i < (int)ulCount; i++) { if (pTemplate[i].type == CKA_VALUE_LEN) {
key_length = *(CK_ULONG *)pTemplate[i].pValue; continue;
} /* some algorithms need keytype specified */ if (pTemplate[i].type == CKA_KEY_TYPE) {
key_type = *(CK_ULONG *)pTemplate[i].pValue; continue;
}
crv = sftk_AddAttributeType(key, sftk_attr_expand(&pTemplate[i])); if (crv != CKR_OK) { break;
}
} if (crv != CKR_OK) { 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; /* fall through */ #ifndef NSS_DISABLE_DEPRECATED_RC2 case CKM_RC2_KEY_GEN: #endif case CKM_RC4_KEY_GEN: case CKM_GENERIC_SECRET_KEY_GEN: #ifndef NSS_DISABLE_DEPRECATED_SEED case CKM_SEED_KEY_GEN: #endif case CKM_CAMELLIA_KEY_GEN: case CKM_AES_KEY_GEN: case CKM_NSS_CHACHA20_KEY_GEN: case CKM_CHACHA20_KEY_GEN: #if NSS_SOFTOKEN_DOES_RC5 case CKM_RC5_KEY_GEN: #endif
crv = nsc_SetupBulkKeyGen(pMechanism->mechanism, &key_type, &key_length); break; case CKM_SSL3_PRE_MASTER_KEY_GEN:
key_type = CKK_GENERIC_SECRET;
key_length = 48;
key_gen_type = nsc_ssl; break; case CKM_PBA_SHA1_WITH_SHA1_HMAC: case CKM_NSS_PBE_SHA1_HMAC_KEY_GEN: case CKM_NSS_PBE_MD5_HMAC_KEY_GEN: case CKM_NSS_PBE_MD2_HMAC_KEY_GEN: case CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN: case CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN: case CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN: case CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN:
key_gen_type = nsc_pbe;
key_type = CKK_GENERIC_SECRET;
crv = nsc_SetupHMACKeyGen(pMechanism, &pbe_param); break; case CKM_NSS_PBE_SHA1_FAULTY_3DES_CBC:
faultyPBE3DES = PR_TRUE; /* fall through */ case CKM_NSS_PBE_SHA1_TRIPLE_DES_CBC: #ifndef NSS_DISABLE_DEPRECATED_RC2 case CKM_NSS_PBE_SHA1_40_BIT_RC2_CBC: case CKM_NSS_PBE_SHA1_128_BIT_RC2_CBC: case CKM_PBE_SHA1_RC2_128_CBC: case CKM_PBE_SHA1_RC2_40_CBC: #endif case CKM_NSS_PBE_SHA1_DES_CBC: case CKM_NSS_PBE_SHA1_40_BIT_RC4: case CKM_NSS_PBE_SHA1_128_BIT_RC4: case CKM_PBE_SHA1_DES3_EDE_CBC: case CKM_PBE_SHA1_DES2_EDE_CBC: case CKM_PBE_SHA1_RC4_128: case CKM_PBE_SHA1_RC4_40: case CKM_PBE_MD5_DES_CBC: case CKM_PBE_MD2_DES_CBC: case CKM_PKCS5_PBKD2:
key_gen_type = nsc_pbe;
crv = nsc_SetupPBEKeyGen(pMechanism, &pbe_param, &key_type, &key_length); break; /*#ifndef NSS_DISABLE_DSA */ /* some applications use CKM_DSA_PARAMETER_GEN for weak DH keys...
* most notably tests and even ssl... continue to allow it for now */ case CKM_DSA_PARAMETER_GEN:
key_gen_type = nsc_param;
key_type = CKK_DSA;
objclass = CKO_DOMAIN_PARAMETERS;
crv = CKR_OK; break; /* #endif */ case CKM_NSS_JPAKE_ROUND1_SHA1:
hashType = HASH_AlgSHA1; goto jpake1; case CKM_NSS_JPAKE_ROUND1_SHA256:
hashType = HASH_AlgSHA256; goto jpake1; case CKM_NSS_JPAKE_ROUND1_SHA384:
hashType = HASH_AlgSHA384; goto jpake1; case CKM_NSS_JPAKE_ROUND1_SHA512:
hashType = HASH_AlgSHA512; goto jpake1;
jpake1:
key_gen_type = nsc_jpake;
key_type = CKK_NSS_JPAKE_ROUND1;
objclass = CKO_PRIVATE_KEY; if (pMechanism->pParameter == NULL ||
pMechanism->ulParameterLen != sizeof(CK_NSS_JPAKERound1Params)) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
} if (sftk_isTrue(key, CKA_TOKEN)) {
crv = CKR_TEMPLATE_INCONSISTENT; break;
}
crv = CKR_OK; break; default:
crv = CKR_MECHANISM_INVALID; break;
}
/* make sure we aren't going to overflow the buffer */ if (sizeof(buf) < key_length) { /* someone is getting pretty optimistic about how big their key can
* be... */
crv = CKR_TEMPLATE_INCONSISTENT;
}
if (crv != CKR_OK) { if (pbe_param) {
nsspkcs5_DestroyPBEParameter(pbe_param);
} goto loser;
}
/* if there was no error,
* key_type *MUST* be set in the switch statement above */
PORT_Assert(key_type != CKK_INVALID_KEY_TYPE);
/* *nowtotheactualkeygen.
*/ switch (key_gen_type) { case nsc_pbe:
crv = nsc_pbe_key_gen(pbe_param, pMechanism, buf, &key_length,
faultyPBE3DES);
nsspkcs5_DestroyPBEParameter(pbe_param); break; case nsc_ssl:
rsa_pms = (SSL3RSAPreMasterSecret *)buf; if (BAD_PARAM_CAST(pMechanism, sizeof(CK_VERSION))) {
crv = CKR_MECHANISM_PARAM_INVALID; goto loser;
}
version = (CK_VERSION *)pMechanism->pParameter;
rsa_pms->client_version[0] = version->major;
rsa_pms->client_version[1] = version->minor;
crv =
NSC_GenerateRandom(0, &rsa_pms->random[0], sizeof(rsa_pms->random)); break; case nsc_bulk: /* get the key, check for weak keys and repeat if found */ do {
crv = NSC_GenerateRandom(0, buf, key_length);
} while (crv == CKR_OK && checkWeak && sftk_IsWeakKey(buf, key_type)); break; case nsc_param: /* generate parameters */
*buf = 0;
crv = nsc_parameter_gen(key_type, key); break; case nsc_jpake: if (BAD_PARAM_CAST(pMechanism, sizeof(CK_NSS_JPAKERound1Params))) {
crv = CKR_MECHANISM_PARAM_INVALID; goto loser;
}
crv = jpake_Round1(hashType,
(CK_NSS_JPAKERound1Params *)pMechanism->pParameter,
key); break;
}
if (crv != CKR_OK) { goto loser;
}
/* Add the class, key_type, and value */
crv = sftk_AddAttributeType(key, CKA_CLASS, &objclass, sizeof(CK_OBJECT_CLASS)); if (crv != CKR_OK) { goto loser;
}
crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE)); if (crv != CKR_OK) { goto loser;
} if (key_length != 0) {
crv = sftk_AddAttributeType(key, CKA_VALUE, buf, key_length); if (crv != CKR_OK) { goto loser;
}
}
/* get the session */
session = sftk_SessionFromHandle(hSession); if (session == NULL) {
crv = CKR_SESSION_HANDLE_INVALID; goto loser;
}
/* *handlethebaseobjectstuff
*/
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 */
sftk_setFIPS(key, sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE,
key, 0));
session->lastOpWasFIPS = sftk_hasFIPS(key);
sftk_FreeSession(session); if (crv != CKR_OK) { goto loser;
} if (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) {
NSC_DestroyObject(hSession, key->handle); goto loser;
}
*phKey = key->handle;
loser:
PORT_Memset(buf, 0, sizeof buf);
sftk_FreeObject(key); return crv;
}
/* takes raw sessions and key handles and determines if the keys
* have the same value. */
PRBool
sftk_compareKeysEqual(CK_SESSION_HANDLE hSession,
CK_OBJECT_HANDLE key1, CK_OBJECT_HANDLE key2)
{
PRBool result = PR_FALSE;
SFTKSession *session;
SFTKObject *key1obj = NULL;
SFTKObject *key2obj = NULL;
SFTKAttribute *att1 = NULL;
SFTKAttribute *att2 = NULL;
/* fetch the pkcs11 objects from the handles */
session = sftk_SessionFromHandle(hSession); if (session == NULL) { return PR_FALSE;
}
key1obj = sftk_ObjectFromHandle(key1, session);
key2obj = sftk_ObjectFromHandle(key2, session);
sftk_FreeSession(session); if ((key1obj == NULL) || (key2obj == NULL)) { goto loser;
} /* fetch the value attributes */
att1 = sftk_FindAttribute(key1obj, CKA_VALUE); if (att1 == NULL) { goto loser;
}
att2 = sftk_FindAttribute(key2obj, CKA_VALUE); if (att2 == NULL) { goto loser;
} /* make sure that they are equal */ if (att1->attrib.ulValueLen != att2->attrib.ulValueLen) { goto loser;
} if (PORT_Memcmp(att1->attrib.pValue, att2->attrib.pValue,
att1->attrib.ulValueLen) != 0) { goto loser;
}
result = PR_TRUE;
loser: if (att1) {
sftk_FreeAttribute(att1);
} if (att2) {
sftk_FreeAttribute(att2);
} if (key1obj) {
sftk_FreeObject(key1obj);
} if (key2obj) {
sftk_FreeObject(key2obj);
} return result;
}
/* Variables used for Signature/Verification functions. */ unsignedchar *signature;
CK_ULONG signature_length;
SFTKAttribute *attribute;
switch (keyType) { case CKK_RSA: /* Get modulus length of private key. */
attribute = sftk_FindAttribute(privateKey, CKA_MODULUS); if (attribute == NULL) { return CKR_DEVICE_ERROR;
}
modulusLen = attribute->attrib.ulValueLen; if (*(unsignedchar *)attribute->attrib.pValue == 0) {
modulusLen--;
}
sftk_FreeAttribute(attribute); #if RSA_MIN_MODULUS_BITS < 1023 /* if we allow weak RSA keys, and this is a weak RSA key and *wearen'tinFIPSmode,skipthetests,Thesekeysare
* factorable anyway, the pairwise test doen't matter. */ if ((modulusLen < 1023) && !sftk_isFIPS(slot->slotID)) { return CKR_OK;
} #endif break; #ifndef NSS_DISABLE_DSA case CKK_DSA: /* Get subprime length of private key. */
attribute = sftk_FindAttribute(privateKey, CKA_SUBPRIME); if (attribute == NULL) { return CKR_DEVICE_ERROR;
}
subPrimeLen = attribute->attrib.ulValueLen; if (subPrimeLen > 1 &&
*(unsignedchar *)attribute->attrib.pValue == 0) {
subPrimeLen--;
}
sftk_FreeAttribute(attribute); break; #endif case CKK_NSS_KYBER: case CKK_NSS_ML_KEM: /* these aren't FIPS. we use them to generate keys without a
* pairwise consistency check */ return CKR_OK;
}
/**************************************************/ /* Pairwise Consistency Check of Encrypt/Decrypt. */ /**************************************************/
/* Allocate space for ciphertext. */
ciphertext = (unsignedchar *)PORT_ZAlloc(bytes_encrypted); if (ciphertext == NULL) { return CKR_HOST_MEMORY;
}
/* Prepare for encryption using the public key. */
crv = NSC_EncryptInit(hSession, &mech, publicKey->handle); if (crv != CKR_OK) {
PORT_Free(ciphertext); return crv;
}
/* Encrypt using the public key. */
crv = NSC_Encrypt(hSession,
known_message,
PAIRWISE_MESSAGE_LENGTH,
ciphertext,
&bytes_encrypted); if (crv != CKR_OK) {
PORT_Free(ciphertext); return crv;
}
/* Always use the smaller of these two values . . . */
bytes_compared = PR_MIN(bytes_encrypted, PAIRWISE_MESSAGE_LENGTH);
/* Finished with ciphertext; free it. */
PORT_Free(ciphertext);
if (crv != CKR_OK) { return crv;
}
/* *Checktoensurethattheoutputplaintext *doesEQUALknowninputmessagetext.
*/ if ((bytes_decrypted != PAIRWISE_MESSAGE_LENGTH) ||
(PORT_Memcmp(plaintext, known_message,
PAIRWISE_MESSAGE_LENGTH) != 0)) { /* Set error to Bad PUBLIC Key. */
PORT_SetError(SEC_ERROR_BAD_KEY); return CKR_GENERAL_ERROR;
}
}
/**********************************************/ /* Pairwise Consistency Check of Sign/Verify. */ /**********************************************/
canSignVerify = sftk_isTrue(privateKey, CKA_SIGN); /* Unfortunately CKA_SIGN is always true in lg dbs. We have to check the
* actual curve to determine if we can do sign/verify. */ if (canSignVerify && keyType == CKK_EC) {
NSSLOWKEYPrivateKey *privKey = sftk_GetPrivKey(privateKey, CKK_EC, &crv); if (privKey && privKey->u.ec.ecParams.name == ECCurve25519) {
canSignVerify = PR_FALSE;
}
}
/* Allocate space for signature data. */
signature = (unsignedchar *)PORT_ZAlloc(signature_length); if (signature == NULL) { return CKR_HOST_MEMORY;
}
/* Sign the known hash using the private key. */
crv = NSC_SignInit(hSession, &mech, privateKey->handle); if (crv != CKR_OK) {
PORT_Free(signature); return crv;
}
/* Verify the known hash using the public key. */
crv = NSC_VerifyInit(hSession, &mech, publicKey->handle); if (crv != CKR_OK) {
PORT_Free(signature); return crv;
}
crv = CKR_OK; /*paranoia, already get's set before we drop to the end */
/* FIPS 140-3 requires we verify that the resulting key is a valid key *byrecalculatingthepubliccanancompareittoourownpublic
* 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:
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_MONTGOMERY: 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.type != ec_params_named) {
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;
}
/* 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 *onlydoespartialvalidationwithapprovedprimes,nowhandle
* full validation */ if (isFIPS && keyType == CKK_DH) {
SECItem pubKey = { siBuffer, pubAttribute->attrib.pValue,
pubAttribute->attrib.ulValueLen };
SECItem base = { siBuffer, NULL, 0 };
SECItem prime = { siBuffer, NULL, 0 };
SECItem subPrime = { siBuffer, NULL, 0 };
SECItem generator = { siBuffer, NULL, 0 }; const SECItem *subPrimePtr = &subPrime;
crv = sftk_Attribute2SecItem(NULL, &prime, privateKey, CKA_PRIME); if (crv != CKR_OK) { goto done;
}
crv = sftk_Attribute2SecItem(NULL, &base, privateKey, CKA_BASE); if (crv != CKR_OK) { goto done;
} /* we ignore the return code an only look at the length */ /* do we have a known prime ? */
subPrimePtr = sftk_VerifyDH_Prime(&prime, &generator, 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;
} /* if we aren't using a defined group, make sure base is in the *subgroup.Ifit'snot,thenourkeycouldfailorsucceedsometimes.
* This makes the failure reliable */ if (!KEA_Verify(&base, &prime, &subPrime)) {
crv = CKR_ATTRIBUTE_VALUE_INVALID;
}
}
subPrimePtr = &subPrime;
} else { /* we're using a known group, make sure we are using the known generator for that group */ if (SECITEM_CompareItem(&generator, &base) != 0) {
crv = CKR_ATTRIBUTE_VALUE_INVALID; goto done;
} if (subPrime.len != 0) { /* we have a known prime and a supplied subPrime, *makesurethesubPrimematchesthesubPrimefor
* the known Prime */ if (SECITEM_CompareItem(subPrimePtr, &subPrime) != 0) {
crv = CKR_ATTRIBUTE_VALUE_INVALID; goto done;
}
}
} if (!KEA_Verify(&pubKey, &prime, (SECItem *)subPrimePtr)) {
crv = CKR_ATTRIBUTE_VALUE_INVALID;
}
done:
SECITEM_ZfreeItem(&base, PR_FALSE);
SECITEM_ZfreeItem(&subPrime, PR_FALSE);
SECITEM_ZfreeItem(&prime, PR_FALSE);
} /* clean up before we return */
sftk_FreeAttribute(pubAttribute); if (crv != CKR_OK) { return crv;
}
}
if (!slot) { return CKR_SESSION_HANDLE_INVALID;
} /* *nowletscreateanobjecttohangtheattributesoffof
*/
publicKey = sftk_NewObject(slot); /* fill in the handle later */ if (publicKey == NULL) { return CKR_HOST_MEMORY;
}
/* *loadthetemplatevaluesintothepublicKey
*/ for (i = 0; i < (int)ulPublicKeyAttributeCount; i++) { if (pPublicKeyTemplate[i].type == CKA_MODULUS_BITS) {
public_modulus_bits = *(CK_ULONG *)pPublicKeyTemplate[i].pValue; continue;
}
crv = sftk_AddAttributeType(publicKey,
sftk_attr_expand(&pPublicKeyTemplate[i])); if (crv != CKR_OK) break;
}
if (crv != CKR_OK) {
sftk_FreeObject(publicKey); return CKR_HOST_MEMORY;
}
privateKey = sftk_NewObject(slot); /* fill in the handle later */ if (privateKey == NULL) {
sftk_FreeObject(publicKey); return CKR_HOST_MEMORY;
} /* *nowloadtheprivatekeytemplate
*/ for (i = 0; i < (int)ulPrivateKeyAttributeCount; i++) { if (pPrivateKeyTemplate[i].type == CKA_VALUE_BITS) { continue;
}
crv = sftk_AddAttributeType(privateKey,
sftk_attr_expand(&pPrivateKeyTemplate[i])); if (crv != CKR_OK) break;
}
if (rv != SECSuccess) { if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
sftk_fatalError = PR_TRUE;
}
crv = sftk_MapCryptError(PORT_GetError()); break;
}
/* store the generated key into the attributes */
crv = sftk_AddAttributeType(publicKey, CKA_VALUE,
sftk_item_expand(&dsaPriv->publicValue)); if (crv != CKR_OK) goto dsagn_done;
/* now fill in the RSA dependent paramenters in the private key */
crv = sftk_AddAttributeType(privateKey, CKA_NSS_DB,
sftk_item_expand(&dsaPriv->publicValue)); if (crv != CKR_OK) goto dsagn_done;
crv = sftk_AddAttributeType(privateKey, CKA_VALUE,
sftk_item_expand(&dsaPriv->privateValue));
dsagn_done: /* should zeroize, since this function doesn't. */
PORT_FreeArena(dsaPriv->params.arena, PR_TRUE); break; #endif case CKM_DH_PKCS_KEY_PAIR_GEN:
sftk_DeleteAttributeType(privateKey, CKA_PRIME);
sftk_DeleteAttributeType(privateKey, CKA_BASE);
sftk_DeleteAttributeType(privateKey, CKA_VALUE);
sftk_DeleteAttributeType(privateKey, CKA_NSS_DB);
key_type = CKK_DH;
dhgn_done: /* should zeroize, since this function doesn't. */
PORT_FreeArena(dhPriv->arena, PR_TRUE); break;
case CKM_EC_KEY_PAIR_GEN: case CKM_NSS_ECDHE_NO_PAIRWISE_CHECK_KEY_PAIR_GEN:
sftk_DeleteAttributeType(privateKey, CKA_EC_PARAMS);
sftk_DeleteAttributeType(privateKey, CKA_VALUE);
sftk_DeleteAttributeType(privateKey, CKA_NSS_DB);
key_type = CKK_EC;
/* extract the necessary parameters and copy them to private keys */
crv = sftk_Attribute2SSecItem(NULL, &ecEncodedParams, publicKey,
CKA_EC_PARAMS); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(privateKey, CKA_NSS_DB,
sftk_item_expand(&ecPriv->publicValue));
ecgn_done: /* should zeroize, since this function doesn't. */
PORT_FreeArena(ecPriv->ecParams.arena, PR_TRUE); break;
#ifndef NSS_DISABLE_KYBER case CKM_NSS_KYBER_KEY_PAIR_GEN:
key_type = CKK_NSS_KYBER; goto do_ml_kem; #endif case CKM_NSS_ML_KEM_KEY_PAIR_GEN:
key_type = CKK_NSS_ML_KEM; goto do_ml_kem;
case CKM_ML_KEM_KEY_PAIR_GEN:
key_type = CKK_ML_KEM;
/* generate the seed here so we can record it with
* the private key */
seed.data = seedData;
seed.len = sizeof(seedData);
rv = RNG_GenerateGlobalRandomBytes(seed.data, seed.len); if (rv != SECSuccess) {
fprintf(stderr, "Generate bytes failed nbytes=%d err=%d\n",
seed.len, PORT_GetError());
crv = sftk_MapCryptError(PORT_GetError()); goto kyber_done;
}
if (rv != SECSuccess) { if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
sftk_fatalError = PR_TRUE;
}
crv = sftk_MapCryptError(PORT_GetError()); break;
}
/* store the generated key into the attributes */
crv = sftk_AddAttributeType(publicKey, CKA_VALUE,
mldsaPub.keyVal, mldsaPub.keyValLen); if (crv != CKR_OK) goto mldsagn_done;
crv = sftk_AddAttributeType(publicKey, CKA_PARAMETER_SET,
&genParamSet, sizeof(CK_ML_DSA_PARAMETER_SET_TYPE)); if (crv != CKR_OK) { goto mldsagn_done;
}
/* now fill in the ML-DSA specfic paramenters in the private key */
crv = sftk_AddAttributeType(privateKey, CKA_NSS_DB,
mldsaPub.keyVal, mldsaPub.keyValLen); if (crv != CKR_OK) goto mldsagn_done;
if (mldsaPriv.seedLen != 0) {
crv = sftk_AddAttributeType(privateKey, CKA_SEED,
mldsaPriv.seed, mldsaPriv.seedLen); if (crv != CKR_OK) { goto mldsagn_done;
} /* pseudo attribute that says the seed came with the key *sodon'ttrytoregeneratethekeyinhandleObject. *itwillberemovedbeforetheobjectseesthelightof
* day. */
crv = sftk_AddAttributeType(privateKey, CKA_NSS_SEED_OK,
NULL, 0); /* it was either this or a comment 'fall through' which would
* be cryptic to some users */ if (crv != CKR_OK) { goto mldsagn_done;
}
}
mldsagn_done:
PORT_SafeZero(&mldsaPriv, sizeof(mldsaPriv));
PORT_SafeZero(&mldsaPub, sizeof(mldsaPub)); break;
case CKM_EC_MONTGOMERY_KEY_PAIR_GEN: case CKM_EC_EDWARDS_KEY_PAIR_GEN:
sftk_DeleteAttributeType(privateKey, CKA_EC_PARAMS);
sftk_DeleteAttributeType(privateKey, CKA_VALUE);
sftk_DeleteAttributeType(privateKey, CKA_NSS_DB);
key_type = (pMechanism->mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN) ? CKK_EC_EDWARDS : CKK_EC_MONTGOMERY;
/* extract the necessary parameters and copy them to private keys */
crv = sftk_Attribute2SSecItem(NULL, &ecEncodedParams, publicKey,
CKA_EC_PARAMS); if (crv != CKR_OK) { break;
}
crv = sftk_AddAttributeType(privateKey, CKA_NSS_DB,
sftk_item_expand(&ecPriv->publicValue));
edgn_done: /* should zeroize, since this function doesn't. */
PORT_FreeArena(ecPriv->ecParams.arena, PR_TRUE); break;
default:
crv = CKR_MECHANISM_INVALID;
}
if (crv != CKR_OK) {
sftk_FreeObject(privateKey);
sftk_FreeObject(publicKey); return crv;
}
/* Add the class, key_type The loop lets us check errors blow out
* on errors and clean up at the bottom */
session = NULL; /* make pedtantic happy... session cannot leave the*/ /* loop below NULL unless an error is set... */ do {
crv = sftk_AddAttributeType(privateKey, CKA_CLASS, &privClass, sizeof(CK_OBJECT_CLASS)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(publicKey, CKA_CLASS, &pubClass, sizeof(CK_OBJECT_CLASS)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(privateKey, CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(publicKey, CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE)); if (crv != CKR_OK) break;
session = sftk_SessionFromHandle(hSession); if (session == NULL)
crv = CKR_SESSION_HANDLE_INVALID;
} while (0);
if (crv != CKR_OK) {
sftk_FreeObject(privateKey);
sftk_FreeObject(publicKey); return crv;
}
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 */
sftk_setFIPS(privateKey, sftk_operationIsFIPS(slot, pMechanism,
CKA_NSS_GENERATE_KEY_PAIR,
privateKey, 0));
session->lastOpWasFIPS = sftk_hasFIPS(privateKey);
sftk_setFIPS(publicKey, session->lastOpWasFIPS);
sftk_FreeSession(session);
*phPrivateKey = privateKey->handle;
*phPublicKey = publicKey->handle;
sftk_FreeObject(publicKey);
sftk_FreeObject(privateKey);
/* determine RSA key type from the CKA_PUBLIC_KEY_INFO if present */
attribute = sftk_FindAttribute(key, CKA_PUBLIC_KEY_INFO); if (attribute) {
NSSLOWKEYSubjectPublicKeyInfo *publicKeyInfo;
SECItem spki;
switch (lk->u.mlkem.mlkemParams) { case params_ml_kem768: case params_ml_kem768_test_mode:
algorithm = SEC_OID_ML_KEM_768; break; case params_ml_kem1024: case params_ml_kem1024_test_mode:
algorithm = SEC_OID_ML_KEM_1024; break; default:
algorithm = SEC_OID_UNKNOWN; break;
} if (algorithm == SEC_OID_UNKNOWN) { break;
} /* save the seed and key items before they are overwritten */ if (lk->u.mlkem.seed.len != 0) {
seed = lk->u.mlkem.seed;
}
rawKey = lk->u.mlkem.key; if (lk == key->objectInfo) { /* we have a cached key, and we are about to
* overwrite it, let's get a duplicate first */
lk = nsslowkey_CopyPrivateKey(lk); if (lk == NULL) { break;
}
} /* this overwrites the mlkem data, but we don't need it any *morebecausewearediscardinglkonceweencode.This *allowsustousethesametemplateformlkemandmldsa *(andpresumablyotherpqalgorithms,thoughmlfnandmlshl
* don't have additional seeds) */
lk->u.genpq.seedItem = seed;
lk->u.genpq.keyItem = rawKey; if (seed.len) {
dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
nsslowkey_PQBothSeedAndPrivateKeyTemplate);
} else {
dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
nsslowkey_PQPrivateKeyTemplate);
}
} break; case NSSLOWKEYMLDSAKey: {
SECItem seed = { siBuffer, NULL, 0 };
SECItem keyVal = { siBuffer, NULL, 0 };
dummy = NULL;
/* paramSet sets the algorithm */ switch (lk->u.mldsa.paramSet) { case CKP_ML_DSA_44:
algorithm = SEC_OID_ML_DSA_44_PUBLIC_KEY; break; case CKP_ML_DSA_65:
algorithm = SEC_OID_ML_DSA_65_PUBLIC_KEY; break; case CKP_ML_DSA_87:
algorithm = SEC_OID_ML_DSA_87_PUBLIC_KEY; break; default:
algorithm = SEC_OID_UNKNOWN; break;
} if (algorithm == SEC_OID_UNKNOWN) { break;
}
/* if we have the seed, copy it */ if (lk->u.mldsa.seedLen != 0) {
rv = SECITEM_MakeItem(arena, &seed, lk->u.mldsa.seed,
lk->u.mldsa.seedLen); if (rv != SECSuccess) { break;
}
}
rv = SECITEM_MakeItem(arena, &keyVal, lk->u.mldsa.keyVal,
lk->u.mldsa.keyValLen); if (rv != SECSuccess) { break;
} if (lk == key->objectInfo) { /* we have a cached key, and we are about to
* overwrite it, let's get a duplicate first */
lk = nsslowkey_CopyPrivateKey(lk); if (lk == NULL) { break;
}
} /* this overwrites the mldsa data, but we don't need it any
* more because we are discarding lk once we encode */
lk->u.genpq.seedItem = seed;
lk->u.genpq.keyItem = keyVal;
if (lk && (lk != key->objectInfo)) {
nsslowkey_DestroyPrivateKey(lk);
}
if (param) {
SECITEM_ZfreeItem((SECItem *)param, PR_TRUE);
}
if (rv != SECSuccess) { return NULL;
}
return encodedKey;
}
/* it doesn't matter yet, since we colapse error conditions in the
* level above, but we really should map those few key error differences */ static CK_RV
sftk_mapWrap(CK_RV crv)
{ switch (crv) { case CKR_ENCRYPTED_DATA_INVALID:
crv = CKR_WRAPPED_KEY_INVALID; break;
} return crv;
}
/* Find out if this is a block cipher. The context was just *installedbysftk_CryptInitabove,sowealreadyholda *sessionreferenceandthecontext'stypeisSFTK_ENCRYPT
* by construction. */
context = sftk_ReturnContextByType(session, SFTK_ENCRYPT); if (!context) {
sftk_FreeAttribute(attribute);
crv = CKR_OPERATION_NOT_INITIALIZED; break;
} if (context->blockSize > 1) { unsignedint remainder = pText.len % context->blockSize; if (!context->doPad && remainder) { /* When wrapping secret keys with unpadded block ciphers, **thekeysarezeropadded,ifnecessary,tofillout **afullblock.
*/
pText.len += context->blockSize - remainder;
pText.data = PORT_ZAlloc(pText.len); if (pText.data)
memcpy(pText.data, attribute->attrib.pValue,
attribute->attrib.ulValueLen); else {
sftk_FreeAttribute(attribute);
crv = CKR_HOST_MEMORY; break;
}
}
}
crv = NSC_Encrypt(hSession, (CK_BYTE_PTR)pText.data,
pText.len, pWrappedKey, pulWrappedKeyLen); /* always force a finalize, both on errors and when
* we are just getting the size */ if (crv != CKR_OK || pWrappedKey == NULL) {
sftk_UninstallContext(session, SFTK_ENCRYPT);
}
if (pText.data != (unsignedchar *)attribute->attrib.pValue)
PORT_ZFree(pText.data, pText.len);
sftk_FreeAttribute(attribute); break;
}
case CKO_PRIVATE_KEY: {
SECItem *bpki = sftk_PackagePrivateKey(key, &crv);
/* if we were given just the seed, we'll regenerate the key
* from the seed in handleObject */ if (lpk->u.genpq.keyItem.len != 0) {
crv = sftk_AddAttributeType(key, CKA_VALUE,
sftk_item_expand(&lpk->u.genpq.keyItem)); /* I know, this is redundant, but it would be too easy *forsomeonetoaddanothersftk_AddAttributeTypeafter
* this without adding this check back because of the if */ if (crv != CKR_OK) break;
} break; case NSSLOWKEYMLDSAKey:
keyType = CKK_ML_DSA;
crv = (sftk_hasAttribute(key, CKA_NSS_DB)) ? CKR_OK : CKR_KEY_TYPE_INCONSISTENT; if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, sizeof(keyType)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, sizeof(CK_BBOOL)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &ckfalse, sizeof(CK_BBOOL)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_PARAMETER_SET, ¶mSet, sizeof(CK_ML_DSA_PARAMETER_SET_TYPE)); if (crv != CKR_OK) break; if (lpk->u.genpq.seedItem.len != 0) {
crv = sftk_AddAttributeType(key, CKA_SEED,
sftk_item_expand(&lpk->u.genpq.seedItem)); if (crv != CKR_OK) break;
}
/* if we were given just the seed, we'll regenerate the key
* from the seed in handleObject */ if (lpk->u.genpq.keyItem.len != 0) {
crv = sftk_AddAttributeType(key, CKA_VALUE,
sftk_item_expand(&lpk->u.genpq.keyItem)); /* I know, this is redundant, but it would be too easy *forsomeonetoaddanothersftk_AddAttributeTypeafter
* this without adding this check back because of the if */ if (crv != CKR_OK) break;
} break; #ifdef notdef case NSSLOWKEYDHKey: template = dhTemplate;
templateCount = sizeof(dhTemplate) / sizeof(CK_ATTRIBUTE);
keyType = CKK_DH; break; #endif /* what about fortezza??? */ case NSSLOWKEYECKey:
keyType = CKK_EC; /* if we weren't passed the CKA_NSS_DB, get it
* from the public key */ if (!sftk_hasAttribute(key, CKA_NSS_DB)) { if (lpk->u.ec.publicValue.len == 0) {
crv = CKR_KEY_TYPE_INCONSISTENT; goto loser;
}
crv = sftk_AddAttributeType(key, CKA_NSS_DB,
sftk_item_expand(&lpk->u.ec.publicValue)); if (crv != CKR_OK) { goto loser;
}
}
crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, sizeof(keyType)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, sizeof(CK_BBOOL)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &ckfalse, sizeof(CK_BBOOL)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_EC_PARAMS,
sftk_item_expand(&lpk->u.ec.ecParams.DEREncoding)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_VALUE,
sftk_item_expand(&lpk->u.ec.privateValue)); if (crv != CKR_OK) break; /* XXX Do we need to decode the EC Params here ?? */ break; default:
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
if (crv != CKR_OK) { goto loser;
}
/* For RSA-PSS, record the original algorithm parameters so
* they can be encrypted altoghether when wrapping */ if (SECOID_GetAlgorithmTag(&pki->algorithm) == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
NSSLOWKEYSubjectPublicKeyInfo spki;
NSSLOWKEYPublicKey pubk;
SECItem *publicKeyInfo;
if (!slot) { return CKR_SESSION_HANDLE_INVALID;
} /* *nowletscreateanobjecttohangtheattributesoffof
*/
key = sftk_NewObject(slot); /* fill in the handle later */ if (key == NULL) { return CKR_HOST_MEMORY;
}
/* *loadthetemplatevaluesintotheobject
*/ for (i = 0; i < (int)ulAttributeCount; i++) { if (pTemplate[i].type == CKA_VALUE_LEN) {
key_length = *(CK_ULONG *)pTemplate[i].pValue; continue;
} if (pTemplate[i].type == CKA_CLASS) {
target_type = *(CK_OBJECT_CLASS *)pTemplate[i].pValue;
}
crv = sftk_AddAttributeType(key, sftk_attr_expand(&pTemplate[i])); if (crv != CKR_OK) break;
} if (crv != CKR_OK) {
sftk_FreeObject(key); return crv;
}
/* allocate the buffer to decrypt into *thisassumestheunwrappedkeyisneverlargerthanthe
* wrapped key. For all the mechanisms we support this is true */
buf = (unsignedchar *)PORT_Alloc(ulWrappedKeyLen);
bsize = ulWrappedKeyLen;
/* get the session */
session = sftk_SessionFromHandle(hSession); if (session == NULL) {
sftk_FreeObject(key); return CKR_SESSION_HANDLE_INVALID;
}
/* mark the key as FIPS if the previous operation was all FIPS */
sftk_setFIPS(key, session->lastOpWasFIPS); /* *handlethebaseobjectstuff
*/
crv = sftk_handleObject(key, session);
*phKey = key->handle;
sftk_FreeSession(session);
sftk_FreeObject(key);
/* if the target key is actually data, don't set the unexpected
* attributes */
crv = sftk_GetULongAttribute(destKey, CKA_CLASS, &objClass); if (crv != CKR_OK) { return crv;
} if (objClass == CKO_DATA) { return CKR_OK;
}
/* if the base key is data, it doesn't have sensitive attributes,
* allow the destKey to get it's own */
crv = sftk_GetULongAttribute(baseKey, CKA_CLASS, &objClass); if (crv != CKR_OK) { return crv;
} if (objClass == CKO_DATA) {
isData = PR_TRUE;
}
}
/* we should inherit the parent's always extractable/ never sensitive info, *buthandleObjectalwaysforcesthisattributes,sowewouldneedtodo
* something special. */ return CKR_OK;
}
/* *makeknownfixedPKCS#11keytypestotheirsizesinbytes
*/ unsignedlong
sftk_MapKeySize(CK_KEY_TYPE keyType)
{ switch (keyType) { case CKK_CDMF: return8; case CKK_DES: return8; case CKK_DES2: return16; case CKK_DES3: return24; /* IDEA and CAST need to be added */ default: break;
} return0;
}
/* Check that key_len isn't too long. The maximum key length could be *greatlyincreasedifthecodebelowdidnotlimitthe4-bytecounter
* to a maximum value of 255. */ if (key_len > 254 * HashLen) return CKR_ARGUMENTS_BAD;
/* 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); if (rawHash == NULL || rawHash->length > sizeof(hashbuf)) { return CKR_MECHANISM_INVALID;
}
hashLen = rawHash->length;
/* 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; /* if the source key is data, clear the FIPS flag
* and only get the FIPS state from the salt */ if (sourceKey->objclass == CKO_DATA) {
sftk_setFIPS(key, PR_FALSE);
}
}
switch (params->ulSaltType) { case CKF_HKDF_SALT_NULL:
saltLen = hashLen;
salt = hashbuf;
memset(salt, 0, saltLen); break; case CKF_HKDF_SALT_DATA:
salt = params->pSalt;
saltLen = params->ulSaltLen; if ((salt == NULL) || (params->ulSaltLen == 0)) { return CKR_MECHANISM_PARAM_INVALID;
} break; case CKF_HKDF_SALT_KEY: /* lookup key */
session = sftk_SessionFromHandle(hSession); if (session == NULL) { return CKR_SESSION_HANDLE_INVALID;
}
saltKey = sftk_ObjectFromHandle(params->hSaltKey, session);
sftk_FreeSession(session); if (saltKey == NULL) { return CKR_KEY_HANDLE_INVALID;
} /* if the base key is not fips, but the salt key is, the
* resulting key can be fips */ if (isFIPS && !sftk_hasFIPS(key) && sftk_hasFIPS(saltKey)) {
CK_MECHANISM mech;
mech.mechanism = CKM_HKDF_DERIVE;
mech.pParameter = params;
mech.ulParameterLen = sizeof(*params);
sftk_setFIPS(key, sftk_operationIsFIPS(saltKey->slot,
&mech, 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) {
sftk_setFIPS(key, PR_FALSE);
}
} if (key)
key->source = SFTK_SOURCE_HKDF_EXTRACT;
if (!slot) { return CKR_SESSION_HANDLE_INVALID;
} if (!pMechanism) { return CKR_MECHANISM_PARAM_INVALID;
}
CK_MECHANISM_TYPE mechanism = pMechanism->mechanism;
/* *nowletscreateanobjecttohangtheattributesoffof
*/ if (phKey) {
*phKey = CK_INVALID_HANDLE;
}
key = sftk_NewObject(slot); /* fill in the handle later */ if (key == NULL) { return CKR_HOST_MEMORY;
}
isFIPS = sftk_isFIPS(slot->slotID);
/* *loadthetemplatevaluesintotheobject
*/ for (i = 0; i < (int)ulAttributeCount; i++) {
crv = sftk_AddAttributeType(key, sftk_attr_expand(&pTemplate[i])); if (crv != CKR_OK) break;
if (pTemplate[i].type == CKA_KEY_TYPE) {
keyType = *(CK_KEY_TYPE *)pTemplate[i].pValue;
} if (pTemplate[i].type == CKA_VALUE_LEN) {
keySize = *(CK_ULONG *)pTemplate[i].pValue;
}
} if (crv != CKR_OK) {
sftk_FreeObject(key); return crv;
}
if (keySize == 0) {
keySize = sftk_MapKeySize(keyType);
}
switch (mechanism) { case CKM_NSS_JPAKE_ROUND2_SHA1: /* fall through */ case CKM_NSS_JPAKE_ROUND2_SHA256: /* fall through */ case CKM_NSS_JPAKE_ROUND2_SHA384: /* fall through */ case CKM_NSS_JPAKE_ROUND2_SHA512:
extractValue = PR_FALSE;
classType = CKO_PRIVATE_KEY; break; case CKM_NSS_PUB_FROM_PRIV:
extractValue = PR_FALSE;
classType = CKO_PUBLIC_KEY; break; case CKM_HKDF_DATA: /* fall through */ case CKM_NSS_SP800_108_COUNTER_KDF_DERIVE_DATA: /* fall through */ case CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA: /* fall through */ case CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA:
classType = CKO_DATA; break; case CKM_NSS_JPAKE_FINAL_SHA1: /* fall through */ case CKM_NSS_JPAKE_FINAL_SHA256: /* fall through */ case CKM_NSS_JPAKE_FINAL_SHA384: /* fall through */ case CKM_NSS_JPAKE_FINAL_SHA512:
extractValue = PR_FALSE; /* fall through */ default:
classType = CKO_SECRET_KEY;
}
/* look up the base key we're deriving with */
session = sftk_SessionFromHandle(hSession); if (session == NULL) {
sftk_FreeObject(key); return CKR_SESSION_HANDLE_INVALID;
}
sourceKey = sftk_ObjectFromHandle(hBaseKey, session); /* is this eventually succeeds, lastOpWasFIPS will be set the resulting key's
* FIPS state below. */
session->lastOpWasFIPS = PR_FALSE;
sftk_FreeSession(session); if (sourceKey == NULL) {
sftk_FreeObject(key); return CKR_KEY_HANDLE_INVALID;
}
if (extractValue) { /* 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;
}
}
sftk_setFIPS(key, 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;
/* store the results */
crv = sftk_forceAttribute(key, CKA_VALUE, key_block, SSL3_MASTER_SECRET_LENGTH);
PORT_Memset(key_block, 0, sizeof key_block); if (crv != CKR_OK) break;
keyType = CKK_GENERIC_SECRET;
crv = sftk_forceAttribute(key, CKA_KEY_TYPE, &keyType, sizeof(keyType)); if (isTLS) { /* TLS's master secret is used to "sign" finished msgs with PRF. */ /* XXX This seems like a hack. But SFTK_Derive only accepts
* one "operation" argument. */
crv = sftk_forceAttribute(key, CKA_SIGN, &cktrue, sizeof(CK_BBOOL)); if (crv != CKR_OK) break;
crv = sftk_forceAttribute(key, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL)); if (crv != CKR_OK) break; /* While we're here, we might as well force this, too. */
crv = sftk_forceAttribute(key, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL)); if (crv != CKR_OK) break;
} break;
}
/* Reflect the version if required */ if (ems_params->pVersion) {
SFTKSessionObject *sessKey = sftk_narrowToSessionObject(key);
rsa_pms = (SSL3RSAPreMasterSecret *)att->attrib.pValue; /* don't leak more key material than necessary for SSL to work */ if ((sessKey == NULL) || sessKey->wasDerived) {
ems_params->pVersion->major = 0xff;
ems_params->pVersion->minor = 0xff;
} else {
ems_params->pVersion->major = rsa_pms->client_version[0];
ems_params->pVersion->minor = rsa_pms->client_version[1];
}
}
/* Store the results */
crv = sftk_forceAttribute(key, CKA_VALUE, key_block,
SSL3_MASTER_SECRET_LENGTH);
PORT_Memset(key_block, 0, sizeof key_block); break;
}
case CKM_TLS12_KEY_AND_MAC_DERIVE: case CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256: case CKM_TLS_KEY_AND_MAC_DERIVE: case CKM_SSL3_KEY_AND_MAC_DERIVE: {
CK_SSL3_KEY_MAT_PARAMS *ssl3_keys;
CK_SSL3_KEY_MAT_OUT *ssl3_keys_out;
CK_ULONG effKeySize; unsignedint block_needed; unsignedchar srcrdata[SSL3_RANDOM_LENGTH * 2];
crv = sftk_forceAttribute(key, CKA_VALUE, buf, keySize);
PORT_ZFree(buf, tmpKeySize); /* preserve the source of the original base key */
key->source = sourceKey->source;
/* make sure this is fully fips approved, and mark it
* unapproved if not */ if (sftk_hasFIPS(key)) {
sftk_setFIPS(key, sftk_hasFIPS(paramKey));
}
sftk_FreeAttribute(att2);
sftk_FreeObject(paramKey); break;
}
case CKM_CONCATENATE_BASE_AND_DATA:
crv = sftk_DeriveSensitiveCheck(sourceKey, key, PR_FALSE); if (crv != CKR_OK) break;
case CKM_EXTRACT_KEY_FROM_KEY: { if (BAD_PARAM_CAST(pMechanism, sizeof(CK_EXTRACT_PARAMS))) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
} /* the following assumes 8 bits per byte */
CK_ULONG extract = *(CK_EXTRACT_PARAMS *)pMechanism->pParameter;
CK_ULONG shift = extract & 0x7; /* extract mod 8 the fast way */
CK_ULONG offset = extract >> 3; /* extract div 8 the fast way */
crv = sftk_DeriveSensitiveCheck(sourceKey, key, PR_FALSE); if (crv != CKR_OK) break;
if (keySize == 0) {
crv = CKR_TEMPLATE_INCOMPLETE; break;
} /* make sure we have enough bits in the original key */ if (att->attrib.ulValueLen <
(offset + keySize + ((shift != 0) ? 1 : 0))) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
buf = (unsignedchar *)PORT_Alloc(keySize); if (buf == NULL) {
crv = CKR_HOST_MEMORY; break;
}
/* copy the bits we need into the new key */ for (i = 0; i < (int)keySize; i++) { unsignedchar *value =
((unsignedchar *)att->attrib.pValue) + offset + i; if (shift) {
buf[i] = (value[0] << (shift)) | (value[1] >> (8 - shift));
} else {
buf[i] = value[0];
}
}
crv = sftk_forceAttribute(key, CKA_VALUE, buf, keySize);
PORT_ZFree(buf, keySize); break;
} case CKM_MD2_KEY_DERIVATION: if (keySize == 0)
keySize = MD2_LENGTH; if (keySize > MD2_LENGTH) {
crv = CKR_TEMPLATE_INCONSISTENT; break;
} /* now allocate the hash contexts */
md2 = MD2_NewContext(); if (md2 == NULL) {
crv = CKR_HOST_MEMORY; break;
}
MD2_Begin(md2);
MD2_Update(md2, (constunsignedchar *)att->attrib.pValue,
att->attrib.ulValueLen);
MD2_End(md2, key_block, &outLen, MD2_LENGTH);
MD2_DestroyContext(md2, PR_TRUE);
case CKM_DH_PKCS_DERIVE: {
SECItem derived, dhPublic;
SECItem dhPrime, dhValue; const SECItem *subPrime; /* sourceKey - values for the local existing low key */ /* get prime and value attributes */
crv = sftk_Attribute2SecItem(NULL, &dhPrime, sourceKey, CKA_PRIME); if (crv != CKR_OK) break;
/* if the prime is an approved prime, we can skip all the other
* checks. */
subPrime = sftk_VerifyDH_Prime(&dhPrime, NULL, isFIPS); if (subPrime == NULL) {
SECItem dhSubPrime; /* If the caller set the subprime value, it means that *eitherthecallerknowsthesubprimevalueandwantsus *tovalidatethekeyagainstthesubprime,orthatthe *callerwantsustoverifythattheprimeisasafeprime
* by passing in subprime = (prime-1)/2 */
dhSubPrime.data = NULL;
dhSubPrime.len = 0;
crv = sftk_Attribute2SecItem(NULL, &dhSubPrime,
sourceKey, CKA_SUBPRIME); /* we ignore the value of crv here, We treat a valid *returnoflen=0andafailuretofindasubrimethesame *NOTE:wefreethesubprimeinbothcasesdependingon
* PORT_Free of NULL to be a noop */ if (dhSubPrime.len != 0) {
PRBool isSafe = PR_FALSE;
/* Callers can set dhSubPrime to q=(p-1)/2 to force *checksforsafeprimes.Ifsoweonlyneedtocheck
* q and p for primality and skip the group test. */
rv = sftk_IsSafePrime(&dhPrime, &dhSubPrime, &isSafe); if (rv != SECSuccess) { /* either p or q was even and therefore not prime,
* we can stop processing here and fail now */
crv = CKR_ARGUMENTS_BAD;
SECITEM_ZfreeItem(&dhPrime, PR_FALSE);
SECITEM_ZfreeItem(&dhSubPrime, PR_FALSE); break;
}
/* first make sure the primes are really prime */ if (!KEA_PrimeCheck(&dhPrime)) {
crv = CKR_ARGUMENTS_BAD;
SECITEM_ZfreeItem(&dhPrime, PR_FALSE);
SECITEM_ZfreeItem(&dhSubPrime, PR_FALSE); break;
} if (!KEA_PrimeCheck(&dhSubPrime)) {
crv = CKR_ARGUMENTS_BAD;
SECITEM_ZfreeItem(&dhPrime, PR_FALSE);
SECITEM_ZfreeItem(&dhSubPrime, PR_FALSE); break;
} if (isFIPS || !isSafe) { /* With safe primes, there is only one other small *subgroup.Aslongasyisn't0,1,or-1modp, *anyotheryissafe.Onlydothefullcheckfor *non-safeprimes,exceptinFIPSmodeweneed *todothischeckonallprimesinwhich
* we receive the subprime value */ if (!KEA_Verify(&dhPublic, &dhPrime, &dhSubPrime)) {
crv = CKR_ARGUMENTS_BAD;
SECITEM_ZfreeItem(&dhPrime, PR_FALSE);
SECITEM_ZfreeItem(&dhSubPrime, PR_FALSE); break;
}
}
} elseif (isFIPS) { /* In FIPS mode we only accept approved primes, or
* primes with the full subprime value */
crv = CKR_ARGUMENTS_BAD;
SECITEM_ZfreeItem(&dhPrime, PR_FALSE); break;
} /* checks are complete, no need for the subPrime any longer */
SECITEM_ZfreeItem(&dhSubPrime, PR_FALSE);
}
/* now that the prime is validated, get the private value */
crv = sftk_Attribute2SecItem(NULL, &dhValue, sourceKey, CKA_VALUE); if (crv != CKR_OK) {
SECITEM_ZfreeItem(&dhPrime, PR_FALSE); break;
}
/* calculate private value - oct */
rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize);
crv = sftk_HKDF(&hkdfParams, hSession, sourceKey,
att->attrib.pValue, att->attrib.ulValueLen,
key, NULL, keySize, PR_FALSE, isFIPS);
} break; case CKM_HKDF_DERIVE: case CKM_HKDF_DATA: /* only difference is the class of key */ if ((pMechanism->pParameter == NULL) ||
(pMechanism->ulParameterLen != sizeof(CK_HKDF_PARAMS))) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
crv = sftk_HKDF((CK_HKDF_PARAMS_PTR)pMechanism->pParameter,
hSession, sourceKey, att->attrib.pValue,
att->attrib.ulValueLen, key, NULL, keySize, PR_TRUE,
isFIPS); break; case CKM_NSS_JPAKE_ROUND2_SHA1:
hashType = HASH_AlgSHA1; goto jpake2; case CKM_NSS_JPAKE_ROUND2_SHA256:
hashType = HASH_AlgSHA256; goto jpake2; case CKM_NSS_JPAKE_ROUND2_SHA384:
hashType = HASH_AlgSHA384; goto jpake2; case CKM_NSS_JPAKE_ROUND2_SHA512:
hashType = HASH_AlgSHA512; goto jpake2;
jpake2: if (pMechanism->pParameter == NULL ||
pMechanism->ulParameterLen != sizeof(CK_NSS_JPAKERound2Params))
crv = CKR_MECHANISM_PARAM_INVALID; if (crv == CKR_OK && sftk_isTrue(key, CKA_TOKEN))
crv = CKR_TEMPLATE_INCONSISTENT; if (crv == CKR_OK)
crv = sftk_DeriveSensitiveCheck(sourceKey, key, PR_FALSE); if (crv == CKR_OK)
crv = jpake_Round2(hashType,
(CK_NSS_JPAKERound2Params *)pMechanism->pParameter,
sourceKey, key); break;
case CKM_NSS_JPAKE_FINAL_SHA1:
hashType = HASH_AlgSHA1; goto jpakeFinal; case CKM_NSS_JPAKE_FINAL_SHA256:
hashType = HASH_AlgSHA256; goto jpakeFinal; case CKM_NSS_JPAKE_FINAL_SHA384:
hashType = HASH_AlgSHA384; goto jpakeFinal; case CKM_NSS_JPAKE_FINAL_SHA512:
hashType = HASH_AlgSHA512; goto jpakeFinal;
jpakeFinal: if (pMechanism->pParameter == NULL ||
pMechanism->ulParameterLen != sizeof(CK_NSS_JPAKEFinalParams))
crv = CKR_MECHANISM_PARAM_INVALID; /* We purposely do not do the derive sensitivity check; we want to be abletoderivenon-sensitivekeyswhileallowingtheROUND1and ROUND2keystobesensitive(whichtheyalwaysare,sincetheyare intheCKO_PRIVATE_KEYclass).ThecallermustincludeCKA_SENSITIVE inthetemplateinorderfortheresultantkeyblockkeytobe sensitive.
*/ if (crv == CKR_OK)
crv = jpake_Final(hashType,
(CK_NSS_JPAKEFinalParams *)pMechanism->pParameter,
sourceKey, key); break;
case CKM_NSS_SP800_108_COUNTER_KDF_DERIVE_DATA: /* fall through */ case CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA: /* fall through */ case CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA: /* fall through */ case CKM_SP800_108_COUNTER_KDF: /* fall through */ case CKM_SP800_108_FEEDBACK_KDF: /* fall through */ case CKM_SP800_108_DOUBLE_PIPELINE_KDF:
crv = sftk_DeriveSensitiveCheck(sourceKey, key, PR_FALSE); if (crv != CKR_OK) { break;
}
/* link the key object into the list */ if (key) {
SFTKSessionObject *sessKey = sftk_narrowToSessionObject(key); if (sessKey == NULL) {
sftk_FreeObject(key); return CKR_DEVICE_ERROR;
}
sessKey->wasDerived = PR_TRUE;
session = sftk_SessionFromHandle(hSession); if (session == NULL) {
sftk_FreeObject(key); return CKR_HOST_MEMORY;
}
/* NSC_GetFunctionStatus obtains an updated status of a function running
* in parallel with an application. */
CK_RV
NSC_GetFunctionStatus(CK_SESSION_HANDLE hSession)
{
CHECK_FORK();
return CKR_FUNCTION_NOT_PARALLEL;
}
/* NSC_CancelFunction cancels a function running in parallel */
CK_RV
NSC_CancelFunction(CK_SESSION_HANDLE hSession)
{
CHECK_FORK();
return CKR_FUNCTION_NOT_PARALLEL;
}
/* NSC_GetOperationState saves the state of the cryptographic *operationinasession. *NOTE:Thiscodeonlyworksfordigestfunctionsfornow.eventuallyneed *toaddfullflatten/resurecttoourstatestuffsothatalltypesofstate
* can be saved */
CK_RV
NSC_GetOperationState(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen)
{
SFTKSessionContext *context;
SFTKSession *session;
CK_RV crv;
CK_ULONG pOSLen = *pulOperationStateLen;
CHECK_FORK();
/* make sure we're legal */
crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, &session); if (crv != CKR_OK) return crv;
/* a zero cipherInfoLen signals that this context cannot be serialized */ if (context->cipherInfoLen == 0) { return CKR_STATE_UNSAVEABLE;
}
/* NSC_SetOperationState restores the state of the cryptographic *operationinasession.Thisiscodedlikeitcanrestorelotsof
* states, but it only works for truly flat cipher structures. */
CK_RV
NSC_SetOperationState(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen,
CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey)
{
SFTKSessionContext *context;
SFTKSession *session;
SFTKContextType type;
CK_MECHANISM mech;
CK_RV crv = CKR_OK;
CHECK_FORK();
while (ulOperationStateLen != 0) { /* get what type of state we're dealing with... */
PORT_Memcpy(&type, pOperationState, sizeof(SFTKContextType));
/* fix up session contexts based on type */
session = sftk_SessionFromHandle(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
sftk_UninstallContext(session, type);
pOperationState += sizeof(SFTKContextType);
sftk_Decrement(ulOperationStateLen, sizeof(SFTKContextType));
/* get the mechanism structure */
PORT_Memcpy(&mech.mechanism, pOperationState, sizeof(CK_MECHANISM_TYPE));
pOperationState += sizeof(CK_MECHANISM_TYPE);
sftk_Decrement(ulOperationStateLen, sizeof(CK_MECHANISM_TYPE)); /* should be filled in... but not necessary for hash */
mech.pParameter = NULL;
mech.ulParameterLen = 0; switch (type) { case SFTK_HASH:
crv = NSC_DigestInit(hSession, &mech); if (crv != CKR_OK) break; /* NSC_DigestInit just installed a SFTK_HASH context on *thissession;theoutersessionreferencekeepsit
* alive across the load below. */
context = sftk_ReturnContextByType(session, SFTK_HASH); if (context == NULL || context->type != SFTK_HASH) {
crv = CKR_OPERATION_NOT_INITIALIZED; break;
} if (context->cipherInfoLen == 0) {
crv = CKR_SAVED_STATE_INVALID; break;
}
PORT_Memcpy(context->cipherInfo, pOperationState,
context->cipherInfoLen);
pOperationState += context->cipherInfoLen;
sftk_Decrement(ulOperationStateLen, context->cipherInfoLen); break; default: /* do sign/encrypt/decrypt later */
crv = CKR_SAVED_STATE_INVALID;
}
sftk_FreeSession(session); if (crv != CKR_OK) break;
} return crv;
}
/* make sure it's a valid key for this operation */ if (key->objclass != CKO_SECRET_KEY) {
sftk_FreeObject(key); return CKR_KEY_TYPE_INCONSISTENT;
} /* get the key value */
att = sftk_FindAttribute(key, CKA_VALUE); if (!att) {
sftk_FreeObject(key); return CKR_KEY_HANDLE_INVALID;
}
crv = NSC_DigestUpdate(hSession, (CK_BYTE_PTR)att->attrib.pValue,
att->attrib.ulValueLen);
sftk_FreeAttribute(att);
sftk_FreeObject(key); return crv;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.528 Sekunden
(vorverarbeitet am 2026-09-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.