mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-13 11:10:13 +01:00
30d33aa8e8
9934c8faef29, 3c3b381c4865, 5a67f6beee9a, 1b1eb6d77728, a8b668fd72f7, bug962760, bug743700, bug857304, bug972653, bug972450, bug971358, bug903885, bug977073, bug976111, bug949939, bug947653, bug947572, bug903885, bug979106, bug966596, bug979004, bug979752, bug980848, bug938369, bug981170, bug668130, bug974693, bug975056, bug979132, bug370717, bug979070, bug985070, bug900067, bug977673, bug519255, bug989558, bug557299, bug987263, bug369802, a751a5146718, bug992343, bug952572, bug979703, bug994883, bug994869, bug993489, bug984608, bug977869, bug667371, bug672828, bug793347, bug977869
2407 lines
66 KiB
C
2407 lines
66 KiB
C
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
/*
|
|
* Deal with PKCS #11 Slots.
|
|
*/
|
|
#include "seccomon.h"
|
|
#include "secmod.h"
|
|
#include "nssilock.h"
|
|
#include "secmodi.h"
|
|
#include "secmodti.h"
|
|
#include "pkcs11t.h"
|
|
#include "pk11func.h"
|
|
#include "secitem.h"
|
|
#include "secerr.h"
|
|
|
|
#include "dev.h"
|
|
#include "dev3hack.h"
|
|
#include "pkim.h"
|
|
#include "utilpars.h"
|
|
|
|
|
|
/*************************************************************
|
|
* local static and global data
|
|
*************************************************************/
|
|
|
|
/*
|
|
* This array helps parsing between names, mechanisms, and flags.
|
|
* to make the config files understand more entries, add them
|
|
* to this table.
|
|
*/
|
|
const PK11DefaultArrayEntry PK11_DefaultArray[] = {
|
|
{ "RSA", SECMOD_RSA_FLAG, CKM_RSA_PKCS },
|
|
{ "DSA", SECMOD_DSA_FLAG, CKM_DSA },
|
|
{ "ECC", SECMOD_ECC_FLAG, CKM_ECDSA },
|
|
{ "DH", SECMOD_DH_FLAG, CKM_DH_PKCS_DERIVE },
|
|
{ "RC2", SECMOD_RC2_FLAG, CKM_RC2_CBC },
|
|
{ "RC4", SECMOD_RC4_FLAG, CKM_RC4 },
|
|
{ "DES", SECMOD_DES_FLAG, CKM_DES_CBC },
|
|
{ "AES", SECMOD_AES_FLAG, CKM_AES_CBC },
|
|
{ "Camellia", SECMOD_CAMELLIA_FLAG, CKM_CAMELLIA_CBC },
|
|
{ "SEED", SECMOD_SEED_FLAG, CKM_SEED_CBC },
|
|
{ "RC5", SECMOD_RC5_FLAG, CKM_RC5_CBC },
|
|
{ "SHA-1", SECMOD_SHA1_FLAG, CKM_SHA_1 },
|
|
/* { "SHA224", SECMOD_SHA256_FLAG, CKM_SHA224 }, */
|
|
{ "SHA256", SECMOD_SHA256_FLAG, CKM_SHA256 },
|
|
/* { "SHA384", SECMOD_SHA512_FLAG, CKM_SHA384 }, */
|
|
{ "SHA512", SECMOD_SHA512_FLAG, CKM_SHA512 },
|
|
{ "MD5", SECMOD_MD5_FLAG, CKM_MD5 },
|
|
{ "MD2", SECMOD_MD2_FLAG, CKM_MD2 },
|
|
{ "SSL", SECMOD_SSL_FLAG, CKM_SSL3_PRE_MASTER_KEY_GEN },
|
|
{ "TLS", SECMOD_TLS_FLAG, CKM_TLS_MASTER_KEY_DERIVE },
|
|
{ "SKIPJACK", SECMOD_FORTEZZA_FLAG, CKM_SKIPJACK_CBC64 },
|
|
{ "Publicly-readable certs", SECMOD_FRIENDLY_FLAG, CKM_INVALID_MECHANISM },
|
|
{ "Random Num Generator", SECMOD_RANDOM_FLAG, CKM_FAKE_RANDOM },
|
|
};
|
|
const int num_pk11_default_mechanisms =
|
|
sizeof(PK11_DefaultArray) / sizeof(PK11_DefaultArray[0]);
|
|
|
|
const PK11DefaultArrayEntry *
|
|
PK11_GetDefaultArray(int *size)
|
|
{
|
|
if (size) {
|
|
*size = num_pk11_default_mechanisms;
|
|
}
|
|
return PK11_DefaultArray;
|
|
}
|
|
|
|
/*
|
|
* These slotlists are lists of modules which provide default support for
|
|
* a given algorithm or mechanism.
|
|
*/
|
|
static PK11SlotList
|
|
pk11_seedSlotList,
|
|
pk11_camelliaSlotList,
|
|
pk11_aesSlotList,
|
|
pk11_desSlotList,
|
|
pk11_rc4SlotList,
|
|
pk11_rc2SlotList,
|
|
pk11_rc5SlotList,
|
|
pk11_sha1SlotList,
|
|
pk11_md5SlotList,
|
|
pk11_md2SlotList,
|
|
pk11_rsaSlotList,
|
|
pk11_dsaSlotList,
|
|
pk11_dhSlotList,
|
|
pk11_ecSlotList,
|
|
pk11_ideaSlotList,
|
|
pk11_sslSlotList,
|
|
pk11_tlsSlotList,
|
|
pk11_randomSlotList,
|
|
pk11_sha256SlotList,
|
|
pk11_sha512SlotList; /* slots do SHA512 and SHA384 */
|
|
|
|
/************************************************************
|
|
* Generic Slot List and Slot List element manipulations
|
|
************************************************************/
|
|
|
|
/*
|
|
* allocate a new list
|
|
*/
|
|
PK11SlotList *
|
|
PK11_NewSlotList(void)
|
|
{
|
|
PK11SlotList *list;
|
|
|
|
list = (PK11SlotList *)PORT_Alloc(sizeof(PK11SlotList));
|
|
if (list == NULL) return NULL;
|
|
list->head = NULL;
|
|
list->tail = NULL;
|
|
list->lock = PZ_NewLock(nssILockList);
|
|
if (list->lock == NULL) {
|
|
PORT_Free(list);
|
|
return NULL;
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
/*
|
|
* free a list element when all the references go away.
|
|
*/
|
|
SECStatus
|
|
PK11_FreeSlotListElement(PK11SlotList *list, PK11SlotListElement *le)
|
|
{
|
|
PRBool freeit = PR_FALSE;
|
|
|
|
if (list == NULL || le == NULL) {
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
return SECFailure;
|
|
}
|
|
|
|
PZ_Lock(list->lock);
|
|
if (le->refCount-- == 1) {
|
|
freeit = PR_TRUE;
|
|
}
|
|
PZ_Unlock(list->lock);
|
|
if (freeit) {
|
|
PK11_FreeSlot(le->slot);
|
|
PORT_Free(le);
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
static void
|
|
pk11_FreeSlotListStatic(PK11SlotList *list)
|
|
{
|
|
PK11SlotListElement *le, *next ;
|
|
if (list == NULL) return;
|
|
|
|
for (le = list->head ; le; le = next) {
|
|
next = le->next;
|
|
PK11_FreeSlotListElement(list,le);
|
|
}
|
|
if (list->lock) {
|
|
PZ_DestroyLock(list->lock);
|
|
}
|
|
list->lock = NULL;
|
|
list->head = NULL;
|
|
}
|
|
|
|
/*
|
|
* if we are freeing the list, we must be the only ones with a pointer
|
|
* to the list.
|
|
*/
|
|
void
|
|
PK11_FreeSlotList(PK11SlotList *list)
|
|
{
|
|
pk11_FreeSlotListStatic(list);
|
|
PORT_Free(list);
|
|
}
|
|
|
|
/*
|
|
* add a slot to a list
|
|
* "slot" is the slot to be added. Ownership is not transferred.
|
|
* "sorted" indicates whether or not the slot should be inserted according to
|
|
* cipherOrder of the associated module. PR_FALSE indicates that the slot
|
|
* should be inserted to the head of the list.
|
|
*/
|
|
SECStatus
|
|
PK11_AddSlotToList(PK11SlotList *list,PK11SlotInfo *slot, PRBool sorted)
|
|
{
|
|
PK11SlotListElement *le;
|
|
PK11SlotListElement *element;
|
|
|
|
le = (PK11SlotListElement *) PORT_Alloc(sizeof(PK11SlotListElement));
|
|
if (le == NULL) return SECFailure;
|
|
|
|
le->slot = PK11_ReferenceSlot(slot);
|
|
le->prev = NULL;
|
|
le->refCount = 1;
|
|
PZ_Lock(list->lock);
|
|
element = list->head;
|
|
/* Insertion sort, with higher cipherOrders are sorted first in the list */
|
|
while (element && sorted && (element->slot->module->cipherOrder >
|
|
le->slot->module->cipherOrder)) {
|
|
element = element->next;
|
|
}
|
|
if (element) {
|
|
le->prev = element->prev;
|
|
element->prev = le;
|
|
le->next = element;
|
|
} else {
|
|
le->prev = list->tail;
|
|
le->next = NULL;
|
|
list->tail = le;
|
|
}
|
|
if (le->prev) le->prev->next = le;
|
|
if (list->head == element) list->head = le;
|
|
PZ_Unlock(list->lock);
|
|
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* remove a slot entry from the list
|
|
*/
|
|
SECStatus
|
|
PK11_DeleteSlotFromList(PK11SlotList *list,PK11SlotListElement *le)
|
|
{
|
|
PZ_Lock(list->lock);
|
|
if (le->prev) le->prev->next = le->next; else list->head = le->next;
|
|
if (le->next) le->next->prev = le->prev; else list->tail = le->prev;
|
|
le->next = le->prev = NULL;
|
|
PZ_Unlock(list->lock);
|
|
PK11_FreeSlotListElement(list,le);
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* Move a list to the end of the target list.
|
|
* NOTE: There is no locking here... This assumes BOTH lists are private copy
|
|
* lists. It also does not re-sort the target list.
|
|
*/
|
|
SECStatus
|
|
pk11_MoveListToList(PK11SlotList *target,PK11SlotList *src)
|
|
{
|
|
if (src->head == NULL) return SECSuccess;
|
|
|
|
if (target->tail == NULL) {
|
|
target->head = src->head;
|
|
} else {
|
|
target->tail->next = src->head;
|
|
}
|
|
src->head->prev = target->tail;
|
|
target->tail = src->tail;
|
|
src->head = src->tail = NULL;
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* get an element from the list with a reference. You must own the list.
|
|
*/
|
|
PK11SlotListElement *
|
|
PK11_GetFirstRef(PK11SlotList *list)
|
|
{
|
|
PK11SlotListElement *le;
|
|
|
|
le = list->head;
|
|
if (le != NULL) (le)->refCount++;
|
|
return le;
|
|
}
|
|
|
|
/*
|
|
* get the next element from the list with a reference. You must own the list.
|
|
*/
|
|
PK11SlotListElement *
|
|
PK11_GetNextRef(PK11SlotList *list, PK11SlotListElement *le, PRBool restart)
|
|
{
|
|
PK11SlotListElement *new_le;
|
|
new_le = le->next;
|
|
if (new_le) new_le->refCount++;
|
|
PK11_FreeSlotListElement(list,le);
|
|
return new_le;
|
|
}
|
|
|
|
/*
|
|
* get an element safely from the list. This just makes sure that if
|
|
* this element is not deleted while we deal with it.
|
|
*/
|
|
PK11SlotListElement *
|
|
PK11_GetFirstSafe(PK11SlotList *list)
|
|
{
|
|
PK11SlotListElement *le;
|
|
|
|
PZ_Lock(list->lock);
|
|
le = list->head;
|
|
if (le != NULL) (le)->refCount++;
|
|
PZ_Unlock(list->lock);
|
|
return le;
|
|
}
|
|
|
|
/*
|
|
* NOTE: if this element gets deleted, we can no longer safely traverse using
|
|
* it's pointers. We can either terminate the loop, or restart from the
|
|
* beginning. This is controlled by the restart option.
|
|
*/
|
|
PK11SlotListElement *
|
|
PK11_GetNextSafe(PK11SlotList *list, PK11SlotListElement *le, PRBool restart)
|
|
{
|
|
PK11SlotListElement *new_le;
|
|
PZ_Lock(list->lock);
|
|
new_le = le->next;
|
|
if (le->next == NULL) {
|
|
/* if the prev and next fields are NULL then either this element
|
|
* has been removed and we need to walk the list again (if restart
|
|
* is true) or this was the only element on the list */
|
|
if ((le->prev == NULL) && restart && (list->head != le)) {
|
|
new_le = list->head;
|
|
}
|
|
}
|
|
if (new_le) new_le->refCount++;
|
|
PZ_Unlock(list->lock);
|
|
PK11_FreeSlotListElement(list,le);
|
|
return new_le;
|
|
}
|
|
|
|
|
|
/*
|
|
* Find the element that holds this slot
|
|
*/
|
|
PK11SlotListElement *
|
|
PK11_FindSlotElement(PK11SlotList *list,PK11SlotInfo *slot)
|
|
{
|
|
PK11SlotListElement *le;
|
|
|
|
for (le = PK11_GetFirstSafe(list); le;
|
|
le = PK11_GetNextSafe(list,le,PR_TRUE)) {
|
|
if (le->slot == slot) return le;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/************************************************************
|
|
* Generic Slot Utilities
|
|
************************************************************/
|
|
/*
|
|
* Create a new slot structure
|
|
*/
|
|
PK11SlotInfo *
|
|
PK11_NewSlotInfo(SECMODModule *mod)
|
|
{
|
|
PK11SlotInfo *slot;
|
|
|
|
slot = (PK11SlotInfo *)PORT_Alloc(sizeof(PK11SlotInfo));
|
|
if (slot == NULL) return slot;
|
|
|
|
slot->sessionLock = mod->isThreadSafe ?
|
|
PZ_NewLock(nssILockSession) : mod->refLock;
|
|
if (slot->sessionLock == NULL) {
|
|
PORT_Free(slot);
|
|
return NULL;
|
|
}
|
|
slot->freeListLock = PZ_NewLock(nssILockFreelist);
|
|
if (slot->freeListLock == NULL) {
|
|
if (mod->isThreadSafe) {
|
|
PZ_DestroyLock(slot->sessionLock);
|
|
}
|
|
PORT_Free(slot);
|
|
return NULL;
|
|
}
|
|
slot->freeSymKeysWithSessionHead = NULL;
|
|
slot->freeSymKeysHead = NULL;
|
|
slot->keyCount = 0;
|
|
slot->maxKeyCount = 0;
|
|
slot->functionList = NULL;
|
|
slot->needTest = PR_TRUE;
|
|
slot->isPerm = PR_FALSE;
|
|
slot->isHW = PR_FALSE;
|
|
slot->isInternal = PR_FALSE;
|
|
slot->isThreadSafe = PR_FALSE;
|
|
slot->disabled = PR_FALSE;
|
|
slot->series = 1;
|
|
slot->wrapKey = 0;
|
|
slot->wrapMechanism = CKM_INVALID_MECHANISM;
|
|
slot->refKeys[0] = CK_INVALID_HANDLE;
|
|
slot->reason = PK11_DIS_NONE;
|
|
slot->readOnly = PR_TRUE;
|
|
slot->needLogin = PR_FALSE;
|
|
slot->hasRandom = PR_FALSE;
|
|
slot->defRWSession = PR_FALSE;
|
|
slot->protectedAuthPath = PR_FALSE;
|
|
slot->flags = 0;
|
|
slot->session = CK_INVALID_SESSION;
|
|
slot->slotID = 0;
|
|
slot->defaultFlags = 0;
|
|
slot->refCount = 1;
|
|
slot->askpw = 0;
|
|
slot->timeout = 0;
|
|
slot->mechanismList = NULL;
|
|
slot->mechanismCount = 0;
|
|
slot->cert_array = NULL;
|
|
slot->cert_count = 0;
|
|
slot->slot_name[0] = 0;
|
|
slot->token_name[0] = 0;
|
|
PORT_Memset(slot->serial,' ',sizeof(slot->serial));
|
|
slot->module = NULL;
|
|
slot->authTransact = 0;
|
|
slot->authTime = LL_ZERO;
|
|
slot->minPassword = 0;
|
|
slot->maxPassword = 0;
|
|
slot->hasRootCerts = PR_FALSE;
|
|
slot->nssToken = NULL;
|
|
return slot;
|
|
}
|
|
|
|
/* create a new reference to a slot so it doesn't go away */
|
|
PK11SlotInfo *
|
|
PK11_ReferenceSlot(PK11SlotInfo *slot)
|
|
{
|
|
PR_ATOMIC_INCREMENT(&slot->refCount);
|
|
return slot;
|
|
}
|
|
|
|
/* Destroy all info on a slot we have built up */
|
|
void
|
|
PK11_DestroySlot(PK11SlotInfo *slot)
|
|
{
|
|
/* free up the cached keys and sessions */
|
|
PK11_CleanKeyList(slot);
|
|
|
|
/* free up all the sessions on this slot */
|
|
if (slot->functionList) {
|
|
PK11_GETTAB(slot)->C_CloseAllSessions(slot->slotID);
|
|
}
|
|
|
|
if (slot->mechanismList) {
|
|
PORT_Free(slot->mechanismList);
|
|
}
|
|
if (slot->isThreadSafe && slot->sessionLock) {
|
|
PZ_DestroyLock(slot->sessionLock);
|
|
}
|
|
slot->sessionLock = NULL;
|
|
if (slot->freeListLock) {
|
|
PZ_DestroyLock(slot->freeListLock);
|
|
slot->freeListLock = NULL;
|
|
}
|
|
|
|
/* finally Tell our parent module that we've gone away so it can unload */
|
|
if (slot->module) {
|
|
SECMOD_SlotDestroyModule(slot->module,PR_TRUE);
|
|
}
|
|
|
|
/* ok, well not quit finally... now we free the memory */
|
|
PORT_Free(slot);
|
|
}
|
|
|
|
|
|
/* We're all done with the slot, free it */
|
|
void
|
|
PK11_FreeSlot(PK11SlotInfo *slot)
|
|
{
|
|
if (PR_ATOMIC_DECREMENT(&slot->refCount) == 0) {
|
|
PK11_DestroySlot(slot);
|
|
}
|
|
}
|
|
|
|
void
|
|
PK11_EnterSlotMonitor(PK11SlotInfo *slot) {
|
|
PZ_Lock(slot->sessionLock);
|
|
}
|
|
|
|
void
|
|
PK11_ExitSlotMonitor(PK11SlotInfo *slot) {
|
|
PZ_Unlock(slot->sessionLock);
|
|
}
|
|
|
|
/***********************************************************
|
|
* Functions to find specific slots.
|
|
***********************************************************/
|
|
PRBool
|
|
SECMOD_HasRootCerts(void)
|
|
{
|
|
SECMODModuleList *mlp;
|
|
SECMODModuleList *modules;
|
|
SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
|
|
int i;
|
|
PRBool found = PR_FALSE;
|
|
|
|
if (!moduleLock) {
|
|
PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
|
return found;
|
|
}
|
|
|
|
/* work through all the slots */
|
|
SECMOD_GetReadLock(moduleLock);
|
|
modules = SECMOD_GetDefaultModuleList();
|
|
for(mlp = modules; mlp != NULL; mlp = mlp->next) {
|
|
for (i=0; i < mlp->module->slotCount; i++) {
|
|
PK11SlotInfo *tmpSlot = mlp->module->slots[i];
|
|
if (PK11_IsPresent(tmpSlot)) {
|
|
if (tmpSlot->hasRootCerts) {
|
|
found = PR_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (found) break;
|
|
}
|
|
SECMOD_ReleaseReadLock(moduleLock);
|
|
|
|
return found;
|
|
}
|
|
|
|
/***********************************************************
|
|
* Functions to find specific slots.
|
|
***********************************************************/
|
|
PK11SlotList *
|
|
PK11_FindSlotsByNames(const char *dllName, const char* slotName,
|
|
const char* tokenName, PRBool presentOnly)
|
|
{
|
|
SECMODModuleList *mlp;
|
|
SECMODModuleList *modules;
|
|
SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
|
|
int i;
|
|
PK11SlotList* slotList = NULL;
|
|
PRUint32 slotcount = 0;
|
|
SECStatus rv = SECSuccess;
|
|
|
|
if (!moduleLock) {
|
|
PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
|
return slotList;
|
|
}
|
|
|
|
slotList = PK11_NewSlotList();
|
|
if (!slotList) {
|
|
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
|
return slotList;
|
|
}
|
|
|
|
if ( ((NULL == dllName) || (0 == *dllName)) &&
|
|
((NULL == slotName) || (0 == *slotName)) &&
|
|
((NULL == tokenName) || (0 == *tokenName)) ) {
|
|
/* default to softoken */
|
|
PK11_AddSlotToList(slotList, PK11_GetInternalKeySlot(), PR_TRUE);
|
|
return slotList;
|
|
}
|
|
|
|
/* work through all the slots */
|
|
SECMOD_GetReadLock(moduleLock);
|
|
modules = SECMOD_GetDefaultModuleList();
|
|
for (mlp = modules; mlp != NULL; mlp = mlp->next) {
|
|
PORT_Assert(mlp->module);
|
|
if (!mlp->module) {
|
|
rv = SECFailure;
|
|
break;
|
|
}
|
|
if ((!dllName) || (mlp->module->dllName &&
|
|
(0 == PORT_Strcmp(mlp->module->dllName, dllName)))) {
|
|
for (i=0; i < mlp->module->slotCount; i++) {
|
|
PK11SlotInfo *tmpSlot = (mlp->module->slots?mlp->module->slots[i]:NULL);
|
|
PORT_Assert(tmpSlot);
|
|
if (!tmpSlot) {
|
|
rv = SECFailure;
|
|
break;
|
|
}
|
|
if ((PR_FALSE == presentOnly || PK11_IsPresent(tmpSlot)) &&
|
|
( (!tokenName) || (tmpSlot->token_name &&
|
|
(0==PORT_Strcmp(tmpSlot->token_name, tokenName)))) &&
|
|
( (!slotName) || (tmpSlot->slot_name &&
|
|
(0==PORT_Strcmp(tmpSlot->slot_name, slotName)))) ) {
|
|
if (tmpSlot) {
|
|
PK11_AddSlotToList(slotList, tmpSlot, PR_TRUE);
|
|
slotcount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
SECMOD_ReleaseReadLock(moduleLock);
|
|
|
|
if ( (0 == slotcount) || (SECFailure == rv) ) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
PK11_FreeSlotList(slotList);
|
|
slotList = NULL;
|
|
}
|
|
|
|
if (SECFailure == rv) {
|
|
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
|
}
|
|
|
|
return slotList;
|
|
}
|
|
|
|
PK11SlotInfo *
|
|
PK11_FindSlotByName(const char *name)
|
|
{
|
|
SECMODModuleList *mlp;
|
|
SECMODModuleList *modules;
|
|
SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
|
|
int i;
|
|
PK11SlotInfo *slot = NULL;
|
|
|
|
if (!moduleLock) {
|
|
PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
|
return slot;
|
|
}
|
|
if ((name == NULL) || (*name == 0)) {
|
|
return PK11_GetInternalKeySlot();
|
|
}
|
|
|
|
/* work through all the slots */
|
|
SECMOD_GetReadLock(moduleLock);
|
|
modules = SECMOD_GetDefaultModuleList();
|
|
for(mlp = modules; mlp != NULL; mlp = mlp->next) {
|
|
for (i=0; i < mlp->module->slotCount; i++) {
|
|
PK11SlotInfo *tmpSlot = mlp->module->slots[i];
|
|
if (PK11_IsPresent(tmpSlot)) {
|
|
if (PORT_Strcmp(tmpSlot->token_name,name) == 0) {
|
|
slot = PK11_ReferenceSlot(tmpSlot);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (slot != NULL) break;
|
|
}
|
|
SECMOD_ReleaseReadLock(moduleLock);
|
|
|
|
if (slot == NULL) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
}
|
|
|
|
return slot;
|
|
}
|
|
|
|
|
|
PK11SlotInfo *
|
|
PK11_FindSlotBySerial(char *serial)
|
|
{
|
|
SECMODModuleList *mlp;
|
|
SECMODModuleList *modules;
|
|
SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
|
|
int i;
|
|
PK11SlotInfo *slot = NULL;
|
|
|
|
if (!moduleLock) {
|
|
PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
|
return slot;
|
|
}
|
|
/* work through all the slots */
|
|
SECMOD_GetReadLock(moduleLock);
|
|
modules = SECMOD_GetDefaultModuleList();
|
|
for(mlp = modules; mlp != NULL; mlp = mlp->next) {
|
|
for (i=0; i < mlp->module->slotCount; i++) {
|
|
PK11SlotInfo *tmpSlot = mlp->module->slots[i];
|
|
if (PK11_IsPresent(tmpSlot)) {
|
|
if (PORT_Memcmp(tmpSlot->serial,serial,
|
|
sizeof(tmpSlot->serial)) == 0) {
|
|
slot = PK11_ReferenceSlot(tmpSlot);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (slot != NULL) break;
|
|
}
|
|
SECMOD_ReleaseReadLock(moduleLock);
|
|
|
|
if (slot == NULL) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
}
|
|
|
|
return slot;
|
|
}
|
|
|
|
/*
|
|
* notification stub. If we ever get interested in any events that
|
|
* the pkcs11 functions may pass back to use, we can catch them here...
|
|
* currently pdata is a slotinfo structure.
|
|
*/
|
|
CK_RV pk11_notify(CK_SESSION_HANDLE session, CK_NOTIFICATION event,
|
|
CK_VOID_PTR pdata)
|
|
{
|
|
return CKR_OK;
|
|
}
|
|
|
|
/*
|
|
* grab a new RW session
|
|
* !!! has a side effect of grabbing the Monitor if either the slot's default
|
|
* session is RW or the slot is not thread safe. Monitor is release in function
|
|
* below
|
|
*/
|
|
CK_SESSION_HANDLE PK11_GetRWSession(PK11SlotInfo *slot)
|
|
{
|
|
CK_SESSION_HANDLE rwsession;
|
|
CK_RV crv;
|
|
PRBool haveMonitor = PR_FALSE;
|
|
|
|
if (!slot->isThreadSafe || slot->defRWSession) {
|
|
PK11_EnterSlotMonitor(slot);
|
|
haveMonitor = PR_TRUE;
|
|
}
|
|
if (slot->defRWSession) {
|
|
PORT_Assert(slot->session != CK_INVALID_SESSION);
|
|
if (slot->session != CK_INVALID_SESSION)
|
|
return slot->session;
|
|
}
|
|
|
|
crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
|
|
CKF_RW_SESSION|CKF_SERIAL_SESSION,
|
|
slot, pk11_notify,&rwsession);
|
|
PORT_Assert(rwsession != CK_INVALID_SESSION || crv != CKR_OK);
|
|
if (crv != CKR_OK || rwsession == CK_INVALID_SESSION) {
|
|
if (crv == CKR_OK)
|
|
crv = CKR_DEVICE_ERROR;
|
|
if (haveMonitor)
|
|
PK11_ExitSlotMonitor(slot);
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return CK_INVALID_SESSION;
|
|
}
|
|
if (slot->defRWSession) { /* we have the monitor */
|
|
slot->session = rwsession;
|
|
}
|
|
return rwsession;
|
|
}
|
|
|
|
PRBool
|
|
PK11_RWSessionHasLock(PK11SlotInfo *slot,CK_SESSION_HANDLE session_handle)
|
|
{
|
|
PRBool hasLock;
|
|
hasLock = (PRBool)(!slot->isThreadSafe ||
|
|
(slot->defRWSession && slot->session != CK_INVALID_SESSION));
|
|
return hasLock;
|
|
}
|
|
|
|
static PRBool
|
|
pk11_RWSessionIsDefault(PK11SlotInfo *slot,CK_SESSION_HANDLE rwsession)
|
|
{
|
|
PRBool isDefault;
|
|
isDefault = (PRBool)(slot->session == rwsession &&
|
|
slot->defRWSession &&
|
|
slot->session != CK_INVALID_SESSION);
|
|
return isDefault;
|
|
}
|
|
|
|
/*
|
|
* close the rwsession and restore our readonly session
|
|
* !!! has a side effect of releasing the Monitor if either the slot's default
|
|
* session is RW or the slot is not thread safe.
|
|
*/
|
|
void
|
|
PK11_RestoreROSession(PK11SlotInfo *slot,CK_SESSION_HANDLE rwsession)
|
|
{
|
|
PORT_Assert(rwsession != CK_INVALID_SESSION);
|
|
if (rwsession != CK_INVALID_SESSION) {
|
|
PRBool doExit = PK11_RWSessionHasLock(slot, rwsession);
|
|
if (!pk11_RWSessionIsDefault(slot, rwsession))
|
|
PK11_GETTAB(slot)->C_CloseSession(rwsession);
|
|
if (doExit)
|
|
PK11_ExitSlotMonitor(slot);
|
|
}
|
|
}
|
|
|
|
/************************************************************
|
|
* Manage the built-In Slot Lists
|
|
************************************************************/
|
|
|
|
/* Init the static built int slot list (should actually integrate
|
|
* with PK11_NewSlotList */
|
|
static void
|
|
pk11_InitSlotListStatic(PK11SlotList *list)
|
|
{
|
|
list->lock = PZ_NewLock(nssILockList);
|
|
list->head = NULL;
|
|
}
|
|
|
|
|
|
/* initialize the system slotlists */
|
|
SECStatus
|
|
PK11_InitSlotLists(void)
|
|
{
|
|
pk11_InitSlotListStatic(&pk11_seedSlotList);
|
|
pk11_InitSlotListStatic(&pk11_camelliaSlotList);
|
|
pk11_InitSlotListStatic(&pk11_aesSlotList);
|
|
pk11_InitSlotListStatic(&pk11_desSlotList);
|
|
pk11_InitSlotListStatic(&pk11_rc4SlotList);
|
|
pk11_InitSlotListStatic(&pk11_rc2SlotList);
|
|
pk11_InitSlotListStatic(&pk11_rc5SlotList);
|
|
pk11_InitSlotListStatic(&pk11_md5SlotList);
|
|
pk11_InitSlotListStatic(&pk11_md2SlotList);
|
|
pk11_InitSlotListStatic(&pk11_sha1SlotList);
|
|
pk11_InitSlotListStatic(&pk11_rsaSlotList);
|
|
pk11_InitSlotListStatic(&pk11_dsaSlotList);
|
|
pk11_InitSlotListStatic(&pk11_dhSlotList);
|
|
pk11_InitSlotListStatic(&pk11_ecSlotList);
|
|
pk11_InitSlotListStatic(&pk11_ideaSlotList);
|
|
pk11_InitSlotListStatic(&pk11_sslSlotList);
|
|
pk11_InitSlotListStatic(&pk11_tlsSlotList);
|
|
pk11_InitSlotListStatic(&pk11_randomSlotList);
|
|
pk11_InitSlotListStatic(&pk11_sha256SlotList);
|
|
pk11_InitSlotListStatic(&pk11_sha512SlotList);
|
|
return SECSuccess;
|
|
}
|
|
|
|
void
|
|
PK11_DestroySlotLists(void)
|
|
{
|
|
pk11_FreeSlotListStatic(&pk11_seedSlotList);
|
|
pk11_FreeSlotListStatic(&pk11_camelliaSlotList);
|
|
pk11_FreeSlotListStatic(&pk11_aesSlotList);
|
|
pk11_FreeSlotListStatic(&pk11_desSlotList);
|
|
pk11_FreeSlotListStatic(&pk11_rc4SlotList);
|
|
pk11_FreeSlotListStatic(&pk11_rc2SlotList);
|
|
pk11_FreeSlotListStatic(&pk11_rc5SlotList);
|
|
pk11_FreeSlotListStatic(&pk11_md5SlotList);
|
|
pk11_FreeSlotListStatic(&pk11_md2SlotList);
|
|
pk11_FreeSlotListStatic(&pk11_sha1SlotList);
|
|
pk11_FreeSlotListStatic(&pk11_rsaSlotList);
|
|
pk11_FreeSlotListStatic(&pk11_dsaSlotList);
|
|
pk11_FreeSlotListStatic(&pk11_dhSlotList);
|
|
pk11_FreeSlotListStatic(&pk11_ecSlotList);
|
|
pk11_FreeSlotListStatic(&pk11_ideaSlotList);
|
|
pk11_FreeSlotListStatic(&pk11_sslSlotList);
|
|
pk11_FreeSlotListStatic(&pk11_tlsSlotList);
|
|
pk11_FreeSlotListStatic(&pk11_randomSlotList);
|
|
pk11_FreeSlotListStatic(&pk11_sha256SlotList);
|
|
pk11_FreeSlotListStatic(&pk11_sha512SlotList);
|
|
return;
|
|
}
|
|
|
|
/* return a system slot list based on mechanism */
|
|
PK11SlotList *
|
|
PK11_GetSlotList(CK_MECHANISM_TYPE type)
|
|
{
|
|
/* XXX a workaround for Bugzilla bug #55267 */
|
|
#if defined(HPUX) && defined(__LP64__)
|
|
if (CKM_INVALID_MECHANISM == type)
|
|
return NULL;
|
|
#endif
|
|
switch (type) {
|
|
case CKM_SEED_CBC:
|
|
case CKM_SEED_ECB:
|
|
return &pk11_seedSlotList;
|
|
case CKM_CAMELLIA_CBC:
|
|
case CKM_CAMELLIA_ECB:
|
|
return &pk11_camelliaSlotList;
|
|
case CKM_AES_CBC:
|
|
case CKM_AES_CCM:
|
|
case CKM_AES_CTR:
|
|
case CKM_AES_CTS:
|
|
case CKM_AES_GCM:
|
|
case CKM_AES_ECB:
|
|
return &pk11_aesSlotList;
|
|
case CKM_DES_CBC:
|
|
case CKM_DES_ECB:
|
|
case CKM_DES3_ECB:
|
|
case CKM_DES3_CBC:
|
|
return &pk11_desSlotList;
|
|
case CKM_RC4:
|
|
return &pk11_rc4SlotList;
|
|
case CKM_RC5_CBC:
|
|
return &pk11_rc5SlotList;
|
|
case CKM_SHA_1:
|
|
return &pk11_sha1SlotList;
|
|
case CKM_SHA224:
|
|
case CKM_SHA256:
|
|
return &pk11_sha256SlotList;
|
|
case CKM_SHA384:
|
|
case CKM_SHA512:
|
|
return &pk11_sha512SlotList;
|
|
case CKM_MD5:
|
|
return &pk11_md5SlotList;
|
|
case CKM_MD2:
|
|
return &pk11_md2SlotList;
|
|
case CKM_RC2_ECB:
|
|
case CKM_RC2_CBC:
|
|
return &pk11_rc2SlotList;
|
|
case CKM_RSA_PKCS:
|
|
case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
|
case CKM_RSA_X_509:
|
|
return &pk11_rsaSlotList;
|
|
case CKM_DSA:
|
|
return &pk11_dsaSlotList;
|
|
case CKM_DH_PKCS_KEY_PAIR_GEN:
|
|
case CKM_DH_PKCS_DERIVE:
|
|
return &pk11_dhSlotList;
|
|
case CKM_ECDSA:
|
|
case CKM_ECDSA_SHA1:
|
|
case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */
|
|
case CKM_ECDH1_DERIVE:
|
|
return &pk11_ecSlotList;
|
|
case CKM_SSL3_PRE_MASTER_KEY_GEN:
|
|
case CKM_SSL3_MASTER_KEY_DERIVE:
|
|
case CKM_SSL3_SHA1_MAC:
|
|
case CKM_SSL3_MD5_MAC:
|
|
return &pk11_sslSlotList;
|
|
case CKM_TLS_MASTER_KEY_DERIVE:
|
|
case CKM_TLS_KEY_AND_MAC_DERIVE:
|
|
case CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256:
|
|
return &pk11_tlsSlotList;
|
|
case CKM_IDEA_CBC:
|
|
case CKM_IDEA_ECB:
|
|
return &pk11_ideaSlotList;
|
|
case CKM_FAKE_RANDOM:
|
|
return &pk11_randomSlotList;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* load the static SlotInfo structures used to select a PKCS11 slot.
|
|
* preSlotInfo has a list of all the default flags for the slots on this
|
|
* module.
|
|
*/
|
|
void
|
|
PK11_LoadSlotList(PK11SlotInfo *slot, PK11PreSlotInfo *psi, int count)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i < count; i++) {
|
|
if (psi[i].slotID == slot->slotID)
|
|
break;
|
|
}
|
|
|
|
if (i == count) return;
|
|
|
|
slot->defaultFlags = psi[i].defaultFlags;
|
|
slot->askpw = psi[i].askpw;
|
|
slot->timeout = psi[i].timeout;
|
|
slot->hasRootCerts = psi[i].hasRootCerts;
|
|
|
|
/* if the slot is already disabled, don't load them into the
|
|
* default slot lists. We get here so we can save the default
|
|
* list value. */
|
|
if (slot->disabled) return;
|
|
|
|
/* if the user has disabled us, don't load us in */
|
|
if (slot->defaultFlags & PK11_DISABLE_FLAG) {
|
|
slot->disabled = PR_TRUE;
|
|
slot->reason = PK11_DIS_USER_SELECTED;
|
|
/* free up sessions and things?? */
|
|
return;
|
|
}
|
|
|
|
for (i=0; i < num_pk11_default_mechanisms; i++) {
|
|
if (slot->defaultFlags & PK11_DefaultArray[i].flag) {
|
|
CK_MECHANISM_TYPE mechanism = PK11_DefaultArray[i].mechanism;
|
|
PK11SlotList *slotList = PK11_GetSlotList(mechanism);
|
|
|
|
if (slotList) PK11_AddSlotToList(slotList,slot,PR_FALSE);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* update a slot to its new attribute according to the slot list
|
|
* returns: SECSuccess if nothing to do or add/delete is successful
|
|
*/
|
|
SECStatus
|
|
PK11_UpdateSlotAttribute(PK11SlotInfo *slot,
|
|
const PK11DefaultArrayEntry *entry,
|
|
PRBool add)
|
|
/* add: PR_TRUE if want to turn on */
|
|
{
|
|
SECStatus result = SECSuccess;
|
|
PK11SlotList *slotList = PK11_GetSlotList(entry->mechanism);
|
|
|
|
if (add) { /* trying to turn on a mechanism */
|
|
|
|
/* turn on the default flag in the slot */
|
|
slot->defaultFlags |= entry->flag;
|
|
|
|
/* add this slot to the list */
|
|
if (slotList!=NULL)
|
|
result = PK11_AddSlotToList(slotList, slot, PR_FALSE);
|
|
|
|
} else { /* trying to turn off */
|
|
|
|
/* turn OFF the flag in the slot */
|
|
slot->defaultFlags &= ~entry->flag;
|
|
|
|
if (slotList) {
|
|
/* find the element in the list & delete it */
|
|
PK11SlotListElement *le = PK11_FindSlotElement(slotList, slot);
|
|
|
|
/* remove the slot from the list */
|
|
if (le)
|
|
result = PK11_DeleteSlotFromList(slotList, le);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* clear a slot off of all of it's default list
|
|
*/
|
|
void
|
|
PK11_ClearSlotList(PK11SlotInfo *slot)
|
|
{
|
|
int i;
|
|
|
|
if (slot->disabled) return;
|
|
if (slot->defaultFlags == 0) return;
|
|
|
|
for (i=0; i < num_pk11_default_mechanisms; i++) {
|
|
if (slot->defaultFlags & PK11_DefaultArray[i].flag) {
|
|
CK_MECHANISM_TYPE mechanism = PK11_DefaultArray[i].mechanism;
|
|
PK11SlotList *slotList = PK11_GetSlotList(mechanism);
|
|
PK11SlotListElement *le = NULL;
|
|
|
|
if (slotList) le = PK11_FindSlotElement(slotList,slot);
|
|
|
|
if (le) {
|
|
PK11_DeleteSlotFromList(slotList,le);
|
|
PK11_FreeSlotListElement(slotList,le);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************
|
|
* Slot initialization
|
|
******************************************************************/
|
|
/*
|
|
* turn a PKCS11 Static Label into a string
|
|
*/
|
|
char *
|
|
PK11_MakeString(PLArenaPool *arena,char *space,
|
|
char *staticString,int stringLen)
|
|
{
|
|
int i;
|
|
char *newString;
|
|
for(i=(stringLen-1); i >= 0; i--) {
|
|
if (staticString[i] != ' ') break;
|
|
}
|
|
/* move i to point to the last space */
|
|
i++;
|
|
if (arena) {
|
|
newString = (char*)PORT_ArenaAlloc(arena,i+1 /* space for NULL */);
|
|
} else if (space) {
|
|
newString = space;
|
|
} else {
|
|
newString = (char*)PORT_Alloc(i+1 /* space for NULL */);
|
|
}
|
|
if (newString == NULL) return NULL;
|
|
|
|
if (i) PORT_Memcpy(newString,staticString, i);
|
|
newString[i] = 0;
|
|
|
|
return newString;
|
|
}
|
|
|
|
/*
|
|
* Reads in the slots mechanism list for later use
|
|
*/
|
|
SECStatus
|
|
PK11_ReadMechanismList(PK11SlotInfo *slot)
|
|
{
|
|
CK_ULONG count;
|
|
CK_RV crv;
|
|
PRUint32 i;
|
|
|
|
if (slot->mechanismList) {
|
|
PORT_Free(slot->mechanismList);
|
|
slot->mechanismList = NULL;
|
|
}
|
|
slot->mechanismCount = 0;
|
|
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GetMechanismList(slot->slotID,NULL,&count);
|
|
if (crv != CKR_OK) {
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return SECFailure;
|
|
}
|
|
|
|
slot->mechanismList = (CK_MECHANISM_TYPE *)
|
|
PORT_Alloc(count *sizeof(CK_MECHANISM_TYPE));
|
|
if (slot->mechanismList == NULL) {
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
return SECFailure;
|
|
}
|
|
crv = PK11_GETTAB(slot)->C_GetMechanismList(slot->slotID,
|
|
slot->mechanismList, &count);
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
PORT_Free(slot->mechanismList);
|
|
slot->mechanismList = NULL;
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return SECSuccess;
|
|
}
|
|
slot->mechanismCount = count;
|
|
PORT_Memset(slot->mechanismBits, 0, sizeof(slot->mechanismBits));
|
|
|
|
for (i=0; i < count; i++) {
|
|
CK_MECHANISM_TYPE mech = slot->mechanismList[i];
|
|
if (mech < 0x7ff) {
|
|
slot->mechanismBits[mech & 0xff] |= 1 << (mech >> 8);
|
|
}
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* initialize a new token
|
|
* unlike initialize slot, this can be called multiple times in the lifetime
|
|
* of NSS. It reads the information associated with a card or token,
|
|
* that is not going to change unless the card or token changes.
|
|
*/
|
|
SECStatus
|
|
PK11_InitToken(PK11SlotInfo *slot, PRBool loadCerts)
|
|
{
|
|
CK_TOKEN_INFO tokenInfo;
|
|
CK_RV crv;
|
|
char *tmp;
|
|
SECStatus rv;
|
|
PRStatus status;
|
|
|
|
/* set the slot flags to the current token values */
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID,&tokenInfo);
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return SECFailure;
|
|
}
|
|
|
|
/* set the slot flags to the current token values */
|
|
slot->series++; /* allow other objects to detect that the
|
|
* slot is different */
|
|
slot->flags = tokenInfo.flags;
|
|
slot->needLogin = ((tokenInfo.flags & CKF_LOGIN_REQUIRED) ?
|
|
PR_TRUE : PR_FALSE);
|
|
slot->readOnly = ((tokenInfo.flags & CKF_WRITE_PROTECTED) ?
|
|
PR_TRUE : PR_FALSE);
|
|
|
|
|
|
slot->hasRandom = ((tokenInfo.flags & CKF_RNG) ? PR_TRUE : PR_FALSE);
|
|
slot->protectedAuthPath =
|
|
((tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
|
|
? PR_TRUE : PR_FALSE);
|
|
slot->lastLoginCheck = 0;
|
|
slot->lastState = 0;
|
|
/* on some platforms Active Card incorrectly sets the
|
|
* CKF_PROTECTED_AUTHENTICATION_PATH bit when it doesn't mean to. */
|
|
if (slot->isActiveCard) {
|
|
slot->protectedAuthPath = PR_FALSE;
|
|
}
|
|
tmp = PK11_MakeString(NULL,slot->token_name,
|
|
(char *)tokenInfo.label, sizeof(tokenInfo.label));
|
|
slot->minPassword = tokenInfo.ulMinPinLen;
|
|
slot->maxPassword = tokenInfo.ulMaxPinLen;
|
|
PORT_Memcpy(slot->serial,tokenInfo.serialNumber,sizeof(slot->serial));
|
|
|
|
nssToken_UpdateName(slot->nssToken);
|
|
|
|
slot->defRWSession = (PRBool)((!slot->readOnly) &&
|
|
(tokenInfo.ulMaxSessionCount == 1));
|
|
rv = PK11_ReadMechanismList(slot);
|
|
if (rv != SECSuccess) return rv;
|
|
|
|
slot->hasRSAInfo = PR_FALSE;
|
|
slot->RSAInfoFlags = 0;
|
|
|
|
/* initialize the maxKeyCount value */
|
|
if (tokenInfo.ulMaxSessionCount == 0) {
|
|
slot->maxKeyCount = 800; /* should be #define or a config param */
|
|
} else if (tokenInfo.ulMaxSessionCount < 20) {
|
|
/* don't have enough sessions to keep that many keys around */
|
|
slot->maxKeyCount = 0;
|
|
} else {
|
|
slot->maxKeyCount = tokenInfo.ulMaxSessionCount/2;
|
|
}
|
|
|
|
/* Make sure our session handle is valid */
|
|
if (slot->session == CK_INVALID_SESSION) {
|
|
/* we know we don't have a valid session, go get one */
|
|
CK_SESSION_HANDLE session;
|
|
|
|
/* session should be Readonly, serial */
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
|
|
(slot->defRWSession ? CKF_RW_SESSION : 0) | CKF_SERIAL_SESSION,
|
|
slot,pk11_notify,&session);
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return SECFailure;
|
|
}
|
|
slot->session = session;
|
|
} else {
|
|
/* The session we have may be defunct (the token associated with it)
|
|
* has been removed */
|
|
CK_SESSION_INFO sessionInfo;
|
|
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session,&sessionInfo);
|
|
if (crv == CKR_DEVICE_ERROR) {
|
|
PK11_GETTAB(slot)->C_CloseSession(slot->session);
|
|
crv = CKR_SESSION_CLOSED;
|
|
}
|
|
if ((crv==CKR_SESSION_CLOSED) || (crv==CKR_SESSION_HANDLE_INVALID)) {
|
|
crv =PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
|
|
(slot->defRWSession ? CKF_RW_SESSION : 0) | CKF_SERIAL_SESSION,
|
|
slot,pk11_notify,&slot->session);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
slot->session = CK_INVALID_SESSION;
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
return SECFailure;
|
|
}
|
|
}
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
}
|
|
|
|
status = nssToken_Refresh(slot->nssToken);
|
|
if (status != PR_SUCCESS)
|
|
return SECFailure;
|
|
|
|
if (!(slot->isInternal) && (slot->hasRandom)) {
|
|
/* if this slot has a random number generater, use it to add entropy
|
|
* to the internal slot. */
|
|
PK11SlotInfo *int_slot = PK11_GetInternalSlot();
|
|
|
|
if (int_slot) {
|
|
unsigned char random_bytes[32];
|
|
|
|
/* if this slot can issue random numbers, get some entropy from
|
|
* that random number generater and give it to our internal token.
|
|
*/
|
|
PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GenerateRandom
|
|
(slot->session,random_bytes, sizeof(random_bytes));
|
|
PK11_ExitSlotMonitor(slot);
|
|
if (crv == CKR_OK) {
|
|
PK11_EnterSlotMonitor(int_slot);
|
|
PK11_GETTAB(int_slot)->C_SeedRandom(int_slot->session,
|
|
random_bytes, sizeof(random_bytes));
|
|
PK11_ExitSlotMonitor(int_slot);
|
|
}
|
|
|
|
/* Now return the favor and send entropy to the token's random
|
|
* number generater */
|
|
PK11_EnterSlotMonitor(int_slot);
|
|
crv = PK11_GETTAB(int_slot)->C_GenerateRandom(int_slot->session,
|
|
random_bytes, sizeof(random_bytes));
|
|
PK11_ExitSlotMonitor(int_slot);
|
|
if (crv == CKR_OK) {
|
|
PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_SeedRandom(slot->session,
|
|
random_bytes, sizeof(random_bytes));
|
|
PK11_ExitSlotMonitor(slot);
|
|
}
|
|
PK11_FreeSlot(int_slot);
|
|
}
|
|
}
|
|
/* work around a problem in softoken where it incorrectly
|
|
* reports databases opened read only as read/write. */
|
|
if (slot->isInternal && !slot->readOnly) {
|
|
CK_SESSION_HANDLE session = CK_INVALID_SESSION;
|
|
|
|
/* try to open a R/W session */
|
|
crv =PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
|
|
CKF_RW_SESSION|CKF_SERIAL_SESSION, slot, pk11_notify ,&session);
|
|
/* what a well behaved token should return if you open
|
|
* a RW session on a read only token */
|
|
if (crv == CKR_TOKEN_WRITE_PROTECTED) {
|
|
slot->readOnly = PR_TRUE;
|
|
} else if (crv == CKR_OK) {
|
|
CK_SESSION_INFO sessionInfo;
|
|
|
|
/* Because of a second bug in softoken, which silently returns
|
|
* a RO session, we need to check what type of session we got. */
|
|
crv = PK11_GETTAB(slot)->C_GetSessionInfo(session, &sessionInfo);
|
|
if (crv == CKR_OK) {
|
|
if ((sessionInfo.flags & CKF_RW_SESSION) == 0) {
|
|
/* session was readonly, so this softoken slot must be * readonly */
|
|
slot->readOnly = PR_TRUE;
|
|
}
|
|
}
|
|
PK11_GETTAB(slot)->C_CloseSession(session);
|
|
}
|
|
}
|
|
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* initialize a new token
|
|
* unlike initialize slot, this can be called multiple times in the lifetime
|
|
* of NSS. It reads the information associated with a card or token,
|
|
* that is not going to change unless the card or token changes.
|
|
*/
|
|
SECStatus
|
|
PK11_TokenRefresh(PK11SlotInfo *slot)
|
|
{
|
|
CK_TOKEN_INFO tokenInfo;
|
|
CK_RV crv;
|
|
|
|
/* set the slot flags to the current token values */
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID,&tokenInfo);
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return SECFailure;
|
|
}
|
|
|
|
slot->flags = tokenInfo.flags;
|
|
slot->needLogin = ((tokenInfo.flags & CKF_LOGIN_REQUIRED) ?
|
|
PR_TRUE : PR_FALSE);
|
|
slot->readOnly = ((tokenInfo.flags & CKF_WRITE_PROTECTED) ?
|
|
PR_TRUE : PR_FALSE);
|
|
slot->hasRandom = ((tokenInfo.flags & CKF_RNG) ? PR_TRUE : PR_FALSE);
|
|
slot->protectedAuthPath =
|
|
((tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
|
|
? PR_TRUE : PR_FALSE);
|
|
/* on some platforms Active Card incorrectly sets the
|
|
* CKF_PROTECTED_AUTHENTICATION_PATH bit when it doesn't mean to. */
|
|
if (slot->isActiveCard) {
|
|
slot->protectedAuthPath = PR_FALSE;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
static PRBool
|
|
pk11_isRootSlot(PK11SlotInfo *slot)
|
|
{
|
|
CK_ATTRIBUTE findTemp[1];
|
|
CK_ATTRIBUTE *attrs;
|
|
CK_OBJECT_CLASS oclass = CKO_NETSCAPE_BUILTIN_ROOT_LIST;
|
|
int tsize;
|
|
CK_OBJECT_HANDLE handle;
|
|
|
|
attrs = findTemp;
|
|
PK11_SETATTRS(attrs, CKA_CLASS, &oclass, sizeof(oclass)); attrs++;
|
|
tsize = attrs - findTemp;
|
|
PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
|
|
|
|
handle = pk11_FindObjectByTemplate(slot,findTemp,tsize);
|
|
if (handle == CK_INVALID_HANDLE) {
|
|
return PR_FALSE;
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
/*
|
|
* Initialize the slot :
|
|
* This initialization code is called on each slot a module supports when
|
|
* it is loaded. It does the bringup initialization. The difference between
|
|
* this and InitToken is Init slot does those one time initialization stuff,
|
|
* usually associated with the reader, while InitToken may get called multiple
|
|
* times as tokens are removed and re-inserted.
|
|
*/
|
|
void
|
|
PK11_InitSlot(SECMODModule *mod, CK_SLOT_ID slotID, PK11SlotInfo *slot)
|
|
{
|
|
SECStatus rv;
|
|
char *tmp;
|
|
CK_SLOT_INFO slotInfo;
|
|
|
|
slot->functionList = mod->functionList;
|
|
slot->isInternal = mod->internal;
|
|
slot->slotID = slotID;
|
|
slot->isThreadSafe = mod->isThreadSafe;
|
|
slot->hasRSAInfo = PR_FALSE;
|
|
|
|
if (PK11_GETTAB(slot)->C_GetSlotInfo(slotID,&slotInfo) != CKR_OK) {
|
|
slot->disabled = PR_TRUE;
|
|
slot->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
|
|
return;
|
|
}
|
|
|
|
/* test to make sure claimed mechanism work */
|
|
slot->needTest = mod->internal ? PR_FALSE : PR_TRUE;
|
|
slot->module = mod; /* NOTE: we don't make a reference here because
|
|
* modules have references to their slots. This
|
|
* works because modules keep implicit references
|
|
* from their slots, and won't unload and disappear
|
|
* until all their slots have been freed */
|
|
tmp = PK11_MakeString(NULL,slot->slot_name,
|
|
(char *)slotInfo.slotDescription, sizeof(slotInfo.slotDescription));
|
|
slot->isHW = (PRBool)((slotInfo.flags & CKF_HW_SLOT) == CKF_HW_SLOT);
|
|
#define ACTIVE_CARD "ActivCard SA"
|
|
slot->isActiveCard = (PRBool)(PORT_Strncmp((char *)slotInfo.manufacturerID,
|
|
ACTIVE_CARD, sizeof(ACTIVE_CARD)-1) == 0);
|
|
if ((slotInfo.flags & CKF_REMOVABLE_DEVICE) == 0) {
|
|
slot->isPerm = PR_TRUE;
|
|
/* permanment slots must have the token present always */
|
|
if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0) {
|
|
slot->disabled = PR_TRUE;
|
|
slot->reason = PK11_DIS_TOKEN_NOT_PRESENT;
|
|
return; /* nothing else to do */
|
|
}
|
|
}
|
|
/* if the token is present, initialize it */
|
|
if ((slotInfo.flags & CKF_TOKEN_PRESENT) != 0) {
|
|
rv = PK11_InitToken(slot,PR_TRUE);
|
|
/* the only hard failures are on permanent devices, or function
|
|
* verify failures... function verify failures are already handled
|
|
* by tokenInit */
|
|
if ((rv != SECSuccess) && (slot->isPerm) && (!slot->disabled)) {
|
|
slot->disabled = PR_TRUE;
|
|
slot->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
|
|
}
|
|
if (rv == SECSuccess && pk11_isRootSlot(slot)) {
|
|
if (!slot->hasRootCerts) {
|
|
slot->module->trustOrder = 100;
|
|
}
|
|
slot->hasRootCerts= PR_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
* Slot mapping utility functions.
|
|
*********************************************************************/
|
|
|
|
/*
|
|
* determine if the token is present. If the token is present, make sure
|
|
* we have a valid session handle. Also set the value of needLogin
|
|
* appropriately.
|
|
*/
|
|
static PRBool
|
|
pk11_IsPresentCertLoad(PK11SlotInfo *slot, PRBool loadCerts)
|
|
{
|
|
CK_SLOT_INFO slotInfo;
|
|
CK_SESSION_INFO sessionInfo;
|
|
CK_RV crv;
|
|
|
|
/* disabled slots are never present */
|
|
if (slot->disabled) {
|
|
return PR_FALSE;
|
|
}
|
|
|
|
/* permanent slots are always present */
|
|
if (slot->isPerm && (slot->session != CK_INVALID_SESSION)) {
|
|
return PR_TRUE;
|
|
}
|
|
|
|
if (slot->nssToken) {
|
|
return nssToken_IsPresent(slot->nssToken);
|
|
}
|
|
|
|
/* removable slots have a flag that says they are present */
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
if (PK11_GETTAB(slot)->C_GetSlotInfo(slot->slotID,&slotInfo) != CKR_OK) {
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
return PR_FALSE;
|
|
}
|
|
if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0) {
|
|
/* if the slot is no longer present, close the session */
|
|
if (slot->session != CK_INVALID_SESSION) {
|
|
PK11_GETTAB(slot)->C_CloseSession(slot->session);
|
|
slot->session = CK_INVALID_SESSION;
|
|
}
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
return PR_FALSE;
|
|
}
|
|
|
|
/* use the session Info to determine if the card has been removed and then
|
|
* re-inserted */
|
|
if (slot->session != CK_INVALID_SESSION) {
|
|
if (slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session, &sessionInfo);
|
|
if (crv != CKR_OK) {
|
|
PK11_GETTAB(slot)->C_CloseSession(slot->session);
|
|
slot->session = CK_INVALID_SESSION;
|
|
}
|
|
if (slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
}
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
|
|
/* card has not been removed, current token info is correct */
|
|
if (slot->session != CK_INVALID_SESSION) return PR_TRUE;
|
|
|
|
/* initialize the token info state */
|
|
if (PK11_InitToken(slot,loadCerts) != SECSuccess) {
|
|
return PR_FALSE;
|
|
}
|
|
|
|
return PR_TRUE;
|
|
}
|
|
|
|
/*
|
|
* old version of the routine
|
|
*/
|
|
PRBool
|
|
PK11_IsPresent(PK11SlotInfo *slot) {
|
|
return pk11_IsPresentCertLoad(slot,PR_TRUE);
|
|
}
|
|
|
|
/* is the slot disabled? */
|
|
PRBool
|
|
PK11_IsDisabled(PK11SlotInfo *slot)
|
|
{
|
|
return slot->disabled;
|
|
}
|
|
|
|
/* and why? */
|
|
PK11DisableReasons
|
|
PK11_GetDisabledReason(PK11SlotInfo *slot)
|
|
{
|
|
return slot->reason;
|
|
}
|
|
|
|
/* returns PR_TRUE if successfully disable the slot */
|
|
/* returns PR_FALSE otherwise */
|
|
PRBool PK11_UserDisableSlot(PK11SlotInfo *slot) {
|
|
|
|
/* Prevent users from disabling the internal module. */
|
|
if (slot->isInternal) {
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
return PR_FALSE;
|
|
}
|
|
|
|
slot->defaultFlags |= PK11_DISABLE_FLAG;
|
|
slot->disabled = PR_TRUE;
|
|
slot->reason = PK11_DIS_USER_SELECTED;
|
|
|
|
return PR_TRUE;
|
|
}
|
|
|
|
PRBool PK11_UserEnableSlot(PK11SlotInfo *slot) {
|
|
|
|
slot->defaultFlags &= ~PK11_DISABLE_FLAG;
|
|
slot->disabled = PR_FALSE;
|
|
slot->reason = PK11_DIS_NONE;
|
|
return PR_TRUE;
|
|
}
|
|
|
|
PRBool PK11_HasRootCerts(PK11SlotInfo *slot) {
|
|
return slot->hasRootCerts;
|
|
}
|
|
|
|
/* Get the module this slot is attached to */
|
|
SECMODModule *
|
|
PK11_GetModule(PK11SlotInfo *slot)
|
|
{
|
|
return slot->module;
|
|
}
|
|
|
|
/* return the default flags of a slot */
|
|
unsigned long
|
|
PK11_GetDefaultFlags(PK11SlotInfo *slot)
|
|
{
|
|
return slot->defaultFlags;
|
|
}
|
|
|
|
/*
|
|
* The following wrapper functions allow us to export an opaque slot
|
|
* function to the rest of libsec and the world... */
|
|
PRBool
|
|
PK11_IsReadOnly(PK11SlotInfo *slot)
|
|
{
|
|
return slot->readOnly;
|
|
}
|
|
|
|
PRBool
|
|
PK11_IsHW(PK11SlotInfo *slot)
|
|
{
|
|
return slot->isHW;
|
|
}
|
|
|
|
PRBool
|
|
PK11_IsRemovable(PK11SlotInfo *slot)
|
|
{
|
|
return !slot->isPerm;
|
|
}
|
|
|
|
PRBool
|
|
PK11_IsInternal(PK11SlotInfo *slot)
|
|
{
|
|
return slot->isInternal;
|
|
}
|
|
|
|
PRBool
|
|
PK11_IsInternalKeySlot(PK11SlotInfo *slot)
|
|
{
|
|
PK11SlotInfo *int_slot;
|
|
PRBool result;
|
|
|
|
if (!slot->isInternal) {
|
|
return PR_FALSE;
|
|
}
|
|
|
|
int_slot = PK11_GetInternalKeySlot();
|
|
result = (int_slot == slot) ? PR_TRUE : PR_FALSE;
|
|
PK11_FreeSlot(int_slot);
|
|
return result;
|
|
}
|
|
|
|
PRBool
|
|
PK11_NeedLogin(PK11SlotInfo *slot)
|
|
{
|
|
return slot->needLogin;
|
|
}
|
|
|
|
PRBool
|
|
PK11_IsFriendly(PK11SlotInfo *slot)
|
|
{
|
|
/* internal slot always has public readable certs */
|
|
return (PRBool)(slot->isInternal ||
|
|
((slot->defaultFlags & SECMOD_FRIENDLY_FLAG) ==
|
|
SECMOD_FRIENDLY_FLAG));
|
|
}
|
|
|
|
char *
|
|
PK11_GetTokenName(PK11SlotInfo *slot)
|
|
{
|
|
return slot->token_name;
|
|
}
|
|
|
|
char *
|
|
PK11_GetSlotName(PK11SlotInfo *slot)
|
|
{
|
|
return slot->slot_name;
|
|
}
|
|
|
|
int
|
|
PK11_GetSlotSeries(PK11SlotInfo *slot)
|
|
{
|
|
return slot->series;
|
|
}
|
|
|
|
int
|
|
PK11_GetCurrentWrapIndex(PK11SlotInfo *slot)
|
|
{
|
|
return slot->wrapKey;
|
|
}
|
|
|
|
CK_SLOT_ID
|
|
PK11_GetSlotID(PK11SlotInfo *slot)
|
|
{
|
|
return slot->slotID;
|
|
}
|
|
|
|
SECMODModuleID
|
|
PK11_GetModuleID(PK11SlotInfo *slot)
|
|
{
|
|
return slot->module->moduleID;
|
|
}
|
|
|
|
static void
|
|
pk11_zeroTerminatedToBlankPadded(CK_CHAR *buffer, size_t buffer_size)
|
|
{
|
|
CK_CHAR *walk = buffer;
|
|
CK_CHAR *end = buffer + buffer_size;
|
|
|
|
/* find the NULL */
|
|
while (walk < end && *walk != '\0') {
|
|
walk++;
|
|
}
|
|
|
|
/* clear out the buffer */
|
|
while (walk < end) {
|
|
*walk++ = ' ';
|
|
}
|
|
}
|
|
|
|
/* return the slot info structure */
|
|
SECStatus
|
|
PK11_GetSlotInfo(PK11SlotInfo *slot, CK_SLOT_INFO *info)
|
|
{
|
|
CK_RV crv;
|
|
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
/*
|
|
* some buggy drivers do not fill the buffer completely,
|
|
* erase the buffer first
|
|
*/
|
|
PORT_Memset(info->slotDescription,' ',sizeof(info->slotDescription));
|
|
PORT_Memset(info->manufacturerID,' ',sizeof(info->manufacturerID));
|
|
crv = PK11_GETTAB(slot)->C_GetSlotInfo(slot->slotID,info);
|
|
pk11_zeroTerminatedToBlankPadded(info->slotDescription,
|
|
sizeof(info->slotDescription));
|
|
pk11_zeroTerminatedToBlankPadded(info->manufacturerID,
|
|
sizeof(info->manufacturerID));
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
/* return the token info structure */
|
|
SECStatus
|
|
PK11_GetTokenInfo(PK11SlotInfo *slot, CK_TOKEN_INFO *info)
|
|
{
|
|
CK_RV crv;
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
/*
|
|
* some buggy drivers do not fill the buffer completely,
|
|
* erase the buffer first
|
|
*/
|
|
PORT_Memset(info->label,' ',sizeof(info->label));
|
|
PORT_Memset(info->manufacturerID,' ',sizeof(info->manufacturerID));
|
|
PORT_Memset(info->model,' ',sizeof(info->model));
|
|
PORT_Memset(info->serialNumber,' ',sizeof(info->serialNumber));
|
|
crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID,info);
|
|
pk11_zeroTerminatedToBlankPadded(info->label,sizeof(info->label));
|
|
pk11_zeroTerminatedToBlankPadded(info->manufacturerID,
|
|
sizeof(info->manufacturerID));
|
|
pk11_zeroTerminatedToBlankPadded(info->model,sizeof(info->model));
|
|
pk11_zeroTerminatedToBlankPadded(info->serialNumber,
|
|
sizeof(info->serialNumber));
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
/* Find out if we need to initialize the user's pin */
|
|
PRBool
|
|
PK11_NeedUserInit(PK11SlotInfo *slot)
|
|
{
|
|
PRBool needUserInit = (PRBool) ((slot->flags & CKF_USER_PIN_INITIALIZED)
|
|
== 0);
|
|
|
|
if (needUserInit) {
|
|
CK_TOKEN_INFO info;
|
|
SECStatus rv;
|
|
|
|
/* see if token has been initialized off line */
|
|
rv = PK11_GetTokenInfo(slot, &info);
|
|
if (rv == SECSuccess) {
|
|
slot->flags = info.flags;
|
|
}
|
|
}
|
|
return (PRBool)((slot->flags & CKF_USER_PIN_INITIALIZED) == 0);
|
|
}
|
|
|
|
static PK11SlotInfo *pk11InternalKeySlot = NULL;
|
|
|
|
/*
|
|
* Set a new default internal keyslot. If one has already been set, clear it.
|
|
* Passing NULL falls back to the NSS normally selected default internal key
|
|
* slot.
|
|
*/
|
|
void
|
|
pk11_SetInternalKeySlot(PK11SlotInfo *slot)
|
|
{
|
|
if (pk11InternalKeySlot) {
|
|
PK11_FreeSlot(pk11InternalKeySlot);
|
|
}
|
|
pk11InternalKeySlot = slot ? PK11_ReferenceSlot(slot) : NULL;
|
|
}
|
|
|
|
/*
|
|
* Set a new default internal keyslot if the normal key slot has not already
|
|
* been overridden. Subsequent calls to this function will be ignored unless
|
|
* pk11_SetInternalKeySlot is used to clear the current default.
|
|
*/
|
|
void
|
|
pk11_SetInternalKeySlotIfFirst(PK11SlotInfo *slot)
|
|
{
|
|
if (pk11InternalKeySlot) {
|
|
return;
|
|
}
|
|
pk11InternalKeySlot = slot ? PK11_ReferenceSlot(slot) : NULL;
|
|
}
|
|
|
|
/*
|
|
* Swap out a default internal keyslot. Caller owns the Slot Reference
|
|
*/
|
|
PK11SlotInfo *
|
|
pk11_SwapInternalKeySlot(PK11SlotInfo *slot)
|
|
{
|
|
PK11SlotInfo *swap = pk11InternalKeySlot;
|
|
|
|
pk11InternalKeySlot = slot ? PK11_ReferenceSlot(slot) : NULL;
|
|
return swap;
|
|
}
|
|
|
|
|
|
/* get the internal key slot. FIPS has only one slot for both key slots and
|
|
* default slots */
|
|
PK11SlotInfo *
|
|
PK11_GetInternalKeySlot(void)
|
|
{
|
|
SECMODModule *mod;
|
|
|
|
if (pk11InternalKeySlot) {
|
|
return PK11_ReferenceSlot(pk11InternalKeySlot);
|
|
}
|
|
|
|
mod = SECMOD_GetInternalModule();
|
|
PORT_Assert(mod != NULL);
|
|
if (!mod) {
|
|
PORT_SetError( SEC_ERROR_NO_MODULE );
|
|
return NULL;
|
|
}
|
|
return PK11_ReferenceSlot(mod->isFIPS ? mod->slots[0] : mod->slots[1]);
|
|
}
|
|
|
|
/* get the internal default slot */
|
|
PK11SlotInfo *
|
|
PK11_GetInternalSlot(void)
|
|
{
|
|
SECMODModule * mod = SECMOD_GetInternalModule();
|
|
PORT_Assert(mod != NULL);
|
|
if (!mod) {
|
|
PORT_SetError( SEC_ERROR_NO_MODULE );
|
|
return NULL;
|
|
}
|
|
if (mod->isFIPS) {
|
|
return PK11_GetInternalKeySlot();
|
|
}
|
|
return PK11_ReferenceSlot(mod->slots[0]);
|
|
}
|
|
|
|
/*
|
|
* check if a given slot supports the requested mechanism
|
|
*/
|
|
PRBool
|
|
PK11_DoesMechanism(PK11SlotInfo *slot, CK_MECHANISM_TYPE type)
|
|
{
|
|
int i;
|
|
|
|
/* CKM_FAKE_RANDOM is not a real PKCS mechanism. It's a marker to
|
|
* tell us we're looking form someone that has implemented get
|
|
* random bits */
|
|
if (type == CKM_FAKE_RANDOM) {
|
|
return slot->hasRandom;
|
|
}
|
|
|
|
/* for most mechanism, bypass the linear lookup */
|
|
if (type < 0x7ff) {
|
|
return (slot->mechanismBits[type & 0xff] & (1 << (type >> 8))) ?
|
|
PR_TRUE : PR_FALSE;
|
|
}
|
|
|
|
for (i=0; i < (int) slot->mechanismCount; i++) {
|
|
if (slot->mechanismList[i] == type) return PR_TRUE;
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
/*
|
|
* Return true if a token that can do the desired mechanism exists.
|
|
* This allows us to have hardware tokens that can do function XYZ magically
|
|
* allow SSL Ciphers to appear if they are plugged in.
|
|
*/
|
|
PRBool
|
|
PK11_TokenExists(CK_MECHANISM_TYPE type)
|
|
{
|
|
SECMODModuleList *mlp;
|
|
SECMODModuleList *modules;
|
|
SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
|
|
PK11SlotInfo *slot;
|
|
PRBool found = PR_FALSE;
|
|
int i;
|
|
|
|
if (!moduleLock) {
|
|
PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
|
return found;
|
|
}
|
|
/* we only need to know if there is a token that does this mechanism.
|
|
* check the internal module first because it's fast, and supports
|
|
* almost everything. */
|
|
slot = PK11_GetInternalSlot();
|
|
if (slot) {
|
|
found = PK11_DoesMechanism(slot,type);
|
|
PK11_FreeSlot(slot);
|
|
}
|
|
if (found) return PR_TRUE; /* bypass getting module locks */
|
|
|
|
SECMOD_GetReadLock(moduleLock);
|
|
modules = SECMOD_GetDefaultModuleList();
|
|
for(mlp = modules; mlp != NULL && (!found); mlp = mlp->next) {
|
|
for (i=0; i < mlp->module->slotCount; i++) {
|
|
slot = mlp->module->slots[i];
|
|
if (PK11_IsPresent(slot)) {
|
|
if (PK11_DoesMechanism(slot,type)) {
|
|
found = PR_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
SECMOD_ReleaseReadLock(moduleLock);
|
|
return found;
|
|
}
|
|
|
|
/*
|
|
* get all the currently available tokens in a list.
|
|
* that can perform the given mechanism. If mechanism is CKM_INVALID_MECHANISM,
|
|
* get all the tokens. Make sure tokens that need authentication are put at
|
|
* the end of this list.
|
|
*/
|
|
PK11SlotList *
|
|
PK11_GetAllTokens(CK_MECHANISM_TYPE type, PRBool needRW, PRBool loadCerts,
|
|
void *wincx)
|
|
{
|
|
PK11SlotList * list;
|
|
PK11SlotList * loginList;
|
|
PK11SlotList * friendlyList;
|
|
SECMODModuleList * mlp;
|
|
SECMODModuleList * modules;
|
|
SECMODListLock * moduleLock;
|
|
int i;
|
|
#if defined( XP_WIN32 )
|
|
int j = 0;
|
|
PRInt32 waste[16];
|
|
#endif
|
|
|
|
moduleLock = SECMOD_GetDefaultModuleListLock();
|
|
if (!moduleLock) {
|
|
PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
|
|
return NULL;
|
|
}
|
|
|
|
list = PK11_NewSlotList();
|
|
loginList = PK11_NewSlotList();
|
|
friendlyList = PK11_NewSlotList();
|
|
if ((list == NULL) || (loginList == NULL) || (friendlyList == NULL)) {
|
|
if (list) PK11_FreeSlotList(list);
|
|
if (loginList) PK11_FreeSlotList(loginList);
|
|
if (friendlyList) PK11_FreeSlotList(friendlyList);
|
|
return NULL;
|
|
}
|
|
|
|
SECMOD_GetReadLock(moduleLock);
|
|
|
|
modules = SECMOD_GetDefaultModuleList();
|
|
for(mlp = modules; mlp != NULL; mlp = mlp->next) {
|
|
|
|
#if defined( XP_WIN32 )
|
|
/* This is works around some horrible cache/page thrashing problems
|
|
** on Win32. Without this, this loop can take up to 6 seconds at
|
|
** 100% CPU on a Pentium-Pro 200. The thing this changes is to
|
|
** increase the size of the stack frame and modify it.
|
|
** Moving the loop code itself seems to have no effect.
|
|
** Dunno why this combination makes a difference, but it does.
|
|
*/
|
|
waste[ j & 0xf] = j++;
|
|
#endif
|
|
|
|
for (i = 0; i < mlp->module->slotCount; i++) {
|
|
PK11SlotInfo *slot = mlp->module->slots[i];
|
|
|
|
if (pk11_IsPresentCertLoad(slot, loadCerts)) {
|
|
if (needRW && slot->readOnly) continue;
|
|
if ((type == CKM_INVALID_MECHANISM)
|
|
|| PK11_DoesMechanism(slot, type)) {
|
|
if (pk11_LoginStillRequired(slot,wincx)) {
|
|
if (PK11_IsFriendly(slot)) {
|
|
PK11_AddSlotToList(friendlyList, slot, PR_TRUE);
|
|
} else {
|
|
PK11_AddSlotToList(loginList, slot, PR_TRUE);
|
|
}
|
|
} else {
|
|
PK11_AddSlotToList(list, slot, PR_TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
SECMOD_ReleaseReadLock(moduleLock);
|
|
|
|
pk11_MoveListToList(list,friendlyList);
|
|
PK11_FreeSlotList(friendlyList);
|
|
pk11_MoveListToList(list,loginList);
|
|
PK11_FreeSlotList(loginList);
|
|
|
|
return list;
|
|
}
|
|
|
|
/*
|
|
* NOTE: This routine is working from a private List generated by
|
|
* PK11_GetAllTokens. That is why it does not need to lock.
|
|
*/
|
|
PK11SlotList *
|
|
PK11_GetPrivateKeyTokens(CK_MECHANISM_TYPE type,PRBool needRW,void *wincx)
|
|
{
|
|
PK11SlotList *list = PK11_GetAllTokens(type,needRW,PR_TRUE,wincx);
|
|
PK11SlotListElement *le, *next ;
|
|
SECStatus rv;
|
|
|
|
if (list == NULL) return list;
|
|
|
|
for (le = list->head ; le; le = next) {
|
|
next = le->next; /* save the pointer here in case we have to
|
|
* free the element later */
|
|
rv = PK11_Authenticate(le->slot,PR_TRUE,wincx);
|
|
if (rv != SECSuccess) {
|
|
PK11_DeleteSlotFromList(list,le);
|
|
continue;
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
/*
|
|
* returns true if the slot doesn't conform to the requested attributes
|
|
*/
|
|
PRBool
|
|
pk11_filterSlot(PK11SlotInfo *slot, CK_MECHANISM_TYPE mechanism,
|
|
CK_FLAGS mechanismInfoFlags, unsigned int keySize)
|
|
{
|
|
CK_MECHANISM_INFO mechanism_info;
|
|
CK_RV crv = CKR_OK;
|
|
|
|
/* handle the only case where we don't actually fetch the mechanisms
|
|
* on the fly */
|
|
if ((keySize == 0) && (mechanism == CKM_RSA_PKCS) && (slot->hasRSAInfo)) {
|
|
mechanism_info.flags = slot->RSAInfoFlags;
|
|
} else {
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID, mechanism,
|
|
&mechanism_info);
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
/* if we were getting the RSA flags, save them */
|
|
if ((crv == CKR_OK) && (mechanism == CKM_RSA_PKCS)
|
|
&& (!slot->hasRSAInfo)) {
|
|
slot->RSAInfoFlags = mechanism_info.flags;
|
|
slot->hasRSAInfo = PR_TRUE;
|
|
}
|
|
}
|
|
/* couldn't get the mechanism info */
|
|
if (crv != CKR_OK ) {
|
|
return PR_TRUE;
|
|
}
|
|
if (keySize && ((mechanism_info.ulMinKeySize > keySize)
|
|
|| (mechanism_info.ulMaxKeySize < keySize)) ) {
|
|
/* Token can do mechanism, but not at the key size we
|
|
* want */
|
|
return PR_TRUE;
|
|
}
|
|
if (mechanismInfoFlags && ((mechanism_info.flags & mechanismInfoFlags) !=
|
|
mechanismInfoFlags) ) {
|
|
return PR_TRUE;
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Find the best slot which supports the given set of mechanisms and key sizes.
|
|
* In normal cases this should grab the first slot on the list with no fuss.
|
|
* The size array is presumed to match one for one with the mechanism type
|
|
* array, which allows you to specify the required key size for each
|
|
* mechanism in the list. Whether key size is in bits or bytes is mechanism
|
|
* dependent. Typically asymetric keys are in bits and symetric keys are in
|
|
* bytes.
|
|
*/
|
|
PK11SlotInfo *
|
|
PK11_GetBestSlotMultipleWithAttributes(CK_MECHANISM_TYPE *type,
|
|
CK_FLAGS *mechanismInfoFlags, unsigned int *keySize,
|
|
unsigned int mech_count, void *wincx)
|
|
{
|
|
PK11SlotList *list = NULL;
|
|
PK11SlotListElement *le ;
|
|
PK11SlotInfo *slot = NULL;
|
|
PRBool freeit = PR_FALSE;
|
|
PRBool listNeedLogin = PR_FALSE;
|
|
int i;
|
|
SECStatus rv;
|
|
|
|
list = PK11_GetSlotList(type[0]);
|
|
|
|
if ((list == NULL) || (list->head == NULL)) {
|
|
/* We need to look up all the tokens for the mechanism */
|
|
list = PK11_GetAllTokens(type[0],PR_FALSE,PR_TRUE,wincx);
|
|
freeit = PR_TRUE;
|
|
}
|
|
|
|
/* no one can do it! */
|
|
if (list == NULL) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
return NULL;
|
|
}
|
|
|
|
PORT_SetError(0);
|
|
|
|
|
|
listNeedLogin = PR_FALSE;
|
|
for (i=0; i < mech_count; i++) {
|
|
if ((type[i] != CKM_FAKE_RANDOM) &&
|
|
(type[i] != CKM_SHA_1) &&
|
|
(type[i] != CKM_SHA224) &&
|
|
(type[i] != CKM_SHA256) &&
|
|
(type[i] != CKM_SHA384) &&
|
|
(type[i] != CKM_SHA512) &&
|
|
(type[i] != CKM_MD5) &&
|
|
(type[i] != CKM_MD2)) {
|
|
listNeedLogin = PR_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (le = PK11_GetFirstSafe(list); le;
|
|
le = PK11_GetNextSafe(list,le,PR_TRUE)) {
|
|
if (PK11_IsPresent(le->slot)) {
|
|
PRBool doExit = PR_FALSE;
|
|
for (i=0; i < mech_count; i++) {
|
|
if (!PK11_DoesMechanism(le->slot,type[i])) {
|
|
doExit = PR_TRUE;
|
|
break;
|
|
}
|
|
if ((mechanismInfoFlags && mechanismInfoFlags[i]) ||
|
|
(keySize && keySize[i])) {
|
|
if (pk11_filterSlot(le->slot, type[i],
|
|
mechanismInfoFlags ? mechanismInfoFlags[i] : 0,
|
|
keySize ? keySize[i] : 0)) {
|
|
doExit = PR_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (doExit) continue;
|
|
|
|
if (listNeedLogin && le->slot->needLogin) {
|
|
rv = PK11_Authenticate(le->slot,PR_TRUE,wincx);
|
|
if (rv != SECSuccess) continue;
|
|
}
|
|
slot = le->slot;
|
|
PK11_ReferenceSlot(slot);
|
|
PK11_FreeSlotListElement(list,le);
|
|
if (freeit) { PK11_FreeSlotList(list); }
|
|
return slot;
|
|
}
|
|
}
|
|
if (freeit) { PK11_FreeSlotList(list); }
|
|
if (PORT_GetError() == 0) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
PK11SlotInfo *
|
|
PK11_GetBestSlotMultiple(CK_MECHANISM_TYPE *type,
|
|
unsigned int mech_count, void *wincx)
|
|
{
|
|
return PK11_GetBestSlotMultipleWithAttributes(type, NULL, NULL,
|
|
mech_count, wincx);
|
|
}
|
|
|
|
/* original get best slot now calls the multiple version with only one type */
|
|
PK11SlotInfo *
|
|
PK11_GetBestSlot(CK_MECHANISM_TYPE type, void *wincx)
|
|
{
|
|
return PK11_GetBestSlotMultipleWithAttributes(&type, NULL, NULL, 1, wincx);
|
|
}
|
|
|
|
PK11SlotInfo *
|
|
PK11_GetBestSlotWithAttributes(CK_MECHANISM_TYPE type, CK_FLAGS mechanismFlags,
|
|
unsigned int keySize, void *wincx)
|
|
{
|
|
return PK11_GetBestSlotMultipleWithAttributes(&type, &mechanismFlags,
|
|
&keySize, 1, wincx);
|
|
}
|
|
|
|
int
|
|
PK11_GetBestKeyLength(PK11SlotInfo *slot,CK_MECHANISM_TYPE mechanism)
|
|
{
|
|
CK_MECHANISM_INFO mechanism_info;
|
|
CK_RV crv;
|
|
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
|
|
mechanism,&mechanism_info);
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) return 0;
|
|
|
|
if (mechanism_info.ulMinKeySize == mechanism_info.ulMaxKeySize)
|
|
return 0;
|
|
return mechanism_info.ulMaxKeySize;
|
|
}
|
|
|
|
|
|
/*
|
|
* This function uses the existing PKCS #11 module to find the
|
|
* longest supported key length in the preferred token for a mechanism.
|
|
* This varies from the above function in that 1) it returns the key length
|
|
* even for fixed key algorithms, and 2) it looks through the tokens
|
|
* generally rather than for a specific token. This is used in liu of
|
|
* a PK11_GetKeyLength function in pk11mech.c since we can actually read
|
|
* supported key lengths from PKCS #11.
|
|
*
|
|
* For symmetric key operations the length is returned in bytes.
|
|
*/
|
|
int
|
|
PK11_GetMaxKeyLength(CK_MECHANISM_TYPE mechanism)
|
|
{
|
|
CK_MECHANISM_INFO mechanism_info;
|
|
PK11SlotList *list = NULL;
|
|
PK11SlotListElement *le ;
|
|
PRBool freeit = PR_FALSE;
|
|
int keyLength = 0;
|
|
|
|
list = PK11_GetSlotList(mechanism);
|
|
|
|
if ((list == NULL) || (list->head == NULL)) {
|
|
/* We need to look up all the tokens for the mechanism */
|
|
list = PK11_GetAllTokens(mechanism,PR_FALSE,PR_FALSE,NULL);
|
|
freeit = PR_TRUE;
|
|
}
|
|
|
|
/* no tokens recognize this mechanism */
|
|
if (list == NULL) {
|
|
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
|
|
return 0;
|
|
}
|
|
|
|
for (le = PK11_GetFirstSafe(list); le;
|
|
le = PK11_GetNextSafe(list,le,PR_TRUE)) {
|
|
PK11SlotInfo *slot = le->slot;
|
|
CK_RV crv;
|
|
if (PK11_IsPresent(slot)) {
|
|
if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
|
|
mechanism,&mechanism_info);
|
|
if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
|
|
if ((crv == CKR_OK) && (mechanism_info.ulMaxKeySize != 0)
|
|
&& (mechanism_info.ulMaxKeySize != 0xffffffff)) {
|
|
keyLength = mechanism_info.ulMaxKeySize;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (le)
|
|
PK11_FreeSlotListElement(list, le);
|
|
if (freeit)
|
|
PK11_FreeSlotList(list);
|
|
return keyLength;
|
|
}
|
|
|
|
SECStatus
|
|
PK11_SeedRandom(PK11SlotInfo *slot, unsigned char *data, int len) {
|
|
CK_RV crv;
|
|
|
|
PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_SeedRandom(slot->session, data, (CK_ULONG)len);
|
|
PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
|
|
SECStatus
|
|
PK11_GenerateRandomOnSlot(PK11SlotInfo *slot, unsigned char *data, int len) {
|
|
CK_RV crv;
|
|
|
|
if (!slot->isInternal) PK11_EnterSlotMonitor(slot);
|
|
crv = PK11_GETTAB(slot)->C_GenerateRandom(slot->session,data,
|
|
(CK_ULONG)len);
|
|
if (!slot->isInternal) PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
/* Attempts to update the Best Slot for "FAKE RANDOM" generation.
|
|
** If that's not the internal slot, then it also attempts to update the
|
|
** internal slot.
|
|
** The return value indicates if the INTERNAL slot was updated OK.
|
|
*/
|
|
SECStatus
|
|
PK11_RandomUpdate(void *data, size_t bytes)
|
|
{
|
|
PK11SlotInfo *slot;
|
|
PRBool bestIsInternal;
|
|
SECStatus status;
|
|
|
|
slot = PK11_GetBestSlot(CKM_FAKE_RANDOM, NULL);
|
|
if (slot == NULL) {
|
|
slot = PK11_GetInternalSlot();
|
|
if (!slot)
|
|
return SECFailure;
|
|
}
|
|
|
|
bestIsInternal = PK11_IsInternal(slot);
|
|
status = PK11_SeedRandom(slot, data, bytes);
|
|
PK11_FreeSlot(slot);
|
|
|
|
if (!bestIsInternal) {
|
|
/* do internal slot, too. */
|
|
slot = PK11_GetInternalSlot(); /* can't fail */
|
|
status = PK11_SeedRandom(slot, data, bytes);
|
|
PK11_FreeSlot(slot);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
SECStatus
|
|
PK11_GenerateRandom(unsigned char *data,int len) {
|
|
PK11SlotInfo *slot;
|
|
SECStatus rv;
|
|
|
|
slot = PK11_GetBestSlot(CKM_FAKE_RANDOM,NULL);
|
|
if (slot == NULL) return SECFailure;
|
|
|
|
rv = PK11_GenerateRandomOnSlot(slot, data, len);
|
|
PK11_FreeSlot(slot);
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* Reset the token to it's initial state. For the internal module, this will
|
|
* Purge your keydb, and reset your cert db certs to USER_INIT.
|
|
*/
|
|
SECStatus
|
|
PK11_ResetToken(PK11SlotInfo *slot, char *sso_pwd)
|
|
{
|
|
unsigned char tokenName[32];
|
|
int tokenNameLen;
|
|
CK_RV crv;
|
|
|
|
/* reconstruct the token name */
|
|
tokenNameLen = PORT_Strlen(slot->token_name);
|
|
if (tokenNameLen > sizeof(tokenName)) {
|
|
tokenNameLen = sizeof(tokenName);
|
|
}
|
|
|
|
PORT_Memcpy(tokenName,slot->token_name,tokenNameLen);
|
|
if (tokenNameLen < sizeof(tokenName)) {
|
|
PORT_Memset(&tokenName[tokenNameLen],' ',
|
|
sizeof(tokenName)-tokenNameLen);
|
|
}
|
|
|
|
/* initialize the token */
|
|
PK11_EnterSlotMonitor(slot);
|
|
|
|
/* first shutdown the token. Existing sessions will get closed here */
|
|
PK11_GETTAB(slot)->C_CloseAllSessions(slot->slotID);
|
|
slot->session = CK_INVALID_SESSION;
|
|
|
|
/* now re-init the token */
|
|
crv = PK11_GETTAB(slot)->C_InitToken(slot->slotID,
|
|
(unsigned char *)sso_pwd, sso_pwd ? PORT_Strlen(sso_pwd): 0, tokenName);
|
|
|
|
/* finally bring the token back up */
|
|
PK11_InitToken(slot,PR_TRUE);
|
|
PK11_ExitSlotMonitor(slot);
|
|
if (crv != CKR_OK) {
|
|
PORT_SetError(PK11_MapError(crv));
|
|
return SECFailure;
|
|
}
|
|
nssTrustDomain_UpdateCachedTokenCerts(slot->nssToken->trustDomain,
|
|
slot->nssToken);
|
|
return SECSuccess;
|
|
}
|
|
void
|
|
PK11Slot_SetNSSToken(PK11SlotInfo *sl, NSSToken *nsst)
|
|
{
|
|
sl->nssToken = nsst;
|
|
}
|
|
|
|
NSSToken *
|
|
PK11Slot_GetNSSToken(PK11SlotInfo *sl)
|
|
{
|
|
return sl->nssToken;
|
|
}
|
|
|
|
/*
|
|
* wait for a token to change it's state. The application passes in the expected
|
|
* new state in event.
|
|
*/
|
|
PK11TokenStatus
|
|
PK11_WaitForTokenEvent(PK11SlotInfo *slot, PK11TokenEvent event,
|
|
PRIntervalTime timeout, PRIntervalTime latency, int series)
|
|
{
|
|
PRIntervalTime first_time = 0;
|
|
PRBool first_time_set = PR_FALSE;
|
|
PRBool waitForRemoval;
|
|
|
|
if (slot->isPerm) {
|
|
return PK11TokenNotRemovable;
|
|
}
|
|
if (latency == 0) {
|
|
latency = PR_SecondsToInterval(5);
|
|
}
|
|
waitForRemoval = (PRBool) (event == PK11TokenRemovedOrChangedEvent);
|
|
|
|
if (series == 0) {
|
|
series = PK11_GetSlotSeries(slot);
|
|
}
|
|
while (PK11_IsPresent(slot) == waitForRemoval ) {
|
|
PRIntervalTime interval;
|
|
|
|
if (waitForRemoval && series != PK11_GetSlotSeries(slot)) {
|
|
return PK11TokenChanged;
|
|
}
|
|
if (timeout == PR_INTERVAL_NO_WAIT) {
|
|
return waitForRemoval ? PK11TokenPresent : PK11TokenRemoved;
|
|
}
|
|
if (timeout != PR_INTERVAL_NO_TIMEOUT ) {
|
|
interval = PR_IntervalNow();
|
|
if (!first_time_set) {
|
|
first_time = interval;
|
|
first_time_set = PR_TRUE;
|
|
}
|
|
if ((interval-first_time) > timeout) {
|
|
return waitForRemoval ? PK11TokenPresent : PK11TokenRemoved;
|
|
}
|
|
}
|
|
PR_Sleep(latency);
|
|
}
|
|
return waitForRemoval ? PK11TokenRemoved : PK11TokenPresent;
|
|
}
|