Mercurial > trustbridge > nss-cmake-static
view nss/lib/softoken/pkcs11u.c @ 4:b513267f632f tip
Build DBM module
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Tue, 05 Aug 2014 18:58:03 +0200 |
parents | 1e5118fa0cb1 |
children |
line wrap: on
line source
/* 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/. */ /* * Internal PKCS #11 functions. Should only be called by pkcs11.c */ #include "pkcs11.h" #include "pkcs11i.h" #include "lowkeyi.h" #include "secasn1.h" #include "blapi.h" #include "secerr.h" #include "prnetdb.h" /* for PR_ntohl */ #include "sftkdb.h" #include "softoken.h" /* * ******************** Attribute Utilities ******************************* */ /* * create a new attribute with type, value, and length. Space is allocated * to hold value. */ static SFTKAttribute * sftk_NewAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, const void *value, CK_ULONG len) { SFTKAttribute *attribute; SFTKSessionObject *so = sftk_narrowToSessionObject(object); int index; if (so == NULL) { /* allocate new attribute in a buffer */ PORT_Assert(0); return NULL; } /* * We attempt to keep down contention on Malloc and Arena locks by * limiting the number of these calls on high traversed paths. This * is done for attributes by 'allocating' them from a pool already * allocated by the parent object. */ PZ_Lock(so->attributeLock); index = so->nextAttr++; PZ_Unlock(so->attributeLock); PORT_Assert(index < MAX_OBJS_ATTRS); if (index >= MAX_OBJS_ATTRS) return NULL; attribute = &so->attrList[index]; attribute->attrib.type = type; attribute->freeAttr = PR_FALSE; attribute->freeData = PR_FALSE; if (value) { if (len <= ATTR_SPACE) { attribute->attrib.pValue = attribute->space; } else { attribute->attrib.pValue = PORT_Alloc(len); attribute->freeData = PR_TRUE; } if (attribute->attrib.pValue == NULL) { return NULL; } PORT_Memcpy(attribute->attrib.pValue,value,len); attribute->attrib.ulValueLen = len; } else { attribute->attrib.pValue = NULL; attribute->attrib.ulValueLen = 0; } attribute->attrib.type = type; attribute->handle = type; attribute->next = attribute->prev = NULL; return attribute; } /* * Free up all the memory associated with an attribute. Reference count * must be zero to call this. */ static void sftk_DestroyAttribute(SFTKAttribute *attribute) { if (attribute->freeData) { if (attribute->attrib.pValue) { /* clear out the data in the attribute value... it may have been * sensitive data */ PORT_Memset(attribute->attrib.pValue, 0, attribute->attrib.ulValueLen); } PORT_Free(attribute->attrib.pValue); } PORT_Free(attribute); } /* * release a reference to an attribute structure */ void sftk_FreeAttribute(SFTKAttribute *attribute) { if (attribute->freeAttr) { sftk_DestroyAttribute(attribute); return; } } static SFTKAttribute * sftk_FindTokenAttribute(SFTKTokenObject *object,CK_ATTRIBUTE_TYPE type) { SFTKAttribute *myattribute = NULL; SFTKDBHandle *dbHandle = NULL; CK_RV crv = CKR_HOST_MEMORY; myattribute = (SFTKAttribute*)PORT_Alloc(sizeof(SFTKAttribute)); if (myattribute == NULL) { goto loser; } dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle); myattribute->handle = type; myattribute->attrib.type = type; myattribute->attrib.pValue = myattribute->space; myattribute->attrib.ulValueLen = ATTR_SPACE; myattribute->next = myattribute->prev = NULL; myattribute->freeAttr = PR_TRUE; myattribute->freeData = PR_FALSE; crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, &myattribute->attrib, 1); /* attribute is bigger than our attribute space buffer, malloc it */ if (crv == CKR_BUFFER_TOO_SMALL) { myattribute->attrib.pValue = NULL; crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, &myattribute->attrib, 1); if (crv != CKR_OK) { goto loser; } myattribute->attrib.pValue = PORT_Alloc(myattribute->attrib.ulValueLen); if (myattribute->attrib.pValue == NULL) { crv = CKR_HOST_MEMORY; goto loser; } myattribute->freeData = PR_TRUE; crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, &myattribute->attrib, 1); } loser: if (dbHandle) { sftk_freeDB(dbHandle); } if (crv != CKR_OK) { if (myattribute) { myattribute->attrib.ulValueLen = 0; sftk_FreeAttribute(myattribute); myattribute = NULL; } } return myattribute; } /* * look up and attribute structure from a type and Object structure. * The returned attribute is referenced and needs to be freed when * it is no longer needed. */ SFTKAttribute * sftk_FindAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type) { SFTKAttribute *attribute; SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); if (sessObject == NULL) { return sftk_FindTokenAttribute(sftk_narrowToTokenObject(object),type); } PZ_Lock(sessObject->attributeLock); sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize); PZ_Unlock(sessObject->attributeLock); return(attribute); } /* * Take a buffer and it's length and return it's true size in bits; */ unsigned int sftk_GetLengthInBits(unsigned char *buf, unsigned int bufLen) { unsigned int size = bufLen * 8; unsigned int i; /* Get the real length in bytes */ for (i=0; i < bufLen; i++) { unsigned char c = *buf++; if (c != 0) { unsigned char m; for (m=0x80; m > 0 ; m = m >> 1) { if ((c & m) != 0) { break; } size--; } break; } size-=8; } return size; } /* * Constrain a big num attribute. to size and padding * minLength means length of the object must be greater than equal to minLength * maxLength means length of the object must be less than equal to maxLength * minMultiple means that object length mod minMultiple must equal 0. * all input sizes are in bits. * if any constraint is '0' that constraint is not checked. */ CK_RV sftk_ConstrainAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, int minLength, int maxLength, int minMultiple) { SFTKAttribute *attribute; int size; unsigned char *ptr; attribute = sftk_FindAttribute(object, type); if (!attribute) { return CKR_TEMPLATE_INCOMPLETE; } ptr = (unsigned char *) attribute->attrib.pValue; if (ptr == NULL) { sftk_FreeAttribute(attribute); return CKR_ATTRIBUTE_VALUE_INVALID; } size = sftk_GetLengthInBits(ptr, attribute->attrib.ulValueLen); sftk_FreeAttribute(attribute); if ((minLength != 0) && (size < minLength)) { return CKR_ATTRIBUTE_VALUE_INVALID; } if ((maxLength != 0) && (size > maxLength)) { return CKR_ATTRIBUTE_VALUE_INVALID; } if ((minMultiple != 0) && ((size % minMultiple) != 0)) { return CKR_ATTRIBUTE_VALUE_INVALID; } return CKR_OK; } PRBool sftk_hasAttributeToken(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) { CK_ATTRIBUTE template; CK_RV crv; SFTKDBHandle *dbHandle; dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle); template.type = type; template.pValue = NULL; template.ulValueLen = 0; crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, &template, 1); sftk_freeDB(dbHandle); /* attribute is bigger than our attribute space buffer, malloc it */ return (crv == CKR_OK) ? PR_TRUE : PR_FALSE; } /* * return true if object has attribute */ PRBool sftk_hasAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type) { SFTKAttribute *attribute; SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); if (sessObject == NULL) { return sftk_hasAttributeToken(sftk_narrowToTokenObject(object), type); } PZ_Lock(sessObject->attributeLock); sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize); PZ_Unlock(sessObject->attributeLock); return (PRBool)(attribute != NULL); } /* * add an attribute to an object */ static void sftk_AddAttribute(SFTKObject *object,SFTKAttribute *attribute) { SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); if (sessObject == NULL) return; PZ_Lock(sessObject->attributeLock); sftkqueue_add(attribute,attribute->handle, sessObject->head, sessObject->hashSize); PZ_Unlock(sessObject->attributeLock); } /* * copy an unsigned attribute into a SECItem. Secitem is allocated in * the specified arena. */ CK_RV sftk_Attribute2SSecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object, CK_ATTRIBUTE_TYPE type) { SFTKAttribute *attribute; item->data = NULL; attribute = sftk_FindAttribute(object, type); if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; (void)SECITEM_AllocItem(arena, item, attribute->attrib.ulValueLen); if (item->data == NULL) { sftk_FreeAttribute(attribute); return CKR_HOST_MEMORY; } PORT_Memcpy(item->data, attribute->attrib.pValue, item->len); sftk_FreeAttribute(attribute); return CKR_OK; } /* * fetch multiple attributes into SECItems. Secitem data is allocated in * the specified arena. */ CK_RV sftk_MultipleAttribute2SecItem(PLArenaPool *arena, SFTKObject *object, SFTKItemTemplate *itemTemplate, int itemTemplateCount) { CK_RV crv = CKR_OK; CK_ATTRIBUTE templateSpace[SFTK_MAX_ITEM_TEMPLATE]; CK_ATTRIBUTE *template; SFTKTokenObject *tokObject; SFTKDBHandle *dbHandle = NULL; int i; tokObject = sftk_narrowToTokenObject(object); /* session objects, just loop through the list */ if (tokObject == NULL) { for (i=0; i < itemTemplateCount; i++) { crv = sftk_Attribute2SecItem(arena,itemTemplate[i].item, object, itemTemplate[i].type); if (crv != CKR_OK) { return crv; } } return CKR_OK; } /* don't do any work if none is required */ if (itemTemplateCount == 0) { return CKR_OK; } /* don't allocate the template unless we need it */ if (itemTemplateCount > SFTK_MAX_ITEM_TEMPLATE) { template = PORT_NewArray(CK_ATTRIBUTE, itemTemplateCount); } else { template = templateSpace; } if (template == NULL) { crv = CKR_HOST_MEMORY; goto loser; } dbHandle = sftk_getDBForTokenObject(object->slot, object->handle); if (dbHandle == NULL) { crv = CKR_OBJECT_HANDLE_INVALID; goto loser; } /* set up the PKCS #11 template */ for (i=0; i < itemTemplateCount; i++) { template[i].type = itemTemplate[i].type; template[i].pValue = NULL; template[i].ulValueLen = 0; } /* fetch the attribute lengths */ crv = sftkdb_GetAttributeValue(dbHandle, object->handle, template, itemTemplateCount); if (crv != CKR_OK) { goto loser; } /* allocate space for the attributes */ for (i=0; i < itemTemplateCount ; i++) { template[i].pValue = PORT_ArenaAlloc(arena, template[i].ulValueLen); if (template[i].pValue == NULL) { crv = CKR_HOST_MEMORY; goto loser; } } /* fetch the attributes */ crv = sftkdb_GetAttributeValue(dbHandle, object->handle, template, itemTemplateCount); if (crv != CKR_OK) { goto loser; } /* Fill in the items */ for (i=0; i < itemTemplateCount; i++) { itemTemplate[i].item->data = template[i].pValue; itemTemplate[i].item->len = template[i].ulValueLen; } loser: if (template != templateSpace) { PORT_Free(template); } if (dbHandle) { sftk_freeDB(dbHandle); } return crv; } /* * delete an attribute from an object */ static void sftk_DeleteAttribute(SFTKObject *object, SFTKAttribute *attribute) { SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); if (sessObject == NULL) { return ; } PZ_Lock(sessObject->attributeLock); if (sftkqueue_is_queued(attribute,attribute->handle, sessObject->head, sessObject->hashSize)) { sftkqueue_delete(attribute,attribute->handle, sessObject->head, sessObject->hashSize); } PZ_Unlock(sessObject->attributeLock); } /* * this is only valid for CK_BBOOL type attributes. Return the state * of that attribute. */ PRBool sftk_isTrue(SFTKObject *object,CK_ATTRIBUTE_TYPE type) { SFTKAttribute *attribute; PRBool tok = PR_FALSE; attribute=sftk_FindAttribute(object,type); if (attribute == NULL) { return PR_FALSE; } tok = (PRBool)(*(CK_BBOOL *)attribute->attrib.pValue); sftk_FreeAttribute(attribute); return tok; } /* * force an attribute to null. * this is for sensitive keys which are stored in the database, we don't * want to keep this info around in memory in the clear. */ void sftk_nullAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type) { SFTKAttribute *attribute; attribute=sftk_FindAttribute(object,type); if (attribute == NULL) return; if (attribute->attrib.pValue != NULL) { PORT_Memset(attribute->attrib.pValue,0,attribute->attrib.ulValueLen); if (attribute->freeData) { PORT_Free(attribute->attrib.pValue); } attribute->freeData = PR_FALSE; attribute->attrib.pValue = NULL; attribute->attrib.ulValueLen = 0; } sftk_FreeAttribute(attribute); } static CK_RV sftk_forceTokenAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type, const void *value, unsigned int len) { CK_ATTRIBUTE attribute; SFTKDBHandle *dbHandle = NULL; SFTKTokenObject *to = sftk_narrowToTokenObject(object); CK_RV crv; PORT_Assert(to); if (to == NULL) { return CKR_DEVICE_ERROR; } dbHandle = sftk_getDBForTokenObject(object->slot, object->handle); attribute.type = type; attribute.pValue = (void *)value; attribute.ulValueLen = len; crv = sftkdb_SetAttributeValue(dbHandle, object, &attribute, 1); sftk_freeDB(dbHandle); return crv; } /* * force an attribute to a specifc value. */ CK_RV sftk_forceAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type, const void *value, unsigned int len) { SFTKAttribute *attribute; void *att_val = NULL; PRBool freeData = PR_FALSE; PORT_Assert(object); PORT_Assert(object->refCount); PORT_Assert(object->slot); if (!object || !object->refCount || !object->slot) { return CKR_DEVICE_ERROR; } if (sftk_isToken(object->handle)) { return sftk_forceTokenAttribute(object,type,value,len); } attribute=sftk_FindAttribute(object,type); if (attribute == NULL) return sftk_AddAttributeType(object,type,value,len); if (value) { if (len <= ATTR_SPACE) { att_val = attribute->space; } else { att_val = PORT_Alloc(len); freeData = PR_TRUE; } if (att_val == NULL) { return CKR_HOST_MEMORY; } if (attribute->attrib.pValue == att_val) { PORT_Memset(attribute->attrib.pValue,0, attribute->attrib.ulValueLen); } PORT_Memcpy(att_val,value,len); } if (attribute->attrib.pValue != NULL) { if (attribute->attrib.pValue != att_val) { PORT_Memset(attribute->attrib.pValue,0, attribute->attrib.ulValueLen); } if (attribute->freeData) { PORT_Free(attribute->attrib.pValue); } attribute->freeData = PR_FALSE; attribute->attrib.pValue = NULL; attribute->attrib.ulValueLen = 0; } if (att_val) { attribute->attrib.pValue = att_val; attribute->attrib.ulValueLen = len; attribute->freeData = freeData; } sftk_FreeAttribute(attribute); return CKR_OK; } /* * return a null terminated string from attribute 'type'. This string * is allocated and needs to be freed with PORT_Free() When complete. */ char * sftk_getString(SFTKObject *object,CK_ATTRIBUTE_TYPE type) { SFTKAttribute *attribute; char *label = NULL; attribute=sftk_FindAttribute(object,type); if (attribute == NULL) return NULL; if (attribute->attrib.pValue != NULL) { label = (char *) PORT_Alloc(attribute->attrib.ulValueLen+1); if (label == NULL) { sftk_FreeAttribute(attribute); return NULL; } PORT_Memcpy(label,attribute->attrib.pValue, attribute->attrib.ulValueLen); label[attribute->attrib.ulValueLen] = 0; } sftk_FreeAttribute(attribute); return label; } /* * decode when a particular attribute may be modified * SFTK_NEVER: This attribute must be set at object creation time and * can never be modified. * SFTK_ONCOPY: This attribute may be modified only when you copy the * object. * SFTK_SENSITIVE: The CKA_SENSITIVE attribute can only be changed from * CK_FALSE to CK_TRUE. * SFTK_ALWAYS: This attribute can always be modified. * Some attributes vary their modification type based on the class of the * object. */ SFTKModifyType sftk_modifyType(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass) { /* if we don't know about it, user user defined, always allow modify */ SFTKModifyType mtype = SFTK_ALWAYS; switch(type) { /* NEVER */ case CKA_CLASS: case CKA_CERTIFICATE_TYPE: case CKA_KEY_TYPE: case CKA_MODULUS: case CKA_MODULUS_BITS: case CKA_PUBLIC_EXPONENT: case CKA_PRIVATE_EXPONENT: case CKA_PRIME: case CKA_SUBPRIME: case CKA_BASE: case CKA_PRIME_1: case CKA_PRIME_2: case CKA_EXPONENT_1: case CKA_EXPONENT_2: case CKA_COEFFICIENT: case CKA_VALUE_LEN: case CKA_ALWAYS_SENSITIVE: case CKA_NEVER_EXTRACTABLE: case CKA_NETSCAPE_DB: mtype = SFTK_NEVER; break; /* ONCOPY */ case CKA_TOKEN: case CKA_PRIVATE: case CKA_MODIFIABLE: mtype = SFTK_ONCOPY; break; /* SENSITIVE */ case CKA_SENSITIVE: case CKA_EXTRACTABLE: mtype = SFTK_SENSITIVE; break; /* ALWAYS */ case CKA_LABEL: case CKA_APPLICATION: case CKA_ID: case CKA_SERIAL_NUMBER: case CKA_START_DATE: case CKA_END_DATE: case CKA_DERIVE: case CKA_ENCRYPT: case CKA_DECRYPT: case CKA_SIGN: case CKA_VERIFY: case CKA_SIGN_RECOVER: case CKA_VERIFY_RECOVER: case CKA_WRAP: case CKA_UNWRAP: mtype = SFTK_ALWAYS; break; /* DEPENDS ON CLASS */ case CKA_VALUE: mtype = (inClass == CKO_DATA) ? SFTK_ALWAYS : SFTK_NEVER; break; case CKA_SUBJECT: mtype = (inClass == CKO_CERTIFICATE) ? SFTK_NEVER : SFTK_ALWAYS; break; default: break; } return mtype; } /* decode if a particular attribute is sensitive (cannot be read * back to the user of if the object is set to SENSITIVE) */ PRBool sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass) { switch(type) { /* ALWAYS */ case CKA_PRIVATE_EXPONENT: case CKA_PRIME_1: case CKA_PRIME_2: case CKA_EXPONENT_1: case CKA_EXPONENT_2: case CKA_COEFFICIENT: return PR_TRUE; /* DEPENDS ON CLASS */ case CKA_VALUE: /* PRIVATE and SECRET KEYS have SENSITIVE values */ return (PRBool)((inClass == CKO_PRIVATE_KEY) || (inClass == CKO_SECRET_KEY)); default: break; } return PR_FALSE; } /* * copy an attribute into a SECItem. Secitem is allocated in the specified * arena. */ CK_RV sftk_Attribute2SecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object, CK_ATTRIBUTE_TYPE type) { int len; SFTKAttribute *attribute; attribute = sftk_FindAttribute(object, type); if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; len = attribute->attrib.ulValueLen; if (arena) { item->data = (unsigned char *) PORT_ArenaAlloc(arena,len); } else { item->data = (unsigned char *) PORT_Alloc(len); } if (item->data == NULL) { sftk_FreeAttribute(attribute); return CKR_HOST_MEMORY; } item->len = len; PORT_Memcpy(item->data,attribute->attrib.pValue, len); sftk_FreeAttribute(attribute); return CKR_OK; } CK_RV sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, CK_ULONG *longData) { SFTKAttribute *attribute; attribute = sftk_FindAttribute(object, type); if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; if (attribute->attrib.ulValueLen != sizeof(CK_ULONG)) { return CKR_ATTRIBUTE_VALUE_INVALID; } *longData = *(CK_ULONG *)attribute->attrib.pValue; sftk_FreeAttribute(attribute); return CKR_OK; } void sftk_DeleteAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type) { SFTKAttribute *attribute; attribute = sftk_FindAttribute(object, type); if (attribute == NULL) return ; sftk_DeleteAttribute(object,attribute); sftk_FreeAttribute(attribute); } CK_RV sftk_AddAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type, const void *valPtr, CK_ULONG length) { SFTKAttribute *attribute; attribute = sftk_NewAttribute(object,type,valPtr,length); if (attribute == NULL) { return CKR_HOST_MEMORY; } sftk_AddAttribute(object,attribute); return CKR_OK; } /* * ******************** Object Utilities ******************************* */ /* must be called holding sftk_tokenKeyLock(slot) */ static SECItem * sftk_lookupTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle) { return (SECItem *)PL_HashTableLookup(slot->tokObjHashTable, (void *)handle); } /* * use the refLock. This operations should be very rare, so the added * contention on the ref lock should be lower than the overhead of adding * a new lock. We use separate functions for this just in case I'm wrong. */ static void sftk_tokenKeyLock(SFTKSlot *slot) { SKIP_AFTER_FORK(PZ_Lock(slot->objectLock)); } static void sftk_tokenKeyUnlock(SFTKSlot *slot) { SKIP_AFTER_FORK(PZ_Unlock(slot->objectLock)); } static PRIntn sftk_freeHashItem(PLHashEntry* entry, PRIntn index, void *arg) { SECItem *item = (SECItem *)entry->value; SECITEM_FreeItem(item, PR_TRUE); return HT_ENUMERATE_NEXT; } CK_RV SFTK_ClearTokenKeyHashTable(SFTKSlot *slot) { sftk_tokenKeyLock(slot); PORT_Assert(!slot->present); PL_HashTableEnumerateEntries(slot->tokObjHashTable, sftk_freeHashItem, NULL); sftk_tokenKeyUnlock(slot); return CKR_OK; } /* allocation hooks that allow us to recycle old object structures */ static SFTKObjectFreeList sessionObjectList = { NULL, NULL, 0 }; static SFTKObjectFreeList tokenObjectList = { NULL, NULL, 0 }; SFTKObject * sftk_GetObjectFromList(PRBool *hasLocks, PRBool optimizeSpace, SFTKObjectFreeList *list, unsigned int hashSize, PRBool isSessionObject) { SFTKObject *object; int size = 0; if (!optimizeSpace) { PZ_Lock(list->lock); object = list->head; if (object) { list->head = object->next; list->count--; } PZ_Unlock(list->lock); if (object) { object->next = object->prev = NULL; *hasLocks = PR_TRUE; return object; } } size = isSessionObject ? sizeof(SFTKSessionObject) + hashSize *sizeof(SFTKAttribute *) : sizeof(SFTKTokenObject); object = (SFTKObject*)PORT_ZAlloc(size); if (isSessionObject && object) { ((SFTKSessionObject *)object)->hashSize = hashSize; } *hasLocks = PR_FALSE; return object; } static void sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list, PRBool isSessionObject) { /* the code below is equivalent to : * optimizeSpace = isSessionObject ? object->optimizeSpace : PR_FALSE; * just faster. */ PRBool optimizeSpace = isSessionObject && ((SFTKSessionObject *)object)->optimizeSpace; if (object->refLock && !optimizeSpace && (list->count < MAX_OBJECT_LIST_SIZE)) { PZ_Lock(list->lock); object->next = list->head; list->head = object; list->count++; PZ_Unlock(list->lock); return; } if (isSessionObject) { SFTKSessionObject *so = (SFTKSessionObject *)object; PZ_DestroyLock(so->attributeLock); so->attributeLock = NULL; } if (object->refLock) { PZ_DestroyLock(object->refLock); object->refLock = NULL; } PORT_Free(object); } static SFTKObject * sftk_freeObjectData(SFTKObject *object) { SFTKObject *next = object->next; PORT_Free(object); return next; } static void sftk_InitFreeList(SFTKObjectFreeList *list) { list->lock = PZ_NewLock(nssILockObject); } void sftk_InitFreeLists(void) { sftk_InitFreeList(&sessionObjectList); sftk_InitFreeList(&tokenObjectList); } static void sftk_CleanupFreeList(SFTKObjectFreeList *list, PRBool isSessionList) { SFTKObject *object; if (!list->lock) { return; } SKIP_AFTER_FORK(PZ_Lock(list->lock)); for (object= list->head; object != NULL; object = sftk_freeObjectData(object)) { PZ_DestroyLock(object->refLock); if (isSessionList) { PZ_DestroyLock(((SFTKSessionObject *)object)->attributeLock); } } list->count = 0; list->head = NULL; SKIP_AFTER_FORK(PZ_Unlock(list->lock)); SKIP_AFTER_FORK(PZ_DestroyLock(list->lock)); list->lock = NULL; } void sftk_CleanupFreeLists(void) { sftk_CleanupFreeList(&sessionObjectList, PR_TRUE); sftk_CleanupFreeList(&tokenObjectList, PR_FALSE); } /* * Create a new object */ SFTKObject * sftk_NewObject(SFTKSlot *slot) { SFTKObject *object; SFTKSessionObject *sessObject; PRBool hasLocks = PR_FALSE; unsigned int i; unsigned int hashSize = 0; hashSize = (slot->optimizeSpace) ? SPACE_ATTRIBUTE_HASH_SIZE : TIME_ATTRIBUTE_HASH_SIZE; object = sftk_GetObjectFromList(&hasLocks, slot->optimizeSpace, &sessionObjectList, hashSize, PR_TRUE); if (object == NULL) { return NULL; } sessObject = (SFTKSessionObject *)object; sessObject->nextAttr = 0; for (i=0; i < MAX_OBJS_ATTRS; i++) { sessObject->attrList[i].attrib.pValue = NULL; sessObject->attrList[i].freeData = PR_FALSE; } sessObject->optimizeSpace = slot->optimizeSpace; object->handle = 0; object->next = object->prev = NULL; object->slot = slot; object->refCount = 1; sessObject->sessionList.next = NULL; sessObject->sessionList.prev = NULL; sessObject->sessionList.parent = object; sessObject->session = NULL; sessObject->wasDerived = PR_FALSE; if (!hasLocks) object->refLock = PZ_NewLock(nssILockRefLock); if (object->refLock == NULL) { PORT_Free(object); return NULL; } if (!hasLocks) sessObject->attributeLock = PZ_NewLock(nssILockAttribute); if (sessObject->attributeLock == NULL) { PZ_DestroyLock(object->refLock); PORT_Free(object); return NULL; } for (i=0; i < sessObject->hashSize; i++) { sessObject->head[i] = NULL; } object->objectInfo = NULL; object->infoFree = NULL; return object; } static CK_RV sftk_DestroySessionObjectData(SFTKSessionObject *so) { int i; for (i=0; i < MAX_OBJS_ATTRS; i++) { unsigned char *value = so->attrList[i].attrib.pValue; if (value) { PORT_Memset(value,0,so->attrList[i].attrib.ulValueLen); if (so->attrList[i].freeData) { PORT_Free(value); } so->attrList[i].attrib.pValue = NULL; so->attrList[i].freeData = PR_FALSE; } } /* PZ_DestroyLock(so->attributeLock);*/ return CKR_OK; } /* * free all the data associated with an object. Object reference count must * be 'zero'. */ static CK_RV sftk_DestroyObject(SFTKObject *object) { CK_RV crv = CKR_OK; SFTKSessionObject *so = sftk_narrowToSessionObject(object); SFTKTokenObject *to = sftk_narrowToTokenObject(object); PORT_Assert(object->refCount == 0); /* delete the database value */ if (to) { if (to->dbKey.data) { PORT_Free(to->dbKey.data); to->dbKey.data = NULL; } } if (so) { sftk_DestroySessionObjectData(so); } if (object->objectInfo) { (*object->infoFree)(object->objectInfo); object->objectInfo = NULL; object->infoFree = NULL; } if (so) { sftk_PutObjectToList(object,&sessionObjectList,PR_TRUE); } else { sftk_PutObjectToList(object,&tokenObjectList,PR_FALSE); } return crv; } void sftk_ReferenceObject(SFTKObject *object) { PZ_Lock(object->refLock); object->refCount++; PZ_Unlock(object->refLock); } static SFTKObject * sftk_ObjectFromHandleOnSlot(CK_OBJECT_HANDLE handle, SFTKSlot *slot) { SFTKObject *object; PRUint32 index = sftk_hash(handle, slot->sessObjHashSize); if (sftk_isToken(handle)) { return sftk_NewTokenObject(slot, NULL, handle); } PZ_Lock(slot->objectLock); sftkqueue_find2(object, handle, index, slot->sessObjHashTable); if (object) { sftk_ReferenceObject(object); } PZ_Unlock(slot->objectLock); return(object); } /* * look up and object structure from a handle. OBJECT_Handles only make * sense in terms of a given session. make a reference to that object * structure returned. */ SFTKObject * sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle, SFTKSession *session) { SFTKSlot *slot = sftk_SlotFromSession(session); return sftk_ObjectFromHandleOnSlot(handle,slot); } /* * release a reference to an object handle */ SFTKFreeStatus sftk_FreeObject(SFTKObject *object) { PRBool destroy = PR_FALSE; CK_RV crv; PZ_Lock(object->refLock); if (object->refCount == 1) destroy = PR_TRUE; object->refCount--; PZ_Unlock(object->refLock); if (destroy) { crv = sftk_DestroyObject(object); if (crv != CKR_OK) { return SFTK_DestroyFailure; } return SFTK_Destroyed; } return SFTK_Busy; } /* * add an object to a slot and session queue. These two functions * adopt the object. */ void sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object) { PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize); sftkqueue_init_element(object); PZ_Lock(slot->objectLock); sftkqueue_add2(object, object->handle, index, slot->sessObjHashTable); PZ_Unlock(slot->objectLock); } void sftk_AddObject(SFTKSession *session, SFTKObject *object) { SFTKSlot *slot = sftk_SlotFromSession(session); SFTKSessionObject *so = sftk_narrowToSessionObject(object); if (so) { PZ_Lock(session->objectLock); sftkqueue_add(&so->sessionList,0,session->objects,0); so->session = session; PZ_Unlock(session->objectLock); } sftk_AddSlotObject(slot,object); sftk_ReferenceObject(object); } /* * delete an object from a slot and session queue */ CK_RV sftk_DeleteObject(SFTKSession *session, SFTKObject *object) { SFTKSlot *slot = sftk_SlotFromSession(session); SFTKSessionObject *so = sftk_narrowToSessionObject(object); SFTKTokenObject *to = sftk_narrowToTokenObject(object); CK_RV crv = CKR_OK; PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize); /* Handle Token case */ if (so && so->session) { SFTKSession *session = so->session; PZ_Lock(session->objectLock); sftkqueue_delete(&so->sessionList,0,session->objects,0); PZ_Unlock(session->objectLock); PZ_Lock(slot->objectLock); sftkqueue_delete2(object, object->handle, index, slot->sessObjHashTable); PZ_Unlock(slot->objectLock); sftkqueue_clear_deleted_element(object); sftk_FreeObject(object); /* free the reference owned by the queue */ } else { SFTKDBHandle *handle = sftk_getDBForTokenObject(slot, object->handle); PORT_Assert(to); crv = sftkdb_DestroyObject(handle, object->handle); sftk_freeDB(handle); } return crv; } /* * Token objects don't explicitly store their attributes, so we need to know * what attributes make up a particular token object before we can copy it. * below are the tables by object type. */ static const CK_ATTRIBUTE_TYPE commonAttrs[] = { CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_MODIFIABLE }; static const CK_ULONG commonAttrsCount = sizeof(commonAttrs)/sizeof(commonAttrs[0]); static const CK_ATTRIBUTE_TYPE commonKeyAttrs[] = { CKA_ID, CKA_START_DATE, CKA_END_DATE, CKA_DERIVE, CKA_LOCAL, CKA_KEY_TYPE }; static const CK_ULONG commonKeyAttrsCount = sizeof(commonKeyAttrs)/sizeof(commonKeyAttrs[0]); static const CK_ATTRIBUTE_TYPE secretKeyAttrs[] = { CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN, CKA_VERIFY, CKA_WRAP, CKA_UNWRAP, CKA_VALUE }; static const CK_ULONG secretKeyAttrsCount = sizeof(secretKeyAttrs)/sizeof(secretKeyAttrs[0]); static const CK_ATTRIBUTE_TYPE commonPubKeyAttrs[] = { CKA_ENCRYPT, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_WRAP, CKA_SUBJECT }; static const CK_ULONG commonPubKeyAttrsCount = sizeof(commonPubKeyAttrs)/sizeof(commonPubKeyAttrs[0]); static const CK_ATTRIBUTE_TYPE rsaPubKeyAttrs[] = { CKA_MODULUS, CKA_PUBLIC_EXPONENT }; static const CK_ULONG rsaPubKeyAttrsCount = sizeof(rsaPubKeyAttrs)/sizeof(rsaPubKeyAttrs[0]); static const CK_ATTRIBUTE_TYPE dsaPubKeyAttrs[] = { CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE }; static const CK_ULONG dsaPubKeyAttrsCount = sizeof(dsaPubKeyAttrs)/sizeof(dsaPubKeyAttrs[0]); static const CK_ATTRIBUTE_TYPE dhPubKeyAttrs[] = { CKA_PRIME, CKA_BASE, CKA_VALUE }; static const CK_ULONG dhPubKeyAttrsCount = sizeof(dhPubKeyAttrs)/sizeof(dhPubKeyAttrs[0]); #ifndef NSS_DISABLE_ECC static const CK_ATTRIBUTE_TYPE ecPubKeyAttrs[] = { CKA_EC_PARAMS, CKA_EC_POINT }; static const CK_ULONG ecPubKeyAttrsCount = sizeof(ecPubKeyAttrs)/sizeof(ecPubKeyAttrs[0]); #endif static const CK_ATTRIBUTE_TYPE commonPrivKeyAttrs[] = { CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_SUBJECT, CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NETSCAPE_DB }; static const CK_ULONG commonPrivKeyAttrsCount = sizeof(commonPrivKeyAttrs)/sizeof(commonPrivKeyAttrs[0]); static const CK_ATTRIBUTE_TYPE rsaPrivKeyAttrs[] = { CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT }; static const CK_ULONG rsaPrivKeyAttrsCount = sizeof(rsaPrivKeyAttrs)/sizeof(rsaPrivKeyAttrs[0]); static const CK_ATTRIBUTE_TYPE dsaPrivKeyAttrs[] = { CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE }; static const CK_ULONG dsaPrivKeyAttrsCount = sizeof(dsaPrivKeyAttrs)/sizeof(dsaPrivKeyAttrs[0]); static const CK_ATTRIBUTE_TYPE dhPrivKeyAttrs[] = { CKA_PRIME, CKA_BASE, CKA_VALUE }; static const CK_ULONG dhPrivKeyAttrsCount = sizeof(dhPrivKeyAttrs)/sizeof(dhPrivKeyAttrs[0]); #ifndef NSS_DISABLE_ECC static const CK_ATTRIBUTE_TYPE ecPrivKeyAttrs[] = { CKA_EC_PARAMS, CKA_VALUE }; static const CK_ULONG ecPrivKeyAttrsCount = sizeof(ecPrivKeyAttrs)/sizeof(ecPrivKeyAttrs[0]); #endif static const CK_ATTRIBUTE_TYPE certAttrs[] = { CKA_CERTIFICATE_TYPE, CKA_VALUE, CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER }; static const CK_ULONG certAttrsCount = sizeof(certAttrs)/sizeof(certAttrs[0]); static const CK_ATTRIBUTE_TYPE trustAttrs[] = { CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH, CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_CODE_SIGNING, CKA_TRUST_STEP_UP_APPROVED }; static const CK_ULONG trustAttrsCount = sizeof(trustAttrs)/sizeof(trustAttrs[0]); static const CK_ATTRIBUTE_TYPE smimeAttrs[] = { CKA_SUBJECT, CKA_NETSCAPE_EMAIL, CKA_NETSCAPE_SMIME_TIMESTAMP, CKA_VALUE }; static const CK_ULONG smimeAttrsCount = sizeof(smimeAttrs)/sizeof(smimeAttrs[0]); static const CK_ATTRIBUTE_TYPE crlAttrs[] = { CKA_SUBJECT, CKA_VALUE, CKA_NETSCAPE_URL, CKA_NETSCAPE_KRL }; static const CK_ULONG crlAttrsCount = sizeof(crlAttrs)/sizeof(crlAttrs[0]); /* copy an object based on it's table */ CK_RV stfk_CopyTokenAttributes(SFTKObject *destObject,SFTKTokenObject *src_to, const CK_ATTRIBUTE_TYPE *attrArray, CK_ULONG attrCount) { SFTKAttribute *attribute; SFTKAttribute *newAttribute; CK_RV crv = CKR_OK; unsigned int i; for (i=0; i < attrCount; i++) { if (!sftk_hasAttribute(destObject,attrArray[i])) { attribute =sftk_FindAttribute(&src_to->obj, attrArray[i]); if (!attribute) { continue; /* return CKR_ATTRIBUTE_VALUE_INVALID; */ } /* we need to copy the attribute since each attribute * only has one set of link list pointers */ newAttribute = sftk_NewAttribute( destObject, sftk_attr_expand(&attribute->attrib)); sftk_FreeAttribute(attribute); /* free the old attribute */ if (!newAttribute) { return CKR_HOST_MEMORY; } sftk_AddAttribute(destObject,newAttribute); } } return crv; } CK_RV stfk_CopyTokenPrivateKey(SFTKObject *destObject,SFTKTokenObject *src_to) { CK_RV crv; CK_KEY_TYPE key_type; SFTKAttribute *attribute; /* copy the common attributes for all keys first */ crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs, commonKeyAttrsCount); if (crv != CKR_OK) { goto fail; } /* copy the common attributes for all private keys next */ crv = stfk_CopyTokenAttributes(destObject, src_to, commonPrivKeyAttrs, commonPrivKeyAttrsCount); if (crv != CKR_OK) { goto fail; } attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE); PORT_Assert(attribute); /* if it wasn't here, ww should have failed * copying the common attributes */ if (!attribute) { /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but * the fact is, the only reason we couldn't get the attribute would * be a memory error or database error (an error in the 'device'). * if we have a database error code, we could return it here */ crv = CKR_DEVICE_ERROR; goto fail; } key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue; sftk_FreeAttribute(attribute); /* finally copy the attributes for various private key types */ switch (key_type) { case CKK_RSA: crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPrivKeyAttrs, rsaPrivKeyAttrsCount); break; case CKK_DSA: crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPrivKeyAttrs, dsaPrivKeyAttrsCount); break; case CKK_DH: crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs, dhPrivKeyAttrsCount); break; #ifndef NSS_DISABLE_ECC case CKK_EC: crv = stfk_CopyTokenAttributes(destObject, src_to, ecPrivKeyAttrs, ecPrivKeyAttrsCount); break; #endif default: crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types * of token keys into our database. */ } fail: return crv; } CK_RV stfk_CopyTokenPublicKey(SFTKObject *destObject,SFTKTokenObject *src_to) { CK_RV crv; CK_KEY_TYPE key_type; SFTKAttribute *attribute; /* copy the common attributes for all keys first */ crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs, commonKeyAttrsCount); if (crv != CKR_OK) { goto fail; } /* copy the common attributes for all public keys next */ crv = stfk_CopyTokenAttributes(destObject, src_to, commonPubKeyAttrs, commonPubKeyAttrsCount); if (crv != CKR_OK) { goto fail; } attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE); PORT_Assert(attribute); /* if it wasn't here, ww should have failed * copying the common attributes */ if (!attribute) { /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but * the fact is, the only reason we couldn't get the attribute would * be a memory error or database error (an error in the 'device'). * if we have a database error code, we could return it here */ crv = CKR_DEVICE_ERROR; goto fail; } key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue; sftk_FreeAttribute(attribute); /* finally copy the attributes for various public key types */ switch (key_type) { case CKK_RSA: crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPubKeyAttrs, rsaPubKeyAttrsCount); break; case CKK_DSA: crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPubKeyAttrs, dsaPubKeyAttrsCount); break; case CKK_DH: crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs, dhPubKeyAttrsCount); break; #ifndef NSS_DISABLE_ECC case CKK_EC: crv = stfk_CopyTokenAttributes(destObject, src_to, ecPubKeyAttrs, ecPubKeyAttrsCount); break; #endif default: crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types * of token keys into our database. */ } fail: return crv; } CK_RV stfk_CopyTokenSecretKey(SFTKObject *destObject,SFTKTokenObject *src_to) { CK_RV crv; crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs, commonKeyAttrsCount); if (crv != CKR_OK) { goto fail; } crv = stfk_CopyTokenAttributes(destObject, src_to, secretKeyAttrs, secretKeyAttrsCount); fail: return crv; } /* * Copy a token object. We need to explicitly copy the relevant * attributes since token objects don't store those attributes in * the token itself. */ CK_RV sftk_CopyTokenObject(SFTKObject *destObject,SFTKObject *srcObject) { SFTKTokenObject *src_to = sftk_narrowToTokenObject(srcObject); CK_RV crv; PORT_Assert(src_to); if (src_to == NULL) { return CKR_DEVICE_ERROR; /* internal state inconsistant */ } crv = stfk_CopyTokenAttributes(destObject, src_to, commonAttrs, commonAttrsCount); if (crv != CKR_OK) { goto fail; } switch (src_to->obj.objclass) { case CKO_CERTIFICATE: crv = stfk_CopyTokenAttributes(destObject, src_to, certAttrs, certAttrsCount); break; case CKO_NETSCAPE_TRUST: crv = stfk_CopyTokenAttributes(destObject, src_to, trustAttrs, trustAttrsCount); break; case CKO_NETSCAPE_SMIME: crv = stfk_CopyTokenAttributes(destObject, src_to, smimeAttrs, smimeAttrsCount); break; case CKO_NETSCAPE_CRL: crv = stfk_CopyTokenAttributes(destObject, src_to, crlAttrs, crlAttrsCount); break; case CKO_PRIVATE_KEY: crv = stfk_CopyTokenPrivateKey(destObject,src_to); break; case CKO_PUBLIC_KEY: crv = stfk_CopyTokenPublicKey(destObject,src_to); break; case CKO_SECRET_KEY: crv = stfk_CopyTokenSecretKey(destObject,src_to); break; default: crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types * of token keys into our database. */ } fail: return crv; } /* * copy the attributes from one object to another. Don't overwrite existing * attributes. NOTE: This is a pretty expensive operation since it * grabs the attribute locks for the src object for a *long* time. */ CK_RV sftk_CopyObject(SFTKObject *destObject,SFTKObject *srcObject) { SFTKAttribute *attribute; SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject); unsigned int i; if (src_so == NULL) { return sftk_CopyTokenObject(destObject,srcObject); } PZ_Lock(src_so->attributeLock); for(i=0; i < src_so->hashSize; i++) { attribute = src_so->head[i]; do { if (attribute) { if (!sftk_hasAttribute(destObject,attribute->handle)) { /* we need to copy the attribute since each attribute * only has one set of link list pointers */ SFTKAttribute *newAttribute = sftk_NewAttribute( destObject,sftk_attr_expand(&attribute->attrib)); if (newAttribute == NULL) { PZ_Unlock(src_so->attributeLock); return CKR_HOST_MEMORY; } sftk_AddAttribute(destObject,newAttribute); } attribute=attribute->next; } } while (attribute != NULL); } PZ_Unlock(src_so->attributeLock); return CKR_OK; } /* * ******************** Search Utilities ******************************* */ /* add an object to a search list */ CK_RV AddToList(SFTKObjectListElement **list,SFTKObject *object) { SFTKObjectListElement *newElem = (SFTKObjectListElement *)PORT_Alloc(sizeof(SFTKObjectListElement)); if (newElem == NULL) return CKR_HOST_MEMORY; newElem->next = *list; newElem->object = object; sftk_ReferenceObject(object); *list = newElem; return CKR_OK; } /* return true if the object matches the template */ PRBool sftk_objectMatch(SFTKObject *object,CK_ATTRIBUTE_PTR theTemplate,int count) { int i; for (i=0; i < count; i++) { SFTKAttribute *attribute = sftk_FindAttribute(object,theTemplate[i].type); if (attribute == NULL) { return PR_FALSE; } if (attribute->attrib.ulValueLen == theTemplate[i].ulValueLen) { if (PORT_Memcmp(attribute->attrib.pValue,theTemplate[i].pValue, theTemplate[i].ulValueLen) == 0) { sftk_FreeAttribute(attribute); continue; } } sftk_FreeAttribute(attribute); return PR_FALSE; } return PR_TRUE; } /* search through all the objects in the queue and return the template matches * in the object list. */ CK_RV sftk_searchObjectList(SFTKSearchResults *search,SFTKObject **head, unsigned int size, PZLock *lock, CK_ATTRIBUTE_PTR theTemplate, int count, PRBool isLoggedIn) { unsigned int i; SFTKObject *object; CK_RV crv = CKR_OK; for(i=0; i < size; i++) { /* We need to hold the lock to copy a consistant version of * the linked list. */ PZ_Lock(lock); for (object = head[i]; object != NULL; object= object->next) { if (sftk_objectMatch(object,theTemplate,count)) { /* don't return objects that aren't yet visible */ if ((!isLoggedIn) && sftk_isTrue(object,CKA_PRIVATE)) continue; sftk_addHandle(search,object->handle); } } PZ_Unlock(lock); } return crv; } /* * free a single list element. Return the Next object in the list. */ SFTKObjectListElement * sftk_FreeObjectListElement(SFTKObjectListElement *objectList) { SFTKObjectListElement *ol = objectList->next; sftk_FreeObject(objectList->object); PORT_Free(objectList); return ol; } /* free an entire object list */ void sftk_FreeObjectList(SFTKObjectListElement *objectList) { SFTKObjectListElement *ol; for (ol= objectList; ol != NULL; ol = sftk_FreeObjectListElement(ol)) {} } /* * free a search structure */ void sftk_FreeSearch(SFTKSearchResults *search) { if (search->handles) { PORT_Free(search->handles); } PORT_Free(search); } /* * ******************** Session Utilities ******************************* */ /* update the sessions state based in it's flags and wether or not it's * logged in */ void sftk_update_state(SFTKSlot *slot,SFTKSession *session) { if (slot->isLoggedIn) { if (slot->ssoLoggedIn) { session->info.state = CKS_RW_SO_FUNCTIONS; } else if (session->info.flags & CKF_RW_SESSION) { session->info.state = CKS_RW_USER_FUNCTIONS; } else { session->info.state = CKS_RO_USER_FUNCTIONS; } } else { if (session->info.flags & CKF_RW_SESSION) { session->info.state = CKS_RW_PUBLIC_SESSION; } else { session->info.state = CKS_RO_PUBLIC_SESSION; } } } /* update the state of all the sessions on a slot */ void sftk_update_all_states(SFTKSlot *slot) { unsigned int i; SFTKSession *session; for (i=0; i < slot->sessHashSize; i++) { PZLock *lock = SFTK_SESSION_LOCK(slot,i); PZ_Lock(lock); for (session = slot->head[i]; session; session = session->next) { sftk_update_state(slot,session); } PZ_Unlock(lock); } } /* * context are cipher and digest contexts that are associated with a session */ void sftk_FreeContext(SFTKSessionContext *context) { if (context->cipherInfo) { (*context->destroy)(context->cipherInfo,PR_TRUE); } if (context->hashInfo) { (*context->hashdestroy)(context->hashInfo,PR_TRUE); } if (context->key) { sftk_FreeObject(context->key); context->key = NULL; } PORT_Free(context); } /* * create a new nession. NOTE: The session handle is not set, and the * session is not added to the slot's session queue. */ SFTKSession * sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication, CK_FLAGS flags) { SFTKSession *session; SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE); if (slot == NULL) return NULL; session = (SFTKSession*)PORT_Alloc(sizeof(SFTKSession)); if (session == NULL) return NULL; session->next = session->prev = NULL; session->refCount = 1; session->enc_context = NULL; session->hash_context = NULL; session->sign_context = NULL; session->search = NULL; session->objectIDCount = 1; session->objectLock = PZ_NewLock(nssILockObject); if (session->objectLock == NULL) { PORT_Free(session); return NULL; } session->objects[0] = NULL; session->slot = slot; session->notify = notify; session->appData = pApplication; session->info.flags = flags; session->info.slotID = slotID; session->info.ulDeviceError = 0; sftk_update_state(slot,session); return session; } /* free all the data associated with a session. */ static void sftk_DestroySession(SFTKSession *session) { SFTKObjectList *op,*next; PORT_Assert(session->refCount == 0); /* clean out the attributes */ /* since no one is referencing us, it's safe to walk the chain * without a lock */ for (op = session->objects[0]; op != NULL; op = next) { next = op->next; /* paranoia */ op->next = op->prev = NULL; sftk_DeleteObject(session,op->parent); } PZ_DestroyLock(session->objectLock); if (session->enc_context) { sftk_FreeContext(session->enc_context); } if (session->hash_context) { sftk_FreeContext(session->hash_context); } if (session->sign_context) { sftk_FreeContext(session->sign_context); } if (session->search) { sftk_FreeSearch(session->search); } PORT_Free(session); } /* * look up a session structure from a session handle * generate a reference to it. */ SFTKSession * sftk_SessionFromHandle(CK_SESSION_HANDLE handle) { SFTKSlot *slot = sftk_SlotFromSessionHandle(handle); SFTKSession *session; PZLock *lock; if (!slot) return NULL; lock = SFTK_SESSION_LOCK(slot,handle); PZ_Lock(lock); sftkqueue_find(session,handle,slot->head,slot->sessHashSize); if (session) session->refCount++; PZ_Unlock(lock); return (session); } /* * release a reference to a session handle */ void sftk_FreeSession(SFTKSession *session) { PRBool destroy = PR_FALSE; SFTKSlot *slot = sftk_SlotFromSession(session); PZLock *lock = SFTK_SESSION_LOCK(slot,session->handle); PZ_Lock(lock); if (session->refCount == 1) destroy = PR_TRUE; session->refCount--; PZ_Unlock(lock); if (destroy) sftk_DestroySession(session); } void sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle) { if (search->handles == NULL) { return; } if (search->size >= search->array_size) { search->array_size += NSC_SEARCH_BLOCK_SIZE; search->handles = (CK_OBJECT_HANDLE *) PORT_Realloc(search->handles, sizeof(CK_OBJECT_HANDLE)* search->array_size); if (search->handles == NULL) { return; } } search->handles[search->size] = handle; search->size++; } static CK_RV handleToClass(SFTKSlot *slot, CK_OBJECT_HANDLE handle, CK_OBJECT_CLASS *objClass) { SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, handle); CK_ATTRIBUTE objClassTemplate; CK_RV crv; *objClass = CKO_DATA; objClassTemplate.type = CKA_CLASS; objClassTemplate.pValue = objClass; objClassTemplate.ulValueLen = sizeof(*objClass); crv = sftkdb_GetAttributeValue(dbHandle, handle, &objClassTemplate, 1); sftk_freeDB(dbHandle); return crv; } SFTKObject * sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle) { SFTKObject *object = NULL; SFTKTokenObject *tokObject = NULL; PRBool hasLocks = PR_FALSE; CK_RV crv; object = sftk_GetObjectFromList(&hasLocks, PR_FALSE, &tokenObjectList, 0, PR_FALSE); if (object == NULL) { return NULL; } tokObject = (SFTKTokenObject *) object; object->handle = handle; /* every object must have a class, if we can't get it, the object * doesn't exist */ crv = handleToClass(slot, handle, &object->objclass); if (crv != CKR_OK) { goto loser; } object->slot = slot; object->objectInfo = NULL; object->infoFree = NULL; if (!hasLocks) { object->refLock = PZ_NewLock(nssILockRefLock); } if (object->refLock == NULL) { goto loser; } object->refCount = 1; return object; loser: if (object) { (void) sftk_DestroyObject(object); } return NULL; } SFTKTokenObject * sftk_convertSessionToToken(SFTKObject *obj) { SECItem *key; SFTKSessionObject *so = (SFTKSessionObject *)obj; SFTKTokenObject *to = sftk_narrowToTokenObject(obj); SECStatus rv; sftk_DestroySessionObjectData(so); PZ_DestroyLock(so->attributeLock); if (to == NULL) { return NULL; } sftk_tokenKeyLock(so->obj.slot); key = sftk_lookupTokenKeyByHandle(so->obj.slot,so->obj.handle); if (key == NULL) { sftk_tokenKeyUnlock(so->obj.slot); return NULL; } rv = SECITEM_CopyItem(NULL,&to->dbKey,key); sftk_tokenKeyUnlock(so->obj.slot); if (rv == SECFailure) { return NULL; } return to; } SFTKSessionObject * sftk_narrowToSessionObject(SFTKObject *obj) { return !sftk_isToken(obj->handle) ? (SFTKSessionObject *)obj : NULL; } SFTKTokenObject * sftk_narrowToTokenObject(SFTKObject *obj) { return sftk_isToken(obj->handle) ? (SFTKTokenObject *)obj : NULL; }