/* * 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; }
/* * 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; }
/* * 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; }
/* * 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); } /* * 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; }
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; }
/* * copy a template of attributes from a source object to a target object. * if target object is not given, create it. */ static SECStatus pk11_copyAttributes(PLArenaPool *arena, PK11SlotInfo *targetSlot, CK_OBJECT_HANDLE targetID, PK11SlotInfo *sourceSlot, CK_OBJECT_HANDLE sourceID, CK_ATTRIBUTE *copyTemplate, CK_ULONG copyTemplateCount) { SECStatus rv; CK_ATTRIBUTE *newTemplate = NULL; CK_RV crv; crv = PK11_GetAttributes(arena, sourceSlot, sourceID, copyTemplate, copyTemplateCount); /* if we have missing attributes, just skip them and create the object */ if (crv == CKR_ATTRIBUTE_TYPE_INVALID) { CK_ULONG i, j; newTemplate = PORT_NewArray(CK_ATTRIBUTE, copyTemplateCount); if (!newTemplate) { return SECFailure; } /* remove the unknown attributes. If we don't have enough attributes * PK11_CreateNewObject() will fail */ for (i = 0, j = 0; i < copyTemplateCount; i++) { if (copyTemplate[i].ulValueLen != -1) { newTemplate[j] = copyTemplate[i]; j++; } } copyTemplate = newTemplate; copyTemplateCount = j; crv = PK11_GetAttributes(arena, sourceSlot, sourceID, copyTemplate, copyTemplateCount); } if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); return SECFailure; } if (targetID == CK_INVALID_HANDLE) { /* we need to create the object */ rv = PK11_CreateNewObject(targetSlot, CK_INVALID_SESSION, copyTemplate, copyTemplateCount, PR_TRUE, &targetID); } else { /* update the existing object with the new attributes */ rv = pk11_setAttributes(targetSlot, targetID, copyTemplate, copyTemplateCount); } if (newTemplate) { free(newTemplate); } 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; }
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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * return the certificate associated with a derCert */ SECItem * PK11_FindSMimeProfile(PK11SlotInfo **slot, char *emailAddr, SECItem *name, SECItem **profileTime) { CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME; CK_ATTRIBUTE theTemplate[] = { { CKA_SUBJECT, NULL, 0 }, { CKA_CLASS, NULL, 0 }, { CKA_NETSCAPE_EMAIL, NULL, 0 }, }; CK_ATTRIBUTE smimeData[] = { { CKA_SUBJECT, NULL, 0 }, { CKA_VALUE, NULL, 0 }, }; /* if you change the array, change the variable below as well */ int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE; CK_ATTRIBUTE *attrs = theTemplate; CK_RV crv; SECItem *emailProfile = NULL; if (!emailAddr || !emailAddr[0]) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++; PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++; PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, emailAddr, strlen(emailAddr)); attrs++; if (*slot) { smimeh = pk11_FindObjectByTemplate(*slot,theTemplate,tsize); } else { PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE,PR_TRUE,NULL); PK11SlotListElement *le; if (!list) { return NULL; } /* loop through all the slots */ for (le = list->head; le; le = le->next) { smimeh = pk11_FindObjectByTemplate(le->slot,theTemplate,tsize); if (smimeh != CK_INVALID_HANDLE) { *slot = PK11_ReferenceSlot(le->slot); break; } } PK11_FreeSlotList(list); } if (smimeh == CK_INVALID_HANDLE) { PORT_SetError(SEC_ERROR_NO_KRL); return NULL; } if (profileTime) { PK11_SETATTRS(smimeData, CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0); } crv = PK11_GetAttributes(NULL,*slot,smimeh,smimeData,2); if (crv != CKR_OK) { PORT_SetError(PK11_MapError (crv)); goto loser; } if (!profileTime) { SECItem profileSubject; profileSubject.data = (unsigned char*) smimeData[0].pValue; profileSubject.len = smimeData[0].ulValueLen; if (!SECITEM_ItemsAreEqual(&profileSubject,name)) { goto loser; } } emailProfile = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); if (emailProfile == NULL) { goto loser; } emailProfile->data = (unsigned char*) smimeData[1].pValue; emailProfile->len = smimeData[1].ulValueLen; if (profileTime) { *profileTime = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); if (*profileTime) { (*profileTime)->data = (unsigned char*) smimeData[0].pValue; (*profileTime)->len = smimeData[0].ulValueLen; } } loser: if (emailProfile == NULL) { if (smimeData[1].pValue) { PORT_Free(smimeData[1].pValue); } } if (profileTime == NULL || *profileTime == NULL) { if (smimeData[0].pValue) { PORT_Free(smimeData[0].pValue); } } return emailProfile; }
static SECStatus pk11_RetrieveCrlsCallback(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID, void *arg) { SECItem* derCrl = NULL; crlOptions* options = (crlOptions*) arg; CERTCrlHeadNode *head = options->head; CERTCrlNode *new_node = NULL; CK_ATTRIBUTE fetchCrl[3] = { { CKA_VALUE, NULL, 0}, { CKA_NETSCAPE_KRL, NULL, 0}, { CKA_NETSCAPE_URL, NULL, 0}, }; const int fetchCrlSize = sizeof(fetchCrl)/sizeof(fetchCrl[2]); CK_RV crv; SECStatus rv = SECFailure; PRBool adopted = PR_FALSE; /* whether the CRL adopted the DER memory successfully */ int i; crv = PK11_GetAttributes(NULL,slot,crlID,fetchCrl,fetchCrlSize); if (CKR_OK != crv) { PORT_SetError(PK11_MapError(crv)); goto loser; } if (!fetchCrl[1].pValue) { /* reject KRLs */ PORT_SetError(SEC_ERROR_CRL_INVALID); goto loser; } new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode)); if (new_node == NULL) { goto loser; } new_node->type = SEC_CRL_TYPE; derCrl = SECITEM_AllocItem(NULL, NULL, 0); if (!derCrl) { goto loser; } derCrl->type = siBuffer; derCrl->data = (unsigned char *)fetchCrl[0].pValue; derCrl->len = fetchCrl[0].ulValueLen; new_node->crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl,new_node->type, options->decodeOptions); if (new_node->crl == NULL) { goto loser; } adopted = PR_TRUE; /* now that the CRL has adopted the DER memory, we won't need to free it upon exit */ if (fetchCrl[2].pValue && fetchCrl[2].ulValueLen) { /* copy the URL if there is one */ int nnlen = fetchCrl[2].ulValueLen; new_node->crl->url = (char *)PORT_ArenaAlloc(new_node->crl->arena, nnlen+1); if ( !new_node->crl->url ) { goto loser; } PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen); new_node->crl->url[nnlen] = 0; } else { new_node->crl->url = NULL; } new_node->next = NULL; if (head->last) { head->last->next = new_node; head->last = new_node; } else { head->first = head->last = new_node; } rv = SECSuccess; new_node->crl->slot = PK11_ReferenceSlot(slot); new_node->crl->pkcs11ID = crlID; loser: /* free attributes that weren't adopted by the CRL */ for (i=1;i<fetchCrlSize;i++) { if (fetchCrl[i].pValue) { PORT_Free(fetchCrl[i].pValue); } } /* free the DER if the CRL object didn't adopt it */ if (fetchCrl[0].pValue && PR_FALSE == adopted) { PORT_Free(fetchCrl[0].pValue); } if (derCrl && !adopted) { /* clear the data fields, which we already took care of above */ derCrl->data = NULL; derCrl->len = 0; /* free the memory for the SECItem structure itself */ SECITEM_FreeItem(derCrl, PR_TRUE); } return(rv); }
static SECStatus pk11_CollectCrls(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID, void *arg) { SECItem derCrl; CERTCrlHeadNode *head = (CERTCrlHeadNode *) arg; CERTCrlNode *new_node = NULL; CK_ATTRIBUTE fetchCrl[3] = { { CKA_VALUE, NULL, 0}, { CKA_NETSCAPE_KRL, NULL, 0}, { CKA_NETSCAPE_URL, NULL, 0}, }; const int fetchCrlSize = sizeof(fetchCrl)/sizeof(fetchCrl[2]); CK_RV crv; SECStatus rv = SECFailure; crv = PK11_GetAttributes(head->arena,slot,crlID,fetchCrl,fetchCrlSize); if (CKR_OK != crv) { PORT_SetError(PK11_MapError(crv)); goto loser; } if (!fetchCrl[1].pValue) { PORT_SetError(SEC_ERROR_CRL_INVALID); goto loser; } new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode)); if (new_node == NULL) { goto loser; } if (*((CK_BBOOL *)fetchCrl[1].pValue)) new_node->type = SEC_KRL_TYPE; else new_node->type = SEC_CRL_TYPE; derCrl.type = siBuffer; derCrl.data = (unsigned char *)fetchCrl[0].pValue; derCrl.len = fetchCrl[0].ulValueLen; new_node->crl=CERT_DecodeDERCrl(head->arena,&derCrl,new_node->type); if (new_node->crl == NULL) { goto loser; } if (fetchCrl[2].pValue) { int nnlen = fetchCrl[2].ulValueLen; new_node->crl->url = (char *)PORT_ArenaAlloc(head->arena, nnlen+1); if ( !new_node->crl->url ) { goto loser; } PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen); new_node->crl->url[nnlen] = 0; } else { new_node->crl->url = NULL; } new_node->next = NULL; if (head->last) { head->last->next = new_node; head->last = new_node; } else { head->first = head->last = new_node; } rv = SECSuccess; loser: return(rv); }
/* * 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; }
/* * map Stan errors into NSS errors * This function examines the stan error stack and automatically sets * PORT_SetError(); to the appropriate SEC_ERROR value. */ void CERT_MapStanError() { PRInt32 *errorStack; NSSError error, prevError; int secError; int i; error = 0; errorStack = NSS_GetErrorStack(); if (errorStack == 0) { PORT_SetError(0); return; } error = prevError = CKR_GENERAL_ERROR; /* get the 'top 2' error codes from the stack */ for (i = 0; errorStack[i]; i++) { prevError = error; error = errorStack[i]; } if (error == NSS_ERROR_PKCS11) { /* map it */ secError = PK11_MapError(prevError); } STAN_MAP_ERROR(NSS_ERROR_NO_ERROR, 0) STAN_MAP_ERROR(NSS_ERROR_NO_MEMORY, SEC_ERROR_NO_MEMORY) STAN_MAP_ERROR(NSS_ERROR_INVALID_BASE64, SEC_ERROR_BAD_DATA) STAN_MAP_ERROR(NSS_ERROR_INVALID_BER, SEC_ERROR_BAD_DER) STAN_MAP_ERROR(NSS_ERROR_INVALID_ATAV, SEC_ERROR_INVALID_AVA) STAN_MAP_ERROR(NSS_ERROR_INVALID_PASSWORD, SEC_ERROR_BAD_PASSWORD) STAN_MAP_ERROR(NSS_ERROR_BUSY, SEC_ERROR_BUSY) STAN_MAP_ERROR(NSS_ERROR_DEVICE_ERROR, SEC_ERROR_IO) STAN_MAP_ERROR(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND, SEC_ERROR_UNKNOWN_ISSUER) STAN_MAP_ERROR(NSS_ERROR_INVALID_CERTIFICATE, SEC_ERROR_CERT_NOT_VALID) STAN_MAP_ERROR(NSS_ERROR_INVALID_UTF8, SEC_ERROR_BAD_DATA) STAN_MAP_ERROR(NSS_ERROR_INVALID_NSSOID, SEC_ERROR_BAD_DATA) /* these are library failure for lack of a better error code */ STAN_MAP_ERROR(NSS_ERROR_NOT_FOUND, SEC_ERROR_LIBRARY_FAILURE) STAN_MAP_ERROR(NSS_ERROR_CERTIFICATE_IN_CACHE, SEC_ERROR_LIBRARY_FAILURE) STAN_MAP_ERROR(NSS_ERROR_MAXIMUM_FOUND, SEC_ERROR_LIBRARY_FAILURE) STAN_MAP_ERROR(NSS_ERROR_USER_CANCELED, SEC_ERROR_LIBRARY_FAILURE) STAN_MAP_ERROR(NSS_ERROR_TRACKER_NOT_INITIALIZED, SEC_ERROR_LIBRARY_FAILURE) STAN_MAP_ERROR(NSS_ERROR_ALREADY_INITIALIZED, SEC_ERROR_LIBRARY_FAILURE) STAN_MAP_ERROR(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD, SEC_ERROR_LIBRARY_FAILURE) STAN_MAP_ERROR(NSS_ERROR_HASH_COLLISION, SEC_ERROR_LIBRARY_FAILURE) STAN_MAP_ERROR(NSS_ERROR_INTERNAL_ERROR, SEC_ERROR_LIBRARY_FAILURE) /* these are all invalid arguments */ STAN_MAP_ERROR(NSS_ERROR_INVALID_ARGUMENT, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_INVALID_POINTER, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_INVALID_ARENA, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_INVALID_ARENA_MARK, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_DUPLICATE_POINTER, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_POINTER_NOT_REGISTERED, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_TRACKER_NOT_EMPTY, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_VALUE_TOO_LARGE, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_UNSUPPORTED_TYPE, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_BUFFER_TOO_SHORT, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_INVALID_ATOB_CONTEXT, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_INVALID_BTOA_CONTEXT, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_INVALID_ITEM, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_INVALID_STRING, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_INVALID_ASN1ENCODER, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_INVALID_ASN1DECODER, SEC_ERROR_INVALID_ARGS) STAN_MAP_ERROR(NSS_ERROR_UNKNOWN_ATTRIBUTE, SEC_ERROR_INVALID_ARGS) else { secError = SEC_ERROR_LIBRARY_FAILURE; } PORT_SetError(secError); }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }