/* 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/. */ /* *DealwithPKCS#11Slots.
*/
PR_Lock(list->lock);
le = list->head; if (le != NULL)
(le)->refCount++;
PR_Unlock(list->lock); return le;
}
/* *NOTE:ifthiselementgetsdeleted,wecannolongersafelytraverseusing *it'spointers.Wecaneitherterminatetheloop,orrestartfromthe *beginning.Thisiscontrolledbytherestartoption.
*/
PK11SlotListElement *
PK11_GetNextSafe(PK11SlotList *list, PK11SlotListElement *le, PRBool restart)
{
PK11SlotListElement *new_le;
PR_Lock(list->lock);
new_le = le->next; if (le->next == NULL) { /* if the prev and next fields are NULL then either this element *hasbeenremovedandweneedtowalkthelistagain(ifrestart
* is true) or this was the only element on the list */ if ((le->prev == NULL) && restart && (list->head != le)) {
new_le = list->head;
}
} if (new_le)
new_le->refCount++;
PR_Unlock(list->lock);
PK11_FreeSlotListElement(list, le); return new_le;
}
for (le = PK11_GetFirstSafe(list); le;
le = PK11_GetNextSafe(list, le, PR_TRUE)) { if (le->slot == slot) return le;
} return NULL;
}
/* like PORT_Memcmp, return -1 if the version is less then the *passedinversion,0ifit'sequaltoand1ifit'sgreaterthan *thepassedinversion,PKCS#11returnsversionsin2places, *onceinthefunctiontableandonceinthemodule.theformer *isgoodtodetermineifitissafetocallanewfunction,
* the latter is good for module functionality */
PRInt32
PK11_CheckPKCS11Version(PK11SlotInfo *slot, CK_BYTE major, CK_BYTE minor,
PRBool useFunctionTable)
{
CK_VERSION version = useFunctionTable ? PK11_GETTAB(slot)->version : slot->module->cryptokiVersion;
if (version.major < major) { return -1;
} elseif (version.major > major) { return1;
} elseif (version.minor < minor) { return -1;
} elseif (version.minor > minor) { return1;
} /* if we get here, they must both be equal */ return0;
}
/* create a new reference to a slot so it doesn't go away */
PK11SlotInfo *
PK11_ReferenceSlot(PK11SlotInfo *slot)
{
PR_ATOMIC_INCREMENT(&slot->refCount); return slot;
}
/* Destroy all info on a slot we have built up */ void
PK11_DestroySlot(PK11SlotInfo *slot)
{ /* free up the cached keys and sessions */
PK11_CleanKeyList(slot);
/* free up all the sessions on this slot */ if (slot->functionList) {
PK11_GETTAB(slot)
->C_CloseAllSessions(slot->slotID);
}
if (slot->mechanismList) {
PORT_Free(slot->mechanismList);
} if (slot->profileList) {
PORT_Free(slot->profileList);
} if (slot->isThreadSafe && slot->sessionLock) {
PR_DestroyLock(slot->sessionLock);
}
slot->sessionLock = NULL; if (slot->freeListLock) {
PR_DestroyLock(slot->freeListLock);
slot->freeListLock = NULL;
} if (slot->nssTokenLock) {
PR_DestroyLock(slot->nssTokenLock);
slot->nssTokenLock = NULL;
}
/* finally Tell our parent module that we've gone away so it can unload */ if (slot->module) {
SECMOD_SlotDestroyModule(slot->module, PR_TRUE);
}
/* ok, well not quit finally... now we free the memory */
PORT_Free(slot);
}
/* We're all done with the slot, free it */ void
PK11_FreeSlot(PK11SlotInfo *slot)
{ if (PR_ATOMIC_DECREMENT(&slot->refCount) == 0) {
PK11_DestroySlot(slot);
}
}
/*********************************************************** *Functionstofindspecificslots.
***********************************************************/
PRBool
SECMOD_HasRootCerts(void)
{
SECMODModuleList *mlp;
SECMODModuleList *modules;
SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock(); int i;
PRBool found = PR_FALSE;
if (!moduleLock) {
PORT_SetError(SEC_ERROR_NOT_INITIALIZED); return found;
}
/* work through all the slots */
SECMOD_GetReadLock(moduleLock);
modules = SECMOD_GetDefaultModuleList(); for (mlp = modules; mlp != NULL; mlp = mlp->next) { for (i = 0; i < mlp->module->slotCount; i++) {
PK11SlotInfo *tmpSlot = mlp->module->slots[i]; if (PK11_IsPresent(tmpSlot)) { if (tmpSlot->hasRootCerts) {
found = PR_TRUE; break;
}
}
} if (found) break;
}
SECMOD_ReleaseReadLock(moduleLock);
/* return a system slot list based on mechanism */
PK11SlotList *
PK11_GetSlotList(CK_MECHANISM_TYPE type)
{ /* XXX a workaround for Bugzilla bug #55267 */ #ifdefined(HPUX) && defined(__LP64__) if (CKM_INVALID_MECHANISM == type) return NULL; #endif switch (type) { case CKM_SEED_CBC: case CKM_SEED_ECB: return &pk11_seedSlotList; case CKM_CAMELLIA_CBC: case CKM_CAMELLIA_ECB: return &pk11_camelliaSlotList; case CKM_AES_CBC: case CKM_AES_CCM: case CKM_AES_CTR: case CKM_AES_CTS: case CKM_AES_GCM: case CKM_AES_ECB: return &pk11_aesSlotList; case CKM_DES_CBC: case CKM_DES_ECB: case CKM_DES3_ECB: case CKM_DES3_CBC: return &pk11_desSlotList; case CKM_RC4: return &pk11_rc4SlotList; case CKM_RC5_CBC: return &pk11_rc5SlotList; case CKM_SHA_1: return &pk11_sha1SlotList; case CKM_SHA224: case CKM_SHA256: case CKM_SHA3_224: case CKM_SHA3_256: return &pk11_sha256SlotList; case CKM_SHA384: case CKM_SHA512: case CKM_SHA3_384: case CKM_SHA3_512: return &pk11_sha512SlotList; case CKM_MD5: return &pk11_md5SlotList; case CKM_MD2: return &pk11_md2SlotList; case CKM_RC2_ECB: case CKM_RC2_CBC: return &pk11_rc2SlotList; case CKM_RSA_PKCS: case CKM_RSA_PKCS_KEY_PAIR_GEN: case CKM_RSA_X_509: return &pk11_rsaSlotList; case CKM_DSA: return &pk11_dsaSlotList; case CKM_DH_PKCS_KEY_PAIR_GEN: case CKM_DH_PKCS_DERIVE: return &pk11_dhSlotList; case CKM_EDDSA: case CKM_EC_EDWARDS_KEY_PAIR_GEN: case CKM_ECDSA: case CKM_ECDSA_SHA1: case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */ case CKM_NSS_ECDHE_NO_PAIRWISE_CHECK_KEY_PAIR_GEN: case CKM_ECDH1_DERIVE: case CKM_NSS_KYBER_KEY_PAIR_GEN: /* Bug 1893029 */ case CKM_NSS_KYBER: case CKM_NSS_ML_KEM_KEY_PAIR_GEN: /* Bug 1893029 */ case CKM_NSS_ML_KEM: case CKM_ML_KEM_KEY_PAIR_GEN: /* Bug 1893029 */ case CKM_ML_KEM: return &pk11_ecSlotList; case CKM_SSL3_PRE_MASTER_KEY_GEN: case CKM_SSL3_MASTER_KEY_DERIVE: case CKM_SSL3_SHA1_MAC: case CKM_SSL3_MD5_MAC: return &pk11_sslSlotList; case CKM_TLS_MASTER_KEY_DERIVE: case CKM_TLS_KEY_AND_MAC_DERIVE: case CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256: return &pk11_tlsSlotList; case CKM_IDEA_CBC: case CKM_IDEA_ECB: return &pk11_ideaSlotList; case CKM_FAKE_RANDOM: return &pk11_randomSlotList; case CKM_ML_DSA: return &pk11_mldsaSlotList;
} return NULL;
}
/* *loadthestaticSlotInfostructuresusedtoselectaPKCS11slot. *preSlotInfohasalistofallthedefaultflagsfortheslotsonthis *module.
*/ void
PK11_LoadSlotList(PK11SlotInfo *slot, PK11PreSlotInfo *psi, int count)
{ int i;
for (i = 0; i < count; i++) { if (psi[i].slotID == slot->slotID) break;
}
/* if the slot is already disabled, don't load them into the *defaultslotlists.Wegetheresowecansavethedefault
* list value. */ if (slot->disabled) return;
/* if the user has disabled us, don't load us in */ if (slot->defaultFlags & PK11_DISABLE_FLAG) {
slot->disabled = PR_TRUE;
slot->reason = PK11_DIS_USER_SELECTED; /* free up sessions and things?? */ return;
}
for (i = 0; i < num_pk11_default_mechanisms; i++) { if (slot->defaultFlags & PK11_DefaultArray[i].flag) {
CK_MECHANISM_TYPE mechanism = PK11_DefaultArray[i].mechanism;
PK11SlotList *slotList = PK11_GetSlotList(mechanism);
if (slotList)
PK11_AddSlotToList(slotList, slot, PR_FALSE);
}
}
return;
}
/* *updateaslottoitsnewattributeaccordingtotheslotlist *returns:SECSuccessifnothingtodooradd/deleteissuccessful
*/
SECStatus
PK11_UpdateSlotAttribute(PK11SlotInfo *slot, const PK11DefaultArrayEntry *entry,
PRBool add) /* add: PR_TRUE if want to turn on */
{
SECStatus result = SECSuccess;
PK11SlotList *slotList = PK11_GetSlotList(entry->mechanism);
if (add) { /* trying to turn on a mechanism */
/* turn on the default flag in the slot */
slot->defaultFlags |= entry->flag;
/* add this slot to the list */ if (slotList != NULL)
result = PK11_AddSlotToList(slotList, slot, PR_FALSE);
} else { /* trying to turn off */
/* turn OFF the flag in the slot */
slot->defaultFlags &= ~entry->flag;
if (slotList) { /* find the element in the list & delete it */
PK11SlotListElement *le = PK11_FindSlotElement(slotList, slot);
/* remove the slot from the list */ if (le)
result = PK11_DeleteSlotFromList(slotList, le);
}
} return result;
}
/* *clearaslotoffofallofit'sdefaultlist
*/ void
PK11_ClearSlotList(PK11SlotInfo *slot)
{ int i;
if (slot->disabled) return; if (slot->defaultFlags == 0) return;
for (i = 0; i < num_pk11_default_mechanisms; i++) { if (slot->defaultFlags & PK11_DefaultArray[i].flag) {
CK_MECHANISM_TYPE mechanism = PK11_DefaultArray[i].mechanism;
PK11SlotList *slotList = PK11_GetSlotList(mechanism);
PK11SlotListElement *le = NULL;
if (slotList)
le = PK11_FindSlotElement(slotList, slot);
/****************************************************************** *Slotinitialization
******************************************************************/ /* *turnaPKCS11StaticLabelintoastring
*/ char *
PK11_MakeString(PLArenaPool *arena, char *space, char *staticString, int stringLen)
{ int i; char *newString; for (i = (stringLen - 1); i >= 0; i--) { if (staticString[i] != ' ') break;
} /* move i to point to the last space */
i++; if (arena) {
newString = (char *)PORT_ArenaAlloc(arena, i + 1/* space for NULL */);
} elseif (space) {
newString = space;
} else {
newString = (char *)PORT_Alloc(i + 1/* space for NULL */);
} if (newString == NULL) return NULL;
if (i)
PORT_Memcpy(newString, staticString, i);
newString[i] = 0;
/* set the slot flags to the current token values */ if (!slot->isThreadSafe)
PK11_EnterSlotMonitor(slot);
crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID, &slot->tokenInfo); if (!slot->isThreadSafe)
PK11_ExitSlotMonitor(slot); if (crv != CKR_OK) {
PORT_SetError(PK11_MapError(crv)); return SECFailure;
}
/* set the slot flags to the current token values */
slot->series++; /* allow other objects to detect that the
* slot is different */
slot->flags = slot->tokenInfo.flags;
slot->needLogin = ((slot->tokenInfo.flags & CKF_LOGIN_REQUIRED) ? PR_TRUE : PR_FALSE);
slot->readOnly = ((slot->tokenInfo.flags & CKF_WRITE_PROTECTED) ? PR_TRUE : PR_FALSE);
slot->hasRandom = ((slot->tokenInfo.flags & CKF_RNG) ? PR_TRUE : PR_FALSE);
slot->protectedAuthPath =
((slot->tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
? PR_TRUE
: PR_FALSE);
PK11_EnterSlotMonitor(slot);
slot->lastLoginCheck = 0;
PK11_ExitSlotMonitor(slot);
slot->lastState = 0; /* on some platforms Active Card incorrectly sets the
* CKF_PROTECTED_AUTHENTICATION_PATH bit when it doesn't mean to. */ if (slot->isActiveCard) {
slot->protectedAuthPath = PR_FALSE;
}
(void)PK11_MakeString(NULL, slot->token_name,
(char *)slot->tokenInfo.label, sizeof(slot->tokenInfo.label));
slot->minPassword = slot->tokenInfo.ulMinPinLen;
slot->maxPassword = slot->tokenInfo.ulMaxPinLen;
PORT_Memcpy(slot->serial, slot->tokenInfo.serialNumber, sizeof(slot->serial));
nssToken = PK11Slot_GetNSSToken(slot);
nssToken_UpdateName(nssToken); /* null token is OK */
(void)nssToken_Destroy(nssToken);
/* initialize the maxKeyCount value */
PR_Lock(slot->freeListLock); if (slot->tokenInfo.ulMaxSessionCount == 0) {
slot->maxKeyCount = 800; /* should be #define or a config param */
} elseif (slot->tokenInfo.ulMaxSessionCount < 20) { /* don't have enough sessions to keep that many keys around */
slot->maxKeyCount = 0;
} else {
slot->maxKeyCount = slot->tokenInfo.ulMaxSessionCount / 2;
}
PR_Unlock(slot->freeListLock);
/* Make sure our session handle is valid */ if (slot->session == CK_INVALID_HANDLE) { /* we know we don't have a valid session, go get one */
CK_SESSION_HANDLE session;
/* session should be Readonly, serial */ if (!slot->isThreadSafe)
PK11_EnterSlotMonitor(slot);
crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
(slot->defRWSession ? CKF_RW_SESSION : 0) | CKF_SERIAL_SESSION,
slot, pk11_notify, &session); if (!slot->isThreadSafe)
PK11_ExitSlotMonitor(slot); if (crv != CKR_OK) {
PORT_SetError(PK11_MapError(crv)); return SECFailure;
}
slot->session = session;
} else { /* The session we have may be defunct (the token associated with it)
* has been removed */
CK_SESSION_INFO sessionInfo;
if (!slot->isThreadSafe)
PK11_EnterSlotMonitor(slot);
crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session, &sessionInfo); if (crv == CKR_DEVICE_ERROR) {
PK11_GETTAB(slot)
->C_CloseSession(slot->session);
crv = CKR_SESSION_CLOSED;
} if ((crv == CKR_SESSION_CLOSED) || (crv == CKR_SESSION_HANDLE_INVALID)) {
crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
(slot->defRWSession ? CKF_RW_SESSION : 0) | CKF_SERIAL_SESSION,
slot, pk11_notify, &slot->session); if (crv != CKR_OK) {
PORT_SetError(PK11_MapError(crv));
slot->session = CK_INVALID_HANDLE; if (!slot->isThreadSafe)
PK11_ExitSlotMonitor(slot); return SECFailure;
}
} if (!slot->isThreadSafe)
PK11_ExitSlotMonitor(slot);
}
nssToken = PK11Slot_GetNSSToken(slot);
status = nssToken_Refresh(nssToken); /* null token is OK */
(void)nssToken_Destroy(nssToken); if (status != PR_SUCCESS) return SECFailure;
/* Not all tokens have profile objects or even recognize what profile
* objects are it's OK for pk11_ReadProfileList to fail */
(void)pk11_ReadProfileList(slot);
slot->validationFIPSFlags =
pk11_GetValidationFlags(slot, CKV_AUTHORITY_TYPE_NIST_CMVP);
if (!(slot->isInternal) && (slot->hasRandom)) { /* if this slot has a random number generater, use it to add entropy
* to the internal slot. */
PK11SlotInfo *int_slot = PK11_GetInternalSlot();
if (int_slot) { unsignedchar random_bytes[32];
/* if this slot can issue random numbers, get some entropy from *thatrandomnumbergeneraterandgiveittoourinternaltoken.
*/
PK11_EnterSlotMonitor(slot);
crv = PK11_GETTAB(slot)->C_GenerateRandom(slot->session, random_bytes, sizeof(random_bytes));
PK11_ExitSlotMonitor(slot); if (crv == CKR_OK) {
PK11_EnterSlotMonitor(int_slot);
PK11_GETTAB(int_slot)
->C_SeedRandom(int_slot->session,
random_bytes, sizeof(random_bytes));
PK11_ExitSlotMonitor(int_slot);
}
/* Now return the favor and send entropy to the token's random
* number generater */
PK11_EnterSlotMonitor(int_slot);
crv = PK11_GETTAB(int_slot)->C_GenerateRandom(int_slot->session,
random_bytes, sizeof(random_bytes));
PK11_ExitSlotMonitor(int_slot); if (crv == CKR_OK) {
PK11_EnterSlotMonitor(slot);
crv = PK11_GETTAB(slot)->C_SeedRandom(slot->session,
random_bytes, sizeof(random_bytes));
PK11_ExitSlotMonitor(slot);
}
PK11_FreeSlot(int_slot);
}
} /* work around a problem in softoken where it incorrectly
* reports databases opened read only as read/write. */ if (slot->isInternal && !slot->readOnly) {
CK_SESSION_HANDLE session = CK_INVALID_HANDLE;
/* try to open a R/W session */
crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
CKF_RW_SESSION | CKF_SERIAL_SESSION, slot, pk11_notify, &session); /* what a well behaved token should return if you open
* a RW session on a read only token */ if (crv == CKR_TOKEN_WRITE_PROTECTED) {
slot->readOnly = PR_TRUE;
} elseif (crv == CKR_OK) {
CK_SESSION_INFO sessionInfo;
/* Because of a second bug in softoken, which silently returns
* a RO session, we need to check what type of session we got. */
crv = PK11_GETTAB(slot)->C_GetSessionInfo(session, &sessionInfo); if (crv == CKR_OK) { if ((sessionInfo.flags & CKF_RW_SESSION) == 0) { /* session was readonly, so this softoken slot must be readonly */
slot->readOnly = PR_TRUE;
}
}
PK11_GETTAB(slot)
->C_CloseSession(session);
}
}
/* set the slot flags to the current token values */ if (!slot->isThreadSafe)
PK11_EnterSlotMonitor(slot);
crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID, &slot->tokenInfo); if (!slot->isThreadSafe)
PK11_ExitSlotMonitor(slot); if (crv != CKR_OK) {
PORT_SetError(PK11_MapError(crv)); return SECFailure;
}
slot->flags = slot->tokenInfo.flags;
slot->needLogin = ((slot->tokenInfo.flags & CKF_LOGIN_REQUIRED) ? PR_TRUE : PR_FALSE);
slot->readOnly = ((slot->tokenInfo.flags & CKF_WRITE_PROTECTED) ? PR_TRUE : PR_FALSE);
slot->hasRandom = ((slot->tokenInfo.flags & CKF_RNG) ? PR_TRUE : PR_FALSE);
slot->protectedAuthPath =
((slot->tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
? PR_TRUE
: PR_FALSE); /* on some platforms Active Card incorrectly sets the
* CKF_PROTECTED_AUTHENTICATION_PATH bit when it doesn't mean to. */ if (slot->isActiveCard) {
slot->protectedAuthPath = PR_FALSE;
} return SECSuccess;
}
slot->functionList = mod->functionList;
slot->isInternal = mod->internal;
slot->slotID = slotID;
slot->isThreadSafe = mod->isThreadSafe;
slot->hasRSAInfo = PR_FALSE;
slot->module = mod; /* NOTE: we don't make a reference here because *moduleshavereferencestotheirslots.This *worksbecausemoduleskeepimplicitreferences *fromtheirslots,andwon'tunloadanddisappear
* until all their slots have been freed */
/* removable slots have a flag that says they are present */ if (PK11_GetSlotInfo(slot, &slotInfo) != SECSuccess) { return PR_FALSE;
}
if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0) { /* if the slot is no longer present, close the session */ if (slot->session != CK_INVALID_HANDLE) { if (!slot->isThreadSafe) {
PK11_EnterSlotMonitor(slot);
}
PK11_GETTAB(slot)
->C_CloseSession(slot->session);
slot->session = CK_INVALID_HANDLE; if (!slot->isThreadSafe) {
PK11_ExitSlotMonitor(slot);
}
} return PR_FALSE;
}
/* use the session Info to determine if the card has been removed and then
* re-inserted */ if (slot->session != CK_INVALID_HANDLE) { if (slot->isThreadSafe) {
PK11_EnterSlotMonitor(slot);
}
crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session, &sessionInfo); if (crv != CKR_OK) {
PK11_GETTAB(slot)
->C_CloseSession(slot->session);
slot->session = CK_INVALID_HANDLE;
} if (slot->isThreadSafe) {
PK11_ExitSlotMonitor(slot);
}
}
/* card has not been removed, current token info is correct */ if (slot->session != CK_INVALID_HANDLE) return PR_TRUE;
/* initialize the token info state */ if (PK11_InitToken(slot, loadCerts) != SECSuccess) { return PR_FALSE;
}
/* Get the module this slot is attached to */
SECMODModule *
PK11_GetModule(PK11SlotInfo *slot)
{ return slot->module;
}
/* return the default flags of a slot */ unsignedlong
PK11_GetDefaultFlags(PK11SlotInfo *slot)
{ return slot->defaultFlags;
}
/* *Thefollowingwrapperfunctionsallowustoexportanopaqueslot
* function to the rest of libsec and the world... */
PRBool
PK11_IsReadOnly(PK11SlotInfo *slot)
{ return slot->readOnly;
}
value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_TOKEN); if (value) { if (!pk11_MatchString(value, (char *)slot->tokenInfo.label, sizeof(slot->tokenInfo.label))) { return PR_FALSE;
}
}
value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_MANUFACTURER); if (value) { if (!pk11_MatchString(value, (char *)slot->tokenInfo.manufacturerID, sizeof(slot->tokenInfo.manufacturerID))) { return PR_FALSE;
}
}
value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_SERIAL); if (value) { if (!pk11_MatchString(value, (char *)slot->tokenInfo.serialNumber, sizeof(slot->tokenInfo.serialNumber))) { return PR_FALSE;
}
}
value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_MODEL); if (value) { if (!pk11_MatchString(value, (char *)slot->tokenInfo.model, sizeof(slot->tokenInfo.model))) { return PR_FALSE;
}
}
return PR_TRUE;
}
/* Find out if we need to initialize the user's pin */
PRBool
PK11_NeedUserInit(PK11SlotInfo *slot)
{
PRBool needUserInit = (PRBool)((slot->flags & CKF_USER_PIN_INITIALIZED) == 0);
if (needUserInit) {
CK_TOKEN_INFO info;
SECStatus rv;
/* see if token has been initialized off line */
rv = PK11_GetTokenInfo(slot, &info); if (rv == SECSuccess) {
slot->flags = info.flags;
}
} return (PRBool)((slot->flags & CKF_USER_PIN_INITIALIZED) == 0);
}
/* get the internal key slot. FIPS has only one slot for both key slots and
* default slots */
PK11SlotInfo *
PK11_GetInternalKeySlot(void)
{
SECMODModule *mod;
if (pk11InternalKeySlot) { return PK11_ReferenceSlot(pk11InternalKeySlot);
}
mod = SECMOD_GetInternalModule();
PORT_Assert(mod != NULL); if (!mod) {
PORT_SetError(SEC_ERROR_NO_MODULE); return NULL;
} return PK11_ReferenceSlot(mod->isFIPS ? mod->slots[0] : mod->slots[1]);
}
/* get the internal default slot */
PK11SlotInfo *
PK11_GetInternalSlot(void)
{
SECMODModule *mod = SECMOD_GetInternalModule();
PORT_Assert(mod != NULL); if (!mod) {
PORT_SetError(SEC_ERROR_NO_MODULE); return NULL;
} if (mod->isFIPS) { return PK11_GetInternalKeySlot();
} return PK11_ReferenceSlot(mod->slots[0]);
}
/* CKM_FAKE_RANDOM is not a real PKCS mechanism. It's a marker to *telluswe'relookingformsomeonethathasimplementedget
* random bits */ if (type == CKM_FAKE_RANDOM) { return slot->hasRandom;
}
/* for most mechanism, bypass the linear lookup */ if (type < 0x7ff) { return (slot->mechanismBits[type & 0xff] & (1 << (type >> 8))) ? PR_TRUE : PR_FALSE;
}
for (i = 0; i < (int)slot->mechanismCount; i++) { if (slot->mechanismList[i] == type) return PR_TRUE;
} return PR_FALSE;
}
if (!moduleLock) {
PORT_SetError(SEC_ERROR_NOT_INITIALIZED); return found;
} /* we only need to know if there is a token that does this mechanism. *checktheinternalmodulefirstbecauseit'sfast,andsupports
* almost everything. */
slot = PK11_GetInternalSlot(); if (slot) {
found = PK11_DoesMechanism(slot, type);
PK11_FreeSlot(slot);
} if (found) return PR_TRUE; /* bypass getting module locks */
SECMOD_GetReadLock(moduleLock);
modules = SECMOD_GetDefaultModuleList(); for (mlp = modules; mlp != NULL && (!found); mlp = mlp->next) { for (i = 0; i < mlp->module->slotCount; i++) {
slot = mlp->module->slots[i]; if (PK11_IsPresent(slot)) { if (PK11_DoesMechanism(slot, type)) {
found = PR_TRUE; break;
}
}
}
}
SECMOD_ReleaseReadLock(moduleLock); return found;
}
for (le = list->head; le; le = next) {
next = le->next; /* save the pointer here in case we have to
* free the element later */
rv = PK11_Authenticate(le->slot, PR_TRUE, wincx); if (rv != SECSuccess) {
PK11_DeleteSlotFromList(list, le); continue;
}
} return list;
}
/* handle the only case where we don't actually fetch the mechanisms
* on the fly */
if ((keySize == 0) && (mechanism == 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, mechanism,
&mechanism_info);
if (!slot->isThreadSafe)
PK11_ExitSlotMonitor(slot);
/* if we were getting the RSA flags, save them */
if ((crv == CKR_OK) && (mechanism == CKM_RSA_PKCS) && (!slot->hasRSAInfo)) {
slot->RSAInfoFlags = mechanism_info.flags;
slot->hasRSAInfo = PR_TRUE;
}
}
/* couldn't get the mechanism info */
if (crv != CKR_OK) {
return PR_TRUE;
}
if (keySize && ((mechanism_info.ulMinKeySize > keySize) || (mechanism_info.ulMaxKeySize < keySize))) {
/* Token can do mechanism, but not at the key size we
* want */
return PR_TRUE;
}
if (mechanismInfoFlags && ((mechanism_info.flags & mechanismInfoFlags) !=
mechanismInfoFlags)) {
return PR_TRUE;
}
return PR_FALSE;
}
/*
* Find the best slot which supports the given set of mechanisms and key sizes.
* In normal cases this should grab the first slot on the list with no fuss.
* The size array is presumed to match one for one with the mechanism type
* array, which allows you to specify the required key size for each
* mechanism in the list. Whether key size is in bits or bytes is mechanism
* dependent. Typically asymetric keys are in bits and symetric keys are in
* bytes.
*/
PK11SlotInfo *
PK11_GetBestSlotMultipleWithAttributes(CK_MECHANISM_TYPE *type,
CK_FLAGS *mechanismInfoFlags, unsigned int *keySize,
unsigned int mech_count, void *wincx)
{
PK11SlotList *list = NULL;
PK11SlotListElement *le;
PK11SlotInfo *slot = NULL;
PRBool freeit = PR_FALSE;
PRBool listNeedLogin = PR_FALSE;
unsigned int i;
SECStatus rv;
list = PK11_GetSlotList(type[0]);
if ((list == NULL) || (list->head == NULL)) {
/* We need to look up all the tokens for the mechanism */
list = PK11_GetAllTokens(type[0], PR_FALSE, PR_TRUE, wincx);
freeit = PR_TRUE;
}
/* no one can do it! */
if (list == NULL) {
PORT_SetError(SEC_ERROR_NO_TOKEN);
return NULL;
}
/* original get best slot now calls the multiple version with only one type */
PK11SlotInfo *
PK11_GetBestSlot(CK_MECHANISM_TYPE type, void *wincx)
{
return PK11_GetBestSlotMultipleWithAttributes(&type, NULL, NULL, 1, wincx);
}
int
PK11_GetBestKeyLength(PK11SlotInfo *slot, CK_MECHANISM_TYPE mechanism)
{
CK_MECHANISM_INFO mechanism_info;
CK_RV crv;
if (!slot->isThreadSafe)
PK11_EnterSlotMonitor(slot);
crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
mechanism, &mechanism_info);
if (!slot->isThreadSafe)
PK11_ExitSlotMonitor(slot);
if (crv != CKR_OK)
return 0;
if (mechanism_info.ulMinKeySize == mechanism_info.ulMaxKeySize)
return 0;
return mechanism_info.ulMaxKeySize;
}
/*
* This function uses the existing PKCS #11 module to find the
* longest supported key length in the preferred token for a mechanism.
* This varies from the above function in that 1) it returns the key length
* even for fixed key algorithms, and 2) it looks through the tokens
* generally rather than for a specific token. This is used in liu of
* a PK11_GetKeyLength function in pk11mech.c since we can actually read
* supported key lengths from PKCS #11.
*
* For symmetric key operations the length is returned in bytes.
*/
int
PK11_GetMaxKeyLength(CK_MECHANISM_TYPE mechanism)
{
CK_MECHANISM_INFO mechanism_info;
PK11SlotList *list = NULL;
PK11SlotListElement *le;
PRBool freeit = PR_FALSE;
int keyLength = 0;
list = PK11_GetSlotList(mechanism);
if ((list == NULL) || (list->head == NULL)) {
/* We need to look up all the tokens for the mechanism */
list = PK11_GetAllTokens(mechanism, PR_FALSE, PR_FALSE, NULL);
freeit = PR_TRUE;
}
/* no tokens recognize this mechanism */
if (list == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return 0;
}
for (le = PK11_GetFirstSafe(list); le;
le = PK11_GetNextSafe(list, le, PR_TRUE)) {
PK11SlotInfo *slot = le->slot;
CK_RV crv;
if (PK11_IsPresent(slot)) {
if (!slot->isThreadSafe)
PK11_EnterSlotMonitor(slot);
crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
mechanism, &mechanism_info);
if (!slot->isThreadSafe)
PK11_ExitSlotMonitor(slot);
if ((crv == CKR_OK) && (mechanism_info.ulMaxKeySize != 0) && (mechanism_info.ulMaxKeySize != 0xffffffff)) {
keyLength = mechanism_info.ulMaxKeySize;
break;
}
}
}
/* fallback to pk11_GetPredefinedKeyLength for fixed key size algorithms */
if (keyLength == 0) {
CK_KEY_TYPE keyType;
keyType = PK11_GetKeyType(mechanism, 0);
keyLength = pk11_GetPredefinedKeyLength(keyType);
}
if (le)
PK11_FreeSlotListElement(list, le);
if (freeit)
PK11_FreeSlotList(list);
return keyLength;
}
if (!slot->isInternal)
PK11_EnterSlotMonitor(slot);
crv = PK11_GETTAB(slot)->C_GenerateRandom(slot->session, data,
(CK_ULONG)len);
if (!slot->isInternal)
PK11_ExitSlotMonitor(slot);
if (crv != CKR_OK) {
PORT_SetError(PK11_MapError(crv));
return SECFailure;
}
return SECSuccess;
}
/* Attempts to update the Best Slot for "FAKE RANDOM" generation.
** If that's not the internal slot, then it also attempts to update the
** internal slot.
** The return value indicates if the INTERNAL slot was updated OK.
*/
SECStatus
PK11_RandomUpdate(void *data, size_t bytes)
{
PK11SlotInfo *slot;
PRBool bestIsInternal;
SECStatus status;
slot = PK11_GetBestSlot(CKM_FAKE_RANDOM, NULL);
if (slot == NULL) {
slot = PK11_GetInternalSlot();
if (!slot)
return SECFailure;
}
bestIsInternal = PK11_IsInternal(slot);
status = PK11_SeedRandom(slot, data, bytes);
PK11_FreeSlot(slot);
if (!bestIsInternal) {
/* do internal slot, too. */
slot = PK11_GetInternalSlot();
PORT_Assert(slot);
if (!slot) {
return SECFailure;
}
status = PK11_SeedRandom(slot, data, bytes);
PK11_FreeSlot(slot);
}
return status;
}
/*
* Reset the token to it's initial state. For the internal module, this will
* Purge your keydb, and reset your cert db certs to USER_INIT.
*/
SECStatus
PK11_ResetToken(PK11SlotInfo *slot, char *sso_pwd)
{
unsigned char tokenName[32];
size_t tokenNameLen;
CK_RV crv;
/* reconstruct the token name */
tokenNameLen = PORT_Strlen(slot->token_name);
if (tokenNameLen > sizeof(tokenName)) {
tokenNameLen = sizeof(tokenName);
}
/* initialize the token */
PK11_EnterSlotMonitor(slot);
/* first shutdown the token. Existing sessions will get closed here */
PK11_GETTAB(slot)
->C_CloseAllSessions(slot->slotID);
slot->session = CK_INVALID_HANDLE;
/* now re-init the token */
crv = PK11_GETTAB(slot)->C_InitToken(slot->slotID,
(unsigned char *)sso_pwd, sso_pwd ? PORT_Strlen(sso_pwd) : 0, tokenName);
PK11_ExitSlotMonitor(slot);
/* finally bring the token back up. PK11_InitToken takes the slot monitor
* itself, so it must be called without the monitor held. */
PK11_InitToken(slot, PR_TRUE);
if (crv != CKR_OK) {
PORT_SetError(PK11_MapError(crv));
return SECFailure;
}
NSSToken *token = PK11Slot_GetNSSToken(slot);
if (token) {
nssTrustDomain_UpdateCachedTokenCerts(token->trustDomain, token);
(void)nssToken_Destroy(token);
}
return SECSuccess;
}
/* module isn't validated */
if (slot->validationFIPSFlags == 0) {
return PR_FALSE;
}
switch (operationType) {
/* in pkcs #11, these are equivalent */
case CKT_NSS_SESSION_LAST_CHECK:
case CKT_NSS_SESSION_CHECK:
crv = PK11_GETTAB(slot)->C_GetSessionValidationFlags(session,
CKS_LAST_VALIDATION_OK, &validationFlags);
if (crv != CKR_OK) {
return PR_FALSE;
}
break;
case CKT_NSS_OBJECT_CHECK:
validationFlags = PK11_ReadULongAttribute(slot, object,
CKA_OBJECT_VALIDATION_FLAGS);
if (validationFlags == CK_UNAVAILABLE_INFORMATION) {
return PR_FALSE;
}
break;
default:
return PR_FALSE;
}
return (PRBool)(validationFlags & slot->validationFIPSFlags) != 0;
}
/* handle the NSS vendor specific indicators, for older modules */
/* handle the obvious conditions:
* 1) the module doesn't have a fipsIndicator - fips state must be false */
if (mod->fipsIndicator == NULL) {
return PR_FALSE;
}
/* 2) the session doesn't exist - fips state must be false */
if (session == CK_INVALID_HANDLE) {
return PR_FALSE;
}
/* go fetch the state */
crv = mod->fipsIndicator(session, object, operationType, &fipsState);
if (crv != CKR_OK) {
return PR_FALSE;
}
return (fipsState == CKS_NSS_FIPS_OK) ? PR_TRUE : PR_FALSE;
}
/*
* wait for a token to change it's state. The application passes in the expected
* new state in event.
*/
PK11TokenStatus
PK11_WaitForTokenEvent(PK11SlotInfo *slot, PK11TokenEvent event,
PRIntervalTime timeout, PRIntervalTime latency, int series)
{
PRIntervalTime first_time = 0;
PRBool first_time_set = PR_FALSE;
PRBool waitForRemoval;
if (slot->isPerm) {
return PK11TokenNotRemovable;
}
if (latency == 0) {
latency = PR_SecondsToInterval(5);
}
waitForRemoval = (PRBool)(event == PK11TokenRemovedOrChangedEvent);
if (series == 0) {
series = PK11_GetSlotSeries(slot);
}
while (PK11_IsPresent(slot) == waitForRemoval) {
PRIntervalTime interval;
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.