NSS_IMPLEMENT NSSItem * nssToken_FinishDigest ( NSSToken *tok, nssSession *sessionOpt, NSSItem *rvOpt, NSSArena *arenaOpt ) { CK_RV ckrv; CK_ULONG digestLen; CK_BYTE_PTR digest; NSSItem *rvItem = NULL; void *epv = nssToken_GetCryptokiEPV(tok); nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession; /* Don't ask the module to use an invalid session handle. */ if (!session || session->handle == CK_INVALID_SESSION) { PORT_SetError(SEC_ERROR_NO_TOKEN); return NULL; } nssSession_EnterMonitor(session); ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen); if (ckrv != CKR_OK || digestLen == 0) { nssSession_ExitMonitor(session); return NULL; } digest = NULL; if (rvOpt) { if (rvOpt->size > 0 && rvOpt->size < digestLen) { nssSession_ExitMonitor(session); /* the error should be bad args */ return NULL; } if (rvOpt->data) { digest = rvOpt->data; } digestLen = rvOpt->size; } if (!digest) { digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen); if (!digest) { nssSession_ExitMonitor(session); return NULL; } } ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen); nssSession_ExitMonitor(session); if (ckrv != CKR_OK) { nss_ZFreeIf(digest); return NULL; } if (!rvOpt) { rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest); } return rvItem; }
NSS_IMPLEMENT PRBool nssCKObject_IsAttributeTrue( CK_OBJECT_HANDLE object, CK_ATTRIBUTE_TYPE attribute, nssSession *session, NSSSlot *slot, PRStatus *rvStatus) { CK_BBOOL bool; CK_ATTRIBUTE_PTR attr; CK_ATTRIBUTE atemplate = { 0, NULL, 0 }; CK_RV ckrv; void *epv = nssSlot_GetCryptokiEPV(slot); attr = &atemplate; NSS_CK_SET_ATTRIBUTE_VAR(attr, attribute, bool); nssSession_EnterMonitor(session); ckrv = CKAPI(epv)->C_GetAttributeValue(session->handle, object, &atemplate, 1); nssSession_ExitMonitor(session); if (ckrv != CKR_OK) { *rvStatus = PR_FAILURE; return PR_FALSE; } *rvStatus = PR_SUCCESS; return (PRBool)(bool == CK_TRUE); }
NSS_IMPLEMENT PRStatus nssCryptokiPrivateKey_SetCertificate ( nssCryptokiObject *keyObject, nssSession *sessionOpt, const NSSUTF8 *nickname, NSSItem *id, NSSDER *subject ) { CK_RV ckrv; CK_ATTRIBUTE_PTR attr; CK_ATTRIBUTE key_template[3]; CK_ULONG key_size; void *epv = nssToken_GetCryptokiEPV(keyObject->token); nssSession *session; NSSToken *token = keyObject->token; nssSession *defaultSession = nssToken_GetDefaultSession(token); PRBool createdSession = PR_FALSE; NSS_CK_TEMPLATE_START(key_template, attr, key_size); NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname); NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id); NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject); NSS_CK_TEMPLATE_FINISH(key_template, attr, key_size); if (sessionOpt) { if (!nssSession_IsReadWrite(sessionOpt)) { return PR_FAILURE; } session = sessionOpt; } else if (defaultSession && nssSession_IsReadWrite(defaultSession)) { session = defaultSession; } else { NSSSlot *slot = nssToken_GetSlot(token); session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE); nssSlot_Destroy(slot); if (!session) { return PR_FAILURE; } createdSession = PR_TRUE; } ckrv = CKAPI(epv)->C_SetAttributeValue(session->handle, keyObject->handle, key_template, key_size); if (createdSession) { nssSession_Destroy(session); } return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE; }
static nssCryptokiObject * import_object ( NSSToken *tok, nssSession *sessionOpt, CK_ATTRIBUTE_PTR objectTemplate, CK_ULONG otsize ) { nssSession *session = NULL; PRBool createdSession = PR_FALSE; nssCryptokiObject *object = NULL; CK_OBJECT_HANDLE handle; CK_RV ckrv; void *epv = nssToken_GetCryptokiEPV(tok); if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) { if (sessionOpt) { if (!nssSession_IsReadWrite(sessionOpt)) { nss_SetError(NSS_ERROR_INVALID_ARGUMENT); return NULL; } session = sessionOpt; } else if (tok->defaultSession && nssSession_IsReadWrite(tok->defaultSession)) { session = tok->defaultSession; } else { session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE); createdSession = PR_TRUE; } } else { session = (sessionOpt) ? sessionOpt : tok->defaultSession; } if (session == NULL) { nss_SetError(NSS_ERROR_INVALID_ARGUMENT); return NULL; } nssSession_EnterMonitor(session); ckrv = CKAPI(epv)->C_CreateObject(session->handle, objectTemplate, otsize, &handle); nssSession_ExitMonitor(session); if (ckrv == CKR_OK) { object = nssCryptokiObject_Create(tok, session, handle); } else { nss_SetError(ckrv); nss_SetError(NSS_ERROR_PKCS11); } if (createdSession) { nssSession_Destroy(session); } return object; }
NSS_IMPLEMENT PRStatus nssCKObject_SetAttributes( CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR obj_template, CK_ULONG count, nssSession *session, NSSSlot *slot) { CK_RV ckrv; void *epv = nssSlot_GetCryptokiEPV(slot); nssSession_EnterMonitor(session); ckrv = CKAPI(epv)->C_SetAttributeValue(session->handle, object, obj_template, count); nssSession_ExitMonitor(session); if (ckrv == CKR_OK) { return PR_SUCCESS; } else { return PR_FAILURE; } }
NSS_IMPLEMENT PRStatus nssToken_DeleteStoredObject ( nssCryptokiObject *instance ) { CK_RV ckrv; PRStatus status; PRBool createdSession = PR_FALSE; NSSToken *token = instance->token; nssSession *session = NULL; void *epv = nssToken_GetCryptokiEPV(instance->token); if (token->cache) { nssTokenObjectCache_RemoveObject(token->cache, instance); } if (instance->isTokenObject) { if (token->defaultSession && nssSession_IsReadWrite(token->defaultSession)) { session = token->defaultSession; } else { session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE); createdSession = PR_TRUE; } } if (session == NULL) { return PR_FAILURE; } nssSession_EnterMonitor(session); ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle); nssSession_ExitMonitor(session); if (createdSession) { nssSession_Destroy(session); } status = PR_SUCCESS; if (ckrv != CKR_OK) { status = PR_FAILURE; /* use the error stack to pass the PKCS #11 error out */ nss_SetError(ckrv); nss_SetError(NSS_ERROR_PKCS11); } return status; }
NSS_IMPLEMENT PRStatus nssToken_BeginDigest ( NSSToken *tok, nssSession *sessionOpt, NSSAlgorithmAndParameters *ap ) { CK_RV ckrv; void *epv = nssToken_GetCryptokiEPV(tok); nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession; /* Don't ask the module to use an invalid session handle. */ if (!session || session->handle == CK_INVALID_SESSION) { PORT_SetError(SEC_ERROR_NO_TOKEN); return PR_FAILURE; } nssSession_EnterMonitor(session); ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism); nssSession_ExitMonitor(session); return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE; }
NSS_IMPLEMENT PRStatus nssToken_ContinueDigest ( NSSToken *tok, nssSession *sessionOpt, NSSItem *item ) { CK_RV ckrv; void *epv = nssToken_GetCryptokiEPV(tok); nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession; /* Don't ask the module to use an invalid session handle. */ if (!session || session->handle == CK_INVALID_SESSION) { PORT_SetError(SEC_ERROR_NO_TOKEN); return PR_FAILURE; } nssSession_EnterMonitor(session); ckrv = CKAPI(epv)->C_DigestUpdate(session->handle, (CK_BYTE_PTR)item->data, (CK_ULONG)item->size); nssSession_ExitMonitor(session); return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE; }
/* Sigh. The methods to find objects declared above cause problems with * the low-level object cache in the softoken -- the objects are found in * toto, then one wave of GetAttributes is done, then another. Having a * large number of objects causes the cache to be thrashed, as the objects * are gone before there's any chance to ask for their attributes. * So, for now, bringing back traversal methods for certs. This way all of * the cert's attributes can be grabbed immediately after finding it, * increasing the likelihood that the cache takes care of it. */ NSS_IMPLEMENT PRStatus nssToken_TraverseCertificates ( NSSToken *token, nssSession *sessionOpt, nssTokenSearchType searchType, PRStatus (* callback)(nssCryptokiObject *instance, void *arg), void *arg ) { CK_RV ckrv; CK_ULONG count; CK_OBJECT_HANDLE *objectHandles; CK_ATTRIBUTE_PTR attr; CK_ATTRIBUTE cert_template[2]; CK_ULONG ctsize; NSSArena *arena; PRStatus status; PRUint32 arraySize, numHandles; nssCryptokiObject **objects; void *epv = nssToken_GetCryptokiEPV(token); nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession; /* Don't ask the module to use an invalid session handle. */ if (!session || session->handle == CK_INVALID_SESSION) { PORT_SetError(SEC_ERROR_NO_TOKEN); return PR_FAILURE; } /* template for all certs */ NSS_CK_TEMPLATE_START(cert_template, attr, ctsize); if (searchType == nssTokenSearchType_SessionOnly) { NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); } else if (searchType == nssTokenSearchType_TokenOnly || searchType == nssTokenSearchType_TokenForced) { NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); } NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert); NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize); /* the arena is only for the array of object handles */ arena = nssArena_Create(); if (!arena) { return PR_FAILURE; } arraySize = OBJECT_STACK_SIZE; numHandles = 0; objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize); if (!objectHandles) { goto loser; } nssSession_EnterMonitor(session); /* ==== session lock === */ /* Initialize the find with the template */ ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle, cert_template, ctsize); if (ckrv != CKR_OK) { nssSession_ExitMonitor(session); goto loser; } while (PR_TRUE) { /* Issue the find for up to arraySize - numHandles objects */ ckrv = CKAPI(epv)->C_FindObjects(session->handle, objectHandles + numHandles, arraySize - numHandles, &count); if (ckrv != CKR_OK) { nssSession_ExitMonitor(session); goto loser; } /* bump the number of found objects */ numHandles += count; if (numHandles < arraySize) { break; } /* the array is filled, double it and continue */ arraySize *= 2; objectHandles = nss_ZREALLOCARRAY(objectHandles, CK_OBJECT_HANDLE, arraySize); if (!objectHandles) { nssSession_ExitMonitor(session); goto loser; } } ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle); nssSession_ExitMonitor(session); /* ==== end session lock === */ if (ckrv != CKR_OK) { goto loser; } if (numHandles > 0) { objects = create_objects_from_handles(token, session, objectHandles, numHandles); if (objects) { nssCryptokiObject **op; for (op = objects; *op; op++) { status = (*callback)(*op, arg); } nss_ZFreeIf(objects); } } nssArena_Destroy(arena); return PR_SUCCESS; loser: nssArena_Destroy(arena); return PR_FAILURE; }
NSS_IMPLEMENT NSSItem * nssToken_Digest ( NSSToken *tok, nssSession *sessionOpt, NSSAlgorithmAndParameters *ap, NSSItem *data, NSSItem *rvOpt, NSSArena *arenaOpt ) { CK_RV ckrv; CK_ULONG digestLen; CK_BYTE_PTR digest; NSSItem *rvItem = NULL; void *epv = nssToken_GetCryptokiEPV(tok); nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession; /* Don't ask the module to use an invalid session handle. */ if (!session || session->handle == CK_INVALID_SESSION) { PORT_SetError(SEC_ERROR_NO_TOKEN); return rvItem; } nssSession_EnterMonitor(session); ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism); if (ckrv != CKR_OK) { nssSession_ExitMonitor(session); return NULL; } #if 0 /* XXX the standard says this should work, but it doesn't */ ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen); if (ckrv != CKR_OK) { nssSession_ExitMonitor(session); return NULL; } #endif digestLen = 0; /* XXX for now */ digest = NULL; if (rvOpt) { if (rvOpt->size > 0 && rvOpt->size < digestLen) { nssSession_ExitMonitor(session); /* the error should be bad args */ return NULL; } if (rvOpt->data) { digest = rvOpt->data; } digestLen = rvOpt->size; } if (!digest) { digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen); if (!digest) { nssSession_ExitMonitor(session); return NULL; } } ckrv = CKAPI(epv)->C_Digest(session->handle, (CK_BYTE_PTR)data->data, (CK_ULONG)data->size, (CK_BYTE_PTR)digest, &digestLen); nssSession_ExitMonitor(session); if (ckrv != CKR_OK) { nss_ZFreeIf(digest); return NULL; } if (!rvOpt) { rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest); } return rvItem; }
NSS_IMPLEMENT PRStatus nssCKObject_GetAttributes( CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR obj_template, CK_ULONG count, NSSArena *arenaOpt, nssSession *session, NSSSlot *slot) { nssArenaMark *mark = NULL; CK_SESSION_HANDLE hSession; CK_ULONG i = 0; CK_RV ckrv; PRStatus nssrv; PRBool alloced = PR_FALSE; void *epv = nssSlot_GetCryptokiEPV(slot); hSession = session->handle; if (arenaOpt) { mark = nssArena_Mark(arenaOpt); if (!mark) { goto loser; } } nssSession_EnterMonitor(session); /* XXX kinda hacky, if the storage size is already in the first template * item, then skip the alloc portion */ if (obj_template[0].ulValueLen == 0) { /* Get the storage size needed for each attribute */ ckrv = CKAPI(epv)->C_GetAttributeValue(hSession, object, obj_template, count); if (ckrv != CKR_OK && ckrv != CKR_ATTRIBUTE_TYPE_INVALID && ckrv != CKR_ATTRIBUTE_SENSITIVE) { nssSession_ExitMonitor(session); nss_SetError(NSS_ERROR_DEVICE_ERROR); goto loser; } /* Allocate memory for each attribute. */ for (i = 0; i < count; i++) { CK_ULONG ulValueLen = obj_template[i].ulValueLen; if (ulValueLen == 0 || ulValueLen == (CK_ULONG)-1) { obj_template[i].pValue = NULL; obj_template[i].ulValueLen = 0; continue; } if (is_string_attribute(obj_template[i].type)) { ulValueLen++; } obj_template[i].pValue = nss_ZAlloc(arenaOpt, ulValueLen); if (!obj_template[i].pValue) { nssSession_ExitMonitor(session); goto loser; } } alloced = PR_TRUE; } /* Obtain the actual attribute values. */ ckrv = CKAPI(epv)->C_GetAttributeValue(hSession, object, obj_template, count); nssSession_ExitMonitor(session); if (ckrv != CKR_OK && ckrv != CKR_ATTRIBUTE_TYPE_INVALID && ckrv != CKR_ATTRIBUTE_SENSITIVE) { nss_SetError(NSS_ERROR_DEVICE_ERROR); goto loser; } if (alloced && arenaOpt) { nssrv = nssArena_Unmark(arenaOpt, mark); if (nssrv != PR_SUCCESS) { goto loser; } } if (count > 1 && ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) || (ckrv == CKR_ATTRIBUTE_SENSITIVE))) { /* old tokens would keep the length of '0' and not deal with any * of the attributes we passed. For those tokens read them one at * a time */ for (i = 0; i < count; i++) { if ((obj_template[i].ulValueLen == 0) || (obj_template[i].ulValueLen == -1)) { obj_template[i].ulValueLen = 0; (void)nssCKObject_GetAttributes(object, &obj_template[i], 1, arenaOpt, session, slot); } } } return PR_SUCCESS; loser: if (alloced) { if (arenaOpt) { /* release all arena memory allocated before the failure. */ (void)nssArena_Release(arenaOpt, mark); } else { CK_ULONG j; /* free each heap object that was allocated before the failure. */ for (j = 0; j < i; j++) { nss_ZFreeIf(obj_template[j].pValue); } } } return PR_FAILURE; }
NSS_IMPLEMENT PRBool nssSlot_IsTokenPresent ( NSSSlot *slot ) { CK_RV ckrv; PRStatus nssrv; /* XXX */ nssSession *session; CK_SLOT_INFO slotInfo; void *epv; /* permanent slots are always present unless they're disabled */ if (nssSlot_IsPermanent(slot)) { return !PK11_IsDisabled(slot->pk11slot); } /* avoid repeated calls to check token status within set interval */ if (within_token_delay_period(slot)) { return ((slot->ckFlags & CKF_TOKEN_PRESENT) != 0); } /* First obtain the slot info */ epv = slot->epv; if (!epv) { return PR_FALSE; } nssSlot_EnterMonitor(slot); ckrv = CKAPI(epv)->C_GetSlotInfo(slot->slotID, &slotInfo); nssSlot_ExitMonitor(slot); if (ckrv != CKR_OK) { slot->token->base.name[0] = 0; /* XXX */ return PR_FALSE; } slot->ckFlags = slotInfo.flags; /* check for the presence of the token */ if ((slot->ckFlags & CKF_TOKEN_PRESENT) == 0) { if (!slot->token) { /* token was never present */ return PR_FALSE; } session = nssToken_GetDefaultSession(slot->token); if (session) { nssSession_EnterMonitor(session); /* token is not present */ if (session->handle != CK_INVALID_SESSION) { /* session is valid, close and invalidate it */ CKAPI(epv)->C_CloseSession(session->handle); session->handle = CK_INVALID_SESSION; } nssSession_ExitMonitor(session); } if (slot->token->base.name[0] != 0) { /* notify the high-level cache that the token is removed */ slot->token->base.name[0] = 0; /* XXX */ nssToken_NotifyCertsNotVisible(slot->token); } slot->token->base.name[0] = 0; /* XXX */ /* clear the token cache */ nssToken_Remove(slot->token); return PR_FALSE; } /* token is present, use the session info to determine if the card * has been removed and reinserted. */ session = nssToken_GetDefaultSession(slot->token); if (session) { PRBool isPresent = PR_FALSE; nssSession_EnterMonitor(session); if (session->handle != CK_INVALID_SESSION) { CK_SESSION_INFO sessionInfo; ckrv = CKAPI(epv)->C_GetSessionInfo(session->handle, &sessionInfo); if (ckrv != CKR_OK) { /* session is screwy, close and invalidate it */ CKAPI(epv)->C_CloseSession(session->handle); session->handle = CK_INVALID_SESSION; } } isPresent = session->handle != CK_INVALID_SESSION; nssSession_ExitMonitor(session); /* token not removed, finished */ if (isPresent) return PR_TRUE; } /* the token has been removed, and reinserted, or the slot contains * a token it doesn't recognize. invalidate all the old * information we had on this token, if we can't refresh, clear * the present flag */ nssToken_NotifyCertsNotVisible(slot->token); nssToken_Remove(slot->token); /* token has been removed, need to refresh with new session */ nssrv = nssSlot_Refresh(slot); if (nssrv != PR_SUCCESS) { slot->token->base.name[0] = 0; /* XXX */ slot->ckFlags &= ~CKF_TOKEN_PRESENT; return PR_FALSE; } return PR_TRUE; }