diff nss/lib/softoken/pkcs11u.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nss/lib/softoken/pkcs11u.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,1979 @@
+/* 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;
+}
+
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)