security/nss/lib/softoken/pkcs11u.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/softoken/pkcs11u.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1979 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +/*
     1.8 + * Internal PKCS #11 functions. Should only be called by pkcs11.c
     1.9 + */
    1.10 +#include "pkcs11.h"
    1.11 +#include "pkcs11i.h"
    1.12 +#include "lowkeyi.h"
    1.13 +#include "secasn1.h"
    1.14 +#include "blapi.h"
    1.15 +#include "secerr.h"
    1.16 +#include "prnetdb.h" /* for PR_ntohl */
    1.17 +#include "sftkdb.h"
    1.18 +#include "softoken.h"
    1.19 +
    1.20 +/*
    1.21 + * ******************** Attribute Utilities *******************************
    1.22 + */
    1.23 +
    1.24 +/*
    1.25 + * create a new attribute with type, value, and length. Space is allocated
    1.26 + * to hold value.
    1.27 + */
    1.28 +static SFTKAttribute *
    1.29 +sftk_NewAttribute(SFTKObject *object,
    1.30 +	CK_ATTRIBUTE_TYPE type, const void *value, CK_ULONG len)
    1.31 +{
    1.32 +    SFTKAttribute *attribute;
    1.33 +
    1.34 +    SFTKSessionObject *so = sftk_narrowToSessionObject(object);
    1.35 +    int index;
    1.36 +
    1.37 +    if (so == NULL)  {
    1.38 +	/* allocate new attribute in a buffer */
    1.39 +	PORT_Assert(0);
    1.40 +	return NULL;
    1.41 +    }
    1.42 +    /* 
    1.43 +     * We attempt to keep down contention on Malloc and Arena locks by
    1.44 +     * limiting the number of these calls on high traversed paths. This
    1.45 +     * is done for attributes by 'allocating' them from a pool already
    1.46 +     * allocated by the parent object.
    1.47 +     */
    1.48 +    PZ_Lock(so->attributeLock);
    1.49 +    index = so->nextAttr++;
    1.50 +    PZ_Unlock(so->attributeLock);
    1.51 +    PORT_Assert(index < MAX_OBJS_ATTRS);
    1.52 +    if (index >= MAX_OBJS_ATTRS) return NULL;
    1.53 +
    1.54 +    attribute = &so->attrList[index];
    1.55 +    attribute->attrib.type = type;
    1.56 +    attribute->freeAttr = PR_FALSE;
    1.57 +    attribute->freeData = PR_FALSE;
    1.58 +    if (value) {
    1.59 +        if (len <= ATTR_SPACE) {
    1.60 +	    attribute->attrib.pValue = attribute->space;
    1.61 +	} else {
    1.62 +	    attribute->attrib.pValue = PORT_Alloc(len);
    1.63 +    	    attribute->freeData = PR_TRUE;
    1.64 +	}
    1.65 +	if (attribute->attrib.pValue == NULL) {
    1.66 +	    return NULL;
    1.67 +	}
    1.68 +	PORT_Memcpy(attribute->attrib.pValue,value,len);
    1.69 +	attribute->attrib.ulValueLen = len;
    1.70 +    } else {
    1.71 +	attribute->attrib.pValue = NULL;
    1.72 +	attribute->attrib.ulValueLen = 0;
    1.73 +    }
    1.74 +    attribute->attrib.type = type;
    1.75 +    attribute->handle = type;
    1.76 +    attribute->next = attribute->prev = NULL;
    1.77 +    return attribute;
    1.78 +}
    1.79 +
    1.80 +/*
    1.81 + * Free up all the memory associated with an attribute. Reference count
    1.82 + * must be zero to call this.
    1.83 + */
    1.84 +static void
    1.85 +sftk_DestroyAttribute(SFTKAttribute *attribute)
    1.86 +{
    1.87 +    if (attribute->freeData) {
    1.88 +	if (attribute->attrib.pValue) {
    1.89 +	    /* clear out the data in the attribute value... it may have been
    1.90 +	     * sensitive data */
    1.91 +	    PORT_Memset(attribute->attrib.pValue, 0,
    1.92 +						attribute->attrib.ulValueLen);
    1.93 +	}
    1.94 +	PORT_Free(attribute->attrib.pValue);
    1.95 +    }
    1.96 +    PORT_Free(attribute);
    1.97 +}
    1.98 +
    1.99 +/*
   1.100 + * release a reference to an attribute structure
   1.101 + */
   1.102 +void
   1.103 +sftk_FreeAttribute(SFTKAttribute *attribute)
   1.104 +{
   1.105 +    if (attribute->freeAttr) {
   1.106 +	sftk_DestroyAttribute(attribute);
   1.107 +	return;
   1.108 +    }
   1.109 +}
   1.110 +
   1.111 +static SFTKAttribute *    
   1.112 +sftk_FindTokenAttribute(SFTKTokenObject *object,CK_ATTRIBUTE_TYPE type)
   1.113 +{
   1.114 +    SFTKAttribute *myattribute = NULL;
   1.115 +    SFTKDBHandle *dbHandle = NULL;
   1.116 +    CK_RV crv = CKR_HOST_MEMORY;
   1.117 +
   1.118 +    myattribute = (SFTKAttribute*)PORT_Alloc(sizeof(SFTKAttribute));
   1.119 +    if (myattribute == NULL) {
   1.120 +	goto loser;
   1.121 +    }
   1.122 +
   1.123 +    dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle);
   1.124 +
   1.125 +    myattribute->handle = type;
   1.126 +    myattribute->attrib.type = type;
   1.127 +    myattribute->attrib.pValue = myattribute->space;
   1.128 +    myattribute->attrib.ulValueLen = ATTR_SPACE;
   1.129 +    myattribute->next = myattribute->prev = NULL;
   1.130 +    myattribute->freeAttr = PR_TRUE;
   1.131 +    myattribute->freeData = PR_FALSE;
   1.132 +
   1.133 +    crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
   1.134 +		&myattribute->attrib, 1);
   1.135 +
   1.136 +    /* attribute is bigger than our attribute space buffer, malloc it */
   1.137 +    if (crv == CKR_BUFFER_TOO_SMALL) {
   1.138 +    	myattribute->attrib.pValue = NULL;
   1.139 +    	crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
   1.140 +		&myattribute->attrib, 1);
   1.141 +	if (crv != CKR_OK) {
   1.142 +	    goto loser;
   1.143 +	}
   1.144 +	myattribute->attrib.pValue = PORT_Alloc(myattribute->attrib.ulValueLen);
   1.145 +	if (myattribute->attrib.pValue == NULL) {
   1.146 +	    crv = CKR_HOST_MEMORY;
   1.147 +	    goto loser;
   1.148 +	}
   1.149 +	myattribute->freeData = PR_TRUE;
   1.150 +    	crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
   1.151 +		 &myattribute->attrib, 1);
   1.152 +    } 
   1.153 +loser:
   1.154 +    if (dbHandle) {
   1.155 +	sftk_freeDB(dbHandle);
   1.156 +    }
   1.157 +    if (crv != CKR_OK) {
   1.158 +	if (myattribute) {
   1.159 +	    myattribute->attrib.ulValueLen = 0;
   1.160 +	    sftk_FreeAttribute(myattribute);
   1.161 +	    myattribute = NULL;
   1.162 +	}
   1.163 +    }
   1.164 +    return myattribute;
   1.165 +} 
   1.166 +
   1.167 +/*
   1.168 + * look up and attribute structure from a type and Object structure.
   1.169 + * The returned attribute is referenced and needs to be freed when 
   1.170 + * it is no longer needed.
   1.171 + */
   1.172 +SFTKAttribute *
   1.173 +sftk_FindAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
   1.174 +{
   1.175 +    SFTKAttribute *attribute;
   1.176 +    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
   1.177 +
   1.178 +    if (sessObject == NULL) {
   1.179 +	return sftk_FindTokenAttribute(sftk_narrowToTokenObject(object),type);
   1.180 +    }
   1.181 +
   1.182 +    PZ_Lock(sessObject->attributeLock);
   1.183 +    sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize);
   1.184 +    PZ_Unlock(sessObject->attributeLock);
   1.185 +
   1.186 +    return(attribute);
   1.187 +}
   1.188 +
   1.189 +/*
   1.190 + * Take a buffer and it's length and return it's true size in bits;
   1.191 + */
   1.192 +unsigned int
   1.193 +sftk_GetLengthInBits(unsigned char *buf, unsigned int bufLen)
   1.194 +{
   1.195 +    unsigned int size = bufLen * 8;
   1.196 +    unsigned int i;
   1.197 +
   1.198 +    /* Get the real length in bytes */
   1.199 +    for (i=0; i < bufLen; i++) {
   1.200 +	unsigned char  c = *buf++;
   1.201 +	if (c != 0) {
   1.202 +	    unsigned char m;
   1.203 +	    for (m=0x80; m > 0 ;  m = m >> 1) {
   1.204 +		if ((c & m) != 0) {
   1.205 +		    break;
   1.206 +		} 
   1.207 +		size--;
   1.208 +	    }
   1.209 +	    break;
   1.210 +	}
   1.211 +	size-=8;
   1.212 +    }
   1.213 +    return size;
   1.214 +}
   1.215 +
   1.216 +/*
   1.217 + * Constrain a big num attribute. to size and padding
   1.218 + * minLength means length of the object must be greater than equal to minLength
   1.219 + * maxLength means length of the object must be less than equal to maxLength
   1.220 + * minMultiple means that object length mod minMultiple must equal 0.
   1.221 + * all input sizes are in bits.
   1.222 + * if any constraint is '0' that constraint is not checked.
   1.223 + */
   1.224 +CK_RV
   1.225 +sftk_ConstrainAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, 
   1.226 +			int minLength, int maxLength, int minMultiple)
   1.227 +{
   1.228 +    SFTKAttribute *attribute;
   1.229 +    int size;
   1.230 +    unsigned char *ptr;
   1.231 +
   1.232 +    attribute = sftk_FindAttribute(object, type);
   1.233 +    if (!attribute) {
   1.234 +	return CKR_TEMPLATE_INCOMPLETE;
   1.235 +    }
   1.236 +    ptr = (unsigned char *) attribute->attrib.pValue;
   1.237 +    if (ptr == NULL) {
   1.238 +	sftk_FreeAttribute(attribute);
   1.239 +	return CKR_ATTRIBUTE_VALUE_INVALID;
   1.240 +    }
   1.241 +    size = sftk_GetLengthInBits(ptr, attribute->attrib.ulValueLen);
   1.242 +    sftk_FreeAttribute(attribute);
   1.243 +
   1.244 +    if ((minLength != 0) && (size <  minLength)) {
   1.245 +	return CKR_ATTRIBUTE_VALUE_INVALID;
   1.246 +    }
   1.247 +    if ((maxLength != 0) && (size >  maxLength)) {
   1.248 +	return CKR_ATTRIBUTE_VALUE_INVALID;
   1.249 +    }
   1.250 +    if ((minMultiple != 0) && ((size % minMultiple) != 0)) {
   1.251 +	return CKR_ATTRIBUTE_VALUE_INVALID;
   1.252 +    }
   1.253 +    return CKR_OK;
   1.254 +}
   1.255 +
   1.256 +PRBool
   1.257 +sftk_hasAttributeToken(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
   1.258 +{
   1.259 +    CK_ATTRIBUTE template;
   1.260 +    CK_RV crv;
   1.261 +    SFTKDBHandle *dbHandle;
   1.262 +
   1.263 +    dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle);
   1.264 +    template.type = type;
   1.265 +    template.pValue = NULL;
   1.266 +    template.ulValueLen = 0;
   1.267 +
   1.268 +    crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, &template, 1);
   1.269 +    sftk_freeDB(dbHandle);
   1.270 +
   1.271 +    /* attribute is bigger than our attribute space buffer, malloc it */
   1.272 +    return (crv == CKR_OK) ? PR_TRUE : PR_FALSE;
   1.273 +}
   1.274 +
   1.275 +/*
   1.276 + * return true if object has attribute
   1.277 + */
   1.278 +PRBool
   1.279 +sftk_hasAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
   1.280 +{
   1.281 +    SFTKAttribute *attribute;
   1.282 +    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
   1.283 +
   1.284 +    if (sessObject == NULL) {
   1.285 +	return sftk_hasAttributeToken(sftk_narrowToTokenObject(object), type);
   1.286 +    }
   1.287 +
   1.288 +    PZ_Lock(sessObject->attributeLock);
   1.289 +    sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize);
   1.290 +    PZ_Unlock(sessObject->attributeLock);
   1.291 +
   1.292 +    return (PRBool)(attribute != NULL);
   1.293 +}
   1.294 +
   1.295 +/*
   1.296 + * add an attribute to an object
   1.297 + */
   1.298 +static void
   1.299 +sftk_AddAttribute(SFTKObject *object,SFTKAttribute *attribute)
   1.300 +{
   1.301 +    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
   1.302 +
   1.303 +    if (sessObject == NULL) return;
   1.304 +    PZ_Lock(sessObject->attributeLock);
   1.305 +    sftkqueue_add(attribute,attribute->handle,
   1.306 +				sessObject->head, sessObject->hashSize);
   1.307 +    PZ_Unlock(sessObject->attributeLock);
   1.308 +}
   1.309 +
   1.310 +/* 
   1.311 + * copy an unsigned attribute into a SECItem. Secitem is allocated in
   1.312 + * the specified arena.
   1.313 + */
   1.314 +CK_RV
   1.315 +sftk_Attribute2SSecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object,
   1.316 +                                      CK_ATTRIBUTE_TYPE type)
   1.317 +{
   1.318 +    SFTKAttribute *attribute;
   1.319 +
   1.320 +    item->data = NULL;
   1.321 +
   1.322 +    attribute = sftk_FindAttribute(object, type);
   1.323 +    if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
   1.324 +
   1.325 +    (void)SECITEM_AllocItem(arena, item, attribute->attrib.ulValueLen);
   1.326 +    if (item->data == NULL) {
   1.327 +	sftk_FreeAttribute(attribute);
   1.328 +	return CKR_HOST_MEMORY;
   1.329 +    }
   1.330 +    PORT_Memcpy(item->data, attribute->attrib.pValue, item->len);
   1.331 +    sftk_FreeAttribute(attribute);
   1.332 +    return CKR_OK;
   1.333 +}
   1.334 +
   1.335 +/* 
   1.336 + * fetch multiple attributes into  SECItems. Secitem data is allocated in
   1.337 + * the specified arena.
   1.338 + */
   1.339 +CK_RV
   1.340 +sftk_MultipleAttribute2SecItem(PLArenaPool *arena, SFTKObject *object,
   1.341 +	 SFTKItemTemplate *itemTemplate, int itemTemplateCount)
   1.342 +{
   1.343 +
   1.344 +    CK_RV crv = CKR_OK;
   1.345 +    CK_ATTRIBUTE templateSpace[SFTK_MAX_ITEM_TEMPLATE];
   1.346 +    CK_ATTRIBUTE *template;
   1.347 +    SFTKTokenObject *tokObject;
   1.348 +    SFTKDBHandle *dbHandle = NULL;
   1.349 +    int i;
   1.350 +
   1.351 +    tokObject = sftk_narrowToTokenObject(object);
   1.352 +
   1.353 +    /* session objects, just loop through the list */
   1.354 +    if (tokObject == NULL) {
   1.355 +	for (i=0; i < itemTemplateCount; i++) {
   1.356 +	    crv = sftk_Attribute2SecItem(arena,itemTemplate[i].item, object,
   1.357 +					 itemTemplate[i].type);
   1.358 +	    if (crv != CKR_OK) {
   1.359 +		return crv;
   1.360 +	    }
   1.361 +	}
   1.362 +	return CKR_OK;
   1.363 +    }
   1.364 +
   1.365 +    /* don't do any work if none is required */
   1.366 +    if (itemTemplateCount == 0) {
   1.367 +	return CKR_OK;
   1.368 +    }
   1.369 +
   1.370 +    /* don't allocate the template unless we need it */
   1.371 +    if (itemTemplateCount > SFTK_MAX_ITEM_TEMPLATE) {
   1.372 +	template = PORT_NewArray(CK_ATTRIBUTE, itemTemplateCount);
   1.373 +    } else {
   1.374 +	template = templateSpace;
   1.375 +    }
   1.376 +
   1.377 +    if (template == NULL) {
   1.378 +	crv = CKR_HOST_MEMORY;
   1.379 +	goto loser;
   1.380 +    }
   1.381 +
   1.382 +    dbHandle = sftk_getDBForTokenObject(object->slot, object->handle);
   1.383 +    if (dbHandle == NULL) {
   1.384 +	crv = CKR_OBJECT_HANDLE_INVALID;
   1.385 +	goto loser;
   1.386 +    }
   1.387 +
   1.388 +    /* set up the PKCS #11 template */
   1.389 +    for (i=0; i < itemTemplateCount; i++) {
   1.390 +	template[i].type = itemTemplate[i].type;
   1.391 +	template[i].pValue = NULL;
   1.392 +	template[i].ulValueLen = 0;
   1.393 +    }
   1.394 +
   1.395 +    /* fetch the attribute lengths */
   1.396 +    crv = sftkdb_GetAttributeValue(dbHandle, object->handle,
   1.397 +				   template, itemTemplateCount);
   1.398 +    if (crv != CKR_OK) {
   1.399 +	goto loser;
   1.400 +    }
   1.401 +
   1.402 +    /* allocate space for the attributes */
   1.403 +    for (i=0; i < itemTemplateCount ; i++) {
   1.404 +	template[i].pValue = PORT_ArenaAlloc(arena, template[i].ulValueLen);
   1.405 +	if (template[i].pValue == NULL) {
   1.406 +	    crv = CKR_HOST_MEMORY;
   1.407 +	    goto loser;
   1.408 +	}
   1.409 +    }
   1.410 +
   1.411 +    /* fetch the attributes */
   1.412 +    crv = sftkdb_GetAttributeValue(dbHandle, object->handle,
   1.413 +				   template, itemTemplateCount);
   1.414 +    if (crv != CKR_OK) {
   1.415 +	goto loser;
   1.416 +    }
   1.417 +
   1.418 +    /* Fill in the items */	
   1.419 +    for (i=0; i < itemTemplateCount; i++) {
   1.420 +	itemTemplate[i].item->data = template[i].pValue;
   1.421 +	itemTemplate[i].item->len = template[i].ulValueLen;
   1.422 +    }
   1.423 +
   1.424 +loser:
   1.425 +    if (template != templateSpace) {
   1.426 +	PORT_Free(template);
   1.427 +    }
   1.428 +    if (dbHandle) {
   1.429 +	sftk_freeDB(dbHandle);
   1.430 +    }
   1.431 +	     
   1.432 +    return crv;
   1.433 +}
   1.434 +
   1.435 +
   1.436 +/*
   1.437 + * delete an attribute from an object
   1.438 + */
   1.439 +static void
   1.440 +sftk_DeleteAttribute(SFTKObject *object, SFTKAttribute *attribute)
   1.441 +{
   1.442 +    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
   1.443 +
   1.444 +    if (sessObject == NULL) {
   1.445 +	return ;
   1.446 +    }
   1.447 +    PZ_Lock(sessObject->attributeLock);
   1.448 +    if (sftkqueue_is_queued(attribute,attribute->handle,
   1.449 +				sessObject->head, sessObject->hashSize)) {
   1.450 +	sftkqueue_delete(attribute,attribute->handle,
   1.451 +				sessObject->head, sessObject->hashSize);
   1.452 +    }
   1.453 +    PZ_Unlock(sessObject->attributeLock);
   1.454 +}
   1.455 +
   1.456 +/*
   1.457 + * this is only valid for CK_BBOOL type attributes. Return the state
   1.458 + * of that attribute.
   1.459 + */
   1.460 +PRBool
   1.461 +sftk_isTrue(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
   1.462 +{
   1.463 +    SFTKAttribute *attribute;
   1.464 +    PRBool tok = PR_FALSE;
   1.465 +
   1.466 +    attribute=sftk_FindAttribute(object,type);
   1.467 +    if (attribute == NULL) { return PR_FALSE; }
   1.468 +    tok = (PRBool)(*(CK_BBOOL *)attribute->attrib.pValue);
   1.469 +    sftk_FreeAttribute(attribute);
   1.470 +
   1.471 +    return tok;
   1.472 +}
   1.473 +
   1.474 +/*
   1.475 + * force an attribute to null.
   1.476 + * this is for sensitive keys which are stored in the database, we don't
   1.477 + * want to keep this info around in memory in the clear.
   1.478 + */
   1.479 +void
   1.480 +sftk_nullAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
   1.481 +{
   1.482 +    SFTKAttribute *attribute;
   1.483 +
   1.484 +    attribute=sftk_FindAttribute(object,type);
   1.485 +    if (attribute == NULL) return;
   1.486 +
   1.487 +    if (attribute->attrib.pValue != NULL) {
   1.488 +	PORT_Memset(attribute->attrib.pValue,0,attribute->attrib.ulValueLen);
   1.489 +	if (attribute->freeData) {
   1.490 +	    PORT_Free(attribute->attrib.pValue);
   1.491 +	}
   1.492 +	attribute->freeData = PR_FALSE;
   1.493 +	attribute->attrib.pValue = NULL;
   1.494 +	attribute->attrib.ulValueLen = 0;
   1.495 +    }
   1.496 +    sftk_FreeAttribute(attribute);
   1.497 +}
   1.498 +
   1.499 +
   1.500 +static CK_RV
   1.501 +sftk_forceTokenAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type, 
   1.502 +				const void *value, unsigned int len)
   1.503 +{
   1.504 +    CK_ATTRIBUTE attribute;
   1.505 +    SFTKDBHandle *dbHandle = NULL;
   1.506 +    SFTKTokenObject *to = sftk_narrowToTokenObject(object);
   1.507 +    CK_RV crv;
   1.508 +
   1.509 +    PORT_Assert(to);
   1.510 +    if (to == NULL) {
   1.511 +	return CKR_DEVICE_ERROR;
   1.512 +    }
   1.513 +
   1.514 +    dbHandle = sftk_getDBForTokenObject(object->slot, object->handle);
   1.515 +
   1.516 +    attribute.type = type;
   1.517 +    attribute.pValue = (void *)value;
   1.518 +    attribute.ulValueLen = len;
   1.519 +
   1.520 +    crv = sftkdb_SetAttributeValue(dbHandle, object, &attribute, 1);
   1.521 +    sftk_freeDB(dbHandle);
   1.522 +    return crv;
   1.523 +}
   1.524 +	
   1.525 +/*
   1.526 + * force an attribute to a specifc value.
   1.527 + */
   1.528 +CK_RV
   1.529 +sftk_forceAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type, 
   1.530 +				const void *value, unsigned int len)
   1.531 +{
   1.532 +    SFTKAttribute *attribute;
   1.533 +    void *att_val = NULL;
   1.534 +    PRBool freeData = PR_FALSE;
   1.535 +
   1.536 +    PORT_Assert(object);
   1.537 +    PORT_Assert(object->refCount);
   1.538 +    PORT_Assert(object->slot);
   1.539 +    if (!object ||
   1.540 +        !object->refCount ||
   1.541 +        !object->slot) {
   1.542 +        return CKR_DEVICE_ERROR;
   1.543 +    }
   1.544 +    if (sftk_isToken(object->handle)) {
   1.545 +	return sftk_forceTokenAttribute(object,type,value,len);
   1.546 +    }
   1.547 +    attribute=sftk_FindAttribute(object,type);
   1.548 +    if (attribute == NULL) return sftk_AddAttributeType(object,type,value,len);
   1.549 +
   1.550 +
   1.551 +    if (value) {
   1.552 +        if (len <= ATTR_SPACE) {
   1.553 +	    att_val = attribute->space;
   1.554 +	} else {
   1.555 +	    att_val = PORT_Alloc(len);
   1.556 +	    freeData = PR_TRUE;
   1.557 +	}
   1.558 +	if (att_val == NULL) {
   1.559 +	    return CKR_HOST_MEMORY;
   1.560 +	}
   1.561 +	if (attribute->attrib.pValue == att_val) {
   1.562 +	    PORT_Memset(attribute->attrib.pValue,0,
   1.563 +					attribute->attrib.ulValueLen);
   1.564 +	}
   1.565 +	PORT_Memcpy(att_val,value,len);
   1.566 +    }
   1.567 +    if (attribute->attrib.pValue != NULL) {
   1.568 +	if (attribute->attrib.pValue != att_val) {
   1.569 +	    PORT_Memset(attribute->attrib.pValue,0,
   1.570 +					attribute->attrib.ulValueLen);
   1.571 +	}
   1.572 +	if (attribute->freeData) {
   1.573 +	    PORT_Free(attribute->attrib.pValue);
   1.574 +	}
   1.575 +	attribute->freeData = PR_FALSE;
   1.576 +	attribute->attrib.pValue = NULL;
   1.577 +	attribute->attrib.ulValueLen = 0;
   1.578 +    }
   1.579 +    if (att_val) {
   1.580 +	attribute->attrib.pValue = att_val;
   1.581 +	attribute->attrib.ulValueLen = len;
   1.582 +	attribute->freeData = freeData;
   1.583 +    }
   1.584 +    sftk_FreeAttribute(attribute);
   1.585 +    return CKR_OK;
   1.586 +}
   1.587 +
   1.588 +/*
   1.589 + * return a null terminated string from attribute 'type'. This string
   1.590 + * is allocated and needs to be freed with PORT_Free() When complete.
   1.591 + */
   1.592 +char *
   1.593 +sftk_getString(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
   1.594 +{
   1.595 +    SFTKAttribute *attribute;
   1.596 +    char *label = NULL;
   1.597 +
   1.598 +    attribute=sftk_FindAttribute(object,type);
   1.599 +    if (attribute == NULL) return NULL;
   1.600 +
   1.601 +    if (attribute->attrib.pValue != NULL) {
   1.602 +	label = (char *) PORT_Alloc(attribute->attrib.ulValueLen+1);
   1.603 +	if (label == NULL) {
   1.604 +    	    sftk_FreeAttribute(attribute);
   1.605 +	    return NULL;
   1.606 +	}
   1.607 +
   1.608 +	PORT_Memcpy(label,attribute->attrib.pValue,
   1.609 +						attribute->attrib.ulValueLen);
   1.610 +	label[attribute->attrib.ulValueLen] = 0;
   1.611 +    }
   1.612 +    sftk_FreeAttribute(attribute);
   1.613 +    return label;
   1.614 +}
   1.615 +
   1.616 +/*
   1.617 + * decode when a particular attribute may be modified
   1.618 + * 	SFTK_NEVER: This attribute must be set at object creation time and
   1.619 + *  can never be modified.
   1.620 + *	SFTK_ONCOPY: This attribute may be modified only when you copy the
   1.621 + *  object.
   1.622 + *	SFTK_SENSITIVE: The CKA_SENSITIVE attribute can only be changed from
   1.623 + *  CK_FALSE to CK_TRUE.
   1.624 + *	SFTK_ALWAYS: This attribute can always be modified.
   1.625 + * Some attributes vary their modification type based on the class of the 
   1.626 + *   object.
   1.627 + */
   1.628 +SFTKModifyType
   1.629 +sftk_modifyType(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
   1.630 +{
   1.631 +    /* if we don't know about it, user user defined, always allow modify */
   1.632 +    SFTKModifyType mtype = SFTK_ALWAYS; 
   1.633 +
   1.634 +    switch(type) {
   1.635 +    /* NEVER */
   1.636 +    case CKA_CLASS:
   1.637 +    case CKA_CERTIFICATE_TYPE:
   1.638 +    case CKA_KEY_TYPE:
   1.639 +    case CKA_MODULUS:
   1.640 +    case CKA_MODULUS_BITS:
   1.641 +    case CKA_PUBLIC_EXPONENT:
   1.642 +    case CKA_PRIVATE_EXPONENT:
   1.643 +    case CKA_PRIME:
   1.644 +    case CKA_SUBPRIME:
   1.645 +    case CKA_BASE:
   1.646 +    case CKA_PRIME_1:
   1.647 +    case CKA_PRIME_2:
   1.648 +    case CKA_EXPONENT_1:
   1.649 +    case CKA_EXPONENT_2:
   1.650 +    case CKA_COEFFICIENT:
   1.651 +    case CKA_VALUE_LEN:
   1.652 +    case CKA_ALWAYS_SENSITIVE:
   1.653 +    case CKA_NEVER_EXTRACTABLE:
   1.654 +    case CKA_NETSCAPE_DB:
   1.655 +	mtype = SFTK_NEVER;
   1.656 +	break;
   1.657 +
   1.658 +    /* ONCOPY */
   1.659 +    case CKA_TOKEN:
   1.660 +    case CKA_PRIVATE:
   1.661 +    case CKA_MODIFIABLE:
   1.662 +	mtype = SFTK_ONCOPY;
   1.663 +	break;
   1.664 +
   1.665 +    /* SENSITIVE */
   1.666 +    case CKA_SENSITIVE:
   1.667 +    case CKA_EXTRACTABLE:
   1.668 +	mtype = SFTK_SENSITIVE;
   1.669 +	break;
   1.670 +
   1.671 +    /* ALWAYS */
   1.672 +    case CKA_LABEL:
   1.673 +    case CKA_APPLICATION:
   1.674 +    case CKA_ID:
   1.675 +    case CKA_SERIAL_NUMBER:
   1.676 +    case CKA_START_DATE:
   1.677 +    case CKA_END_DATE:
   1.678 +    case CKA_DERIVE:
   1.679 +    case CKA_ENCRYPT:
   1.680 +    case CKA_DECRYPT:
   1.681 +    case CKA_SIGN:
   1.682 +    case CKA_VERIFY:
   1.683 +    case CKA_SIGN_RECOVER:
   1.684 +    case CKA_VERIFY_RECOVER:
   1.685 +    case CKA_WRAP:
   1.686 +    case CKA_UNWRAP:
   1.687 +	mtype = SFTK_ALWAYS;
   1.688 +	break;
   1.689 +
   1.690 +    /* DEPENDS ON CLASS */
   1.691 +    case CKA_VALUE:
   1.692 +	mtype = (inClass == CKO_DATA) ? SFTK_ALWAYS : SFTK_NEVER;
   1.693 +	break;
   1.694 +
   1.695 +    case CKA_SUBJECT:
   1.696 +	mtype = (inClass == CKO_CERTIFICATE) ? SFTK_NEVER : SFTK_ALWAYS;
   1.697 +	break;
   1.698 +    default:
   1.699 +	break;
   1.700 +    }
   1.701 +    return mtype;
   1.702 +}
   1.703 +
   1.704 +/* decode if a particular attribute is sensitive (cannot be read
   1.705 + * back to the user of if the object is set to SENSITIVE) */
   1.706 +PRBool
   1.707 +sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
   1.708 +{
   1.709 +    switch(type) {
   1.710 +    /* ALWAYS */
   1.711 +    case CKA_PRIVATE_EXPONENT:
   1.712 +    case CKA_PRIME_1:
   1.713 +    case CKA_PRIME_2:
   1.714 +    case CKA_EXPONENT_1:
   1.715 +    case CKA_EXPONENT_2:
   1.716 +    case CKA_COEFFICIENT:
   1.717 +	return PR_TRUE;
   1.718 +
   1.719 +    /* DEPENDS ON CLASS */
   1.720 +    case CKA_VALUE:
   1.721 +	/* PRIVATE and SECRET KEYS have SENSITIVE values */
   1.722 +	return (PRBool)((inClass == CKO_PRIVATE_KEY) || (inClass == CKO_SECRET_KEY));
   1.723 +
   1.724 +    default:
   1.725 +	break;
   1.726 +    }
   1.727 +    return PR_FALSE;
   1.728 +}
   1.729 +
   1.730 +/* 
   1.731 + * copy an attribute into a SECItem. Secitem is allocated in the specified
   1.732 + * arena.
   1.733 + */
   1.734 +CK_RV
   1.735 +sftk_Attribute2SecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object,
   1.736 +					CK_ATTRIBUTE_TYPE type)
   1.737 +{
   1.738 +    int len;
   1.739 +    SFTKAttribute *attribute;
   1.740 +
   1.741 +    attribute = sftk_FindAttribute(object, type);
   1.742 +    if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
   1.743 +    len = attribute->attrib.ulValueLen;
   1.744 +
   1.745 +    if (arena) {
   1.746 +    	item->data = (unsigned char *) PORT_ArenaAlloc(arena,len);
   1.747 +    } else {
   1.748 +    	item->data = (unsigned char *) PORT_Alloc(len);
   1.749 +    }
   1.750 +    if (item->data == NULL) {
   1.751 +	sftk_FreeAttribute(attribute);
   1.752 +	return CKR_HOST_MEMORY;
   1.753 +    }
   1.754 +    item->len = len;
   1.755 +    PORT_Memcpy(item->data,attribute->attrib.pValue, len);
   1.756 +    sftk_FreeAttribute(attribute);
   1.757 +    return CKR_OK;
   1.758 +}
   1.759 +
   1.760 +CK_RV
   1.761 +sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
   1.762 +							 CK_ULONG *longData)
   1.763 +{
   1.764 +    SFTKAttribute *attribute;
   1.765 +
   1.766 +    attribute = sftk_FindAttribute(object, type);
   1.767 +    if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
   1.768 +
   1.769 +    if (attribute->attrib.ulValueLen != sizeof(CK_ULONG)) {
   1.770 +	return CKR_ATTRIBUTE_VALUE_INVALID;
   1.771 +    }
   1.772 +
   1.773 +    *longData = *(CK_ULONG *)attribute->attrib.pValue;
   1.774 +    sftk_FreeAttribute(attribute);
   1.775 +    return CKR_OK;
   1.776 +}
   1.777 +
   1.778 +void
   1.779 +sftk_DeleteAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
   1.780 +{
   1.781 +    SFTKAttribute *attribute;
   1.782 +    attribute = sftk_FindAttribute(object, type);
   1.783 +    if (attribute == NULL) return ;
   1.784 +    sftk_DeleteAttribute(object,attribute);
   1.785 +    sftk_FreeAttribute(attribute);
   1.786 +}
   1.787 +
   1.788 +CK_RV
   1.789 +sftk_AddAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type,
   1.790 +				const void *valPtr, CK_ULONG length)
   1.791 +{
   1.792 +    SFTKAttribute *attribute;
   1.793 +    attribute = sftk_NewAttribute(object,type,valPtr,length);
   1.794 +    if (attribute == NULL) { return CKR_HOST_MEMORY; }
   1.795 +    sftk_AddAttribute(object,attribute);
   1.796 +    return CKR_OK;
   1.797 +}
   1.798 +
   1.799 +/*
   1.800 + * ******************** Object Utilities *******************************
   1.801 + */
   1.802 +
   1.803 +/* must be called holding sftk_tokenKeyLock(slot) */
   1.804 +static SECItem *
   1.805 +sftk_lookupTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle)
   1.806 +{
   1.807 +    return (SECItem *)PL_HashTableLookup(slot->tokObjHashTable, (void *)handle);
   1.808 +}
   1.809 +
   1.810 +/*
   1.811 + * use the refLock. This operations should be very rare, so the added
   1.812 + * contention on the ref lock should be lower than the overhead of adding
   1.813 + * a new lock. We use separate functions for this just in case I'm wrong.
   1.814 + */
   1.815 +static void
   1.816 +sftk_tokenKeyLock(SFTKSlot *slot) {
   1.817 +    SKIP_AFTER_FORK(PZ_Lock(slot->objectLock));
   1.818 +}
   1.819 +
   1.820 +static void
   1.821 +sftk_tokenKeyUnlock(SFTKSlot *slot) {
   1.822 +    SKIP_AFTER_FORK(PZ_Unlock(slot->objectLock));
   1.823 +}
   1.824 +
   1.825 +static PRIntn
   1.826 +sftk_freeHashItem(PLHashEntry* entry, PRIntn index, void *arg)
   1.827 +{
   1.828 +    SECItem *item = (SECItem *)entry->value;
   1.829 +
   1.830 +    SECITEM_FreeItem(item, PR_TRUE);
   1.831 +    return HT_ENUMERATE_NEXT;
   1.832 +}
   1.833 +
   1.834 +CK_RV
   1.835 +SFTK_ClearTokenKeyHashTable(SFTKSlot *slot)
   1.836 +{
   1.837 +    sftk_tokenKeyLock(slot);
   1.838 +    PORT_Assert(!slot->present);
   1.839 +    PL_HashTableEnumerateEntries(slot->tokObjHashTable, sftk_freeHashItem, NULL);
   1.840 +    sftk_tokenKeyUnlock(slot);
   1.841 +    return CKR_OK;
   1.842 +}
   1.843 +
   1.844 +
   1.845 +/* allocation hooks that allow us to recycle old object structures */
   1.846 +static SFTKObjectFreeList sessionObjectList = { NULL, NULL, 0 };
   1.847 +static SFTKObjectFreeList tokenObjectList = { NULL, NULL, 0 };
   1.848 +
   1.849 +SFTKObject *
   1.850 +sftk_GetObjectFromList(PRBool *hasLocks, PRBool optimizeSpace, 
   1.851 +     SFTKObjectFreeList *list, unsigned int hashSize, PRBool isSessionObject)
   1.852 +{
   1.853 +    SFTKObject *object;
   1.854 +    int size = 0;
   1.855 +
   1.856 +    if (!optimizeSpace) {
   1.857 +	PZ_Lock(list->lock);
   1.858 +	object = list->head;
   1.859 +	if (object) {
   1.860 +	    list->head = object->next;
   1.861 +	    list->count--;
   1.862 +	}    	
   1.863 +	PZ_Unlock(list->lock);
   1.864 +	if (object) {
   1.865 +	    object->next = object->prev = NULL;
   1.866 +            *hasLocks = PR_TRUE;
   1.867 +	    return object;
   1.868 +	}
   1.869 +    }
   1.870 +    size = isSessionObject ? sizeof(SFTKSessionObject) 
   1.871 +		+ hashSize *sizeof(SFTKAttribute *) : sizeof(SFTKTokenObject);
   1.872 +
   1.873 +    object  = (SFTKObject*)PORT_ZAlloc(size);
   1.874 +    if (isSessionObject && object) {
   1.875 +	((SFTKSessionObject *)object)->hashSize = hashSize;
   1.876 +    }
   1.877 +    *hasLocks = PR_FALSE;
   1.878 +    return object;
   1.879 +}
   1.880 +
   1.881 +static void
   1.882 +sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list,
   1.883 +						PRBool isSessionObject) {
   1.884 +
   1.885 +    /* the code below is equivalent to :
   1.886 +     *     optimizeSpace = isSessionObject ? object->optimizeSpace : PR_FALSE;
   1.887 +     * just faster.
   1.888 +     */
   1.889 +    PRBool optimizeSpace = isSessionObject && 
   1.890 +				((SFTKSessionObject *)object)->optimizeSpace; 
   1.891 +    if (object->refLock && !optimizeSpace 
   1.892 +	               && (list->count < MAX_OBJECT_LIST_SIZE)) {
   1.893 +	PZ_Lock(list->lock);
   1.894 +	object->next = list->head;
   1.895 +	list->head = object;
   1.896 +	list->count++;
   1.897 +	PZ_Unlock(list->lock);
   1.898 +	return;
   1.899 +    }
   1.900 +    if (isSessionObject) {
   1.901 +	SFTKSessionObject *so = (SFTKSessionObject *)object;
   1.902 +	PZ_DestroyLock(so->attributeLock);
   1.903 +	so->attributeLock = NULL;
   1.904 +    }
   1.905 +    if (object->refLock) {
   1.906 +	PZ_DestroyLock(object->refLock);
   1.907 +	object->refLock = NULL;
   1.908 +    }
   1.909 +    PORT_Free(object);
   1.910 +}
   1.911 +
   1.912 +static SFTKObject *
   1.913 +sftk_freeObjectData(SFTKObject *object) {
   1.914 +   SFTKObject *next = object->next;
   1.915 +
   1.916 +   PORT_Free(object);
   1.917 +   return next;
   1.918 +}
   1.919 +
   1.920 +static void
   1.921 +sftk_InitFreeList(SFTKObjectFreeList *list)
   1.922 +{
   1.923 +    list->lock = PZ_NewLock(nssILockObject);
   1.924 +}
   1.925 +
   1.926 +void sftk_InitFreeLists(void)
   1.927 +{
   1.928 +    sftk_InitFreeList(&sessionObjectList);
   1.929 +    sftk_InitFreeList(&tokenObjectList);
   1.930 +}
   1.931 +   
   1.932 +static void
   1.933 +sftk_CleanupFreeList(SFTKObjectFreeList *list, PRBool isSessionList)
   1.934 +{
   1.935 +    SFTKObject *object;
   1.936 +
   1.937 +    if (!list->lock) {
   1.938 +	return;
   1.939 +    }
   1.940 +    SKIP_AFTER_FORK(PZ_Lock(list->lock));
   1.941 +    for (object= list->head; object != NULL; 
   1.942 +					object = sftk_freeObjectData(object)) {
   1.943 +	PZ_DestroyLock(object->refLock);
   1.944 +	if (isSessionList) {
   1.945 +	    PZ_DestroyLock(((SFTKSessionObject *)object)->attributeLock);
   1.946 +	}
   1.947 +    }
   1.948 +    list->count = 0;
   1.949 +    list->head = NULL;
   1.950 +    SKIP_AFTER_FORK(PZ_Unlock(list->lock));
   1.951 +    SKIP_AFTER_FORK(PZ_DestroyLock(list->lock));
   1.952 +    list->lock = NULL;
   1.953 +}
   1.954 +
   1.955 +void
   1.956 +sftk_CleanupFreeLists(void)
   1.957 +{
   1.958 +    sftk_CleanupFreeList(&sessionObjectList, PR_TRUE);
   1.959 +    sftk_CleanupFreeList(&tokenObjectList, PR_FALSE);
   1.960 +}
   1.961 +
   1.962 +
   1.963 +/*
   1.964 + * Create a new object
   1.965 + */
   1.966 +SFTKObject *
   1.967 +sftk_NewObject(SFTKSlot *slot)
   1.968 +{
   1.969 +    SFTKObject *object;
   1.970 +    SFTKSessionObject *sessObject;
   1.971 +    PRBool hasLocks = PR_FALSE;
   1.972 +    unsigned int i;
   1.973 +    unsigned int hashSize = 0;
   1.974 +
   1.975 +    hashSize = (slot->optimizeSpace) ? SPACE_ATTRIBUTE_HASH_SIZE :
   1.976 +				TIME_ATTRIBUTE_HASH_SIZE;
   1.977 +
   1.978 +    object = sftk_GetObjectFromList(&hasLocks, slot->optimizeSpace,
   1.979 +				&sessionObjectList,  hashSize, PR_TRUE);
   1.980 +    if (object == NULL) {
   1.981 +	return NULL;
   1.982 +    }
   1.983 +    sessObject = (SFTKSessionObject *)object;
   1.984 +    sessObject->nextAttr = 0;
   1.985 +
   1.986 +    for (i=0; i < MAX_OBJS_ATTRS; i++) {
   1.987 +	sessObject->attrList[i].attrib.pValue = NULL;
   1.988 +	sessObject->attrList[i].freeData = PR_FALSE;
   1.989 +    }
   1.990 +    sessObject->optimizeSpace = slot->optimizeSpace;
   1.991 +
   1.992 +    object->handle = 0;
   1.993 +    object->next = object->prev = NULL;
   1.994 +    object->slot = slot;
   1.995 +    
   1.996 +    object->refCount = 1;
   1.997 +    sessObject->sessionList.next = NULL;
   1.998 +    sessObject->sessionList.prev = NULL;
   1.999 +    sessObject->sessionList.parent = object;
  1.1000 +    sessObject->session = NULL;
  1.1001 +    sessObject->wasDerived = PR_FALSE;
  1.1002 +    if (!hasLocks) object->refLock = PZ_NewLock(nssILockRefLock);
  1.1003 +    if (object->refLock == NULL) {
  1.1004 +	PORT_Free(object);
  1.1005 +	return NULL;
  1.1006 +    }
  1.1007 +    if (!hasLocks) sessObject->attributeLock = PZ_NewLock(nssILockAttribute);
  1.1008 +    if (sessObject->attributeLock == NULL) {
  1.1009 +	PZ_DestroyLock(object->refLock);
  1.1010 +	PORT_Free(object);
  1.1011 +	return NULL;
  1.1012 +    }
  1.1013 +    for (i=0; i < sessObject->hashSize; i++) {
  1.1014 +	sessObject->head[i] = NULL;
  1.1015 +    }
  1.1016 +    object->objectInfo = NULL;
  1.1017 +    object->infoFree = NULL;
  1.1018 +    return object;
  1.1019 +}
  1.1020 +
  1.1021 +static CK_RV
  1.1022 +sftk_DestroySessionObjectData(SFTKSessionObject *so)
  1.1023 +{
  1.1024 +	int i;
  1.1025 +
  1.1026 +	for (i=0; i < MAX_OBJS_ATTRS; i++) {
  1.1027 +	    unsigned char *value = so->attrList[i].attrib.pValue;
  1.1028 +	    if (value) {
  1.1029 +		PORT_Memset(value,0,so->attrList[i].attrib.ulValueLen);
  1.1030 +		if (so->attrList[i].freeData) {
  1.1031 +		    PORT_Free(value);
  1.1032 +		}
  1.1033 +		so->attrList[i].attrib.pValue = NULL;
  1.1034 +		so->attrList[i].freeData = PR_FALSE;
  1.1035 +	    }
  1.1036 +	}
  1.1037 +/*	PZ_DestroyLock(so->attributeLock);*/
  1.1038 +	return CKR_OK;
  1.1039 +}
  1.1040 +
  1.1041 +/*
  1.1042 + * free all the data associated with an object. Object reference count must
  1.1043 + * be 'zero'.
  1.1044 + */
  1.1045 +static CK_RV
  1.1046 +sftk_DestroyObject(SFTKObject *object)
  1.1047 +{
  1.1048 +    CK_RV crv = CKR_OK;
  1.1049 +    SFTKSessionObject *so = sftk_narrowToSessionObject(object);
  1.1050 +    SFTKTokenObject *to = sftk_narrowToTokenObject(object);
  1.1051 +
  1.1052 +    PORT_Assert(object->refCount == 0);
  1.1053 +
  1.1054 +    /* delete the database value */
  1.1055 +    if (to) {
  1.1056 +	if (to->dbKey.data) {
  1.1057 +	   PORT_Free(to->dbKey.data);
  1.1058 +	   to->dbKey.data = NULL;
  1.1059 +	}
  1.1060 +    } 
  1.1061 +    if (so) {
  1.1062 +	sftk_DestroySessionObjectData(so);
  1.1063 +    }
  1.1064 +    if (object->objectInfo) {
  1.1065 +	(*object->infoFree)(object->objectInfo);
  1.1066 +	object->objectInfo = NULL;
  1.1067 +	object->infoFree = NULL;
  1.1068 +    }
  1.1069 +    if (so) {
  1.1070 +	sftk_PutObjectToList(object,&sessionObjectList,PR_TRUE);
  1.1071 +    } else {
  1.1072 +	sftk_PutObjectToList(object,&tokenObjectList,PR_FALSE);
  1.1073 +    }
  1.1074 +    return crv;
  1.1075 +}
  1.1076 +
  1.1077 +void
  1.1078 +sftk_ReferenceObject(SFTKObject *object)
  1.1079 +{
  1.1080 +    PZ_Lock(object->refLock);
  1.1081 +    object->refCount++;
  1.1082 +    PZ_Unlock(object->refLock);
  1.1083 +}
  1.1084 +
  1.1085 +static SFTKObject *
  1.1086 +sftk_ObjectFromHandleOnSlot(CK_OBJECT_HANDLE handle, SFTKSlot *slot)
  1.1087 +{
  1.1088 +    SFTKObject *object;
  1.1089 +    PRUint32 index = sftk_hash(handle, slot->sessObjHashSize);
  1.1090 +
  1.1091 +    if (sftk_isToken(handle)) {
  1.1092 +	return sftk_NewTokenObject(slot, NULL, handle);
  1.1093 +    }
  1.1094 +
  1.1095 +    PZ_Lock(slot->objectLock);
  1.1096 +    sftkqueue_find2(object, handle, index, slot->sessObjHashTable);
  1.1097 +    if (object) {
  1.1098 +	sftk_ReferenceObject(object);
  1.1099 +    }
  1.1100 +    PZ_Unlock(slot->objectLock);
  1.1101 +
  1.1102 +    return(object);
  1.1103 +}
  1.1104 +/*
  1.1105 + * look up and object structure from a handle. OBJECT_Handles only make
  1.1106 + * sense in terms of a given session.  make a reference to that object
  1.1107 + * structure returned.
  1.1108 + */
  1.1109 +SFTKObject *
  1.1110 +sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle, SFTKSession *session)
  1.1111 +{
  1.1112 +    SFTKSlot *slot = sftk_SlotFromSession(session);
  1.1113 +
  1.1114 +    return sftk_ObjectFromHandleOnSlot(handle,slot);
  1.1115 +}
  1.1116 +
  1.1117 +
  1.1118 +/*
  1.1119 + * release a reference to an object handle
  1.1120 + */
  1.1121 +SFTKFreeStatus
  1.1122 +sftk_FreeObject(SFTKObject *object)
  1.1123 +{
  1.1124 +    PRBool destroy = PR_FALSE;
  1.1125 +    CK_RV crv;
  1.1126 +
  1.1127 +    PZ_Lock(object->refLock);
  1.1128 +    if (object->refCount == 1) destroy = PR_TRUE;
  1.1129 +    object->refCount--;
  1.1130 +    PZ_Unlock(object->refLock);
  1.1131 +
  1.1132 +    if (destroy) {
  1.1133 +	crv = sftk_DestroyObject(object);
  1.1134 +	if (crv != CKR_OK) {
  1.1135 +	   return SFTK_DestroyFailure;
  1.1136 +	} 
  1.1137 +	return SFTK_Destroyed;
  1.1138 +    }
  1.1139 +    return SFTK_Busy;
  1.1140 +}
  1.1141 + 
  1.1142 +/*
  1.1143 + * add an object to a slot and session queue. These two functions
  1.1144 + * adopt the object.
  1.1145 + */
  1.1146 +void
  1.1147 +sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object)
  1.1148 +{
  1.1149 +    PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize);
  1.1150 +    sftkqueue_init_element(object);
  1.1151 +    PZ_Lock(slot->objectLock);
  1.1152 +    sftkqueue_add2(object, object->handle, index, slot->sessObjHashTable);
  1.1153 +    PZ_Unlock(slot->objectLock);
  1.1154 +}
  1.1155 +
  1.1156 +void
  1.1157 +sftk_AddObject(SFTKSession *session, SFTKObject *object)
  1.1158 +{
  1.1159 +    SFTKSlot *slot = sftk_SlotFromSession(session);
  1.1160 +    SFTKSessionObject *so = sftk_narrowToSessionObject(object);
  1.1161 +
  1.1162 +    if (so) {
  1.1163 +	PZ_Lock(session->objectLock);
  1.1164 +	sftkqueue_add(&so->sessionList,0,session->objects,0);
  1.1165 +	so->session = session;
  1.1166 +	PZ_Unlock(session->objectLock);
  1.1167 +    }
  1.1168 +    sftk_AddSlotObject(slot,object);
  1.1169 +    sftk_ReferenceObject(object);
  1.1170 +} 
  1.1171 +
  1.1172 +/*
  1.1173 + * delete an object from a slot and session queue
  1.1174 + */
  1.1175 +CK_RV
  1.1176 +sftk_DeleteObject(SFTKSession *session, SFTKObject *object)
  1.1177 +{
  1.1178 +    SFTKSlot *slot = sftk_SlotFromSession(session);
  1.1179 +    SFTKSessionObject *so = sftk_narrowToSessionObject(object);
  1.1180 +    SFTKTokenObject *to = sftk_narrowToTokenObject(object);
  1.1181 +    CK_RV crv = CKR_OK;
  1.1182 +    PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize);
  1.1183 +
  1.1184 +    /* Handle Token case */
  1.1185 +    if (so && so->session) {
  1.1186 +	SFTKSession *session = so->session;
  1.1187 +	PZ_Lock(session->objectLock);
  1.1188 +	sftkqueue_delete(&so->sessionList,0,session->objects,0);
  1.1189 +	PZ_Unlock(session->objectLock);
  1.1190 +	PZ_Lock(slot->objectLock);
  1.1191 +	sftkqueue_delete2(object, object->handle, index, slot->sessObjHashTable);
  1.1192 +	PZ_Unlock(slot->objectLock);
  1.1193 +	sftkqueue_clear_deleted_element(object);
  1.1194 +	sftk_FreeObject(object); /* free the reference owned by the queue */
  1.1195 +    } else {
  1.1196 +	SFTKDBHandle *handle = sftk_getDBForTokenObject(slot, object->handle);
  1.1197 +
  1.1198 +	PORT_Assert(to);
  1.1199 +	crv = sftkdb_DestroyObject(handle, object->handle);
  1.1200 +	sftk_freeDB(handle);
  1.1201 +    } 
  1.1202 +    return crv;
  1.1203 +}
  1.1204 +
  1.1205 +/*
  1.1206 + * Token objects don't explicitly store their attributes, so we need to know
  1.1207 + * what attributes make up a particular token object before we can copy it.
  1.1208 + * below are the tables by object type.
  1.1209 + */
  1.1210 +static const CK_ATTRIBUTE_TYPE commonAttrs[] = {
  1.1211 +    CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_MODIFIABLE
  1.1212 +};
  1.1213 +static const CK_ULONG commonAttrsCount = 
  1.1214 +			sizeof(commonAttrs)/sizeof(commonAttrs[0]);
  1.1215 +
  1.1216 +static const CK_ATTRIBUTE_TYPE commonKeyAttrs[] = {
  1.1217 +    CKA_ID, CKA_START_DATE, CKA_END_DATE, CKA_DERIVE, CKA_LOCAL, CKA_KEY_TYPE
  1.1218 +};
  1.1219 +static const CK_ULONG commonKeyAttrsCount = 
  1.1220 +			sizeof(commonKeyAttrs)/sizeof(commonKeyAttrs[0]);
  1.1221 +
  1.1222 +static const CK_ATTRIBUTE_TYPE secretKeyAttrs[] = {
  1.1223 +    CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN,
  1.1224 +    CKA_VERIFY, CKA_WRAP, CKA_UNWRAP, CKA_VALUE
  1.1225 +};
  1.1226 +static const CK_ULONG secretKeyAttrsCount = 
  1.1227 +			sizeof(secretKeyAttrs)/sizeof(secretKeyAttrs[0]);
  1.1228 +
  1.1229 +static const CK_ATTRIBUTE_TYPE commonPubKeyAttrs[] = {
  1.1230 +    CKA_ENCRYPT, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_WRAP, CKA_SUBJECT
  1.1231 +};
  1.1232 +static const CK_ULONG commonPubKeyAttrsCount = 
  1.1233 +			sizeof(commonPubKeyAttrs)/sizeof(commonPubKeyAttrs[0]);
  1.1234 +
  1.1235 +static const CK_ATTRIBUTE_TYPE rsaPubKeyAttrs[] = {
  1.1236 +    CKA_MODULUS, CKA_PUBLIC_EXPONENT
  1.1237 +};
  1.1238 +static const CK_ULONG rsaPubKeyAttrsCount = 
  1.1239 +			sizeof(rsaPubKeyAttrs)/sizeof(rsaPubKeyAttrs[0]);
  1.1240 +
  1.1241 +static const CK_ATTRIBUTE_TYPE dsaPubKeyAttrs[] = {
  1.1242 +    CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
  1.1243 +};
  1.1244 +static const CK_ULONG dsaPubKeyAttrsCount = 
  1.1245 +			sizeof(dsaPubKeyAttrs)/sizeof(dsaPubKeyAttrs[0]);
  1.1246 +
  1.1247 +static const CK_ATTRIBUTE_TYPE dhPubKeyAttrs[] = {
  1.1248 +    CKA_PRIME, CKA_BASE, CKA_VALUE
  1.1249 +};
  1.1250 +static const CK_ULONG dhPubKeyAttrsCount = 
  1.1251 +			sizeof(dhPubKeyAttrs)/sizeof(dhPubKeyAttrs[0]);
  1.1252 +#ifndef NSS_DISABLE_ECC
  1.1253 +static const CK_ATTRIBUTE_TYPE ecPubKeyAttrs[] = {
  1.1254 +    CKA_EC_PARAMS, CKA_EC_POINT
  1.1255 +};
  1.1256 +static const CK_ULONG ecPubKeyAttrsCount = 
  1.1257 +			sizeof(ecPubKeyAttrs)/sizeof(ecPubKeyAttrs[0]);
  1.1258 +#endif
  1.1259 +
  1.1260 +static const CK_ATTRIBUTE_TYPE commonPrivKeyAttrs[] = {
  1.1261 +    CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_SUBJECT,
  1.1262 +    CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NETSCAPE_DB
  1.1263 +};
  1.1264 +static const CK_ULONG commonPrivKeyAttrsCount = 
  1.1265 +		sizeof(commonPrivKeyAttrs)/sizeof(commonPrivKeyAttrs[0]);
  1.1266 +
  1.1267 +static const CK_ATTRIBUTE_TYPE rsaPrivKeyAttrs[] = {
  1.1268 +    CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, 
  1.1269 +    CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT
  1.1270 +};
  1.1271 +static const CK_ULONG rsaPrivKeyAttrsCount = 
  1.1272 +			sizeof(rsaPrivKeyAttrs)/sizeof(rsaPrivKeyAttrs[0]);
  1.1273 +
  1.1274 +static const CK_ATTRIBUTE_TYPE dsaPrivKeyAttrs[] = {
  1.1275 +    CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
  1.1276 +};
  1.1277 +static const CK_ULONG dsaPrivKeyAttrsCount = 
  1.1278 +			sizeof(dsaPrivKeyAttrs)/sizeof(dsaPrivKeyAttrs[0]);
  1.1279 +
  1.1280 +static const CK_ATTRIBUTE_TYPE dhPrivKeyAttrs[] = {
  1.1281 +    CKA_PRIME, CKA_BASE, CKA_VALUE
  1.1282 +};
  1.1283 +static const CK_ULONG dhPrivKeyAttrsCount = 
  1.1284 +			sizeof(dhPrivKeyAttrs)/sizeof(dhPrivKeyAttrs[0]);
  1.1285 +#ifndef NSS_DISABLE_ECC
  1.1286 +static const CK_ATTRIBUTE_TYPE ecPrivKeyAttrs[] = {
  1.1287 +    CKA_EC_PARAMS, CKA_VALUE
  1.1288 +};
  1.1289 +static const CK_ULONG ecPrivKeyAttrsCount = 
  1.1290 +			sizeof(ecPrivKeyAttrs)/sizeof(ecPrivKeyAttrs[0]);
  1.1291 +#endif
  1.1292 +
  1.1293 +static const CK_ATTRIBUTE_TYPE certAttrs[] = {
  1.1294 +    CKA_CERTIFICATE_TYPE, CKA_VALUE, CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER
  1.1295 +};
  1.1296 +static const CK_ULONG certAttrsCount = 
  1.1297 +		sizeof(certAttrs)/sizeof(certAttrs[0]);
  1.1298 +
  1.1299 +static const CK_ATTRIBUTE_TYPE trustAttrs[] = {
  1.1300 +    CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
  1.1301 +    CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_EMAIL_PROTECTION,
  1.1302 +    CKA_TRUST_CODE_SIGNING, CKA_TRUST_STEP_UP_APPROVED
  1.1303 +};
  1.1304 +static const CK_ULONG trustAttrsCount = 
  1.1305 +		sizeof(trustAttrs)/sizeof(trustAttrs[0]);
  1.1306 +
  1.1307 +static const CK_ATTRIBUTE_TYPE smimeAttrs[] = {
  1.1308 +    CKA_SUBJECT, CKA_NETSCAPE_EMAIL, CKA_NETSCAPE_SMIME_TIMESTAMP, CKA_VALUE
  1.1309 +};
  1.1310 +static const CK_ULONG smimeAttrsCount = 
  1.1311 +		sizeof(smimeAttrs)/sizeof(smimeAttrs[0]);
  1.1312 +
  1.1313 +static const CK_ATTRIBUTE_TYPE crlAttrs[] = {
  1.1314 +    CKA_SUBJECT, CKA_VALUE, CKA_NETSCAPE_URL, CKA_NETSCAPE_KRL
  1.1315 +};
  1.1316 +static const CK_ULONG crlAttrsCount = 
  1.1317 +		sizeof(crlAttrs)/sizeof(crlAttrs[0]);
  1.1318 +
  1.1319 +/* copy an object based on it's table */
  1.1320 +CK_RV
  1.1321 +stfk_CopyTokenAttributes(SFTKObject *destObject,SFTKTokenObject *src_to,
  1.1322 +	const CK_ATTRIBUTE_TYPE *attrArray, CK_ULONG attrCount)
  1.1323 +{
  1.1324 +    SFTKAttribute *attribute;
  1.1325 +    SFTKAttribute *newAttribute;
  1.1326 +    CK_RV crv = CKR_OK;
  1.1327 +    unsigned int i;
  1.1328 +
  1.1329 +    for (i=0; i < attrCount; i++) {
  1.1330 +	if (!sftk_hasAttribute(destObject,attrArray[i])) {
  1.1331 +	    attribute =sftk_FindAttribute(&src_to->obj, attrArray[i]);
  1.1332 +	    if (!attribute) {
  1.1333 +		continue; /* return CKR_ATTRIBUTE_VALUE_INVALID; */
  1.1334 +	    }
  1.1335 +	    /* we need to copy the attribute since each attribute
  1.1336 +	     * only has one set of link list pointers */
  1.1337 +	    newAttribute = sftk_NewAttribute( destObject,
  1.1338 +				sftk_attr_expand(&attribute->attrib));
  1.1339 +	    sftk_FreeAttribute(attribute); /* free the old attribute */
  1.1340 +	    if (!newAttribute) {
  1.1341 +		return CKR_HOST_MEMORY;
  1.1342 +	    }
  1.1343 +	    sftk_AddAttribute(destObject,newAttribute);
  1.1344 +	}
  1.1345 +    }
  1.1346 +    return crv;
  1.1347 +}
  1.1348 +
  1.1349 +CK_RV
  1.1350 +stfk_CopyTokenPrivateKey(SFTKObject *destObject,SFTKTokenObject *src_to)
  1.1351 +{
  1.1352 +    CK_RV crv;
  1.1353 +    CK_KEY_TYPE key_type;
  1.1354 +    SFTKAttribute *attribute;
  1.1355 +
  1.1356 +    /* copy the common attributes for all keys first */
  1.1357 +    crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
  1.1358 +							commonKeyAttrsCount);
  1.1359 +    if (crv != CKR_OK) {
  1.1360 +	goto fail;
  1.1361 +    }
  1.1362 +    /* copy the common attributes for all private keys next */
  1.1363 +    crv = stfk_CopyTokenAttributes(destObject, src_to, commonPrivKeyAttrs,
  1.1364 +						commonPrivKeyAttrsCount);
  1.1365 +    if (crv != CKR_OK) {
  1.1366 +	goto fail;
  1.1367 +    }
  1.1368 +    attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
  1.1369 +    PORT_Assert(attribute); /* if it wasn't here, ww should have failed
  1.1370 +			     * copying the common attributes */
  1.1371 +    if (!attribute) {
  1.1372 +	/* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
  1.1373 +	 * the fact is, the only reason we couldn't get the attribute would
  1.1374 +	 * be a memory error or database error (an error in the 'device').
  1.1375 +	 * if we have a database error code, we could return it here */
  1.1376 +	crv = CKR_DEVICE_ERROR;
  1.1377 +	goto fail;
  1.1378 +    }
  1.1379 +    key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
  1.1380 +    sftk_FreeAttribute(attribute);
  1.1381 +    
  1.1382 +    /* finally copy the attributes for various private key types */
  1.1383 +    switch (key_type) {
  1.1384 +    case CKK_RSA:
  1.1385 +	crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPrivKeyAttrs,
  1.1386 +							rsaPrivKeyAttrsCount);
  1.1387 +	break;
  1.1388 +    case CKK_DSA:
  1.1389 +	crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPrivKeyAttrs,
  1.1390 +							dsaPrivKeyAttrsCount);
  1.1391 +	break;
  1.1392 +    case CKK_DH:
  1.1393 +	crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs,
  1.1394 +							dhPrivKeyAttrsCount);
  1.1395 +	break;
  1.1396 +#ifndef NSS_DISABLE_ECC
  1.1397 +    case CKK_EC:
  1.1398 +	crv = stfk_CopyTokenAttributes(destObject, src_to, ecPrivKeyAttrs,
  1.1399 +							ecPrivKeyAttrsCount);
  1.1400 +	break;
  1.1401 +#endif
  1.1402 +     default:
  1.1403 +	crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
  1.1404 +				* of token keys into our database. */
  1.1405 +    }
  1.1406 +fail:
  1.1407 +    return crv;
  1.1408 +}
  1.1409 +
  1.1410 +CK_RV
  1.1411 +stfk_CopyTokenPublicKey(SFTKObject *destObject,SFTKTokenObject *src_to)
  1.1412 +{
  1.1413 +    CK_RV crv;
  1.1414 +    CK_KEY_TYPE key_type;
  1.1415 +    SFTKAttribute *attribute;
  1.1416 +
  1.1417 +    /* copy the common attributes for all keys first */
  1.1418 +    crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
  1.1419 +							commonKeyAttrsCount);
  1.1420 +    if (crv != CKR_OK) {
  1.1421 +	goto fail;
  1.1422 +    }
  1.1423 +
  1.1424 +    /* copy the common attributes for all public keys next */
  1.1425 +    crv = stfk_CopyTokenAttributes(destObject, src_to, commonPubKeyAttrs,
  1.1426 +							commonPubKeyAttrsCount);
  1.1427 +    if (crv != CKR_OK) {
  1.1428 +	goto fail;
  1.1429 +    }
  1.1430 +    attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
  1.1431 +    PORT_Assert(attribute); /* if it wasn't here, ww should have failed
  1.1432 +			     * copying the common attributes */
  1.1433 +    if (!attribute) {
  1.1434 +	/* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
  1.1435 +	 * the fact is, the only reason we couldn't get the attribute would
  1.1436 +	 * be a memory error or database error (an error in the 'device').
  1.1437 +	 * if we have a database error code, we could return it here */
  1.1438 +	crv = CKR_DEVICE_ERROR;
  1.1439 +	goto fail;
  1.1440 +    }
  1.1441 +    key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
  1.1442 +    sftk_FreeAttribute(attribute);
  1.1443 +    
  1.1444 +    /* finally copy the attributes for various public key types */
  1.1445 +    switch (key_type) {
  1.1446 +    case CKK_RSA:
  1.1447 +	crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPubKeyAttrs,
  1.1448 +							rsaPubKeyAttrsCount);
  1.1449 +	break;
  1.1450 +    case CKK_DSA:
  1.1451 +	crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPubKeyAttrs,
  1.1452 +							dsaPubKeyAttrsCount);
  1.1453 +	break;
  1.1454 +    case CKK_DH:
  1.1455 +	crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs,
  1.1456 +							dhPubKeyAttrsCount);
  1.1457 +	break;
  1.1458 +#ifndef NSS_DISABLE_ECC
  1.1459 +    case CKK_EC:
  1.1460 +	crv = stfk_CopyTokenAttributes(destObject, src_to, ecPubKeyAttrs,
  1.1461 +							ecPubKeyAttrsCount);
  1.1462 +	break;
  1.1463 +#endif
  1.1464 +     default:
  1.1465 +	crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
  1.1466 +				* of token keys into our database. */
  1.1467 +    }
  1.1468 +fail:
  1.1469 +    return crv;
  1.1470 +}
  1.1471 +CK_RV
  1.1472 +stfk_CopyTokenSecretKey(SFTKObject *destObject,SFTKTokenObject *src_to)
  1.1473 +{
  1.1474 +    CK_RV crv;
  1.1475 +    crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
  1.1476 +							commonKeyAttrsCount);
  1.1477 +    if (crv != CKR_OK) {
  1.1478 +	goto fail;
  1.1479 +    }
  1.1480 +    crv = stfk_CopyTokenAttributes(destObject, src_to, secretKeyAttrs,
  1.1481 +							secretKeyAttrsCount);
  1.1482 +fail:
  1.1483 +    return crv;
  1.1484 +}
  1.1485 +
  1.1486 +/*
  1.1487 + * Copy a token object. We need to explicitly copy the relevant
  1.1488 + * attributes since token objects don't store those attributes in
  1.1489 + * the token itself.
  1.1490 + */
  1.1491 +CK_RV
  1.1492 +sftk_CopyTokenObject(SFTKObject *destObject,SFTKObject *srcObject)
  1.1493 +{
  1.1494 +    SFTKTokenObject *src_to = sftk_narrowToTokenObject(srcObject);
  1.1495 +    CK_RV crv;
  1.1496 +
  1.1497 +    PORT_Assert(src_to);
  1.1498 +    if (src_to == NULL) {
  1.1499 +	return CKR_DEVICE_ERROR; /* internal state inconsistant */
  1.1500 +    }
  1.1501 +
  1.1502 +    crv = stfk_CopyTokenAttributes(destObject, src_to, commonAttrs,
  1.1503 +							commonAttrsCount);
  1.1504 +    if (crv != CKR_OK) {
  1.1505 +	goto fail;
  1.1506 +    }
  1.1507 +    switch (src_to->obj.objclass) {
  1.1508 +    case CKO_CERTIFICATE:
  1.1509 +	crv = stfk_CopyTokenAttributes(destObject, src_to, certAttrs,
  1.1510 +							certAttrsCount);
  1.1511 + 	break;
  1.1512 +    case CKO_NETSCAPE_TRUST:
  1.1513 +	crv = stfk_CopyTokenAttributes(destObject, src_to, trustAttrs,
  1.1514 +							trustAttrsCount);
  1.1515 +	break;
  1.1516 +    case CKO_NETSCAPE_SMIME:
  1.1517 +	crv = stfk_CopyTokenAttributes(destObject, src_to, smimeAttrs,
  1.1518 +							smimeAttrsCount);
  1.1519 +	break;
  1.1520 +    case CKO_NETSCAPE_CRL:
  1.1521 +	crv = stfk_CopyTokenAttributes(destObject, src_to, crlAttrs,
  1.1522 +							crlAttrsCount);
  1.1523 +	break;
  1.1524 +    case CKO_PRIVATE_KEY:
  1.1525 +	crv = stfk_CopyTokenPrivateKey(destObject,src_to);
  1.1526 +	break;
  1.1527 +    case CKO_PUBLIC_KEY:
  1.1528 +	crv = stfk_CopyTokenPublicKey(destObject,src_to);
  1.1529 +	break;
  1.1530 +    case CKO_SECRET_KEY:
  1.1531 +	crv = stfk_CopyTokenSecretKey(destObject,src_to);
  1.1532 +	break;
  1.1533 +    default:
  1.1534 +	crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
  1.1535 +				* of token keys into our database. */
  1.1536 +    }
  1.1537 +fail:
  1.1538 +    return crv;
  1.1539 +}
  1.1540 +
  1.1541 +/*
  1.1542 + * copy the attributes from one object to another. Don't overwrite existing
  1.1543 + * attributes. NOTE: This is a pretty expensive operation since it
  1.1544 + * grabs the attribute locks for the src object for a *long* time.
  1.1545 + */
  1.1546 +CK_RV
  1.1547 +sftk_CopyObject(SFTKObject *destObject,SFTKObject *srcObject)
  1.1548 +{
  1.1549 +    SFTKAttribute *attribute;
  1.1550 +    SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);
  1.1551 +    unsigned int i;
  1.1552 +
  1.1553 +    if (src_so == NULL) {
  1.1554 +	return sftk_CopyTokenObject(destObject,srcObject); 
  1.1555 +    }
  1.1556 +
  1.1557 +    PZ_Lock(src_so->attributeLock);
  1.1558 +    for(i=0; i < src_so->hashSize; i++) {
  1.1559 +	attribute = src_so->head[i];
  1.1560 +	do {
  1.1561 +	    if (attribute) {
  1.1562 +		if (!sftk_hasAttribute(destObject,attribute->handle)) {
  1.1563 +		    /* we need to copy the attribute since each attribute
  1.1564 +		     * only has one set of link list pointers */
  1.1565 +		    SFTKAttribute *newAttribute = sftk_NewAttribute(
  1.1566 +			  destObject,sftk_attr_expand(&attribute->attrib));
  1.1567 +		    if (newAttribute == NULL) {
  1.1568 +			PZ_Unlock(src_so->attributeLock);
  1.1569 +			return CKR_HOST_MEMORY;
  1.1570 +		    }
  1.1571 +		    sftk_AddAttribute(destObject,newAttribute);
  1.1572 +		}
  1.1573 +		attribute=attribute->next;
  1.1574 +	    }
  1.1575 +	} while (attribute != NULL);
  1.1576 +    }
  1.1577 +    PZ_Unlock(src_so->attributeLock);
  1.1578 +
  1.1579 +    return CKR_OK;
  1.1580 +}
  1.1581 +
  1.1582 +/*
  1.1583 + * ******************** Search Utilities *******************************
  1.1584 + */
  1.1585 +
  1.1586 +/* add an object to a search list */
  1.1587 +CK_RV
  1.1588 +AddToList(SFTKObjectListElement **list,SFTKObject *object)
  1.1589 +{
  1.1590 +     SFTKObjectListElement *newElem = 
  1.1591 +	(SFTKObjectListElement *)PORT_Alloc(sizeof(SFTKObjectListElement));
  1.1592 +
  1.1593 +     if (newElem == NULL) return CKR_HOST_MEMORY;
  1.1594 +
  1.1595 +     newElem->next = *list;
  1.1596 +     newElem->object = object;
  1.1597 +     sftk_ReferenceObject(object);
  1.1598 +
  1.1599 +    *list = newElem;
  1.1600 +    return CKR_OK;
  1.1601 +}
  1.1602 +
  1.1603 +
  1.1604 +/* return true if the object matches the template */
  1.1605 +PRBool
  1.1606 +sftk_objectMatch(SFTKObject *object,CK_ATTRIBUTE_PTR theTemplate,int count)
  1.1607 +{
  1.1608 +    int i;
  1.1609 +
  1.1610 +    for (i=0; i < count; i++) {
  1.1611 +	SFTKAttribute *attribute = sftk_FindAttribute(object,theTemplate[i].type);
  1.1612 +	if (attribute == NULL) {
  1.1613 +	    return PR_FALSE;
  1.1614 +	}
  1.1615 +	if (attribute->attrib.ulValueLen == theTemplate[i].ulValueLen) {
  1.1616 +	    if (PORT_Memcmp(attribute->attrib.pValue,theTemplate[i].pValue,
  1.1617 +					theTemplate[i].ulValueLen) == 0) {
  1.1618 +        	sftk_FreeAttribute(attribute);
  1.1619 +		continue;
  1.1620 +	    }
  1.1621 +	}
  1.1622 +        sftk_FreeAttribute(attribute);
  1.1623 +	return PR_FALSE;
  1.1624 +    }
  1.1625 +    return PR_TRUE;
  1.1626 +}
  1.1627 +
  1.1628 +/* search through all the objects in the queue and return the template matches
  1.1629 + * in the object list.
  1.1630 + */
  1.1631 +CK_RV
  1.1632 +sftk_searchObjectList(SFTKSearchResults *search,SFTKObject **head, 
  1.1633 +	unsigned int size, PZLock *lock, CK_ATTRIBUTE_PTR theTemplate, 
  1.1634 +						int count, PRBool isLoggedIn)
  1.1635 +{
  1.1636 +    unsigned int i;
  1.1637 +    SFTKObject *object;
  1.1638 +    CK_RV crv = CKR_OK;
  1.1639 +
  1.1640 +    for(i=0; i < size; i++) {
  1.1641 +        /* We need to hold the lock to copy a consistant version of
  1.1642 +         * the linked list. */
  1.1643 +        PZ_Lock(lock);
  1.1644 +	for (object = head[i]; object != NULL; object= object->next) {
  1.1645 +	    if (sftk_objectMatch(object,theTemplate,count)) {
  1.1646 +		/* don't return objects that aren't yet visible */
  1.1647 +		if ((!isLoggedIn) && sftk_isTrue(object,CKA_PRIVATE)) continue;
  1.1648 +		sftk_addHandle(search,object->handle);
  1.1649 +	    }
  1.1650 +	}
  1.1651 +        PZ_Unlock(lock);
  1.1652 +    }
  1.1653 +    return crv;
  1.1654 +}
  1.1655 +
  1.1656 +/*
  1.1657 + * free a single list element. Return the Next object in the list.
  1.1658 + */
  1.1659 +SFTKObjectListElement *
  1.1660 +sftk_FreeObjectListElement(SFTKObjectListElement *objectList)
  1.1661 +{
  1.1662 +    SFTKObjectListElement *ol = objectList->next;
  1.1663 +
  1.1664 +    sftk_FreeObject(objectList->object);
  1.1665 +    PORT_Free(objectList);
  1.1666 +    return ol;
  1.1667 +}
  1.1668 +
  1.1669 +/* free an entire object list */
  1.1670 +void
  1.1671 +sftk_FreeObjectList(SFTKObjectListElement *objectList)
  1.1672 +{
  1.1673 +    SFTKObjectListElement *ol;
  1.1674 +
  1.1675 +    for (ol= objectList; ol != NULL; ol = sftk_FreeObjectListElement(ol)) {}
  1.1676 +}
  1.1677 +
  1.1678 +/*
  1.1679 + * free a search structure
  1.1680 + */
  1.1681 +void
  1.1682 +sftk_FreeSearch(SFTKSearchResults *search)
  1.1683 +{
  1.1684 +    if (search->handles) {
  1.1685 +	PORT_Free(search->handles);
  1.1686 +    }
  1.1687 +    PORT_Free(search);
  1.1688 +}
  1.1689 +
  1.1690 +/*
  1.1691 + * ******************** Session Utilities *******************************
  1.1692 + */
  1.1693 +
  1.1694 +/* update the sessions state based in it's flags and wether or not it's
  1.1695 + * logged in */
  1.1696 +void
  1.1697 +sftk_update_state(SFTKSlot *slot,SFTKSession *session)
  1.1698 +{
  1.1699 +    if (slot->isLoggedIn) {
  1.1700 +	if (slot->ssoLoggedIn) {
  1.1701 +    	    session->info.state = CKS_RW_SO_FUNCTIONS;
  1.1702 +	} else if (session->info.flags & CKF_RW_SESSION) {
  1.1703 +    	    session->info.state = CKS_RW_USER_FUNCTIONS;
  1.1704 +	} else {
  1.1705 +    	    session->info.state = CKS_RO_USER_FUNCTIONS;
  1.1706 +	}
  1.1707 +    } else {
  1.1708 +	if (session->info.flags & CKF_RW_SESSION) {
  1.1709 +    	    session->info.state = CKS_RW_PUBLIC_SESSION;
  1.1710 +	} else {
  1.1711 +    	    session->info.state = CKS_RO_PUBLIC_SESSION;
  1.1712 +	}
  1.1713 +    }
  1.1714 +}
  1.1715 +
  1.1716 +/* update the state of all the sessions on a slot */
  1.1717 +void
  1.1718 +sftk_update_all_states(SFTKSlot *slot)
  1.1719 +{
  1.1720 +    unsigned int i;
  1.1721 +    SFTKSession *session;
  1.1722 +
  1.1723 +    for (i=0; i < slot->sessHashSize; i++) {
  1.1724 +	PZLock *lock = SFTK_SESSION_LOCK(slot,i);
  1.1725 +	PZ_Lock(lock);
  1.1726 +	for (session = slot->head[i]; session; session = session->next) {
  1.1727 +	    sftk_update_state(slot,session);
  1.1728 +	}
  1.1729 +	PZ_Unlock(lock);
  1.1730 +    }
  1.1731 +}
  1.1732 +
  1.1733 +/*
  1.1734 + * context are cipher and digest contexts that are associated with a session
  1.1735 + */
  1.1736 +void
  1.1737 +sftk_FreeContext(SFTKSessionContext *context)
  1.1738 +{
  1.1739 +    if (context->cipherInfo) {
  1.1740 +	(*context->destroy)(context->cipherInfo,PR_TRUE);
  1.1741 +    }
  1.1742 +    if (context->hashInfo) {
  1.1743 +	(*context->hashdestroy)(context->hashInfo,PR_TRUE);
  1.1744 +    }
  1.1745 +    if (context->key) {
  1.1746 +	sftk_FreeObject(context->key);
  1.1747 +	context->key = NULL;
  1.1748 +    }
  1.1749 +    PORT_Free(context);
  1.1750 +}
  1.1751 +
  1.1752 +/*
  1.1753 + * create a new nession. NOTE: The session handle is not set, and the
  1.1754 + * session is not added to the slot's session queue.
  1.1755 + */
  1.1756 +SFTKSession *
  1.1757 +sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
  1.1758 +							     CK_FLAGS flags)
  1.1759 +{
  1.1760 +    SFTKSession *session;
  1.1761 +    SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
  1.1762 +
  1.1763 +    if (slot == NULL) return NULL;
  1.1764 +
  1.1765 +    session = (SFTKSession*)PORT_Alloc(sizeof(SFTKSession));
  1.1766 +    if (session == NULL) return NULL;
  1.1767 +
  1.1768 +    session->next = session->prev = NULL;
  1.1769 +    session->refCount = 1;
  1.1770 +    session->enc_context = NULL;
  1.1771 +    session->hash_context = NULL;
  1.1772 +    session->sign_context = NULL;
  1.1773 +    session->search = NULL;
  1.1774 +    session->objectIDCount = 1;
  1.1775 +    session->objectLock = PZ_NewLock(nssILockObject);
  1.1776 +    if (session->objectLock == NULL) {
  1.1777 +	PORT_Free(session);
  1.1778 +	return NULL;
  1.1779 +    }
  1.1780 +    session->objects[0] = NULL;
  1.1781 +
  1.1782 +    session->slot = slot;
  1.1783 +    session->notify = notify;
  1.1784 +    session->appData = pApplication;
  1.1785 +    session->info.flags = flags;
  1.1786 +    session->info.slotID = slotID;
  1.1787 +    session->info.ulDeviceError = 0;
  1.1788 +    sftk_update_state(slot,session);
  1.1789 +    return session;
  1.1790 +}
  1.1791 +
  1.1792 +
  1.1793 +/* free all the data associated with a session. */
  1.1794 +static void
  1.1795 +sftk_DestroySession(SFTKSession *session)
  1.1796 +{
  1.1797 +    SFTKObjectList *op,*next;
  1.1798 +    PORT_Assert(session->refCount == 0);
  1.1799 +
  1.1800 +    /* clean out the attributes */
  1.1801 +    /* since no one is referencing us, it's safe to walk the chain
  1.1802 +     * without a lock */
  1.1803 +    for (op = session->objects[0]; op != NULL; op = next) {
  1.1804 +        next = op->next;
  1.1805 +        /* paranoia */
  1.1806 +	op->next = op->prev = NULL;
  1.1807 +	sftk_DeleteObject(session,op->parent);
  1.1808 +    }
  1.1809 +    PZ_DestroyLock(session->objectLock);
  1.1810 +    if (session->enc_context) {
  1.1811 +	sftk_FreeContext(session->enc_context);
  1.1812 +    }
  1.1813 +    if (session->hash_context) {
  1.1814 +	sftk_FreeContext(session->hash_context);
  1.1815 +    }
  1.1816 +    if (session->sign_context) {
  1.1817 +	sftk_FreeContext(session->sign_context);
  1.1818 +    }
  1.1819 +    if (session->search) {
  1.1820 +	sftk_FreeSearch(session->search);
  1.1821 +    }
  1.1822 +    PORT_Free(session);
  1.1823 +}
  1.1824 +
  1.1825 +
  1.1826 +/*
  1.1827 + * look up a session structure from a session handle
  1.1828 + * generate a reference to it.
  1.1829 + */
  1.1830 +SFTKSession *
  1.1831 +sftk_SessionFromHandle(CK_SESSION_HANDLE handle)
  1.1832 +{
  1.1833 +    SFTKSlot	*slot = sftk_SlotFromSessionHandle(handle);
  1.1834 +    SFTKSession *session;
  1.1835 +    PZLock	*lock;
  1.1836 +    
  1.1837 +    if (!slot) return NULL;
  1.1838 +    lock = SFTK_SESSION_LOCK(slot,handle);
  1.1839 +
  1.1840 +    PZ_Lock(lock);
  1.1841 +    sftkqueue_find(session,handle,slot->head,slot->sessHashSize);
  1.1842 +    if (session) session->refCount++;
  1.1843 +    PZ_Unlock(lock);
  1.1844 +
  1.1845 +    return (session);
  1.1846 +}
  1.1847 +
  1.1848 +/*
  1.1849 + * release a reference to a session handle
  1.1850 + */
  1.1851 +void
  1.1852 +sftk_FreeSession(SFTKSession *session)
  1.1853 +{
  1.1854 +    PRBool destroy = PR_FALSE;
  1.1855 +    SFTKSlot *slot = sftk_SlotFromSession(session);
  1.1856 +    PZLock *lock = SFTK_SESSION_LOCK(slot,session->handle);
  1.1857 +
  1.1858 +    PZ_Lock(lock);
  1.1859 +    if (session->refCount == 1) destroy = PR_TRUE;
  1.1860 +    session->refCount--;
  1.1861 +    PZ_Unlock(lock);
  1.1862 +
  1.1863 +    if (destroy) sftk_DestroySession(session);
  1.1864 +}
  1.1865 +
  1.1866 +void
  1.1867 +sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle)
  1.1868 +{
  1.1869 +    if (search->handles == NULL) {
  1.1870 +	return;
  1.1871 +    }
  1.1872 +    if (search->size >= search->array_size) {
  1.1873 +	search->array_size += NSC_SEARCH_BLOCK_SIZE;
  1.1874 +	search->handles = (CK_OBJECT_HANDLE *) PORT_Realloc(search->handles,
  1.1875 +				 sizeof(CK_OBJECT_HANDLE)* search->array_size);
  1.1876 +	if (search->handles == NULL) {
  1.1877 +	   return;
  1.1878 +	}
  1.1879 +    }
  1.1880 +    search->handles[search->size] = handle;
  1.1881 +    search->size++;
  1.1882 +}
  1.1883 +
  1.1884 +static  CK_RV
  1.1885 +handleToClass(SFTKSlot *slot, CK_OBJECT_HANDLE handle, 
  1.1886 +	      CK_OBJECT_CLASS *objClass)
  1.1887 +{
  1.1888 +    SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, handle);
  1.1889 +    CK_ATTRIBUTE objClassTemplate;
  1.1890 +    CK_RV crv;
  1.1891 +
  1.1892 +    *objClass = CKO_DATA;
  1.1893 +    objClassTemplate.type = CKA_CLASS;
  1.1894 +    objClassTemplate.pValue = objClass;
  1.1895 +    objClassTemplate.ulValueLen = sizeof(*objClass);
  1.1896 +    crv = sftkdb_GetAttributeValue(dbHandle, handle, &objClassTemplate, 1);
  1.1897 +    sftk_freeDB(dbHandle);
  1.1898 +    return crv;
  1.1899 +}
  1.1900 +
  1.1901 +SFTKObject *
  1.1902 +sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle)
  1.1903 +{
  1.1904 +    SFTKObject *object = NULL;
  1.1905 +    SFTKTokenObject *tokObject = NULL;
  1.1906 +    PRBool hasLocks = PR_FALSE;
  1.1907 +    CK_RV crv;
  1.1908 +
  1.1909 +    object = sftk_GetObjectFromList(&hasLocks, PR_FALSE, &tokenObjectList,  0,
  1.1910 +							PR_FALSE);
  1.1911 +    if (object == NULL) {
  1.1912 +	return NULL;
  1.1913 +    }
  1.1914 +    tokObject = (SFTKTokenObject *) object;
  1.1915 +
  1.1916 +    object->handle = handle;
  1.1917 +    /* every object must have a class, if we can't get it, the object
  1.1918 +     * doesn't exist */
  1.1919 +    crv = handleToClass(slot, handle, &object->objclass);
  1.1920 +    if (crv != CKR_OK) {
  1.1921 +	goto loser;
  1.1922 +    }
  1.1923 +    object->slot = slot;
  1.1924 +    object->objectInfo = NULL;
  1.1925 +    object->infoFree = NULL;
  1.1926 +    if (!hasLocks) {
  1.1927 +	object->refLock = PZ_NewLock(nssILockRefLock);
  1.1928 +    }
  1.1929 +    if (object->refLock == NULL) {
  1.1930 +	goto loser;
  1.1931 +    }
  1.1932 +    object->refCount = 1;
  1.1933 +
  1.1934 +    return object;
  1.1935 +loser:
  1.1936 +    if (object) {
  1.1937 +	(void) sftk_DestroyObject(object);
  1.1938 +    }
  1.1939 +    return NULL;
  1.1940 +
  1.1941 +}
  1.1942 +
  1.1943 +SFTKTokenObject *
  1.1944 +sftk_convertSessionToToken(SFTKObject *obj)
  1.1945 +{
  1.1946 +    SECItem *key;
  1.1947 +    SFTKSessionObject *so = (SFTKSessionObject *)obj;
  1.1948 +    SFTKTokenObject *to = sftk_narrowToTokenObject(obj);
  1.1949 +    SECStatus rv;
  1.1950 +
  1.1951 +    sftk_DestroySessionObjectData(so);
  1.1952 +    PZ_DestroyLock(so->attributeLock);
  1.1953 +    if (to == NULL) {
  1.1954 +	return NULL;
  1.1955 +    }
  1.1956 +    sftk_tokenKeyLock(so->obj.slot);
  1.1957 +    key = sftk_lookupTokenKeyByHandle(so->obj.slot,so->obj.handle);
  1.1958 +    if (key == NULL) {
  1.1959 +    	sftk_tokenKeyUnlock(so->obj.slot);
  1.1960 +	return NULL;
  1.1961 +    }
  1.1962 +    rv = SECITEM_CopyItem(NULL,&to->dbKey,key);
  1.1963 +    sftk_tokenKeyUnlock(so->obj.slot);
  1.1964 +    if (rv == SECFailure) {
  1.1965 +	return NULL;
  1.1966 +    }
  1.1967 +
  1.1968 +    return to;
  1.1969 +}
  1.1970 +
  1.1971 +SFTKSessionObject *
  1.1972 +sftk_narrowToSessionObject(SFTKObject *obj)
  1.1973 +{
  1.1974 +    return !sftk_isToken(obj->handle) ? (SFTKSessionObject *)obj : NULL;
  1.1975 +}
  1.1976 +
  1.1977 +SFTKTokenObject *
  1.1978 +sftk_narrowToTokenObject(SFTKObject *obj)
  1.1979 +{
  1.1980 +    return sftk_isToken(obj->handle) ? (SFTKTokenObject *)obj : NULL;
  1.1981 +}
  1.1982 +

mercurial