/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* *ThisfileimplementstheSymkeywrapperandthePKCScontext *Interfaces.
*/
PR_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--;
}
}
PR_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. *sessioncouldbeinvalidifthetokenhasbeenremovedorbecause
* 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 *unlikelywepk11_GetNewSessionwillsucceedifwecallitasecond
* time. */ return NULL;
}
if (symKey == NULL) { return NULL;
} /* if needSession was specified, make sure we have a valid session. *callerswhichspecifyneedSessionasfalseshoulddotheirown
* 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 *structurewitharefcountsothesessiongoesawayonlyafterallthe
* 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 *checksymKey->session.Weneedtoassertheretomakesure.
* 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;
}
}
/* *Thisfunctionsetsanattributeonthecurrentslotwithawrappingkey.The *datasavedisephemeral;itneedstoberuneverytimetheprogramis *invoked. * *SinceNSS3.45,thisfunctionismarginallymorethreadsafe.Itusesthe *slotlock(ifpresent)andfailssilentlyifavalueisalreadyset.Use *PK11_GetWrapKey()aftercallingthisfunctiontogetthecurrentwrappingkey *incasetherewasanupdateonanotherthread. * *Eitherway,usingthisfunctionisinadvisable.It'sprovidedforABI *compatibilityonly.
*/ 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 *freedwhenthekeygoesway...thatletsusreusethekey
* later */
slot->refKeys[uwrap] = wrapKey->objectID;
wrapKey->owner = PR_FALSE;
wrapKey->sessionOwner = PR_FALSE;
slot->wrapMechanism = wrapKey->type;
}
}
PK11_ExitSlotMonitor(slot);
}
/* CKA_NSS_MESSAGE is a fake operation to distinguish between *NormalEncrypt/DecryptandMessageEncrypt/Decrypt.Don'ttrytoset
* 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;
}
/* CKA_NSS_MESSAGE is a fake operation to distinguish between *NormalEncrypt/DecryptandMessageEncrypt/Decrypt.Don'ttrytoset
* 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;
}
/* *extractasymmetrickeyvalue.NOTE:ifthekeyissensitive,wewill *notbeabletodothisoperation.Thisfunctionisusedtomove
* 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#11keyTypeswithpredefinedlength
*/ 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)itreturnsthesizeinbits,and2)itreturnsonlythesecretportions *ofthekeyminusanychecksumsorparity.
*/ 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: return40; case CKK_DES: return56; case CKK_DES3: case CKK_DES2:
size = PK11_GetKeyLength(key); if (size == 16) { /* double des */ return112; /* 16*7 */
} return168; /* *RC2hasisdifferentthanotherciphersinthatitallowstheuser *todeprecatingkeysizewhilestillrequiringallthebitsforthe *originalkey.Theinfo *onwhattheeffectivekeystrengthisintheparameterforthekey. *InS/MIMEthisparameterisstoredintheDERencodedalgid.InOur *otherusesofRC2,effectiveBits==keyBits,sothiscodefunctions *correctlywithoutanalgid.
*/ 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 */
/* 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);
}
}
/* 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 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 *supportedtheoperation,trymovingbothkeysintoacommonslotthat
* can do the operation. */ return pk11_moveTwoKeys(mech, preferedOperation, movingOperation,
preferedKey, movingKey,
newPreferedKey, newMovingKey);
}
/* 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;
}
if (numAttrs > MAX_TEMPL_ATTRS) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL;
} /* CKA_NSS_MESSAGE is a fake operation to distinguish between *NormalEncrypt/DecryptandMessageEncrypt/Decrypt.Don'ttrytoset
* 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'talreadysupplythem.
*/ 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;
}
/* Check that key_len isn't too long. The maximum key length could be *greatlyincreasedifthecodebelowdidnotlimitthe4-bytecounter
* to a maximum value of 255. */ if (derivedKeySize > 254 * HashLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL;
}
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 *lessthanorequaltothelengthofthehashoutput. *So,theoutputofthehashoperationwillbethe
* dervied key. */
hashOutput = pk11_HashKeyDerivation(toBeHashed, hashMechanism,
target, operation, keySize);
} else { /* In this case, the output of the hash operation will be
* concatenated with other data to create the derived key. */
hashOutput = pk11_HashKeyDerivation(toBeHashed, hashMechanism,
CKM_CONCATENATE_BASE_AND_KEY, operation, 0);
}
PK11_FreeSymKey(toBeHashed); if (hashOutput == NULL) { goto loser;
}
/* Append result to intermediate result, if necessary */
oldIntermediateResult = intermediateResult;
if (oldIntermediateResult == NULL) {
intermediateResult = hashOutput;
} else { if (counter == maxCounter) { /* This is the final concatenation, and so the output
* will be the derived key. */
intermediateResult =
pk11_ConcatenateBaseAndKey(oldIntermediateResult,
hashOutput, target, operation, keySize);
} else { /* The output of this concatenation will be concatenated
* with other data to create the derived key. */
intermediateResult =
pk11_ConcatenateBaseAndKey(oldIntermediateResult,
hashOutput, CKM_CONCATENATE_BASE_AND_KEY,
operation, 0);
}
/* CKA_NSS_MESSAGE is a fake operation to distinguish between *NormalEncrypt/DecryptandMessageEncrypt/Decrypt.Don'ttrytoset
* 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(target, keySize);
key_size = keySize; if (key_size == 0) { if ((key_size = pk11_GetPredefinedKeyLength(keyType))) {
templateCount--;
} else { /* sigh, some tokens can't figure this out and require
* CKA_VALUE_LEN to be set */
key_size = SHA1_LENGTH;
}
}
symKey->size = key_size;
/* old PKCS #11 spec was ambiguous on what needed to be passed,
* try this again with and encoded public key */ if (crv != CKR_OK && pk11_ECGetPubkeyEncoding(pubKey) != ECPoint_XOnly) {
SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
&pubKey->u.ec.publicValue,
SEC_ASN1_GET(SEC_OctetStringTemplate)); if (pubValue == NULL) {
PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS)); break;
}
mechParams->ulPublicDataLen = pubValue->len;
mechParams->pPublicData = pubValue->data;
if (crv == CKR_OK) return symKey;
PORT_SetError(PK11_MapError(crv));
} /* most keys are not KEA keys, so assume they are bad if they
* are not handled explicitly */ default:
PORT_SetError(SEC_ERROR_BAD_KEY); break;
}
PK11_FreeSymKey(symKey); return NULL;
}
/* Test for curves that are known to use a special encoding.
* Extend this function when additional curves are added. */ static ECPointEncoding
pk11_ECGetPubkeyEncoding(const SECKEYPublicKey *pubKey)
{
SECItem oid;
SECStatus rv;
PORTCheapArenaPool tmpArena;
ECPointEncoding encoding = ECPoint_Undefined;
/* decode the OID tag */
rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &oid,
SEC_ASN1_GET(SEC_ObjectIDTemplate),
&pubKey->u.ec.DEREncodedParams); if (rv == SECSuccess) {
SECOidTag tag = SECOID_FindOIDTag(&oid); switch (tag) { case SEC_OID_X25519: case SEC_OID_CURVE25519:
encoding = ECPoint_XOnly; break; case SEC_OID_SECG_EC_SECP256R1: case SEC_OID_SECG_EC_SECP384R1: case SEC_OID_SECG_EC_SECP521R1: default: /* unknown curve, default to uncompressed */
encoding = ECPoint_Uncompressed;
}
}
PORT_DestroyCheapArena(&tmpArena); return encoding;
}
/* Returns the size of the public key, or 0 if there
* is an error. */ static CK_ULONG
pk11_ECPubKeySize(SECKEYPublicKey *pubKey)
{
SECItem *publicValue = &pubKey->u.ec.publicValue;
ECPointEncoding encoding = pk11_ECGetPubkeyEncoding(pubKey); if (encoding == ECPoint_XOnly) { return publicValue->len;
} if (encoding == ECPoint_Uncompressed) { /* key encoded in uncompressed form */ return ((publicValue->len - 1) / 2);
} /* key encoding not recognized */ return0;
}
/* get our key Structure */
symKey = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, wincx); if (symKey == NULL) { return NULL;
} /* CKA_NSS_MESSAGE is a fake operation to distinguish between *NormalEncrypt/DecryptandMessageEncrypt/Decrypt.Don'ttrytoset
* 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;
}
/* old PKCS #11 spec was ambiguous on what needed to be passed,
* try this again with an encoded public key */ if (crv != CKR_OK) { /* For curves that only use X as public value and no encoding we don't
* have to try again. (Currently only Curve25519) */ if (pk11_ECGetPubkeyEncoding(pubKey) == ECPoint_XOnly) { goto loser;
}
SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
&pubKey->u.ec.publicValue,
SEC_ASN1_GET(SEC_OctetStringTemplate)); if (pubValue == NULL) { goto loser;
}
mechParams->ulPublicDataLen = pubValue->len;
mechParams->pPublicData = pubValue->data;
if (crv != CKR_OK) { /* old PKCS #11 spec was ambiguous on what needed to be passed,
* try this one final time with an encoded public key */
mechParams->ulPublicDataLen = pubValue->len;
mechParams->pPublicData = pubValue->data;
/* remove any VALUE_LEN parameters */ if (keyTemplate[templateCount - 1].type == CKA_VALUE_LEN) {
templateCount--;
}
/* keys are almost always aligned, but if we get this far,
* we've gone above and beyond anyway... */
outKey.data = (unsignedchar *)PORT_Alloc(inKey->len); if (outKey.data == NULL) {
PORT_SetError(SEC_ERROR_NO_MEMORY); if (crvp)
*crvp = CKR_HOST_MEMORY; return NULL;
}
len = inKey->len;
/* use NULL IV's for wrapping */
session = pk11_GetNewSession(slot, &owner); if (!owner || !(slot->isThreadSafe))
PK11_EnterSlotMonitor(slot);
crv = PK11_GETTAB(slot)->C_DecryptInit(session, mech, wrappingKey); if (crv != CKR_OK) { if (!owner || !(slot->isThreadSafe))
PK11_ExitSlotMonitor(slot);
pk11_CloseSession(slot, session, owner);
PORT_Free(outKey.data);
PORT_SetError(PK11_MapError(crv)); if (crvp)
*crvp = crv; return NULL;
}
crv = PK11_GETTAB(slot)->C_Decrypt(session, inKey->data, inKey->len,
outKey.data, &len); if (!owner || !(slot->isThreadSafe))
PK11_ExitSlotMonitor(slot);
pk11_CloseSession(slot, session, owner); if (crv != CKR_OK) {
PORT_Free(outKey.data);
PORT_SetError(PK11_MapError(crv)); if (crvp)
*crvp = crv; return NULL;
}
if (numAttrs > MAX_TEMPL_ATTRS) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL;
} /* CKA_NSS_MESSAGE is a fake operation to distinguish between *NormalEncrypt/DecryptandMessageEncrypt/Decrypt.Don'ttrytoset
* 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'talreadysupplythem.
*/ 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 ((operation != CKA_FLAGS_ONLY) &&
!pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
PK11_SETATTRS(attrs, operation, &cktrue, 1);
attrs++;
}
/* find out if we can do wrap directly. Because the RSA case if *very*
* common, cache the results for it. */ if ((wrapType == CKM_RSA_PKCS) && (slot->hasRSAInfo)) {
mechanism_info.flags = slot->RSAInfoFlags;
} else { if (!slot->isThreadSafe)
PK11_EnterSlotMonitor(slot);
crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID, wrapType,
&mechanism_info); if (!slot->isThreadSafe)
PK11_ExitSlotMonitor(slot); if (crv != CKR_OK) {
mechanism_info.flags = 0;
} if (wrapType == CKM_RSA_PKCS) {
slot->RSAInfoFlags = mechanism_info.flags;
slot->hasRSAInfo = PR_TRUE;
}
}
/* initialize the mechanism structure */
mechanism.mechanism = wrapType; /* use NULL IV's for wrapping */ if (param == NULL)
param = param_free = PK11_ParamFromIV(wrapType, NULL); if (param) {
mechanism.pParameter = param->data;
mechanism.ulParameterLen = param->len;
} else {
mechanism.pParameter = NULL;
mechanism.ulParameterLen = 0;
}
if ((mechanism_info.flags & CKF_DECRYPT) && !PK11_DoesMechanism(slot, target)) {
symKey = pk11_HandUnwrap(slot, wrappingKey, &mechanism, wrappedKey,
target, keyTemplate, templateCount, keySize,
wincx, &crv, isPerm); if (symKey) { if (param_free)
SECITEM_FreeItem(param_free, PR_TRUE); return symKey;
} /* *iftheRSAOPsimplyfailed,don'ttrytounwrapagain *withthismodule.
*/ if (crv == CKR_DEVICE_ERROR) { if (param_free)
SECITEM_FreeItem(param_free, PR_TRUE); return NULL;
} /* fall through, maybe they incorrectly set CKF_DECRYPT */
}
/* get our key Structure */
symKey = pk11_CreateSymKey(slot, target, !isPerm, PR_TRUE, wincx); if (symKey == NULL) { if (param_free)
SECITEM_FreeItem(param_free, PR_TRUE); return NULL;
}
/* unwrap a symmetric key with a private key with the given parameters. */
PK11SymKey *
PK11_PubUnwrapSymKeyWithMechanism(SECKEYPrivateKey *wrappingKey,
CK_MECHANISM_TYPE mechType, SECItem *param,
SECItem *wrappedKey, CK_MECHANISM_TYPE target,
CK_ATTRIBUTE_TYPE operation, int keySize)
{
PK11SlotInfo *slot = wrappingKey->pkcs11Slot;
if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey, CKA_PRIVATE)) {
PK11_HandlePasswordCheck(slot, wrappingKey->wincx);
}
/* first just try to set this key up for signing */
PK11_SETATTRS(&setTemplate, CKA_SIGN, &ckTrue, sizeof(ckTrue));
pk11_EnterKeyMonitor(originalKey);
crv = PK11_GETTAB(slot)->C_SetAttributeValue(originalKey->session,
originalKey->objectID, &setTemplate, 1);
pk11_ExitKeyMonitor(originalKey); if (crv == CKR_OK) { return PK11_ReferenceSymKey(originalKey);
}
/* nope, doesn't like it, use the pk11 copy object command */ return pk11_CopyToSlot(slot, mech, CKA_SIGN, originalKey);
}
/* the old API expected the parameter set as a parameter, the
* pkcs11 v3.2 gets it from the key */
kemParameterSet = PK11_ReadULongAttribute(slot,
pubKey->pkcs11ID,
CKA_NSS_PARAMETER_SET); if (kemParameterSet == CK_UNAVAILABLE_INFORMATION) {
kemParameterSet = PK11_ReadULongAttribute(slot,
pubKey->pkcs11ID,
CKA_PARAMETER_SET); if (kemParameterSet == CK_UNAVAILABLE_INFORMATION) {
crv = CKR_PUBLIC_KEY_INVALID; goto loser;
}
} /* The old interface only ever supported KYBER768 and MLKEM768 *SOMEversionsofRHELhasMLKEM1024support,ifwewantto *makesurethisworkswiththoseversionsofsoftoken(withouttheir *NSS)weshouldcheckthekemParamSetandsetthemechto *CKM_NSS_ML_KEMifthekeyisn'tKYBERandtheciphertestto
* MLKEM104_CIPHERTEXT_BYTES if the kemParmset is MLKEM1024 */
mech.mechanism = CKM_NSS_KYBER;
mech.pParameter = (CK_VOID_PTR)&kemParameterSet;
mech.ulParameterLen = sizeof(kemParameterSet);
ciphertextLen = KYBER768_CIPHERTEXT_BYTES;
/* the old API expected the parameter set as a parameter, the
* pkcs11 v3.2 gets it from the key */
CK_ULONG kemParameterSet = PK11_ReadULongAttribute(slot,
privKey->pkcs11ID,
CKA_NSS_PARAMETER_SET); if (kemParameterSet == CK_UNAVAILABLE_INFORMATION) {
kemParameterSet = PK11_ReadULongAttribute(slot,
privKey->pkcs11ID,
CKA_PARAMETER_SET); if (kemParameterSet == CK_UNAVAILABLE_INFORMATION) {
crv = CKR_KEY_HANDLE_INVALID; goto loser;
}
} /* The old interface only ever supported KYBER768 and MLKEM768 *SOMEversionsofRHELhasMLKEM1024support,ifwewantto *makesurethisworkswiththoseversionsofsoftoken(withouttheir *NSS)weshouldcheckthekemParamSetandsetthemechto *CKM_NSS_ML_KEMifthekeyisn'tKYBERandtheciphertestto
* MLKEM104_CIPHERTEXT_BYTES if the kemParmset is MLKEM1024 */
mech.mechanism = CKM_NSS_KYBER;
mech.pParameter = (CK_VOID_PTR)&kemParameterSet;
mech.ulParameterLen = sizeof(kemParameterSet);
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.62Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-11)
¤
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.