/* 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 the Symkey wrapper and the PKCS context * Interfaces.
*/
staticvoid
pk11_EnterKeyMonitor(PK11SymKey *symKey)
{ if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe))
PK11_EnterSlotMonitor(symKey->slot);
}
staticvoid
pk11_ExitKeyMonitor(PK11SymKey *symKey)
{ if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe))
PK11_ExitSlotMonitor(symKey->slot);
}
/* * pk11_getKeyFromList returns a symKey that has a session (if needSession * was specified), or explicitly does not have a session (if needSession * was not specified).
*/ static PK11SymKey *
pk11_getKeyFromList(PK11SlotInfo *slot, PRBool needSession)
{
PK11SymKey *symKey = NULL;
PZ_Lock(slot->freeListLock); /* own session list are symkeys with sessions that the symkey owns.
* 'most' symkeys will own their own session. */ if (needSession) { if (slot->freeSymKeysWithSessionHead) {
symKey = slot->freeSymKeysWithSessionHead;
slot->freeSymKeysWithSessionHead = symKey->next;
slot->keyCount--;
}
} /* if we don't need a symkey with its own session, or we couldn't find
* one on the owner list, get one from the non-owner free list. */ if (!symKey) { if (slot->freeSymKeysHead) {
symKey = slot->freeSymKeysHead;
slot->freeSymKeysHead = symKey->next;
slot->keyCount--;
}
}
PZ_Unlock(slot->freeListLock); if (symKey) {
symKey->next = NULL; if (!needSession) { return symKey;
} /* if we are getting an owner key, make sure we have a valid session. * session could be invalid if the token has been removed or because
* we got it from the non-owner free list */ if ((symKey->series != slot->series) ||
(symKey->session == CK_INVALID_HANDLE)) {
symKey->session = pk11_GetNewSession(slot, &symKey->sessionOwner);
}
PORT_Assert(symKey->session != CK_INVALID_HANDLE); if (symKey->session != CK_INVALID_HANDLE) return symKey;
PK11_FreeSymKey(symKey); /* if we are here, we need a session, but couldn't get one, it's * unlikely we pk11_GetNewSession will succeed if we call it a second
* time. */ return NULL;
}
/* * create a symetric key: * Slot is the slot to create the key in. * type is the mechanism type * owner is does this symKey structure own it's object handle (rare * that this is false). * needSession means the returned symKey will return with a valid session * allocated already.
*/ static PK11SymKey *
pk11_CreateSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
PRBool owner, PRBool needSession, void *wincx)
{
if (symKey == NULL) { return NULL;
} /* if needSession was specified, make sure we have a valid session. * callers which specify needSession as false should do their own
* check of the session before returning the symKey */ if (needSession && symKey->session == CK_INVALID_HANDLE) {
PK11_FreeSymKey(symKey);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return NULL;
}
/* adopt the parent's session */ /* This is only used by SSL. What we really want here is a session * structure with a ref count so the session goes away only after all the
* keys do. */ if (!needSession) {
symKey->sessionOwner = PR_FALSE;
symKey->session = parent->session;
symKey->parent = PK11_ReferenceSymKey(parent); /* This is the only case where pk11_CreateSymKey does not explicitly * check symKey->session. We need to assert here to make sure.
* the session isn't invalid. */
PORT_Assert(parent->session != CK_INVALID_HANDLE); if (parent->session == CK_INVALID_HANDLE) {
PK11_FreeSymKey(symKey);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return NULL;
}
}
return symKey;
}
/* * Restore a symmetric wrapping key that was saved using PK11_SetWrapKey. * * This function is provided for ABI compatibility; see PK11_SetWrapKey below.
*/
PK11SymKey *
PK11_GetWrapKey(PK11SlotInfo *slot, int wrap, CK_MECHANISM_TYPE type, int series, void *wincx)
{
PK11SymKey *symKey = NULL;
CK_OBJECT_HANDLE keyHandle;
PK11_EnterSlotMonitor(slot); if (slot->series != series ||
slot->refKeys[wrap] == CK_INVALID_HANDLE) {
PK11_ExitSlotMonitor(slot); return NULL;
}
if (type == CKM_INVALID_MECHANISM) {
type = slot->wrapMechanism;
}
/* * This function sets an attribute on the current slot with a wrapping key. The * data saved is ephemeral; it needs to be run every time the program is * invoked. * * Since NSS 3.45, this function is marginally more thread safe. It uses the * slot lock (if present) and fails silently if a value is already set. Use * PK11_GetWrapKey() after calling this function to get the current wrapping key * in case there was an update on another thread. * * Either way, using this function is inadvisable. It's provided for ABI * compatibility only.
*/ void
PK11_SetWrapKey(PK11SlotInfo *slot, int wrap, PK11SymKey *wrapKey)
{
PK11_EnterSlotMonitor(slot); if (wrap >= 0) {
size_t uwrap = (size_t)wrap; if (uwrap < PR_ARRAY_SIZE(slot->refKeys) &&
slot->refKeys[uwrap] == CK_INVALID_HANDLE) { /* save the handle and mechanism for the wrapping key */ /* mark the key and session as not owned by us so they don't get * freed when the key goes way... that lets us reuse the key
* later */
slot->refKeys[uwrap] = wrapKey->objectID;
wrapKey->owner = PR_FALSE;
wrapKey->sessionOwner = PR_FALSE;
slot->wrapMechanism = wrapKey->type;
}
}
PK11_ExitSlotMonitor(slot);
}
/* * figure out if a key is still valid or if it is stale.
*/
PRBool
PK11_VerifyKeyOK(PK11SymKey *key)
{ if (!PK11_IsPresent(key->slot)) { return PR_FALSE;
} return (PRBool)(key->series == key->slot->series);
}
/* CKA_NSS_MESSAGE is a fake operation to distinguish between * Normal Encrypt/Decrypt and MessageEncrypt/Decrypt. Don't try to set
* it as a real attribute */ if ((operation & CKA_NSS_MESSAGE_MASK) == CKA_NSS_MESSAGE) { /* Message is or'd with a real Attribute (CKA_ENCRYPT, CKA_DECRYPT),
* etc. Strip out the real attribute here */
operation &= ~CKA_NSS_MESSAGE_MASK;
}
keyType = PK11_GetKeyType(type, key->len);
symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, PR_FALSE,
keyTemplate, templateCount, key, wincx); return symKey;
} /* Import a PKCS #11 data object and return it as a key. This key is
* only useful in a limited number of mechanisms, such as HKDF. */
PK11SymKey *
PK11_ImportDataKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, PK11Origin origin,
CK_ATTRIBUTE_TYPE operation, SECItem *key, void *wincx)
{
CK_OBJECT_CLASS ckoData = CKO_DATA;
CK_ATTRIBUTE template[2] = { { CKA_CLASS, (CK_BYTE_PTR)&ckoData, sizeof(ckoData) },
{ CKA_VALUE, (CK_BYTE_PTR)key->data, key->len } };
CK_OBJECT_HANDLE handle;
PK11GenericObject *genObject;
genObject = PK11_CreateGenericObject(slot, template, PR_ARRAY_SIZE(template), PR_FALSE); if (genObject == NULL) { return NULL;
}
handle = PK11_GetObjectHandle(PK11_TypeGeneric, genObject, NULL); /* A note about ownership of the PKCS #11 handle: * PK11_CreateGenericObject() will not destroy the object it creates * on Free, For that you want PK11_CreateManagedGenericObject(). * Below we import the handle into the symKey structure. We pass * PR_TRUE as the owner so that the symKey will destroy the object
* once it's freed. This is why it's safe to destroy genObject now. */
PK11_DestroyGenericObject(genObject); if (handle == CK_INVALID_HANDLE) { return NULL;
} return PK11_SymKeyFromHandle(slot, NULL, origin, type, handle, PR_TRUE, wincx);
}
/* CKA_NSS_MESSAGE is a fake operation to distinguish between * Normal Encrypt/Decrypt and MessageEncrypt/Decrypt. Don't try to set
* it as a real attribute */ if ((operation & CKA_NSS_MESSAGE_MASK) == CKA_NSS_MESSAGE) { /* Message is or'd with a real Attribute (CKA_ENCRYPT, CKA_DECRYPT),
* etc. Strip out the real attribute here */
operation &= ~CKA_NSS_MESSAGE_MASK;
}
/* * extract a symmetric key value. NOTE: if the key is sensitive, we will * not be able to do this operation. This function is used to move
* keys from one token to another */
SECStatus
PK11_ExtractKeyValue(PK11SymKey *symKey)
{
SECStatus rv;
if (symKey == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure;
}
if (symKey->data.data != NULL) { if (symKey->size == 0) {
symKey->size = symKey->data.len;
} return SECSuccess;
}
if (symKey->slot == NULL) {
PORT_SetError(SEC_ERROR_INVALID_KEY); return SECFailure;
}
/* This symbol is exported for backward compatibility. */
SECItem *
__PK11_GetKeyData(PK11SymKey *symKey)
{ return PK11_GetKeyData(symKey);
}
/* * PKCS #11 key Types with predefined length
*/ unsignedint
pk11_GetPredefinedKeyLength(CK_KEY_TYPE keyType)
{ int length = 0; switch (keyType) { case CKK_DES:
length = 8; break; case CKK_DES2:
length = 16; break; case CKK_DES3:
length = 24; break; case CKK_SKIPJACK:
length = 10; break; case CKK_BATON:
length = 20; break; case CKK_JUNIPER:
length = 20; break; default: break;
} return length;
}
/* return the keylength if possible. '0' if not */ unsignedint
PK11_GetKeyLength(PK11SymKey *key)
{
CK_KEY_TYPE keyType;
if (key->size != 0) return key->size;
/* First try to figure out the key length from its type */
keyType = PK11_ReadULongAttribute(key->slot, key->objectID, CKA_KEY_TYPE);
key->size = pk11_GetPredefinedKeyLength(keyType); if ((keyType == CKK_GENERIC_SECRET) &&
(key->type == CKM_SSL3_PRE_MASTER_KEY_GEN)) {
key->size = 48;
}
if (key->size != 0) return key->size;
if (key->data.data == NULL) {
PK11_ExtractKeyValue(key);
} /* key is probably secret. Look up its length */ /* this is new PKCS #11 version 2.0 functionality. */ if (key->size == 0) {
CK_ULONG keyLength;
/* return the strength of a key. This is different from length in that * 1) it returns the size in bits, and 2) it returns only the secret portions * of the key minus any checksums or parity.
*/ unsignedint
PK11_GetKeyStrength(PK11SymKey *key, SECAlgorithmID *algid)
{ int size = 0;
CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; /* RC2 only */
SECItem *param = NULL; /* RC2 only */
CK_RC2_CBC_PARAMS *rc2_params = NULL; /* RC2 ONLY */ unsignedint effectiveBits = 0; /* RC2 ONLY */
switch (PK11_GetKeyType(key->type, 0)) { case CKK_CDMF: return 40; case CKK_DES: return 56; case CKK_DES3: case CKK_DES2:
size = PK11_GetKeyLength(key); if (size == 16) { /* double des */ return 112; /* 16*7 */
} return 168; /* * RC2 has is different than other ciphers in that it allows the user * to deprecating keysize while still requiring all the bits for the * original key. The info * on what the effective key strength is in the parameter for the key. * In S/MIME this parameter is stored in the DER encoded algid. In Our * other uses of RC2, effectiveBits == keyBits, so this code functions * correctly without an algid.
*/ case CKK_RC2: /* if no algid was provided, fall through to default */ if (!algid) { break;
} /* verify that the algid is for RC2 */
mechanism = PK11_AlgtagToMechanism(SECOID_GetAlgorithmTag(algid)); if ((mechanism != CKM_RC2_CBC) && (mechanism != CKM_RC2_ECB)) { break;
}
/* now get effective bits from the algorithm ID. */
param = PK11_ParamFromAlgid(algid); /* if we couldn't get memory just use key length */ if (param == NULL) { break;
}
/* we have effective bits, is and allocated memory is free, now
* we need to return the smaller of effective bits and keysize */
size = PK11_GetKeyLength(key); if ((unsignedint)size * 8 > effectiveBits) { return effectiveBits;
}
return size * 8; /* the actual key is smaller, the strength can't be
* greater than the actual key size */
/* * The next three utilities are to deal with the fact that a given operation * may be a multi-slot affair. This creates a new key object that is copied * into the new slot.
*/
PK11SymKey *
pk11_CopyToSlotPerm(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
CK_ATTRIBUTE_TYPE operation, CK_FLAGS flags,
PRBool isPerm, PK11SymKey *symKey)
{
SECStatus rv;
PK11SymKey *newKey = NULL;
/* Extract the raw key data if possible */ if (symKey->data.data == NULL) {
rv = PK11_ExtractKeyValue(symKey); /* KEY is sensitive, we're try key exchanging it. */ if (rv != SECSuccess) { return pk11_KeyExchange(slot, type, operation,
flags, isPerm, symKey);
}
}
/* * Make sure the slot we are in is the correct slot for the operation * by verifying that it supports all of the specified mechanism types.
*/
PK11SymKey *
pk11_ForceSlotMultiple(PK11SymKey *symKey, CK_MECHANISM_TYPE *type, int mechCount, CK_ATTRIBUTE_TYPE operation)
{
PK11SlotInfo *slot = symKey->slot;
PK11SymKey *newKey = NULL;
PRBool needToCopy = PR_FALSE; int i;
if (slot == NULL) {
needToCopy = PR_TRUE;
} else {
i = 0; while ((i < mechCount) && (needToCopy == PR_FALSE)) { if (!PK11_DoesMechanism(slot, type[i])) {
needToCopy = PR_TRUE;
}
i++;
}
}
/* * Make sure the slot we are in is the correct slot for the operation
*/
PK11SymKey *
pk11_ForceSlot(PK11SymKey *symKey, CK_MECHANISM_TYPE type,
CK_ATTRIBUTE_TYPE operation)
{ return pk11_ForceSlotMultiple(symKey, &type, 1, operation);
}
/* * Use the token to generate a key. * * keySize must be 'zero' for fixed key length algorithms. A nonzero * keySize causes the CKA_VALUE_LEN attribute to be added to the template * for the key. Most PKCS #11 modules fail if you specify the CKA_VALUE_LEN * attribute for keys with fixed length. The exception is DES2. If you * select a CKM_DES3_CBC mechanism, this code will not add the CKA_VALUE_LEN * parameter and use the key size to determine which underlying DES keygen * function to use (CKM_DES2_KEY_GEN or CKM_DES3_KEY_GEN). * * keyType must be -1 for most algorithms. Some PBE algorthims cannot * determine the correct key type from the mechanism or the parameters, * so key type must be specified. Other PKCS #11 mechanisms may do so in * the future. Currently there is no need to export this publically. * Keep it private until there is a need in case we need to expand the * keygen parameters again... * * CK_FLAGS flags: key operation flags * PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags
*/
PK11SymKey *
pk11_TokenKeyGenWithFlagsAndKeyType(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
SECItem *param, CK_KEY_TYPE keyType, int keySize, SECItem *keyid,
CK_FLAGS opFlags, PK11AttrFlags attrFlags, void *wincx)
{
PK11SymKey *symKey;
CK_ATTRIBUTE genTemplate[MAX_TEMPL_ATTRS];
CK_ATTRIBUTE *attrs = genTemplate; int count = sizeof(genTemplate) / sizeof(genTemplate[0]);
CK_MECHANISM_TYPE keyGenType;
CK_BBOOL cktrue = CK_TRUE;
CK_BBOOL ckfalse = CK_FALSE;
CK_ULONG ck_key_size; /* only used for variable-length keys */
if (pk11_BadAttrFlags(attrFlags)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL;
}
if ((keySize != 0) && (type != CKM_DES3_CBC) &&
(type != CKM_DES3_CBC_PAD) && (type != CKM_DES3_ECB)) {
ck_key_size = keySize; /* Convert to PK11 type */
/* * Use the token to generate a key. - Public * * keySize must be 'zero' for fixed key length algorithms. A nonzero * keySize causes the CKA_VALUE_LEN attribute to be added to the template * for the key. Most PKCS #11 modules fail if you specify the CKA_VALUE_LEN * attribute for keys with fixed length. The exception is DES2. If you * select a CKM_DES3_CBC mechanism, this code will not add the CKA_VALUE_LEN * parameter and use the key size to determine which underlying DES keygen * function to use (CKM_DES2_KEY_GEN or CKM_DES3_KEY_GEN). * * CK_FLAGS flags: key operation flags * PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags
*/
PK11SymKey *
PK11_TokenKeyGenWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
SECItem *param, int keySize, SECItem *keyid, CK_FLAGS opFlags,
PK11AttrFlags attrFlags, void *wincx)
{ return pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, param, -1, keySize,
keyid, opFlags, attrFlags, wincx);
}
/* * Use the token to generate a key. keySize must be 'zero' for fixed key * length algorithms. A nonzero keySize causes the CKA_VALUE_LEN attribute * to be added to the template for the key. PKCS #11 modules fail if you * specify the CKA_VALUE_LEN attribute for keys with fixed length. * NOTE: this means to generate a DES2 key from this interface you must * specify CKM_DES2_KEY_GEN as the mechanism directly; specifying * CKM_DES3_CBC as the mechanism and 16 as keySize currently doesn't work.
*/
PK11SymKey *
PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param, int keySize, SECItem *keyid, PRBool isToken, void *wincx)
{
PK11SymKey *symKey;
PRBool weird = PR_FALSE; /* hack for fortezza */
CK_FLAGS opFlags = CKF_SIGN;
PK11AttrFlags attrFlags = 0;
/* Set the parameters for the key gen if provided */
mechanism.mechanism = keyGenType;
mechanism.pParameter = NULL;
mechanism.ulParameterLen = 0; if (param) {
mechanism.pParameter = param->data;
mechanism.ulParameterLen = param->len;
}
/* Get session and perform locking */ if (isToken) {
PK11_Authenticate(symKey->slot, PR_TRUE, wincx); /* Should always be original slot */
session = PK11_GetRWSession(symKey->slot);
symKey->owner = PR_FALSE;
} else {
session = symKey->session; if (session != CK_INVALID_HANDLE)
pk11_EnterKeyMonitor(symKey);
} if (session == CK_INVALID_HANDLE) {
PK11_FreeSymKey(symKey);
PORT_SetError(SEC_ERROR_BAD_DATA); return NULL;
}
/* This function does a straight public key wrap with the CKM_RSA_PKCS
* mechanism. */
SECStatus
PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
PK11SymKey *symKey, SECItem *wrappedKey)
{
CK_MECHANISM_TYPE inferred = pk11_mapWrapKeyType(pubKey->keyType); return PK11_PubWrapSymKeyWithMechanism(pubKey, inferred, NULL, symKey,
wrappedKey);
}
/* This function wraps a symmetric key with a public key, such as with the
* CKM_RSA_PKCS and CKM_RSA_PKCS_OAEP mechanisms. */
SECStatus
PK11_PubWrapSymKeyWithMechanism(SECKEYPublicKey *pubKey,
CK_MECHANISM_TYPE mechType, SECItem *param,
PK11SymKey *symKey, SECItem *wrappedKey)
{
PK11SlotInfo *slot;
CK_ULONG len = wrappedKey->len;
PK11SymKey *newKey = NULL;
CK_OBJECT_HANDLE id;
CK_MECHANISM mechanism;
PRBool owner = PR_TRUE;
CK_SESSION_HANDLE session;
CK_RV crv;
if (symKey == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure;
}
/* if this slot doesn't support the mechanism, go to a slot that does */
newKey = pk11_ForceSlot(symKey, mechType, CKA_ENCRYPT); if (newKey != NULL) {
symKey = newKey;
}
if (symKey->slot == NULL) {
PORT_SetError(SEC_ERROR_NO_MODULE); return SECFailure;
}
id = PK11_ImportPublicKey(slot, pubKey, PR_FALSE); if (id == CK_INVALID_HANDLE) { if (newKey) {
PK11_FreeSymKey(newKey);
} return SECFailure; /* Error code has been set. */
}
session = pk11_GetNewSession(slot, &owner); if (!owner || !(slot->isThreadSafe))
PK11_EnterSlotMonitor(slot);
crv = PK11_GETTAB(slot)->C_WrapKey(session, &mechanism,
id, symKey->objectID, wrappedKey->data, &len); if (!owner || !(slot->isThreadSafe))
PK11_ExitSlotMonitor(slot);
pk11_CloseSession(slot, session, owner); if (newKey) {
PK11_FreeSymKey(newKey);
}
/* * this little function uses the Encrypt function to wrap a key, just in * case we have problems with the wrap implementation for a token.
*/ static SECStatus
pk11_HandWrap(PK11SymKey *wrappingKey, SECItem *param, CK_MECHANISM_TYPE type,
SECItem *inKey, SECItem *outKey)
{
PK11SlotInfo *slot;
CK_ULONG len;
SECItem *data;
CK_MECHANISM mech;
PRBool owner = PR_TRUE;
CK_SESSION_HANDLE session;
CK_RV crv;
/* keys are almost always aligned, but if we get this far,
* we've gone above and beyond anyway... */
data = PK11_BlockData(inKey, PK11_GetBlockSize(type, param)); if (data == NULL) { if (!owner || !(slot->isThreadSafe))
PK11_ExitSlotMonitor(slot);
pk11_CloseSession(slot, session, owner);
PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure;
}
len = outKey->len;
crv = PK11_GETTAB(slot)->C_Encrypt(session, data->data, data->len,
outKey->data, &len); if (!owner || !(slot->isThreadSafe))
PK11_ExitSlotMonitor(slot);
pk11_CloseSession(slot, session, owner);
SECITEM_FreeItem(data, PR_TRUE);
outKey->len = len; if (crv != CKR_OK) {
PORT_SetError(PK11_MapError(crv)); return SECFailure;
} return SECSuccess;
}
/* * helper function which moves two keys into a new slot based on the * desired mechanism.
*/ static SECStatus
pk11_moveTwoKeys(CK_MECHANISM_TYPE mech,
CK_ATTRIBUTE_TYPE preferedOperation,
CK_ATTRIBUTE_TYPE movingOperation,
PK11SymKey *preferedKey, PK11SymKey *movingKey,
PK11SymKey **newPreferedKey, PK11SymKey **newMovingKey)
{
PK11SlotInfo *newSlot;
*newMovingKey = NULL;
*newPreferedKey = NULL;
/* * To do joint operations, we often need two keys in the same slot. * Usually the PKCS #11 wrappers handle this correctly (like for PK11_WrapKey), * but sometimes the wrappers don't know about mechanism specific keys in * the Mechanism params. This function makes sure the two keys are in the * same slot by copying one or both of the keys into a common slot. This * functions makes sure the slot can handle the target mechanism. If the copy * is warranted, this function will prefer to move the movingKey first, then * the preferedKey. If the keys are moved, the new keys are returned in * newMovingKey and/or newPreferedKey. The application is responsible * for freeing those keys once the operation is complete.
*/
SECStatus
PK11_SymKeysToSameSlot(CK_MECHANISM_TYPE mech,
CK_ATTRIBUTE_TYPE preferedOperation,
CK_ATTRIBUTE_TYPE movingOperation,
PK11SymKey *preferedKey, PK11SymKey *movingKey,
PK11SymKey **newPreferedKey, PK11SymKey **newMovingKey)
{ /* usually don't return new keys */
*newMovingKey = NULL;
*newPreferedKey = NULL; if (movingKey->slot == preferedKey->slot) {
/* this should be the most common case */ if ((preferedKey->slot != NULL) &&
PK11_DoesMechanism(preferedKey->slot, mech)) { return SECSuccess;
}
/* we are in the same slot, but it doesn't do the operation,
* move both keys to an appropriate target slot */ return pk11_moveTwoKeys(mech, preferedOperation, movingOperation,
preferedKey, movingKey,
newPreferedKey, newMovingKey);
}
/* keys are in different slot, try moving the moving key to the prefered
* key's slot */ if ((preferedKey->slot != NULL) &&
PK11_DoesMechanism(preferedKey->slot, mech)) {
*newMovingKey = pk11_CopyToSlot(preferedKey->slot, movingKey->type,
movingOperation, movingKey); if (*newMovingKey != NULL) { return SECSuccess;
}
} /* couldn't moving the moving key to the prefered slot, try moving
* the prefered key */ if ((movingKey->slot != NULL) &&
PK11_DoesMechanism(movingKey->slot, mech)) {
*newPreferedKey = pk11_CopyToSlot(movingKey->slot, preferedKey->type,
preferedOperation, preferedKey); if (*newPreferedKey != NULL) { return SECSuccess;
}
} /* Neither succeeded, but that could be that they were not in slots that * supported the operation, try moving both keys into a common slot that
* can do the operation. */ return pk11_moveTwoKeys(mech, preferedOperation, movingOperation,
preferedKey, movingKey,
newPreferedKey, newMovingKey);
}
/* * This function does a symetric based wrap.
*/
SECStatus
PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *param,
PK11SymKey *wrappingKey, PK11SymKey *symKey,
SECItem *wrappedKey)
{
PK11SlotInfo *slot;
CK_ULONG len = wrappedKey->len;
PK11SymKey *newSymKey = NULL;
PK11SymKey *newWrappingKey = NULL;
SECItem *param_save = NULL;
CK_MECHANISM mechanism;
PRBool owner = PR_TRUE;
CK_SESSION_HANDLE session;
CK_RV crv;
SECStatus rv;
/* force the keys into same slot */
rv = PK11_SymKeysToSameSlot(type, CKA_ENCRYPT, CKA_WRAP,
symKey, wrappingKey,
&newSymKey, &newWrappingKey); if (rv != SECSuccess) { /* Couldn't move the keys as desired, try to hand unwrap if possible */ if (symKey->data.data == NULL) {
rv = PK11_ExtractKeyValue(symKey); if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_NO_MODULE); return SECFailure;
}
} if (param == NULL) {
param_save = param = PK11_ParamFromIV(type, NULL);
}
rv = pk11_HandWrap(wrappingKey, param, type, &symKey->data, wrappedKey); if (param_save)
SECITEM_FreeItem(param_save, PR_TRUE); return rv;
} if (newSymKey) {
symKey = newSymKey;
} if (newWrappingKey) {
wrappingKey = newWrappingKey;
}
/* at this point both keys are in the same token */
slot = wrappingKey->slot;
mechanism.mechanism = type; /* use NULL IV's for wrapping */ if (param == NULL) {
param_save = param = PK11_ParamFromIV(type, NULL);
} if (param) {
mechanism.pParameter = param->data;
mechanism.ulParameterLen = param->len;
} else {
mechanism.pParameter = NULL;
mechanism.ulParameterLen = 0;
}
len = wrappedKey->len;
session = pk11_GetNewSession(slot, &owner); if (!owner || !(slot->isThreadSafe))
PK11_EnterSlotMonitor(slot);
crv = PK11_GETTAB(slot)->C_WrapKey(session, &mechanism,
wrappingKey->objectID, symKey->objectID,
wrappedKey->data, &len); if (!owner || !(slot->isThreadSafe))
PK11_ExitSlotMonitor(slot);
pk11_CloseSession(slot, session, owner);
rv = SECSuccess; if (crv != CKR_OK) { /* can't wrap it? try hand wrapping it... */ do { if (symKey->data.data == NULL) {
rv = PK11_ExtractKeyValue(symKey); if (rv != SECSuccess) break;
}
rv = pk11_HandWrap(wrappingKey, param, type, &symKey->data,
wrappedKey);
} while (PR_FALSE);
} else {
wrappedKey->len = len;
}
PK11_FreeSymKey(newSymKey);
PK11_FreeSymKey(newWrappingKey); if (param_save)
SECITEM_FreeItem(param_save, PR_TRUE); return rv;
}
/* * This Generates a new key based on a symetricKey
*/
PK11SymKey *
PK11_Derive(PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, SECItem *param,
CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize)
{ return PK11_DeriveWithTemplate(baseKey, derive, param, target, operation,
keySize, NULL, 0, PR_FALSE);
}
if (numAttrs > MAX_TEMPL_ATTRS) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL;
} /* CKA_NSS_MESSAGE is a fake operation to distinguish between * Normal Encrypt/Decrypt and MessageEncrypt/Decrypt. Don't try to set
* it as a real attribute */ if ((operation & CKA_NSS_MESSAGE_MASK) == CKA_NSS_MESSAGE) { /* Message is or'd with a real Attribute (CKA_ENCRYPT, CKA_DECRYPT),
* etc. Strip out the real attribute here */
operation &= ~CKA_NSS_MESSAGE_MASK;
}
/* first copy caller attributes in. */ for (templateCount = 0; templateCount < numAttrs; ++templateCount) {
*attrs++ = *userAttr++;
}
/* We only add the following attributes to the template if the caller ** didn't already supply them.
*/ if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_CLASS)) {
PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof keyClass);
attrs++;
} if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_KEY_TYPE)) {
keyType = PK11_GetKeyType(target, keySize);
PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof keyType);
attrs++;
} if (keySize > 0 &&
!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_VALUE_LEN)) {
valueLen = (CK_ULONG)keySize;
PK11_SETATTRS(attrs, CKA_VALUE_LEN, &valueLen, sizeof valueLen);
attrs++;
} if ((operation != CKA_FLAGS_ONLY) &&
!pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
PK11_SETATTRS(attrs, operation, &cktrue, sizeof cktrue);
attrs++;
}
/* move the key to a slot that can do the function */ if (!PK11_DoesMechanism(slot, derive)) { /* get a new base key & slot */
PK11SlotInfo *newSlot = PK11_GetBestSlot(derive, baseKey->cx);
/* Create a new key by concatenating base and data
*/ static PK11SymKey *
pk11_ConcatenateBaseAndData(PK11SymKey *base,
CK_BYTE *data, CK_ULONG dataLen, CK_MECHANISM_TYPE target,
CK_ATTRIBUTE_TYPE operation)
{
CK_KEY_DERIVATION_STRING_DATA mechParams;
SECItem param;
if (base == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL;
}
/* Create a new key whose value is the hash of tobehashed. * type is the mechanism for the derived key.
*/ static PK11SymKey *
pk11_HashKeyDerivation(PK11SymKey *toBeHashed,
CK_MECHANISM_TYPE hashMechanism, CK_MECHANISM_TYPE target,
CK_ATTRIBUTE_TYPE operation, CK_ULONG keySize)
{ return PK11_Derive(toBeHashed, hashMechanism, NULL, target, operation, keySize);
}
/* 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 (derivedKeySize > 254 * HashLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL;
}
/* Look for a slot that supports the mechanisms needed * to implement the ANSI X9.63 KDF as well as the * target mechanism.
*/
mechanismArray[0] = CKM_CONCATENATE_BASE_AND_DATA;
mechanismArray[1] = hashMechanism;
mechanismArray[2] = CKM_CONCATENATE_BASE_AND_KEY;
mechanismArray[3] = target;
for (counter = 1; counter <= maxCounter; counter++) { /* Concatenate shared_secret and buffer */
toBeHashed = pk11_ConcatenateBaseAndData(sharedSecret, buffer,
bufferLen, hashMechanism, operation); if (toBeHashed == NULL) { goto loser;
}
/* Hash value */ if (maxCounter == 1) { /* In this case the length of the key to be derived is * less than or equal to the length of the hash output. * So, the output of the hash operation will be the
* dervied key. */
hashOutput = pk11_HashKeyDerivation(toBeHashed, hashMechanism,
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.52 Sekunden
(vorverarbeitet)
¤
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.