/* * Return the final digested or signed data... * this routine can either take pre initialized data, or allocate data * either out of an arena or out of the standard heap. */ SECStatus PK11_DigestFinal(PK11Context *context,unsigned char *data, unsigned int *outLen, unsigned int length) { CK_ULONG len; CK_RV crv; SECStatus rv; /* if we ran out of session, we need to restore our previously stored * state. */ PK11_EnterContextMonitor(context); if (!context->ownSession) { rv = pk11_restoreContext(context,context->savedData, context->savedLength); if (rv != SECSuccess) { PK11_ExitContextMonitor(context); return rv; } } len = length; switch (context->operation) { case CKA_SIGN: crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session, data,&len); break; case CKA_VERIFY: crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session, data,len); break; case CKA_DIGEST: crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session, data,&len); break; case CKA_ENCRYPT: crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, data, &len); break; case CKA_DECRYPT: crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session, data, &len); break; default: crv = CKR_OPERATION_NOT_INITIALIZED; break; } PK11_ExitContextMonitor(context); *outLen = (unsigned int) len; context->init = PR_FALSE; /* allow Begin to start up again */ if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); return SECFailure; } return SECSuccess; }
/* * save the current context. Allocate Space if necessary. */ static unsigned char * pk11_saveContextHelper(PK11Context *context, unsigned char *buffer, unsigned long *savedLength) { CK_RV crv; /* If buffer is NULL, this will get the length */ crv = PK11_GETTAB(context->slot)->C_GetOperationState(context->session, (CK_BYTE_PTR)buffer, savedLength); if (!buffer || (crv == CKR_BUFFER_TOO_SMALL)) { /* the given buffer wasn't big enough (or was NULL), but we * have the length, so try again with a new buffer and the * correct length */ unsigned long bufLen = *savedLength; buffer = PORT_Alloc(bufLen); if (buffer == NULL) { return (unsigned char *)NULL; } crv = PK11_GETTAB(context->slot)->C_GetOperationState( context->session, (CK_BYTE_PTR)buffer, savedLength); if (crv != CKR_OK) { PORT_ZFree(buffer, bufLen); } } if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); return (unsigned char *)NULL; } return buffer; }
/* * Check the user's password. Logout before hand to make sure that * we are really checking the password. */ SECStatus PK11_CheckUserPassword(PK11SlotInfo *slot, const char *pw) { int len = 0; CK_RV crv; SECStatus rv; int64 currtime = PR_Now(); if (slot->protectedAuthPath) { len = 0; pw = NULL; } else if (pw == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } else { len = PORT_Strlen(pw); } /* * If the token does't need a login, don't try to relogin beause the * effect is undefined. It's not clear what it means to check a non-empty * password with such a token, so treat that as an error. */ if (!slot->needLogin) { if (len == 0) { rv = SECSuccess; } else { PORT_SetError(SEC_ERROR_BAD_PASSWORD); rv = SECFailure; } return rv; } /* force a logout */ PK11_EnterSlotMonitor(slot); PK11_GETTAB(slot)->C_Logout(slot->session); crv = PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER, (unsigned char *)pw,len); slot->lastLoginCheck = 0; PK11_ExitSlotMonitor(slot); switch (crv) { /* if we're already logged in, we're good to go */ case CKR_OK: slot->authTransact = PK11_Global.transaction; slot->authTime = currtime; rv = SECSuccess; break; case CKR_PIN_INCORRECT: PORT_SetError(SEC_ERROR_BAD_PASSWORD); rv = SECWouldBlock; /* everything else is ok, only the pin is bad */ break; default: PORT_SetError(PK11_MapError(crv)); rv = SECFailure; /* some failure we can't fix by retrying */ } return rv; }
/* * NOTE: this assumes that we are logged out of the card before hand */ SECStatus PK11_CheckSSOPassword(PK11SlotInfo *slot, char *ssopw) { CK_SESSION_HANDLE rwsession; CK_RV crv; SECStatus rv = SECFailure; int len = 0; /* get a rwsession */ rwsession = PK11_GetRWSession(slot); if (rwsession == CK_INVALID_SESSION) { PORT_SetError(SEC_ERROR_BAD_DATA); return rv; } if (slot->protectedAuthPath) { len = 0; ssopw = NULL; } else if (ssopw == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } else { len = PORT_Strlen(ssopw); } /* check the password */ crv = PK11_GETTAB(slot)->C_Login(rwsession,CKU_SO, (unsigned char *)ssopw,len); slot->lastLoginCheck = 0; switch (crv) { /* if we're already logged in, we're good to go */ case CKR_OK: rv = SECSuccess; break; case CKR_PIN_INCORRECT: PORT_SetError(SEC_ERROR_BAD_PASSWORD); rv = SECWouldBlock; /* everything else is ok, only the pin is bad */ break; default: PORT_SetError(PK11_MapError(crv)); rv = SECFailure; /* some failure we can't fix by retrying */ } PK11_GETTAB(slot)->C_Logout(rwsession); slot->lastLoginCheck = 0; /* release rwsession */ PK11_RestoreROSession(slot,rwsession); return rv; }
/* * before we do a private key op, we check to see if we * need to reauthenticate. */ void PK11_HandlePasswordCheck(PK11SlotInfo *slot,void *wincx) { int askpw = slot->askpw; PRBool NeedAuth = PR_FALSE; if (!slot->needLogin) return; if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) { PK11SlotInfo *def_slot = PK11_GetInternalKeySlot(); if (def_slot) { askpw = def_slot->askpw; PK11_FreeSlot(def_slot); } } /* timeouts are handled by isLoggedIn */ if (!PK11_IsLoggedIn(slot,wincx)) { NeedAuth = PR_TRUE; } else if (askpw == -1) { if (!PK11_Global.inTransaction || (PK11_Global.transaction != slot->authTransact)) { PK11_EnterSlotMonitor(slot); PK11_GETTAB(slot)->C_Logout(slot->session); slot->lastLoginCheck = 0; PK11_ExitSlotMonitor(slot); NeedAuth = PR_TRUE; } } if (NeedAuth) PK11_DoPassword(slot,PR_TRUE,wincx); }
/* * Change an existing user password */ SECStatus PK11_ChangePW(PK11SlotInfo *slot, const char *oldpw, const char *newpw) { CK_RV crv; SECStatus rv = SECFailure; int newLen; int oldLen; CK_SESSION_HANDLE rwsession; if (newpw == NULL) newpw = ""; if (oldpw == NULL) oldpw = ""; newLen = PORT_Strlen(newpw); oldLen = PORT_Strlen(oldpw); /* get a rwsession */ rwsession = PK11_GetRWSession(slot); if (rwsession == CK_INVALID_SESSION) { PORT_SetError(SEC_ERROR_BAD_DATA); return rv; } crv = PK11_GETTAB(slot)->C_SetPIN(rwsession, (unsigned char *)oldpw,oldLen,(unsigned char *)newpw,newLen); if (crv == CKR_OK) { rv = SECSuccess; } else { PORT_SetError(PK11_MapError(crv)); } PK11_RestoreROSession(slot,rwsession); /* update our view of the world */ PK11_InitToken(slot,PR_TRUE); return rv; }
SECStatus SECMOD_UnloadModule(SECMODModule *mod) { PRLibrary *library; char *disableUnload = NULL; if (!mod->loaded) { return SECFailure; } if (finalizeModules) { if (mod->functionList &&!mod->moduleDBOnly) { PK11_GETTAB(mod)->C_Finalize(NULL); } } mod->moduleID = 0; mod->loaded = PR_FALSE; /* do we want the semantics to allow unloading the internal library? * if not, we should change this to SECFailure and move it above the * mod->loaded = PR_FALSE; */ if (mod->internal && (mod->dllName == NULL)) { #ifndef NSS_STATIC if (0 == PR_ATOMIC_DECREMENT(&softokenLoadCount)) { if (softokenLib) { disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD"); if (!disableUnload) { #ifdef DEBUG PRStatus status = PR_UnloadLibrary(softokenLib); PORT_Assert(PR_SUCCESS == status); #else PR_UnloadLibrary(softokenLib); #endif } softokenLib = NULL; } loadSoftokenOnce = pristineCallOnce; } #endif return SECSuccess; } library = (PRLibrary *)mod->library; /* paranoia */ if (library == NULL) { #if defined(NSS_STATIC) && !defined(NSS_DISABLE_ROOT_CERTS) if (strstr(mod->dllName, "nssckbi") != NULL) { return SECSuccess; } #endif return SECFailure; } disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD"); if (!disableUnload) { PR_UnloadLibrary(library); } return SECSuccess; }
/* * Context initialization. Used by all flavors of CreateContext */ static SECStatus pk11_context_init(PK11Context *context, CK_MECHANISM *mech_info) { CK_RV crv; PK11SymKey *symKey = context->key; SECStatus rv = SECSuccess; switch (context->operation) { case CKA_ENCRYPT: crv=PK11_GETTAB(context->slot)->C_EncryptInit(context->session, mech_info, symKey->objectID); break; case CKA_DECRYPT: if (context->fortezzaHack) { CK_ULONG count = 0;; /* generate the IV for fortezza */ crv=PK11_GETTAB(context->slot)->C_EncryptInit(context->session, mech_info, symKey->objectID); if (crv != CKR_OK) break; PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, NULL, &count); } crv=PK11_GETTAB(context->slot)->C_DecryptInit(context->session, mech_info, symKey->objectID); break; case CKA_SIGN: crv=PK11_GETTAB(context->slot)->C_SignInit(context->session, mech_info, symKey->objectID); break; case CKA_VERIFY: crv=PK11_GETTAB(context->slot)->C_SignInit(context->session, mech_info, symKey->objectID); break; case CKA_DIGEST: crv=PK11_GETTAB(context->slot)->C_DigestInit(context->session, mech_info); break; default: crv = CKR_OPERATION_NOT_INITIALIZED; break; } if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); return SECFailure; } /* * handle session starvation case.. use our last session to multiplex */ if (!context->ownSession) { context->savedData = pk11_saveContext(context,context->savedData, &context->savedLength); if (context->savedData == NULL) rv = SECFailure; /* clear out out session for others to use */ pk11_Finalize(context); } return rv; }
/* * Check the user's password. Logout before hand to make sure that * we are really checking the password. */ SECStatus PK11_CheckUserPassword(PK11SlotInfo *slot, const char *pw) { int len = 0; CK_RV crv; SECStatus rv; int64 currtime = PR_Now(); if (slot->protectedAuthPath) { len = 0; pw = NULL; } else if (pw == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } else { len = PORT_Strlen(pw); } /* force a logout */ PK11_EnterSlotMonitor(slot); PK11_GETTAB(slot)->C_Logout(slot->session); crv = PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER, (unsigned char *)pw,len); slot->lastLoginCheck = 0; PK11_ExitSlotMonitor(slot); switch (crv) { /* if we're already logged in, we're good to go */ case CKR_OK: slot->authTransact = PK11_Global.transaction; slot->authTime = currtime; rv = SECSuccess; break; case CKR_PIN_INCORRECT: PORT_SetError(SEC_ERROR_BAD_PASSWORD); rv = SECWouldBlock; /* everything else is ok, only the pin is bad */ break; default: PORT_SetError(PK11_MapError(crv)); rv = SECFailure; /* some failure we can't fix by retrying */ } return rv; }
SECStatus PK11_GetModInfo(SECMODModule *mod,CK_INFO *info) { CK_RV crv; if (mod->functionList == NULL) return SECFailure; crv = PK11_GETTAB(mod)->C_GetInfo(info); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); } return (crv == CKR_OK) ? SECSuccess : SECFailure; }
SECStatus PK11_Logout(PK11SlotInfo *slot) { CK_RV crv; /* force a logout */ PK11_EnterSlotMonitor(slot); crv = PK11_GETTAB(slot)->C_Logout(slot->session); slot->lastLoginCheck = 0; PK11_ExitSlotMonitor(slot); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); return SECFailure; } return SECSuccess; }
/* * Determine if the token is logged in. We have to actually query the token, * because it's state can change without intervention from us. */ PRBool PK11_IsLoggedIn(PK11SlotInfo *slot,void *wincx) { CK_SESSION_INFO sessionInfo; int askpw = slot->askpw; int timeout = slot->timeout; CK_RV crv; PRIntervalTime curTime; static PRIntervalTime login_delay_time = 0; if (login_delay_time == 0) { login_delay_time = PR_SecondsToInterval(1); } /* If we don't have our own password default values, use the system * ones */ if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) { PK11SlotInfo *def_slot = PK11_GetInternalKeySlot(); if (def_slot) { askpw = def_slot->askpw; timeout = def_slot->timeout; PK11_FreeSlot(def_slot); } } if ((wincx != NULL) && (PK11_Global.isLoggedIn != NULL) && (*PK11_Global.isLoggedIn)(slot, wincx) == PR_FALSE) { return PR_FALSE; } /* forget the password if we've been inactive too long */ if (askpw == 1) { int64 currtime = PR_Now(); int64 result; int64 mult; LL_I2L(result, timeout); LL_I2L(mult, 60*1000*1000); LL_MUL(result,result,mult); LL_ADD(result, result, slot->authTime); if (LL_CMP(result, <, currtime) ) { PK11_EnterSlotMonitor(slot); PK11_GETTAB(slot)->C_Logout(slot->session); slot->lastLoginCheck = 0; PK11_ExitSlotMonitor(slot); } else {
/* * restore the current context */ SECStatus pk11_restoreContext(PK11Context *context, void *space, unsigned long savedLength) { CK_RV crv; CK_OBJECT_HANDLE objectID = (context->key) ? context->key->objectID : CK_INVALID_HANDLE; PORT_Assert(space != NULL); if (space == NULL) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } crv = PK11_GETTAB(context->slot)->C_SetOperationState(context->session, (CK_BYTE_PTR)space, savedLength, objectID, 0); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); return SECFailure; } return SECSuccess; }
/* * This function "wakes up" WaitForAnyTokenEvent. It's a pretty drastic * function, possibly bringing down the pkcs #11 module in question. This * should be OK because 1) it does reinitialize, and 2) it should only be * called when we are on our way to tear the whole system down anyway. */ SECStatus SECMOD_CancelWait(SECMODModule *mod) { unsigned long controlMask; SECStatus rv = SECSuccess; CK_RV crv; PZ_Lock(mod->refLock); mod->evControlMask |= SECMOD_END_WAIT; controlMask = mod->evControlMask; if (controlMask & SECMOD_WAIT_PKCS11_EVENT) { if (!pk11_getFinalizeModulesOption()) { /* can't get here unless pk11_getFinalizeModulesOption is set */ PORT_Assert(0); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); rv = SECFailure; goto loser; } /* NOTE: this call will drop all transient keys, in progress * operations, and any authentication. This is the only documented * way to get WaitForSlotEvent to return. Also note: for non-thread * safe tokens, we need to hold the module lock, this is not yet at * system shutdown/startup time, so we need to protect these calls */ crv = PK11_GETTAB(mod)->C_Finalize(NULL); /* ok, we slammed the module down, now we need to reinit it in case * we intend to use it again */ if (CKR_OK == crv) { PRBool alreadyLoaded; secmod_ModuleInit(mod, NULL, &alreadyLoaded); } else { /* Finalized failed for some reason, notify the application * so maybe it has a prayer of recovering... */ PORT_SetError(PK11_MapError(crv)); rv = SECFailure; } } else if (controlMask & SECMOD_WAIT_SIMULATED_EVENT) { mod->evControlMask &= ~SECMOD_WAIT_SIMULATED_EVENT; /* Simulated events will eventually timeout * and wake up in the loop */ } loser: PZ_Unlock(mod->refLock); return rv; }
/* * write a bunch of attributes out to an existing object. */ static SECStatus pk11_setAttributes(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, CK_ATTRIBUTE *setTemplate, CK_ULONG setTemplCount) { CK_RV crv; CK_SESSION_HANDLE rwsession; rwsession = PK11_GetRWSession(slot); if (rwsession == CK_INVALID_SESSION) { PORT_SetError(SEC_ERROR_BAD_DATA); return SECFailure; } crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id, setTemplate, setTemplCount); PK11_RestoreROSession(slot, rwsession); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); return SECFailure; } return SECSuccess; }
/* * clean up a cipher operation, so the session can be used by * someone new. */ SECStatus pk11_Finalize(PK11Context *context) { CK_ULONG count = 0; CK_RV crv; unsigned char stackBuf[256]; unsigned char *buffer = NULL; if (!context->ownSession) { return SECSuccess; } finalize: switch (context->operation) { case CKA_ENCRYPT: crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, buffer, &count); break; case CKA_DECRYPT: crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session, buffer, &count); break; case CKA_SIGN: crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session, buffer, &count); break; case CKA_VERIFY: crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session, buffer, count); break; case CKA_DIGEST: crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session, buffer, &count); break; default: crv = CKR_OPERATION_NOT_INITIALIZED; break; } if (crv != CKR_OK) { if (buffer != stackBuf) { PORT_Free(buffer); } if (crv == CKR_OPERATION_NOT_INITIALIZED) { /* if there's no operation, it is finalized */ return SECSuccess; } PORT_SetError( PK11_MapError(crv) ); return SECFailure; } /* try to finalize the session with a buffer */ if (buffer == NULL) { if (count <= sizeof stackBuf) { buffer = stackBuf; } else { buffer = PORT_Alloc(count); if (buffer == NULL) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } } goto finalize; } if (buffer != stackBuf) { PORT_Free(buffer); } return SECSuccess; }
/* * Digest a key if possible./ */ SECStatus PK11_DigestKey(PK11Context *context, PK11SymKey *key) { CK_RV crv = CKR_OK; SECStatus rv = SECSuccess; PK11SymKey *newKey = NULL; if (!context || !key) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* if we ran out of session, we need to restore our previously stored * state. */ if (context->slot != key->slot) { newKey = pk11_CopyToSlot(context->slot,CKM_SSL3_SHA1_MAC,CKA_SIGN,key); } else { newKey = PK11_ReferenceSymKey(key); } context->init = PR_FALSE; PK11_EnterContextMonitor(context); if (!context->ownSession) { rv = pk11_restoreContext(context,context->savedData, context->savedLength); if (rv != SECSuccess) { PK11_ExitContextMonitor(context); PK11_FreeSymKey(newKey); return rv; } } if (newKey == NULL) { crv = CKR_KEY_TYPE_INCONSISTENT; if (key->data.data) { crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session, key->data.data,key->data.len); } } else { crv=PK11_GETTAB(context->slot)->C_DigestKey(context->session, newKey->objectID); } if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); rv = SECFailure; } /* * handle session starvation case.. use our last session to multiplex */ if (!context->ownSession) { context->savedData = pk11_saveContext(context,context->savedData, &context->savedLength); if (context->savedData == NULL) rv = SECFailure; /* clear out out session for others to use */ pk11_Finalize(context); } PK11_ExitContextMonitor(context); if (newKey) PK11_FreeSymKey(newKey); return rv; }
/* * execute a digest/signature operation */ SECStatus PK11_DigestOp(PK11Context *context, const unsigned char * in, unsigned inLen) { CK_RV crv = CKR_OK; SECStatus rv = SECSuccess; if (!in) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* if we ran out of session, we need to restore our previously stored * state. */ context->init = PR_FALSE; PK11_EnterContextMonitor(context); if (!context->ownSession) { rv = pk11_restoreContext(context,context->savedData, context->savedLength); if (rv != SECSuccess) { PK11_ExitContextMonitor(context); return rv; } } switch (context->operation) { /* also for MAC'ing */ case CKA_SIGN: crv=PK11_GETTAB(context->slot)->C_SignUpdate(context->session, (unsigned char *)in, inLen); break; case CKA_VERIFY: crv=PK11_GETTAB(context->slot)->C_VerifyUpdate(context->session, (unsigned char *)in, inLen); break; case CKA_DIGEST: crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session, (unsigned char *)in, inLen); break; default: crv = CKR_OPERATION_NOT_INITIALIZED; break; } if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); rv = SECFailure; } /* * handle session starvation case.. use our last session to multiplex */ if (!context->ownSession) { context->savedData = pk11_saveContext(context,context->savedData, &context->savedLength); if (context->savedData == NULL) rv = SECFailure; /* clear out out session for others to use */ pk11_Finalize(context); } PK11_ExitContextMonitor(context); return rv; }
/* * execute a bulk encryption operation */ SECStatus PK11_CipherOp(PK11Context *context, unsigned char * out, int *outlen, int maxout, unsigned char *in, int inlen) { CK_RV crv = CKR_OK; CK_ULONG length = maxout; CK_ULONG offset =0; SECStatus rv = SECSuccess; unsigned char *saveOut = out; unsigned char *allocOut = NULL; /* if we ran out of session, we need to restore our previously stored * state. */ PK11_EnterContextMonitor(context); if (!context->ownSession) { rv = pk11_restoreContext(context,context->savedData, context->savedLength); if (rv != SECSuccess) { PK11_ExitContextMonitor(context); return rv; } } /* * The fortezza hack is to send 8 extra bytes on the first encrypted and * loose them on the first decrypt. */ if (context->fortezzaHack) { unsigned char random[8]; if (context->operation == CKA_ENCRYPT) { PK11_ExitContextMonitor(context); rv = PK11_GenerateRandom(random,sizeof(random)); PK11_EnterContextMonitor(context); /* since we are offseting the output, we can't encrypt back into * the same buffer... allocate a temporary buffer just for this * call. */ allocOut = out = (unsigned char*)PORT_Alloc(maxout); if (out == NULL) { PK11_ExitContextMonitor(context); return SECFailure; } crv = PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session, random,sizeof(random),out,&length); out += length; maxout -= length; offset = length; } else if (context->operation == CKA_DECRYPT) { length = sizeof(random); crv = PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session, in,sizeof(random),random,&length); inlen -= length; in += length; context->fortezzaHack = PR_FALSE; } } switch (context->operation) { case CKA_ENCRYPT: length = maxout; crv=PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session, in, inlen, out, &length); length += offset; break; case CKA_DECRYPT: length = maxout; crv=PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session, in, inlen, out, &length); break; default: crv = CKR_OPERATION_NOT_INITIALIZED; break; } if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); *outlen = 0; rv = SECFailure; } else { *outlen = length; } if (context->fortezzaHack) { if (context->operation == CKA_ENCRYPT) { PORT_Assert(allocOut); PORT_Memcpy(saveOut, allocOut, length); PORT_Free(allocOut); } context->fortezzaHack = PR_FALSE; } /* * handle session starvation case.. use our last session to multiplex */ if (!context->ownSession) { context->savedData = pk11_saveContext(context,context->savedData, &context->savedLength); if (context->savedData == NULL) rv = SECFailure; /* clear out out session for others to use */ pk11_Finalize(context); } PK11_ExitContextMonitor(context); return rv; }
/* * Check the user's password. Log into the card if it's correct. * succeed if the user is already logged in. */ static SECStatus pk11_CheckPassword(PK11SlotInfo *slot, CK_SESSION_HANDLE session, char *pw, PRBool alreadyLocked, PRBool contextSpecific) { int len = 0; CK_RV crv; SECStatus rv; int64 currtime = PR_Now(); PRBool mustRetry; int retry = 0; if (slot->protectedAuthPath) { len = 0; pw = NULL; } else if (pw == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } else { len = PORT_Strlen(pw); } do { if (!alreadyLocked) PK11_EnterSlotMonitor(slot); crv = PK11_GETTAB(slot)->C_Login(session, contextSpecific ? CKU_CONTEXT_SPECIFIC : CKU_USER, (unsigned char *)pw,len); slot->lastLoginCheck = 0; mustRetry = PR_FALSE; if (!alreadyLocked) PK11_ExitSlotMonitor(slot); switch (crv) { /* if we're already logged in, we're good to go */ case CKR_OK: /* TODO If it was for CKU_CONTEXT_SPECIFIC should we do this */ slot->authTransact = PK11_Global.transaction; /* Fall through */ case CKR_USER_ALREADY_LOGGED_IN: slot->authTime = currtime; rv = SECSuccess; break; case CKR_PIN_INCORRECT: PORT_SetError(SEC_ERROR_BAD_PASSWORD); rv = SECWouldBlock; /* everything else is ok, only the pin is bad */ break; /* someone called reset while we fetched the password, try again once * if the token is still there. */ case CKR_SESSION_HANDLE_INVALID: case CKR_SESSION_CLOSED: if (session != slot->session) { /* don't bother retrying, we were in a middle of an operation, * which is now lost. Just fail. */ PORT_SetError(PK11_MapError(crv)); rv = SECFailure; break; } if (retry++ == 0) { rv = PK11_InitToken(slot,PR_FALSE); if (rv == SECSuccess) { if (slot->session != CK_INVALID_SESSION) { session = slot->session; /* we should have * a new session now */ mustRetry = PR_TRUE; } else { PORT_SetError(PK11_MapError(crv)); rv = SECFailure; } } break; } /* Fall through */ default: PORT_SetError(PK11_MapError(crv)); rv = SECFailure; /* some failure we can't fix by retrying */ } } while (mustRetry); return rv; }
/* * initialize a user PIN Value */ SECStatus PK11_InitPin(PK11SlotInfo *slot, const char *ssopw, const char *userpw) { CK_SESSION_HANDLE rwsession = CK_INVALID_SESSION; CK_RV crv; SECStatus rv = SECFailure; int len; int ssolen; if (userpw == NULL) userpw = ""; if (ssopw == NULL) ssopw = ""; len = PORT_Strlen(userpw); ssolen = PORT_Strlen(ssopw); /* get a rwsession */ rwsession = PK11_GetRWSession(slot); if (rwsession == CK_INVALID_SESSION) { PORT_SetError(SEC_ERROR_BAD_DATA); slot->lastLoginCheck = 0; return rv; } if (slot->protectedAuthPath) { len = 0; ssolen = 0; ssopw = NULL; userpw = NULL; } /* check the password */ crv = PK11_GETTAB(slot)->C_Login(rwsession,CKU_SO, (unsigned char *)ssopw,ssolen); slot->lastLoginCheck = 0; if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); goto done; } crv = PK11_GETTAB(slot)->C_InitPIN(rwsession,(unsigned char *)userpw,len); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); } else { rv = SECSuccess; } done: PK11_GETTAB(slot)->C_Logout(rwsession); slot->lastLoginCheck = 0; PK11_RestoreROSession(slot,rwsession); if (rv == SECSuccess) { /* update our view of the world */ PK11_InitToken(slot,PR_TRUE); if (slot->needLogin) { PK11_EnterSlotMonitor(slot); PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER, (unsigned char *)userpw,len); slot->lastLoginCheck = 0; PK11_ExitSlotMonitor(slot); } } return rv; }
/* * Check the user's password. Log into the card if it's correct. * succeed if the user is already logged in. */ SECStatus pk11_CheckPassword(PK11SlotInfo *slot,char *pw) { int len = 0; CK_RV crv; SECStatus rv; int64 currtime = PR_Now(); PRBool mustRetry; int retry = 0; if (slot->protectedAuthPath) { len = 0; pw = NULL; } else if (pw == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } else { len = PORT_Strlen(pw); } do { PK11_EnterSlotMonitor(slot); crv = PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER, (unsigned char *)pw,len); slot->lastLoginCheck = 0; mustRetry = PR_FALSE; PK11_ExitSlotMonitor(slot); switch (crv) { /* if we're already logged in, we're good to go */ case CKR_OK: slot->authTransact = PK11_Global.transaction; /* Fall through */ case CKR_USER_ALREADY_LOGGED_IN: slot->authTime = currtime; rv = SECSuccess; break; case CKR_PIN_INCORRECT: PORT_SetError(SEC_ERROR_BAD_PASSWORD); rv = SECWouldBlock; /* everything else is ok, only the pin is bad */ break; /* someone called reset while we fetched the password, try again once * if the token is still there. */ case CKR_SESSION_HANDLE_INVALID: case CKR_SESSION_CLOSED: if (retry++ == 0) { rv = PK11_InitToken(slot,PR_FALSE); if (rv == SECSuccess) { if (slot->session != CK_INVALID_SESSION) { mustRetry = PR_TRUE; } else { PORT_SetError(PK11_MapError(crv)); rv = SECFailure; } } break; } /* Fall through */ default: PORT_SetError(PK11_MapError(crv)); rv = SECFailure; /* some failure we can't fix by retrying */ } } while (mustRetry); return rv; }
SECStatus PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj, SECItem *emailProfile, SECItem *profileTime) { CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME; CK_BBOOL ck_true = CK_TRUE; CK_ATTRIBUTE theTemplate[] = { { CKA_CLASS, NULL, 0 }, { CKA_TOKEN, NULL, 0 }, { CKA_SUBJECT, NULL, 0 }, { CKA_NETSCAPE_EMAIL, NULL, 0 }, { CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0 }, { CKA_VALUE, NULL, 0 } }; /* if you change the array, change the variable below as well */ int realSize = 0; CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE; CK_ATTRIBUTE *attrs = theTemplate; CK_SESSION_HANDLE rwsession; PK11SlotInfo *free_slot = NULL; CK_RV crv; #ifdef DEBUG int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); #endif PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++; PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true, sizeof(ck_true)); attrs++; PK11_SETATTRS(attrs, CKA_SUBJECT, derSubj->data, derSubj->len); attrs++; PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, emailAddr, PORT_Strlen(emailAddr)+1); attrs++; if (profileTime) { PK11_SETATTRS(attrs, CKA_NETSCAPE_SMIME_TIMESTAMP, profileTime->data, profileTime->len); attrs++; PK11_SETATTRS(attrs, CKA_VALUE,emailProfile->data, emailProfile->len); attrs++; } realSize = attrs - theTemplate; PORT_Assert (realSize <= tsize); if (slot == NULL) { free_slot = slot = PK11_GetInternalKeySlot(); /* we need to free the key slot in the end!!! */ } rwsession = PK11_GetRWSession(slot); if (rwsession == CK_INVALID_SESSION) { PORT_SetError(SEC_ERROR_READ_ONLY); if (free_slot) { PK11_FreeSlot(free_slot); } return SECFailure; } crv = PK11_GETTAB(slot)-> C_CreateObject(rwsession,theTemplate,realSize,&smimeh); if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); } PK11_RestoreROSession(slot,rwsession); if (free_slot) { PK11_FreeSlot(free_slot); } return SECSuccess; }
/* * load a new module into our address space and initialize it. */ SECStatus secmod_LoadPKCS11Module(SECMODModule *mod, SECMODModule **oldModule) { PRLibrary *library = NULL; CK_C_GetFunctionList entry = NULL; CK_INFO info; CK_ULONG slotCount = 0; SECStatus rv; PRBool alreadyLoaded = PR_FALSE; char *disableUnload = NULL; if (mod->loaded) return SECSuccess; /* internal modules get loaded from their internal list */ if (mod->internal && (mod->dllName == NULL)) { #ifdef NSS_TEST_BUILD entry = (CK_C_GetFunctionList)NSC_GetFunctionList; #else /* * Loads softoken as a dynamic library, * even though the rest of NSS assumes this as the "internal" module. */ if (!softokenLib && PR_SUCCESS != PR_CallOnce(&loadSoftokenOnce, &softoken_LoadDSO)) return SECFailure; PR_ATOMIC_INCREMENT(&softokenLoadCount); if (mod->isFIPS) { entry = (CK_C_GetFunctionList) PR_FindSymbol(softokenLib, "FC_GetFunctionList"); } else { entry = (CK_C_GetFunctionList) PR_FindSymbol(softokenLib, "NSC_GetFunctionList"); } if (!entry) return SECFailure; #endif if (mod->isModuleDB) { mod->moduleDBFunc = (CK_C_GetFunctionList) #ifdef NSS_TEST_BUILD NSC_ModuleDBFunc; #else PR_FindSymbol(softokenLib, "NSC_ModuleDBFunc"); #endif } if (mod->moduleDBOnly) { mod->loaded = PR_TRUE; return SECSuccess; } } else { /* Not internal, load the DLL and look up C_GetFunctionList */ if (mod->dllName == NULL) { return SECFailure; } /* load the library. If this succeeds, then we have to remember to * unload the library if anything goes wrong from here on out... */ library = PR_LoadLibrary(mod->dllName); mod->library = (void *)library; if (library == NULL) { return SECFailure; } /* * now we need to get the entry point to find the function pointers */ if (!mod->moduleDBOnly) { entry = (CK_C_GetFunctionList) PR_FindSymbol(library, "C_GetFunctionList"); } if (mod->isModuleDB) { mod->moduleDBFunc = (void *) PR_FindSymbol(library, "NSS_ReturnModuleSpecData"); } if (mod->moduleDBFunc == NULL) mod->isModuleDB = PR_FALSE; if (entry == NULL) { if (mod->isModuleDB) { mod->loaded = PR_TRUE; mod->moduleDBOnly = PR_TRUE; return SECSuccess; } PR_UnloadLibrary(library); return SECFailure; } } /* * We need to get the function list */ if ((*entry)((CK_FUNCTION_LIST_PTR *)&mod->functionList) != CKR_OK) goto fail; #ifdef DEBUG_MODULE if (PR_TRUE) { modToDBG = PR_GetEnvSecure("NSS_DEBUG_PKCS11_MODULE"); if (modToDBG && strcmp(mod->commonName, modToDBG) == 0) { mod->functionList = (void *)nss_InsertDeviceLog( (CK_FUNCTION_LIST_PTR)mod->functionList); } } #endif mod->isThreadSafe = PR_TRUE; /* Now we initialize the module */ rv = secmod_ModuleInit(mod, oldModule, &alreadyLoaded); if (rv != SECSuccess) { goto fail; } /* module has been reloaded, this module itself is done, * return to the caller */ if (mod->functionList == NULL) { mod->loaded = PR_TRUE; /* technically the module is loaded.. */ return SECSuccess; } /* check the version number */ if (PK11_GETTAB(mod)->C_GetInfo(&info) != CKR_OK) goto fail2; if (info.cryptokiVersion.major != 2) goto fail2; /* all 2.0 are a priori *not* thread safe */ if (info.cryptokiVersion.minor < 1) { if (!loadSingleThreadedModules) { PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11); goto fail2; } else { mod->isThreadSafe = PR_FALSE; } } mod->cryptokiVersion = info.cryptokiVersion; /* If we don't have a common name, get it from the PKCS 11 module */ if ((mod->commonName == NULL) || (mod->commonName[0] == 0)) { mod->commonName = PK11_MakeString(mod->arena, NULL, (char *)info.libraryDescription, sizeof(info.libraryDescription)); if (mod->commonName == NULL) goto fail2; } /* initialize the Slots */ if (PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, NULL, &slotCount) == CKR_OK) { CK_SLOT_ID *slotIDs; int i; CK_RV crv; mod->slots = (PK11SlotInfo **)PORT_ArenaAlloc(mod->arena, sizeof(PK11SlotInfo *) * slotCount); if (mod->slots == NULL) goto fail2; slotIDs = (CK_SLOT_ID *)PORT_Alloc(sizeof(CK_SLOT_ID) * slotCount); if (slotIDs == NULL) { goto fail2; } crv = PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, slotIDs, &slotCount); if (crv != CKR_OK) { PORT_Free(slotIDs); goto fail2; } /* Initialize each slot */ for (i = 0; i < (int)slotCount; i++) { mod->slots[i] = PK11_NewSlotInfo(mod); PK11_InitSlot(mod, slotIDs[i], mod->slots[i]); /* look down the slot info table */ PK11_LoadSlotList(mod->slots[i], mod->slotInfo, mod->slotInfoCount); SECMOD_SetRootCerts(mod->slots[i], mod); /* explicitly mark the internal slot as such if IsInternalKeySlot() * is set */ if (secmod_IsInternalKeySlot(mod) && (i == (mod->isFIPS ? 0 : 1))) { pk11_SetInternalKeySlotIfFirst(mod->slots[i]); } } mod->slotCount = slotCount; mod->slotInfoCount = 0; PORT_Free(slotIDs); } mod->loaded = PR_TRUE; mod->moduleID = nextModuleID++; return SECSuccess; fail2: if (enforceAlreadyInitializedError || (!alreadyLoaded)) { PK11_GETTAB(mod)->C_Finalize(NULL); } fail: mod->functionList = NULL; disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD"); if (library && !disableUnload) { PR_UnloadLibrary(library); } return SECFailure; }
/* * collect the steps we need to initialize a module in a single function */ SECStatus secmod_ModuleInit(SECMODModule *mod, SECMODModule **reload, PRBool *alreadyLoaded) { CK_C_INITIALIZE_ARGS moduleArgs; CK_VOID_PTR pInitArgs; CK_RV crv; if (reload) { *reload = NULL; } if (!mod || !alreadyLoaded) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (mod->libraryParams == NULL) { if (mod->isThreadSafe) { pInitArgs = (void *)&secmodLockFunctions; } else { pInitArgs = NULL; } } else { if (mod->isThreadSafe) { moduleArgs = secmodLockFunctions; } else { moduleArgs = secmodNoLockArgs; } moduleArgs.LibraryParameters = (void *)mod->libraryParams; pInitArgs = &moduleArgs; } crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs); if (CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) { SECMODModule *oldModule = NULL; /* Library has already been loaded once, if caller expects it, and it * has additional configuration, try reloading it as well. */ if (reload != NULL && mod->libraryParams) { oldModule = secmod_FindModuleByFuncPtr(mod->functionList); } /* Library has been loaded by NSS. It means it may be capable of * reloading */ if (oldModule) { SECStatus rv; rv = secmod_handleReload(oldModule, mod); if (rv == SECSuccess) { /* This module should go away soon, since we've * simply expanded the slots on the old module. * When it goes away, it should not Finalize since * that will close our old module as well. Setting * the function list to NULL will prevent that close */ mod->functionList = NULL; *reload = oldModule; return SECSuccess; } SECMOD_DestroyModule(oldModule); } /* reload not possible, fall back to old semantics */ if (!enforceAlreadyInitializedError) { *alreadyLoaded = PR_TRUE; return SECSuccess; } } if (crv != CKR_OK) { if (!mod->isThreadSafe || crv == CKR_NETSCAPE_CERTDB_FAILED || crv == CKR_NETSCAPE_KEYDB_FAILED) { PORT_SetError(PK11_MapError(crv)); return SECFailure; } /* If we had attempted to init a single threaded module "with" * parameters and it failed, should we retry "without" parameters? * (currently we don't retry in this scenario) */ if (!loadSingleThreadedModules) { PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11); return SECFailure; } /* If we arrive here, the module failed a ThreadSafe init. */ mod->isThreadSafe = PR_FALSE; if (!mod->libraryParams) { pInitArgs = NULL; } else { moduleArgs = secmodNoLockArgs; moduleArgs.LibraryParameters = (void *)mod->libraryParams; pInitArgs = &moduleArgs; } crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs); if ((CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) && (!enforceAlreadyInitializedError)) { *alreadyLoaded = PR_TRUE; return SECSuccess; } if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); return SECFailure; } } return SECSuccess; }
/* * destroy a symetric key */ void PK11_FreeSymKey(PK11SymKey *symKey) { PK11SlotInfo *slot; PRBool freeit = PR_TRUE; if (PR_ATOMIC_DECREMENT(&symKey->refCount) == 0) { PK11SymKey *parent = symKey->parent; symKey->parent = NULL; if ((symKey->owner) && symKey->objectID != CK_INVALID_HANDLE) { pk11_EnterKeyMonitor(symKey); (void) PK11_GETTAB(symKey->slot)-> C_DestroyObject(symKey->session, symKey->objectID); pk11_ExitKeyMonitor(symKey); } if (symKey->data.data) { PORT_Memset(symKey->data.data, 0, symKey->data.len); PORT_Free(symKey->data.data); } /* free any existing data */ if (symKey->userData && symKey->freeFunc) { (*symKey->freeFunc)(symKey->userData); } slot = symKey->slot; PZ_Lock(slot->freeListLock); if (slot->keyCount < slot->maxKeyCount) { /* * freeSymkeysWithSessionHead contain a list of reusable * SymKey structures with valid sessions. * sessionOwner must be true. * session must be valid. * freeSymKeysHead contain a list of SymKey structures without * valid session. * session must be CK_INVALID_SESSION. * though sessionOwner is false, callers should not depend on * this fact. */ if (symKey->sessionOwner) { PORT_Assert (symKey->session != CK_INVALID_SESSION); symKey->next = slot->freeSymKeysWithSessionHead; slot->freeSymKeysWithSessionHead = symKey; } else { symKey->session = CK_INVALID_SESSION; symKey->next = slot->freeSymKeysHead; slot->freeSymKeysHead = symKey; } slot->keyCount++; symKey->slot = NULL; freeit = PR_FALSE; } PZ_Unlock(slot->freeListLock); if (freeit) { pk11_CloseSession(symKey->slot, symKey->session, symKey->sessionOwner); PORT_Free(symKey); } PK11_FreeSlot(slot); if (parent) { PK11_FreeSymKey(parent); } } }
/* * check to see if the module has added new slots. PKCS 11 v2.20 allows for * modules to add new slots, but never remove them. Slots cannot be added * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently * grow on the caller. It is permissible for the slots to increase between * successive calls with NULL to get the size. */ SECStatus SECMOD_UpdateSlotList(SECMODModule *mod) { CK_RV crv; CK_ULONG count; CK_ULONG i, oldCount; PRBool freeRef = PR_FALSE; void *mark = NULL; CK_ULONG *slotIDs = NULL; PK11SlotInfo **newSlots = NULL; PK11SlotInfo **oldSlots = NULL; if (!moduleLock) { PORT_SetError(SEC_ERROR_NOT_INITIALIZED); return SECFailure; } /* C_GetSlotList is not a session function, make sure * calls are serialized */ PZ_Lock(mod->refLock); freeRef = PR_TRUE; /* see if the number of slots have changed */ crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, NULL, &count); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); goto loser; } /* nothing new, blow out early, we want this function to be quick * and cheap in the normal case */ if (count == mod->slotCount) { PZ_Unlock(mod->refLock); return SECSuccess; } if (count < (CK_ULONG)mod->slotCount) { /* shouldn't happen with a properly functioning PKCS #11 module */ PORT_SetError( SEC_ERROR_INCOMPATIBLE_PKCS11 ); goto loser; } /* get the new slot list */ slotIDs = PORT_NewArray(CK_SLOT_ID, count); if (slotIDs == NULL) { goto loser; } crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, slotIDs, &count); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); goto loser; } freeRef = PR_FALSE; PZ_Unlock(mod->refLock); mark = PORT_ArenaMark(mod->arena); if (mark == NULL) { goto loser; } newSlots = PORT_ArenaZNewArray(mod->arena,PK11SlotInfo *,count); /* walk down the new slot ID list returned from the module. We keep * the old slots which match a returned ID, and we initialize the new * slots. */ for (i=0; i < count; i++) { PK11SlotInfo *slot = SECMOD_FindSlotByID(mod,slotIDs[i]); if (!slot) { /* we have a new slot create a new slot data structure */ slot = PK11_NewSlotInfo(mod); if (!slot) { goto loser; } PK11_InitSlot(mod, slotIDs[i], slot); STAN_InitTokenForSlotInfo(NULL, slot); } newSlots[i] = slot; } STAN_ResetTokenInterator(NULL); PORT_Free(slotIDs); slotIDs = NULL; PORT_ArenaUnmark(mod->arena, mark); /* until this point we're still using the old slot list. Now we update * module slot list. We update the slots (array) first then the count, * since we've already guarrenteed that count has increased (just in case * someone is looking at the slots field of module without holding the * moduleLock */ SECMOD_GetWriteLock(moduleLock); oldCount =mod->slotCount; oldSlots = mod->slots; mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is * allocated out of the module arena and won't * be freed until the module is freed */ mod->slotCount = count; SECMOD_ReleaseWriteLock(moduleLock); /* free our old references before forgetting about oldSlot*/ for (i=0; i < oldCount; i++) { PK11_FreeSlot(oldSlots[i]); } return SECSuccess; loser: if (freeRef) { PZ_Unlock(mod->refLock); } if (slotIDs) { PORT_Free(slotIDs); } /* free all the slots we allocated. newSlots are part of the * mod arena. NOTE: the newSlots array contain both new and old * slots, but we kept a reference to the old slots when we built the new * array, so we need to free all the slots in newSlots array. */ if (newSlots) { for (i=0; i < count; i++) { if (newSlots[i] == NULL) { break; /* hit the last one */ } PK11_FreeSlot(newSlots[i]); } } /* must come after freeing newSlots */ if (mark) { PORT_ArenaRelease(mod->arena, mark); } return SECFailure; }
/* * this function waits for a token event on any slot of a given module * This function should not be called from more than one thread of the * same process (though other threads can make other library calls * on this module while this call is blocked). */ PK11SlotInfo * SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags, PRIntervalTime latency) { CK_SLOT_ID id; CK_RV crv; PK11SlotInfo *slot; if (!pk11_getFinalizeModulesOption() || ((mod->cryptokiVersion.major == 2) && (mod->cryptokiVersion.minor < 1))) { /* if we are sharing the module with other software in our * address space, we can't reliably use C_WaitForSlotEvent(), * and if the module is version 2.0, C_WaitForSlotEvent() doesn't * exist */ return secmod_HandleWaitForSlotEvent(mod, flags, latency); } /* first the the PKCS #11 call */ PZ_Lock(mod->refLock); if (mod->evControlMask & SECMOD_END_WAIT) { goto end_wait; } mod->evControlMask |= SECMOD_WAIT_PKCS11_EVENT; PZ_Unlock(mod->refLock); crv = PK11_GETTAB(mod)->C_WaitForSlotEvent(flags, &id, NULL); PZ_Lock(mod->refLock); mod->evControlMask &= ~SECMOD_WAIT_PKCS11_EVENT; /* if we are in end wait, short circuit now, don't even risk * going into secmod_HandleWaitForSlotEvent */ if (mod->evControlMask & SECMOD_END_WAIT) { goto end_wait; } PZ_Unlock(mod->refLock); if (crv == CKR_FUNCTION_NOT_SUPPORTED) { /* module doesn't support that call, simulate it */ return secmod_HandleWaitForSlotEvent(mod, flags, latency); } if (crv != CKR_OK) { /* we can get this error if finalize was called while we were * still running. This is the only way to force a C_WaitForSlotEvent() * to return in PKCS #11. In this case, just return that there * was no event. */ if (crv == CKR_CRYPTOKI_NOT_INITIALIZED) { PORT_SetError(SEC_ERROR_NO_EVENT); } else { PORT_SetError(PK11_MapError(crv)); } return NULL; } slot = SECMOD_FindSlotByID(mod, id); if (slot == NULL) { /* possibly a new slot that was added? */ SECMOD_UpdateSlotList(mod); slot = SECMOD_FindSlotByID(mod, id); } /* if we are in the delay period for the "isPresent" call, reset * the delay since we know things have probably changed... */ if (slot && slot->nssToken && slot->nssToken->slot) { nssSlot_ResetDelay(slot->nssToken->slot); } return slot; /* must be called with the lock on. */ end_wait: mod->evControlMask &= ~SECMOD_END_WAIT; PZ_Unlock(mod->refLock); PORT_SetError(SEC_ERROR_NO_EVENT); return NULL; }