/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * This file implements PKCS 11 on top of our existing security modules * * For more information about PKCS 11 See PKCS 11 Token Inteface Standard. * This implementation has two slots: * slot 1 is our generic crypto support. It does not require login. * It supports Public Key ops, and all they bulk ciphers and hashes. * It can also support Private Key ops for imported Private keys. It does * not have any token storage. * slot 2 is our private key support. It requires a login before use. It * can store Private Keys and Certs as token objects. Currently only private * keys and their associated Certificates are saved on the token. * * In this implementation, session objects are only visible to the session * that created or generated them.
*/
#include <limits.h> /* for UINT_MAX and ULONG_MAX */
/* 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
/* * turn a CDMF key into a des key. CDMF is an old IBM scheme to export DES by * Deprecating a full des key to 40 bit key strenth.
*/ static CK_RV
sftk_cdmf2des(unsignedchar *cdmfkey, unsignedchar *deskey)
{ unsignedchar key1[8] = { 0xc4, 0x08, 0xb0, 0x54, 0x0b, 0xa1, 0xe0, 0xae }; unsignedchar key2[8] = { 0xef, 0x2c, 0x04, 0x1c, 0xe6, 0x38, 0x2f, 0xe6 }; unsignedchar enc_src[8]; unsignedchar enc_dest[8]; unsignedint leng, i;
DESContext *descx;
SECStatus rv;
CK_RV crv = CKR_OK;
/* zero the parity bits */ for (i = 0; i < 8; i++) {
enc_src[i] = cdmfkey[i] & 0xfe;
}
/* 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;
}
if (slot == NULL) { return CKR_SESSION_HANDLE_INVALID;
} /* * This whole block just makes sure we really can destroy the * requested object.
*/
session = sftk_SessionFromHandle(hSession); if (session == NULL) { return CKR_SESSION_HANDLE_INVALID;
}
/* don't destroy a private object if we aren't logged in */ if ((!slot->isLoggedIn) && (slot->needLogin) &&
(sftk_isTrue(object, CKA_PRIVATE))) {
sftk_FreeSession(session);
sftk_FreeObject(object); return CKR_USER_NOT_LOGGED_IN;
}
/* don't destroy a token object if we aren't in a rw session */
/* * get some indication if the object is destroyed. Note: this is not * 100%. Someone may have an object reference outstanding (though that * should not be the case by here. Also note that the object is "half" * destroyed. Our internal representation is destroyed, but it may still * be in the data base.
*/
status = sftk_FreeObject(object);
/* * Returns true if "params" contains a valid set of PSS parameters
*/ static PRBool
sftk_ValidatePssParams(const CK_RSA_PKCS_PSS_PARAMS *params)
{ if (!params) { return PR_FALSE;
} if (sftk_GetHashTypeFromMechanism(params->hashAlg) == HASH_AlgNULL ||
sftk_GetHashTypeFromMechanism(params->mgf) == HASH_AlgNULL) { return PR_FALSE;
} return PR_TRUE;
}
/* * Returns true if "params" contains a valid set of OAEP parameters
*/ 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: * If the parameter is empty, pSourceData must be NULL and * ulSourceDataLen must be zero.
*/ 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;
}
/* * return a context based on the SFTKContext type.
*/
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;
}
/* * change a context based on the SFTKContext type.
*/ 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;
}
/* * code to grab the context. Needed by every C_XXXUpdate, C_XXXFinal, * and C_XXX function. The function takes a session handle, the context type, * and wether or not the session needs to be multipart. It returns the context, * and optionally returns the session pointer (if sessionPtr != NULL) if session * pointer is returned, the caller is responsible for freeing it.
*/
CK_RV
sftk_GetContext(CK_SESSION_HANDLE handle, SFTKSessionContext **contextPtr,
SFTKContextType type, PRBool needMulti, SFTKSession **sessionPtr)
{
SFTKSession *session;
SFTKSessionContext *context;
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; if (sessionPtr != NULL) {
*sessionPtr = session;
} else {
sftk_FreeSession(session);
} return CKR_OK;
}
/** Terminate operation (in the PKCS#11 spec sense). * Intuitive name for FreeContext/SetNullContext pair.
*/ void
sftk_TerminateOp(SFTKSession *session, SFTKContextType ctype,
SFTKSessionContext *context)
{
session->lastOpWasFIPS = context->isFIPS;
sftk_FreeContext(context);
sftk_SetContextByType(session, ctype, NULL);
}
/* * All the NSC_InitXXX functions have a set of common checks and processing they * all need to do at the beginning. This is done here.
*/
CK_RV
sftk_InitGeneric(SFTKSession *session, CK_MECHANISM *pMechanism,
SFTKSessionContext **contextPtr,
SFTKContextType ctype, SFTKObject **keyPtr,
CK_OBJECT_HANDLE hKey, CK_KEY_TYPE *keyTypePtr,
CK_OBJECT_CLASS pubKeyType, CK_ATTRIBUTE_TYPE operation)
{
SFTKObject *key = NULL;
SFTKAttribute *att;
SFTKSessionContext *context;
/* We can only init if there is not current context active */ if (sftk_ReturnContextByType(session, ctype) != NULL) { return CKR_OPERATION_ACTIVE;
}
/* find the key */ if (keyPtr) {
key = sftk_ObjectFromHandle(hKey, session); if (key == NULL) { return CKR_KEY_HANDLE_INVALID;
}
/* make sure it's a valid key for this operation */ if (((key->objclass != CKO_SECRET_KEY) &&
(key->objclass != pubKeyType)) ||
!sftk_isTrue(key, operation)) {
sftk_FreeObject(key); return CKR_KEY_TYPE_INCONSISTENT;
} /* get the key type */
att = sftk_FindAttribute(key, CKA_KEY_TYPE); if (att == NULL) {
sftk_FreeObject(key); return CKR_KEY_TYPE_INCONSISTENT;
}
PORT_Assert(att->attrib.ulValueLen == sizeof(CK_KEY_TYPE)); if (att->attrib.ulValueLen != sizeof(CK_KEY_TYPE)) {
sftk_FreeAttribute(att);
sftk_FreeObject(key); return CKR_ATTRIBUTE_VALUE_INVALID;
}
PORT_Memcpy(keyTypePtr, att->attrib.pValue, sizeof(CK_KEY_TYPE));
sftk_FreeAttribute(att);
*keyPtr = key;
}
#if NSS_SOFTOKEN_DOES_RC5 case CKM_RC5_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_RC5_ECB: case CKM_RC5_CBC: if (key_type != CKK_RC5) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
att = sftk_FindAttribute(key, CKA_VALUE); if (att == NULL) {
crv = CKR_KEY_HANDLE_INVALID; break;
}
if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC5_CBC_PARAMS))) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
rc5_param = (CK_RC5_CBC_PARAMS *)pMechanism->pParameter;
context->blockSize = rc5_param->ulWordsize * 2;
rc5Key.data = (unsignedchar *)att->attrib.pValue;
rc5Key.len = att->attrib.ulValueLen;
context->cipherInfo = RC5_CreateContext(&rc5Key, rc5_param->ulRounds,
rc5_param->ulWordsize, rc5_param->pIv,
pMechanism->mechanism == CKM_RC5_ECB ? NSS_RC5 : NSS_RC5_CBC);
sftk_FreeAttribute(att); if (context->cipherInfo == NULL) {
crv = CKR_HOST_MEMORY; break;
}
context->update = isEncrypt ? SFTKCipher_RC5_Encrypt : SFTKCipher_RC5_Decrypt;
context->destroy = SFTKCipher_RC5_DestroyContext; break; #endif case CKM_RC4: if (key_type != CKK_RC4) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
att = sftk_FindAttribute(key, CKA_VALUE); if (att == NULL) {
crv = CKR_KEY_HANDLE_INVALID; break;
}
context->cipherInfo =
RC4_CreateContext((unsignedchar *)att->attrib.pValue,
att->attrib.ulValueLen);
sftk_FreeAttribute(att); if (context->cipherInfo == NULL) {
crv = CKR_HOST_MEMORY; /* WRONG !!! */ break;
}
context->update = isEncrypt ? SFTKCipher_RC4_Encrypt : SFTKCipher_RC4_Decrypt;
context->destroy = SFTKCipher_RC4_DestroyContext; break; case CKM_CDMF_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_CDMF_ECB: case CKM_CDMF_CBC: if (key_type != CKK_CDMF) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
t = (pMechanism->mechanism == CKM_CDMF_ECB) ? NSS_DES : NSS_DES_CBC; goto finish_des; case CKM_DES_ECB: if (key_type != CKK_DES) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
t = NSS_DES; goto finish_des; case CKM_DES_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_DES_CBC: if (key_type != CKK_DES) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
t = NSS_DES_CBC; goto finish_des; case CKM_DES3_ECB: if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
t = NSS_DES_EDE3; goto finish_des; case CKM_DES3_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_DES3_CBC: if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
t = NSS_DES_EDE3_CBC;
finish_des: if ((t != NSS_DES && t != NSS_DES_EDE3) && (pMechanism->pParameter == NULL ||
pMechanism->ulParameterLen < 8)) {
crv = CKR_DOMAIN_PARAMS_INVALID; break;
}
context->blockSize = 8;
att = sftk_FindAttribute(key, CKA_VALUE); if (att == NULL) {
crv = CKR_KEY_HANDLE_INVALID; break;
} if (key_type == CKK_DES2 &&
(t == NSS_DES_EDE3_CBC || t == NSS_DES_EDE3)) { /* extend DES2 key to DES3 key. */
memcpy(newdeskey, att->attrib.pValue, 16);
memcpy(newdeskey + 16, newdeskey, 8);
useNewKey = PR_TRUE;
} elseif (key_type == CKK_CDMF) {
crv = sftk_cdmf2des((unsignedchar *)att->attrib.pValue, newdeskey); if (crv != CKR_OK) {
sftk_FreeAttribute(att); break;
}
useNewKey = PR_TRUE;
}
context->cipherInfo = DES_CreateContext(
useNewKey ? newdeskey : (unsignedchar *)att->attrib.pValue,
(unsignedchar *)pMechanism->pParameter, t, isEncrypt); if (useNewKey)
memset(newdeskey, 0, sizeof newdeskey);
sftk_FreeAttribute(att); if (context->cipherInfo == NULL) {
crv = CKR_HOST_MEMORY; break;
}
context->update = isEncrypt ? SFTKCipher_DES_Encrypt : SFTKCipher_DES_Decrypt;
context->destroy = SFTKCipher_DES_DestroyContext; break; #ifndef NSS_DISABLE_DEPRECATED_SEED case CKM_SEED_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_SEED_CBC: if (!pMechanism->pParameter ||
pMechanism->ulParameterLen != 16) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
} /* fall thru */ case CKM_SEED_ECB:
context->blockSize = 16; if (key_type != CKK_SEED) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
att = sftk_FindAttribute(key, CKA_VALUE); if (att == NULL) {
crv = CKR_KEY_HANDLE_INVALID; break;
}
context->cipherInfo = SEED_CreateContext(
(unsignedchar *)att->attrib.pValue,
(unsignedchar *)pMechanism->pParameter,
pMechanism->mechanism == CKM_SEED_ECB ? NSS_SEED : NSS_SEED_CBC,
isEncrypt);
sftk_FreeAttribute(att); if (context->cipherInfo == NULL) {
crv = CKR_HOST_MEMORY; break;
}
context->update = isEncrypt ? SFTKCipher_SEED_Encrypt : SFTKCipher_SEED_Decrypt;
context->destroy = SFTKCipher_SEED_DestroyContext; break; #endif/* NSS_DISABLE_DEPRECATED_SEED */ case CKM_CAMELLIA_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_CAMELLIA_CBC: if (!pMechanism->pParameter ||
pMechanism->ulParameterLen != 16) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
} /* fall thru */ case CKM_CAMELLIA_ECB:
context->blockSize = 16; if (key_type != CKK_CAMELLIA) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
att = sftk_FindAttribute(key, CKA_VALUE); if (att == NULL) {
crv = CKR_KEY_HANDLE_INVALID; break;
}
context->cipherInfo = Camellia_CreateContext(
(unsignedchar *)att->attrib.pValue,
(unsignedchar *)pMechanism->pParameter,
pMechanism->mechanism ==
CKM_CAMELLIA_ECB
? NSS_CAMELLIA
: NSS_CAMELLIA_CBC,
isEncrypt, att->attrib.ulValueLen);
sftk_FreeAttribute(att); if (context->cipherInfo == NULL) {
crv = CKR_HOST_MEMORY; break;
}
context->update = isEncrypt ? SFTKCipher_Camellia_Encrypt : SFTKCipher_Camellia_Decrypt;
context->destroy = SFTKCipher_Camellia_DestroyContext; break;
case CKM_AES_CBC_PAD:
context->doPad = PR_TRUE; /* fall thru */ case CKM_AES_ECB: case CKM_AES_CBC:
context->blockSize = 16; case CKM_AES_CTS: case CKM_AES_CTR: case CKM_AES_GCM:
aes_param = pMechanism->pParameter; /* * Due to a mismatch between the documentation and the header * file, two different definitions for CK_GCM_PARAMS exist. * The header file is normative according to Oasis, but NSS used * the documentation. In PKCS #11 v3.0, this was reconciled in * favor of the header file definition. To maintain binary * compatibility, NSS now defines CK_GCM_PARAMS_V3 as the official * version v3 (V2.4 header file) and CK_NSS_GCM_PARAMS as the * legacy (V2.4 documentation, NSS version). CK_GCM_PARAMS * is defined as CK_GCM_PARAMS_V3 if NSS_PKCS11_2_0_COMPAT is not * defined and CK_NSS_GCM_PARAMS if it is. Internally * softoken continues to use the legacy version. The code below * automatically detects which parameter was passed in and * converts CK_GCM_PARAMS_V3 to the CK_NSS_GCM_PARAMS (legacy * version) on the fly. NSS proper will eventually start * using the CK_GCM_PARAMS_V3 version and fall back to the * CK_NSS_GCM_PARAMS if the CK_GCM_PARAMS_V3 version fails with * CKR_MECHANISM_PARAM_INVALID.
*/ if (pMechanism->mechanism == CKM_AES_GCM) { if (!aes_param) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
} if (pMechanism->ulParameterLen == sizeof(CK_GCM_PARAMS_V3)) { /* convert the true V3 parameters into the old NSS parameters */
CK_GCM_PARAMS_V3 *gcm_params = (CK_GCM_PARAMS_V3 *)aes_param; if (gcm_params->ulIvLen * 8 != gcm_params->ulIvBits) { /* only support byte aligned IV lengths */
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
aes_param = (void *)&nss_gcm_param;
nss_gcm_param.pIv = gcm_params->pIv;
nss_gcm_param.ulIvLen = gcm_params->ulIvLen;
nss_gcm_param.pAAD = gcm_params->pAAD;
nss_gcm_param.ulAADLen = gcm_params->ulAADLen;
nss_gcm_param.ulTagBits = gcm_params->ulTagBits;
} elseif (pMechanism->ulParameterLen != sizeof(CK_NSS_GCM_PARAMS)) { /* neither old nor new style params, must be invalid */
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
} elseif ((pMechanism->mechanism == CKM_AES_CTR && BAD_PARAM_CAST(pMechanism, sizeof(CK_AES_CTR_PARAMS))) ||
((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CTS) && BAD_PARAM_CAST(pMechanism, AES_BLOCK_SIZE))) {
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
/* 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;
/* 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; return CKR_OK;
} /* encrypt the current padded data */
rv = (*context->update)(context->cipherInfo, pEncryptedPart,
&padoutlen, maxout, context->padBuf,
context->blockSize); if (rv != SECSuccess) { return sftk_MapCryptError(PORT_GetError());
}
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; return CKR_OK;
}
}
/* 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) { return sftk_MapCryptError(PORT_GetError());
}
*pulEncryptedPartLen = (CK_ULONG)(outlen + padoutlen); return CKR_OK;
}
/* 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;
}
/* make sure we're legal */
crv = sftk_GetContext(hSession, &context, SFTK_DECRYPT, PR_TRUE, NULL); 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, * then we must be using a block cipher. In the non-padding case * the error will be returned by the underlying decryption * function when we do the actual decrypt. We need to do the * check here to avoid returning a negative length to the caller * or reading before the beginning of the pEncryptedPart buffer.
*/ if ((ulEncryptedPartLen == 0) ||
(ulEncryptedPartLen % context->blockSize) != 0) { return CKR_ENCRYPTED_DATA_LEN_RANGE;
}
}
if (!pPart) { if (context->doPad) {
*pulPartLen =
ulEncryptedPartLen + context->padDataLength - context->blockSize; return CKR_OK;
} /* for stream ciphers there is are no constraints on ulEncryptedPartLen. * for block ciphers, it must be a multiple of blockSize. The error is * detected when this function is called again do decrypt the output.
*/
*pulPartLen = ulEncryptedPartLen; return CKR_OK;
}
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) return sftk_MapDecryptError(PORT_GetError());
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) { return sftk_MapDecryptError(PORT_GetError());
}
*pulPartLen = (CK_ULONG)(outlen + padoutlen); return CKR_OK;
}
/* 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;
/* make sure we're legal */
crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, NULL); 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;
session->maxLen = context->mac_size;
return CKR_OK;
}
/* * SSL Macing support. SSL Macs are inited, then update with the base * hashing algorithm, then finalized in sign and verify
*/
/* * FROM SSL: * 60 bytes is 3 times the maximum length MAC size that is supported. * We probably should have one copy of this table. We still need this table * in ssl to 'sign' the handshake hashes.
*/ staticunsignedchar ssl_pad_1[60] = {
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36
}; staticunsignedchar ssl_pad_2[60] = {
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c
};
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 * are used at the end in the pad step. k1 replaces the input
* 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;
crv = sftk_GetContext(hSession, &context, contextType, PR_TRUE, NULL);
/* 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);
} 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;
}
/* NSC_SignInit setups up the signing operations. There are three basic * types of signing: * (1) the tradition single part, where "Raw RSA" or "Raw DSA" is applied * to data in a single Sign operation (which often looks a lot like an * encrypt, with data coming in and data going out). * (2) Hash based signing, where we continually hash the data, then apply * some sort of signature to the end. * (3) Block Encryption CBC MAC's, where the Data is encrypted with a key, * and only the final block is part of the mac. * * For case number 3, we initialize a context much like the Encryption Context * (in fact we share code). We detect case 3 in C_SignUpdate, C_Sign, and * C_Final by the following method... if it's not multi-part, and it's doesn't * have a hash context, it must be a block Encryption CBC MAC. * * For case number 2, we initialize a hash structure, as well as make it * multi-part. Updates are simple calls to the hash update function. Final * calls the hashend, then passes the result to the 'update' function (which * operates as a final signature function). In some hash based MAC'ing (as * opposed to hash base signatures), the update function is can be simply a * copy (as is the case with HMAC).
*/
CK_RV
NSC_SignInit(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
{
SFTKSession *session;
SFTKObject *key;
SFTKSessionContext *context;
CK_KEY_TYPE key_type;
CK_RV crv = CKR_OK;
NSSLOWKEYPrivateKey *privKey;
SFTKHashSignInfo *info = NULL;
SFTKPSSSignInfo *pinfo = NULL;
CHECK_FORK();
/* Block Cipher MACing Algorithms use a different Context init method..*/
crv = sftk_InitCBCMac(hSession, pMechanism, hKey, CKA_SIGN, SFTK_SIGN); if (crv != CKR_FUNCTION_NOT_SUPPORTED) return crv;
/* we're not using a block cipher mac */
session = sftk_SessionFromHandle(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
crv = sftk_InitGeneric(session, pMechanism, &context, SFTK_SIGN, &key,
hKey, &key_type, CKO_PRIVATE_KEY, CKA_SIGN); if (crv != CKR_OK) {
sftk_FreeSession(session); return crv;
}
case CKM_RSA_PKCS:
context->update = sftk_RSASign; goto finish_rsa; case CKM_RSA_X_509:
context->update = sftk_RSASignRaw;
finish_rsa: if (key_type != CKK_RSA) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
context->rsa = PR_TRUE;
privKey = sftk_GetPrivKey(key, CKK_RSA, &crv); if (privKey == NULL) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
} /* OK, info is allocated only if we're doing hash and sign mechanism. * It's necessary to be able to set the correct OID in the final * signature.
*/ if (info) {
info->key = privKey;
context->cipherInfo = info;
context->destroy = sftk_Space;
} else {
context->cipherInfo = privKey;
context->destroy = sftk_Null;
}
context->maxLen = nsslowkey_PrivateModulusLen(privKey); 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;
}
sftk_SetContextByType(session, SFTK_SIGN, context);
sftk_FreeSession(session); return CKR_OK;
}
/** 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 * * Call once, then terminate MACing operation.
*/ 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 * setup and final operations). * * A call which results in an error terminates the operation [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_SignUpdate continues a multiple-part signature operation, * where the signature is (will be) an appendix to the data, * and plaintext cannot be recovered from the signature * * A call which results in an error terminates the operation [PKCS#11,v2.11]
*/
CK_RV
NSC_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
CK_ULONG ulPartLen)
{
CHECK_FORK(); return sftk_MACUpdate(hSession, pPart, ulPartLen, SFTK_SIGN);
}
/* NSC_Sign signs (encrypts with private key) data in a single part, * where the signature is (will be) an appendix to the data,
* 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, context);
} /* single-part */
finish:
sftk_FreeSession(session); return crv;
}
/* ************** Crypto Functions: Sign Recover ************************
*/ /* NSC_SignRecoverInit initializes a signature operation, * where the (digest) data can be recovered from the signature.
* 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 * where the (digest) data can be recovered from the signature.
* 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;
}
sftk_SetContextByType(session, SFTK_VERIFY, context);
sftk_FreeSession(session); return CKR_OK;
}
/* NSC_Verify verifies a signature in a single-part operation, * where the signature is an appendix to the data,
* 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());
/* NSC_VerifyUpdate continues a multiple-part verification operation, * where the signature is an appendix to the data, * and plaintext cannot be recovered from the signature * * A call which results in an error terminates the operation [PKCS#11,v2.11]
*/
CK_RV
NSC_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
CK_ULONG ulPartLen)
{
CHECK_FORK(); return sftk_MACUpdate(hSession, pPart, ulPartLen, SFTK_VERIFY);
}
/* NSC_VerifyRecoverInit initializes a signature verification operation, * where the data is recovered from the signature.
* E.g. Decryption with the user's public key */
CK_RV
NSC_VerifyRecoverInit(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
{
SFTKSession *session;
SFTKObject *key;
SFTKSessionContext *context;
CK_KEY_TYPE key_type;
CK_RV crv = CKR_OK;
NSSLOWKEYPublicKey *pubKey;
/* NSC_VerifyRecover verifies a signature in a single-part operation, * where the data is recovered from the signature.
* 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;
}
/* **************************** Random Functions: ************************
*/
/* 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;
rv = RNG_GenerateGlobalRandomBytes(pRandomData, ulRandomLen); /* * This may fail with SEC_ERROR_NEED_RANDOM, which means the RNG isn't * seeded with enough entropy.
*/ return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
}
/* 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 * generation methods. We want to beable to read these, but not * produce them any more. The affected algorithm was 3DES.
*/
PRBool faultyPBE3DES = PR_FALSE;
HASH_HashType hashType = HASH_AlgNULL;
CHECK_FORK();
if (!slot) { return CKR_SESSION_HANDLE_INVALID;
} /* * now lets create an object to hang the attributes off of
*/
key = sftk_NewObject(slot); /* fill in the handle later */ if (key == NULL) { return CKR_HOST_MEMORY;
}
/* * load the template values into the object
*/ 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; case CKM_DSA_PARAMETER_GEN:
key_gen_type = nsc_param;
key_type = CKK_DSA;
objclass = CKO_DOMAIN_PARAMETERS;
crv = CKR_OK; break; 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);
/* * now to the actual key gen.
*/ 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;
}
/* Variables used for Signature/Verification functions. */ /* Must be at least 256 bits for DSA2 digest */ unsignedchar *known_digest = (unsignedchar *)"Mozilla Rules the World through NSS!"; unsignedchar *signature;
CK_ULONG signature_length;
if (keyType == CKK_RSA) {
SFTKAttribute *attribute;
/* 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);
} elseif (keyType == CKK_DSA) {
SFTKAttribute *attribute;
/* 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);
}
/**************************************************/ /* Pairwise Consistency Check of Encrypt/Decrypt. */ /**************************************************/
/* * If the decryption attribute is set, attempt to encrypt * with the public key and decrypt with the private key.
*/ if (isEncryptable) { if (keyType != CKK_RSA) { return CKR_DEVICE_ERROR;
}
bytes_encrypted = modulusLen;
mech.mechanism = CKM_RSA_PKCS;
/* 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);
/* * If there was a failure, the plaintext * goes at the end, therefore . . .
*/
text_compared = ciphertext + bytes_encrypted - bytes_compared;
/* * Check to ensure that ciphertext does * NOT EQUAL known input message text * per FIPS PUB 140-2 directive.
*/ if (PORT_Memcmp(text_compared, known_message,
bytes_compared) == 0) { /* Set error to Invalid PRIVATE Key. */
PORT_SetError(SEC_ERROR_INVALID_KEY);
PORT_Free(ciphertext); return CKR_GENERAL_ERROR;
}
/* Prepare for decryption using the private key. */
crv = NSC_DecryptInit(hSession, &mech, privateKey->handle); if (crv != CKR_OK) {
PORT_Free(ciphertext); return crv;
}
memset(plaintext, 0, PAIRWISE_MESSAGE_LENGTH);
/* * Initialize bytes decrypted to be the * expected PAIRWISE_MESSAGE_LENGTH.
*/
bytes_decrypted = PAIRWISE_MESSAGE_LENGTH;
/* * Decrypt using the private key. * NOTE: No need to reset the * value of bytes_encrypted.
*/
crv = NSC_Decrypt(hSession,
ciphertext,
bytes_encrypted,
plaintext,
&bytes_decrypted);
/* Finished with ciphertext; free it. */
PORT_Free(ciphertext);
if (crv != CKR_OK) { return crv;
}
/* * Check to ensure that the output plaintext * does EQUAL known input message text.
*/ 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;
}
}
if (canSignVerify) { /* Determine length of signature. */ switch (keyType) { case CKK_RSA:
signature_length = modulusLen;
mech.mechanism = CKM_RSA_PKCS; break; case CKK_DSA:
signature_length = DSA_MAX_SIGNATURE_LEN;
pairwise_digest_length = subPrimeLen;
mech.mechanism = CKM_DSA; break; case CKK_EC:
signature_length = MAX_ECKEY_LEN * 2;
mech.mechanism = CKM_ECDSA; break; case CKK_EC_EDWARDS:
signature_length = ED25519_SIGN_LEN;
mech.mechanism = CKM_EDDSA; break; default: return CKR_DEVICE_ERROR;
}
/* 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-2 requires we verify that the resulting key is a valid key. * The easiest way to do this is to do a derive operation, which checks
* the validity of the key */
crv = NSC_DeriveKey(hSession, &mech, privateKey->handle, template, templateCount, &newKey); if (crv != CKR_OK) {
sftk_FreeAttribute(pubAttribute); return crv;
} /* FIPS requires full validation, but in fipx mode NSC_Derive * only does partial validation with approved primes, now handle
* full validation */ if (isFIPS && keyType == CKK_DH) {
SECItem pubKey;
SECItem prime;
SECItem subPrime; const SECItem *subPrimePtr = &subPrime;
pubKey.data = pubAttribute->attrib.pValue;
pubKey.len = pubAttribute->attrib.ulValueLen;
prime.data = subPrime.data = NULL;
prime.len = subPrime.len = 0;
crv = sftk_Attribute2SecItem(NULL, &prime, privateKey, CKA_PRIME); if (crv != CKR_OK) { goto done;
}
crv = sftk_Attribute2SecItem(NULL, &prime, privateKey, CKA_PRIME); /* we ignore the return code an only look at the length */ if (subPrime.len == 0) { /* subprime not supplied, In this case look it up. * This only works with approved primes, but in FIPS mode
* that's the only kine of prime that will get here */
subPrimePtr = sftk_VerifyDH_Prime(&prime, isFIPS); if (subPrimePtr == NULL) {
crv = CKR_GENERAL_ERROR; goto done;
}
} if (!KEA_Verify(&pubKey, &prime, (SECItem *)subPrimePtr)) {
crv = CKR_GENERAL_ERROR;
}
done:
SECITEM_ZfreeItem(&subPrime, PR_FALSE);
SECITEM_ZfreeItem(&prime, PR_FALSE);
} /* clean up before we return */
sftk_FreeAttribute(pubAttribute);
crv2 = NSC_DestroyObject(hSession, newKey); if (crv != CKR_OK) { return crv;
} if (crv2 != CKR_OK) { return crv2;
}
}
if (!slot) { return CKR_SESSION_HANDLE_INVALID;
} /* * now lets create an object to hang the attributes off of
*/
publicKey = sftk_NewObject(slot); /* fill in the handle later */ if (publicKey == NULL) { return CKR_HOST_MEMORY;
}
/* * load the template values into the publicKey
*/ 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;
} /* * now load the private key template
*/ 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;
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;
case CKM_NSS_KYBER_KEY_PAIR_GEN: case CKM_NSS_ML_KEM_KEY_PAIR_GEN:
sftk_DeleteAttributeType(privateKey, CKA_NSS_DB);
key_type = CKK_NSS_KYBER;
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;
}
/* * handle the base object cleanup for the public Key
*/
crv = sftk_handleObject(privateKey, session); if (crv != CKR_OK) {
sftk_FreeSession(session);
sftk_FreeObject(privateKey);
sftk_FreeObject(publicKey); return crv;
}
/* * 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_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));
} if (crv == CKR_OK && sftk_isTrue(publicKey, CKA_SENSITIVE)) {
crv = sftk_forceAttribute(publicKey, CKA_ALWAYS_SENSITIVE,
&cktrue, sizeof(CK_BBOOL));
} if (crv == CKR_OK && !sftk_isTrue(privateKey, CKA_EXTRACTABLE)) {
crv = sftk_forceAttribute(privateKey, CKA_NEVER_EXTRACTABLE,
&cktrue, sizeof(CK_BBOOL));
} if (crv == CKR_OK && !sftk_isTrue(publicKey, CKA_EXTRACTABLE)) {
crv = sftk_forceAttribute(publicKey, CKA_NEVER_EXTRACTABLE,
&cktrue, sizeof(CK_BBOOL));
}
/* 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;
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. */
crv = sftk_GetContext(hSession, &context, SFTK_ENCRYPT, PR_FALSE, NULL); if (crv != CKR_OK || !context) break; if (context->blockSize > 1) { unsignedint remainder = pText.len % context->blockSize; if (!context->doPad && remainder) { /* When wrapping secret keys with unpadded block ciphers, ** the keys are zero padded, if necessary, to fill out ** a full block.
*/
pText.len += context->blockSize - remainder;
pText.data = PORT_ZAlloc(pText.len); if (pText.data)
memcpy(pText.data, attribute->attrib.pValue,
attribute->attrib.ulValueLen); else {
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) {
CK_RV lcrv;
lcrv = sftk_GetContext(hSession, &context,
SFTK_ENCRYPT, PR_FALSE, NULL);
sftk_SetContextByType(session, SFTK_ENCRYPT, NULL); if (lcrv == CKR_OK && context) {
sftk_FreeContext(context);
}
}
if (pText.data != (unsignedchar *)attribute->attrib.pValue)
PORT_ZFree(pText.data, pText.len);
sftk_FreeAttribute(attribute); break;
}
/* decode the private key and any algorithm parameters */
rv = SEC_QuickDERDecodeItem(arena, lpk, keyTemplate, &pki->privateKey);
if (lpk->keyType == NSSLOWKEYECKey) { /* convert length in bits to length in bytes */
lpk->u.ec.publicValue.len >>= 3;
rv = SECITEM_CopyItem(arena,
&(lpk->u.ec.ecParams.DEREncoding),
&(pki->algorithm.parameters)); if (rv != SECSuccess) { goto loser;
}
}
if (rv != SECSuccess) { goto loser;
} if (paramDest && paramTemplate) {
rv = SEC_QuickDERDecodeItem(arena, paramDest, paramTemplate,
&(pki->algorithm.parameters)); if (rv != SECSuccess) { goto loser;
}
}
rv = SECFailure;
switch (lpk->keyType) { case NSSLOWKEYRSAKey:
keyType = CKK_RSA; if (sftk_hasAttribute(key, CKA_NSS_DB)) {
sftk_DeleteAttributeType(key, CKA_NSS_DB);
}
crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, sizeof(keyType)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_UNWRAP, &cktrue, sizeof(CK_BBOOL)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_DECRYPT, &cktrue, sizeof(CK_BBOOL)); 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, &cktrue, sizeof(CK_BBOOL)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_MODULUS,
sftk_item_expand(&lpk->u.rsa.modulus)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_PUBLIC_EXPONENT,
sftk_item_expand(&lpk->u.rsa.publicExponent)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_PRIVATE_EXPONENT,
sftk_item_expand(&lpk->u.rsa.privateExponent)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_PRIME_1,
sftk_item_expand(&lpk->u.rsa.prime1)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_PRIME_2,
sftk_item_expand(&lpk->u.rsa.prime2)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_EXPONENT_1,
sftk_item_expand(&lpk->u.rsa.exponent1)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_EXPONENT_2,
sftk_item_expand(&lpk->u.rsa.exponent2)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_COEFFICIENT,
sftk_item_expand(&lpk->u.rsa.coefficient)); break; case NSSLOWKEYDSAKey:
keyType = CKK_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, &cktrue, sizeof(CK_BBOOL)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_PRIME,
sftk_item_expand(&lpk->u.dsa.params.prime)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_SUBPRIME,
sftk_item_expand(&lpk->u.dsa.params.subPrime)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_BASE,
sftk_item_expand(&lpk->u.dsa.params.base)); if (crv != CKR_OK) break;
crv = sftk_AddAttributeType(key, CKA_VALUE,
sftk_item_expand(&lpk->u.dsa.privateValue)); 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;
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, &cktrue, 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;
} /* * now lets create an object to hang the attributes off of
*/
key = sftk_NewObject(slot); /* fill in the handle later */ if (key == NULL) { return CKR_HOST_MEMORY;
}
/* * load the template values into the object
*/ 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 * this assumes the unwrapped key is never larger than the
* 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 */
key->isFIPS = session->lastOpWasFIPS;
/* * handle the base object stuff
*/
crv = sftk_handleObject(key, session);
*phKey = key->handle;
sftk_FreeSession(session);
sftk_FreeObject(key);
return crv;
}
/* * The SSL key gen mechanism create's lots of keys. This function handles the * details of each of these key creation.
*/ static CK_RV
sftk_buildSSLKey(CK_SESSION_HANDLE hSession, SFTKObject *baseKey,
PRBool isMacKey, unsignedchar *keyBlock, unsignedint keySize,
CK_OBJECT_HANDLE *keyHandle)
{
SFTKObject *key;
SFTKSession *session;
CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
CK_BBOOL cktrue = CK_TRUE;
CK_BBOOL ckfalse = CK_FALSE;
CK_RV crv = CKR_HOST_MEMORY;
/* * now lets create an object to hang the attributes off of
*/
*keyHandle = CK_INVALID_HANDLE;
key = sftk_NewObject(baseKey->slot); if (key == NULL) return CKR_HOST_MEMORY;
sftk_narrowToSessionObject(key)->wasDerived = PR_TRUE;
/* * if there is an error, we need to free the keys we already created in SSL * This is the routine that will do it..
*/ staticvoid
sftk_freeSSLKeys(CK_SESSION_HANDLE session,
CK_SSL3_KEY_MAT_OUT *returnedMaterial)
{ if (returnedMaterial->hClientMacSecret != CK_INVALID_HANDLE) {
NSC_DestroyObject(session, returnedMaterial->hClientMacSecret);
} if (returnedMaterial->hServerMacSecret != CK_INVALID_HANDLE) {
NSC_DestroyObject(session, returnedMaterial->hServerMacSecret);
} if (returnedMaterial->hClientKey != CK_INVALID_HANDLE) {
NSC_DestroyObject(session, returnedMaterial->hClientKey);
} if (returnedMaterial->hServerKey != CK_INVALID_HANDLE) {
NSC_DestroyObject(session, returnedMaterial->hServerKey);
}
}
/* * when deriving from sensitive and extractable keys, we need to preserve some * of the semantics in the derived key. This helper routine maintains these * semantics.
*/ static CK_RV
sftk_DeriveSensitiveCheck(SFTKObject *baseKey, SFTKObject *destKey,
PRBool canBeData)
{
PRBool hasSensitive;
PRBool sensitive = PR_FALSE;
CK_BBOOL bFalse = CK_FALSE;
PRBool hasExtractable;
PRBool extractable = PR_TRUE;
CK_BBOOL bTrue = CK_TRUE;
CK_RV crv = CKR_OK;
SFTKAttribute *att;
PRBool isData = PR_TRUE;
if (canBeData) {
CK_OBJECT_CLASS objClass;
/* 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, * but handleObject always forces this attributes, so we would need to do
* something special. */ return CKR_OK;
}
/* * make known fixed PKCS #11 key types to their sizes in bytes
*/ unsignedlong
sftk_MapKeySize(CK_KEY_TYPE keyType)
{ switch (keyType) { case CKK_CDMF: return 8; case CKK_DES: return 8; case CKK_DES2: return 16; case CKK_DES3: return 24; /* IDEA and CAST need to be added */ default: break;
} return 0;
}
/* Inputs: * key_len: Length of derived key to be generated. * SharedSecret: a shared secret that is the output of a key agreement primitive. * SharedInfo: (Optional) some data shared by the entities computing the secret key. * SharedInfoLen: the length in octets of SharedInfo * Hash: The hash function to be used in the KDF * HashLen: the length in octets of the output of Hash * Output: * key: Pointer to a buffer containing derived key, if return value is SECSuccess.
*/ static CK_RV
sftk_compute_ANSI_X9_63_kdf(CK_BYTE **key, CK_ULONG key_len, SECItem *SharedSecret,
CK_BYTE_PTR SharedInfo, CK_ULONG SharedInfoLen,
SECStatus Hash(unsignedchar *, constunsignedchar *, PRUint32),
CK_ULONG HashLen)
{ unsignedchar *buffer = NULL, *output_buffer = NULL;
PRUint32 buffer_len, max_counter, i;
SECStatus rv;
CK_RV crv;
/* Check that key_len isn't too long. The maximum key length could be * greatly increased if the code below did not limit the 4-byte counter
* 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;
}
/* HKDF-Extract(salt, base key value) */ if (params->bExtract) {
CK_BYTE *salt;
CK_ULONG saltLen;
HMACContext *hmac; unsignedint bufLen;
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 && (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);
}
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;
}
if (!slot) { return CKR_SESSION_HANDLE_INVALID;
} if (!pMechanism) { return CKR_MECHANISM_PARAM_INVALID;
}
CK_MECHANISM_TYPE mechanism = pMechanism->mechanism;
/* * now lets create an object to hang the attributes off of
*/ 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);
/* * load the template values into the object
*/ 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);
sftk_FreeSession(session); /* is this eventually succeeds, lastOpWasFIPS will be set the resulting key's
* FIPS state below. */
session->lastOpWasFIPS = PR_FALSE; 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;
}
}
key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_DERIVE, sourceKey);
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;
}
/* First do the consistency checks */ if ((mechanism == CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE) &&
(att->attrib.ulValueLen != SSL3_PMS_LENGTH)) {
crv = CKR_KEY_TYPE_INCONSISTENT; break;
}
att2 = sftk_FindAttribute(sourceKey, CKA_KEY_TYPE); if ((att2 == NULL) ||
(*(CK_KEY_TYPE *)att2->attrib.pValue != CKK_GENERIC_SECRET)) { if (att2)
sftk_FreeAttribute(att2);
crv = CKR_KEY_FUNCTION_NOT_PERMITTED; break;
}
sftk_FreeAttribute(att2); if (keyType != CKK_GENERIC_SECRET) {
crv = CKR_KEY_FUNCTION_NOT_PERMITTED; break;
} if ((keySize != 0) && (keySize != SSL3_MASTER_SECRET_LENGTH)) {
crv = CKR_KEY_FUNCTION_NOT_PERMITTED; break;
}
/* Do the key derivation */
pms.data = (unsignedchar *)att->attrib.pValue;
pms.len = att->attrib.ulValueLen;
seed.data = ems_params->pSessionHash;
seed.len = ems_params->ulSessionHashLen;
master.data = key_block;
master.len = SSL3_MASTER_SECRET_LENGTH; if (ems_params->prfHashMechanism == CKM_TLS_PRF) { /* * In this case, the session hash is the concatenation of SHA-1 * and MD5, so it should be 36 bytes long.
*/ if (seed.len != MD5_LENGTH + SHA1_LENGTH) {
crv = CKR_TEMPLATE_INCONSISTENT; 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];
/* * clear out our returned keys so we can recover on failure
*/
ssl3_keys_out = ssl3_keys->pReturnedKeyMaterial;
ssl3_keys_out->hClientMacSecret = CK_INVALID_HANDLE;
ssl3_keys_out->hServerMacSecret = CK_INVALID_HANDLE;
ssl3_keys_out->hClientKey = CK_INVALID_HANDLE;
ssl3_keys_out->hServerKey = CK_INVALID_HANDLE;
/* * How much key material do we need?
*/
macSize = ssl3_keys->ulMacSizeInBits / 8;
effKeySize = ssl3_keys->ulKeySizeInBits / 8;
IVSize = ssl3_keys->ulIVSizeInBits / 8; if (keySize == 0) {
effKeySize = keySize;
}
/* bIsExport must be false. */ if (ssl3_keys->bIsExport) {
MD5_DestroyContext(md5, PR_TRUE);
SHA1_DestroyContext(sha, PR_TRUE);
PORT_Memset(srcrdata, 0, sizeof srcrdata);
crv = CKR_MECHANISM_PARAM_INVALID; break;
}
/* * generate the key material: This looks amazingly similar to the * PMS code, and is clearly crying out for a function to provide it.
*/ if (isTLS) {
SECStatus status;
SECItem srcr = { siBuffer, NULL, 0 };
SECItem keyblk = { siBuffer, NULL, 0 };
SECItem master = { siBuffer, NULL, 0 };
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, isFIPS); if (subPrime == NULL) {
SECItem dhSubPrime; /* If the caller set the subprime value, it means that * either the caller knows the subprime value and wants us * to validate the key against the subprime, or that the * caller wants us to verify that the prime is a safe prime
* 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 * return of len = 0 and a failure to find a subrime the same * NOTE: we free the subprime in both cases depending on
* 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 * checks for safe primes. If so we only need to check
* 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. As long as y isn't 0, 1, or -1 mod p, * any other y is safe. Only do the full check for * non-safe primes, except in FIPS mode we need * to do this check on all primes in which
* 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);
if (rv != SECSuccess) {
crv = sftk_MapCryptError(PORT_GetError()); break;
}
/* * apply the kdf function.
*/ if (mechParams->kdf == CKD_NULL) { /* * 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;
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;
tmp.len = secretlen;
}
/* * if keySize is supplied, then we are generating a key of a specific * length. This is done by taking the least significant 'keySize' * bytes from the unsigned value calculated by ECDH. Note: this may * mean padding temp with extra leading zeros from what ECDH_Derive * already returned (which itself may contain leading zeros).
*/ if (keySize) { if (secretlen < keySize) {
keyData = PORT_ZAlloc(keySize); if (!keyData) {
PORT_ZFree(tmp.data, tmp.len);
crv = CKR_HOST_MEMORY; break;
}
PORT_Memcpy(&keyData[keySize - secretlen], secret, secretlen);
secret = keyData;
} else {
secret += (secretlen - keySize);
}
secretlen = 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 able to derive non-sensitive keys while allowing the ROUND1 and ROUND2 keys to be sensitive (which they always are, since they are in the CKO_PRIVATE_KEY class). The caller must include CKA_SENSITIVE in the template in order for the resultant keyblock key to be 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);
PORT_Assert(sessKey); /* get the session */
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 * operation in a session. * NOTE: This code only works for digest functions for now. eventually need * to add full flatten/resurect to our state stuff so that all types of state
* 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 * operation in a session. This is coded like it can restore lots of
* 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;
context = sftk_ReturnContextByType(session, type);
sftk_SetContextByType(session, type, NULL); if (context) {
sftk_FreeContext(context);
}
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;
crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE,
NULL); if (crv != CKR_OK) 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;
}
/* NSC_DigestKey continues a multi-part message-digesting operation, * by digesting the value of a secret key as part of the data already digested.
*/
CK_RV
NSC_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey)
{
SFTKSession *session = NULL;
SFTKObject *key = NULL;
SFTKAttribute *att;
CK_RV crv;
CHECK_FORK();
session = sftk_SessionFromHandle(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
/* 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);
sftk_FreeObject(key); if (!att) { return CKR_KEY_HANDLE_INVALID;
}
crv = NSC_DigestUpdate(hSession, (CK_BYTE_PTR)att->attrib.pValue,
att->attrib.ulValueLen);
sftk_FreeAttribute(att); return crv;
}
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.351Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-05-01)
¤
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.