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