security/nss/lib/softoken/pkcs11u.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 /*
michael@0 5 * Internal PKCS #11 functions. Should only be called by pkcs11.c
michael@0 6 */
michael@0 7 #include "pkcs11.h"
michael@0 8 #include "pkcs11i.h"
michael@0 9 #include "lowkeyi.h"
michael@0 10 #include "secasn1.h"
michael@0 11 #include "blapi.h"
michael@0 12 #include "secerr.h"
michael@0 13 #include "prnetdb.h" /* for PR_ntohl */
michael@0 14 #include "sftkdb.h"
michael@0 15 #include "softoken.h"
michael@0 16
michael@0 17 /*
michael@0 18 * ******************** Attribute Utilities *******************************
michael@0 19 */
michael@0 20
michael@0 21 /*
michael@0 22 * create a new attribute with type, value, and length. Space is allocated
michael@0 23 * to hold value.
michael@0 24 */
michael@0 25 static SFTKAttribute *
michael@0 26 sftk_NewAttribute(SFTKObject *object,
michael@0 27 CK_ATTRIBUTE_TYPE type, const void *value, CK_ULONG len)
michael@0 28 {
michael@0 29 SFTKAttribute *attribute;
michael@0 30
michael@0 31 SFTKSessionObject *so = sftk_narrowToSessionObject(object);
michael@0 32 int index;
michael@0 33
michael@0 34 if (so == NULL) {
michael@0 35 /* allocate new attribute in a buffer */
michael@0 36 PORT_Assert(0);
michael@0 37 return NULL;
michael@0 38 }
michael@0 39 /*
michael@0 40 * We attempt to keep down contention on Malloc and Arena locks by
michael@0 41 * limiting the number of these calls on high traversed paths. This
michael@0 42 * is done for attributes by 'allocating' them from a pool already
michael@0 43 * allocated by the parent object.
michael@0 44 */
michael@0 45 PZ_Lock(so->attributeLock);
michael@0 46 index = so->nextAttr++;
michael@0 47 PZ_Unlock(so->attributeLock);
michael@0 48 PORT_Assert(index < MAX_OBJS_ATTRS);
michael@0 49 if (index >= MAX_OBJS_ATTRS) return NULL;
michael@0 50
michael@0 51 attribute = &so->attrList[index];
michael@0 52 attribute->attrib.type = type;
michael@0 53 attribute->freeAttr = PR_FALSE;
michael@0 54 attribute->freeData = PR_FALSE;
michael@0 55 if (value) {
michael@0 56 if (len <= ATTR_SPACE) {
michael@0 57 attribute->attrib.pValue = attribute->space;
michael@0 58 } else {
michael@0 59 attribute->attrib.pValue = PORT_Alloc(len);
michael@0 60 attribute->freeData = PR_TRUE;
michael@0 61 }
michael@0 62 if (attribute->attrib.pValue == NULL) {
michael@0 63 return NULL;
michael@0 64 }
michael@0 65 PORT_Memcpy(attribute->attrib.pValue,value,len);
michael@0 66 attribute->attrib.ulValueLen = len;
michael@0 67 } else {
michael@0 68 attribute->attrib.pValue = NULL;
michael@0 69 attribute->attrib.ulValueLen = 0;
michael@0 70 }
michael@0 71 attribute->attrib.type = type;
michael@0 72 attribute->handle = type;
michael@0 73 attribute->next = attribute->prev = NULL;
michael@0 74 return attribute;
michael@0 75 }
michael@0 76
michael@0 77 /*
michael@0 78 * Free up all the memory associated with an attribute. Reference count
michael@0 79 * must be zero to call this.
michael@0 80 */
michael@0 81 static void
michael@0 82 sftk_DestroyAttribute(SFTKAttribute *attribute)
michael@0 83 {
michael@0 84 if (attribute->freeData) {
michael@0 85 if (attribute->attrib.pValue) {
michael@0 86 /* clear out the data in the attribute value... it may have been
michael@0 87 * sensitive data */
michael@0 88 PORT_Memset(attribute->attrib.pValue, 0,
michael@0 89 attribute->attrib.ulValueLen);
michael@0 90 }
michael@0 91 PORT_Free(attribute->attrib.pValue);
michael@0 92 }
michael@0 93 PORT_Free(attribute);
michael@0 94 }
michael@0 95
michael@0 96 /*
michael@0 97 * release a reference to an attribute structure
michael@0 98 */
michael@0 99 void
michael@0 100 sftk_FreeAttribute(SFTKAttribute *attribute)
michael@0 101 {
michael@0 102 if (attribute->freeAttr) {
michael@0 103 sftk_DestroyAttribute(attribute);
michael@0 104 return;
michael@0 105 }
michael@0 106 }
michael@0 107
michael@0 108 static SFTKAttribute *
michael@0 109 sftk_FindTokenAttribute(SFTKTokenObject *object,CK_ATTRIBUTE_TYPE type)
michael@0 110 {
michael@0 111 SFTKAttribute *myattribute = NULL;
michael@0 112 SFTKDBHandle *dbHandle = NULL;
michael@0 113 CK_RV crv = CKR_HOST_MEMORY;
michael@0 114
michael@0 115 myattribute = (SFTKAttribute*)PORT_Alloc(sizeof(SFTKAttribute));
michael@0 116 if (myattribute == NULL) {
michael@0 117 goto loser;
michael@0 118 }
michael@0 119
michael@0 120 dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle);
michael@0 121
michael@0 122 myattribute->handle = type;
michael@0 123 myattribute->attrib.type = type;
michael@0 124 myattribute->attrib.pValue = myattribute->space;
michael@0 125 myattribute->attrib.ulValueLen = ATTR_SPACE;
michael@0 126 myattribute->next = myattribute->prev = NULL;
michael@0 127 myattribute->freeAttr = PR_TRUE;
michael@0 128 myattribute->freeData = PR_FALSE;
michael@0 129
michael@0 130 crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
michael@0 131 &myattribute->attrib, 1);
michael@0 132
michael@0 133 /* attribute is bigger than our attribute space buffer, malloc it */
michael@0 134 if (crv == CKR_BUFFER_TOO_SMALL) {
michael@0 135 myattribute->attrib.pValue = NULL;
michael@0 136 crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
michael@0 137 &myattribute->attrib, 1);
michael@0 138 if (crv != CKR_OK) {
michael@0 139 goto loser;
michael@0 140 }
michael@0 141 myattribute->attrib.pValue = PORT_Alloc(myattribute->attrib.ulValueLen);
michael@0 142 if (myattribute->attrib.pValue == NULL) {
michael@0 143 crv = CKR_HOST_MEMORY;
michael@0 144 goto loser;
michael@0 145 }
michael@0 146 myattribute->freeData = PR_TRUE;
michael@0 147 crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,
michael@0 148 &myattribute->attrib, 1);
michael@0 149 }
michael@0 150 loser:
michael@0 151 if (dbHandle) {
michael@0 152 sftk_freeDB(dbHandle);
michael@0 153 }
michael@0 154 if (crv != CKR_OK) {
michael@0 155 if (myattribute) {
michael@0 156 myattribute->attrib.ulValueLen = 0;
michael@0 157 sftk_FreeAttribute(myattribute);
michael@0 158 myattribute = NULL;
michael@0 159 }
michael@0 160 }
michael@0 161 return myattribute;
michael@0 162 }
michael@0 163
michael@0 164 /*
michael@0 165 * look up and attribute structure from a type and Object structure.
michael@0 166 * The returned attribute is referenced and needs to be freed when
michael@0 167 * it is no longer needed.
michael@0 168 */
michael@0 169 SFTKAttribute *
michael@0 170 sftk_FindAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
michael@0 171 {
michael@0 172 SFTKAttribute *attribute;
michael@0 173 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
michael@0 174
michael@0 175 if (sessObject == NULL) {
michael@0 176 return sftk_FindTokenAttribute(sftk_narrowToTokenObject(object),type);
michael@0 177 }
michael@0 178
michael@0 179 PZ_Lock(sessObject->attributeLock);
michael@0 180 sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize);
michael@0 181 PZ_Unlock(sessObject->attributeLock);
michael@0 182
michael@0 183 return(attribute);
michael@0 184 }
michael@0 185
michael@0 186 /*
michael@0 187 * Take a buffer and it's length and return it's true size in bits;
michael@0 188 */
michael@0 189 unsigned int
michael@0 190 sftk_GetLengthInBits(unsigned char *buf, unsigned int bufLen)
michael@0 191 {
michael@0 192 unsigned int size = bufLen * 8;
michael@0 193 unsigned int i;
michael@0 194
michael@0 195 /* Get the real length in bytes */
michael@0 196 for (i=0; i < bufLen; i++) {
michael@0 197 unsigned char c = *buf++;
michael@0 198 if (c != 0) {
michael@0 199 unsigned char m;
michael@0 200 for (m=0x80; m > 0 ; m = m >> 1) {
michael@0 201 if ((c & m) != 0) {
michael@0 202 break;
michael@0 203 }
michael@0 204 size--;
michael@0 205 }
michael@0 206 break;
michael@0 207 }
michael@0 208 size-=8;
michael@0 209 }
michael@0 210 return size;
michael@0 211 }
michael@0 212
michael@0 213 /*
michael@0 214 * Constrain a big num attribute. to size and padding
michael@0 215 * minLength means length of the object must be greater than equal to minLength
michael@0 216 * maxLength means length of the object must be less than equal to maxLength
michael@0 217 * minMultiple means that object length mod minMultiple must equal 0.
michael@0 218 * all input sizes are in bits.
michael@0 219 * if any constraint is '0' that constraint is not checked.
michael@0 220 */
michael@0 221 CK_RV
michael@0 222 sftk_ConstrainAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
michael@0 223 int minLength, int maxLength, int minMultiple)
michael@0 224 {
michael@0 225 SFTKAttribute *attribute;
michael@0 226 int size;
michael@0 227 unsigned char *ptr;
michael@0 228
michael@0 229 attribute = sftk_FindAttribute(object, type);
michael@0 230 if (!attribute) {
michael@0 231 return CKR_TEMPLATE_INCOMPLETE;
michael@0 232 }
michael@0 233 ptr = (unsigned char *) attribute->attrib.pValue;
michael@0 234 if (ptr == NULL) {
michael@0 235 sftk_FreeAttribute(attribute);
michael@0 236 return CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 237 }
michael@0 238 size = sftk_GetLengthInBits(ptr, attribute->attrib.ulValueLen);
michael@0 239 sftk_FreeAttribute(attribute);
michael@0 240
michael@0 241 if ((minLength != 0) && (size < minLength)) {
michael@0 242 return CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 243 }
michael@0 244 if ((maxLength != 0) && (size > maxLength)) {
michael@0 245 return CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 246 }
michael@0 247 if ((minMultiple != 0) && ((size % minMultiple) != 0)) {
michael@0 248 return CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 249 }
michael@0 250 return CKR_OK;
michael@0 251 }
michael@0 252
michael@0 253 PRBool
michael@0 254 sftk_hasAttributeToken(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)
michael@0 255 {
michael@0 256 CK_ATTRIBUTE template;
michael@0 257 CK_RV crv;
michael@0 258 SFTKDBHandle *dbHandle;
michael@0 259
michael@0 260 dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle);
michael@0 261 template.type = type;
michael@0 262 template.pValue = NULL;
michael@0 263 template.ulValueLen = 0;
michael@0 264
michael@0 265 crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, &template, 1);
michael@0 266 sftk_freeDB(dbHandle);
michael@0 267
michael@0 268 /* attribute is bigger than our attribute space buffer, malloc it */
michael@0 269 return (crv == CKR_OK) ? PR_TRUE : PR_FALSE;
michael@0 270 }
michael@0 271
michael@0 272 /*
michael@0 273 * return true if object has attribute
michael@0 274 */
michael@0 275 PRBool
michael@0 276 sftk_hasAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
michael@0 277 {
michael@0 278 SFTKAttribute *attribute;
michael@0 279 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
michael@0 280
michael@0 281 if (sessObject == NULL) {
michael@0 282 return sftk_hasAttributeToken(sftk_narrowToTokenObject(object), type);
michael@0 283 }
michael@0 284
michael@0 285 PZ_Lock(sessObject->attributeLock);
michael@0 286 sftkqueue_find(attribute,type,sessObject->head, sessObject->hashSize);
michael@0 287 PZ_Unlock(sessObject->attributeLock);
michael@0 288
michael@0 289 return (PRBool)(attribute != NULL);
michael@0 290 }
michael@0 291
michael@0 292 /*
michael@0 293 * add an attribute to an object
michael@0 294 */
michael@0 295 static void
michael@0 296 sftk_AddAttribute(SFTKObject *object,SFTKAttribute *attribute)
michael@0 297 {
michael@0 298 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
michael@0 299
michael@0 300 if (sessObject == NULL) return;
michael@0 301 PZ_Lock(sessObject->attributeLock);
michael@0 302 sftkqueue_add(attribute,attribute->handle,
michael@0 303 sessObject->head, sessObject->hashSize);
michael@0 304 PZ_Unlock(sessObject->attributeLock);
michael@0 305 }
michael@0 306
michael@0 307 /*
michael@0 308 * copy an unsigned attribute into a SECItem. Secitem is allocated in
michael@0 309 * the specified arena.
michael@0 310 */
michael@0 311 CK_RV
michael@0 312 sftk_Attribute2SSecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object,
michael@0 313 CK_ATTRIBUTE_TYPE type)
michael@0 314 {
michael@0 315 SFTKAttribute *attribute;
michael@0 316
michael@0 317 item->data = NULL;
michael@0 318
michael@0 319 attribute = sftk_FindAttribute(object, type);
michael@0 320 if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
michael@0 321
michael@0 322 (void)SECITEM_AllocItem(arena, item, attribute->attrib.ulValueLen);
michael@0 323 if (item->data == NULL) {
michael@0 324 sftk_FreeAttribute(attribute);
michael@0 325 return CKR_HOST_MEMORY;
michael@0 326 }
michael@0 327 PORT_Memcpy(item->data, attribute->attrib.pValue, item->len);
michael@0 328 sftk_FreeAttribute(attribute);
michael@0 329 return CKR_OK;
michael@0 330 }
michael@0 331
michael@0 332 /*
michael@0 333 * fetch multiple attributes into SECItems. Secitem data is allocated in
michael@0 334 * the specified arena.
michael@0 335 */
michael@0 336 CK_RV
michael@0 337 sftk_MultipleAttribute2SecItem(PLArenaPool *arena, SFTKObject *object,
michael@0 338 SFTKItemTemplate *itemTemplate, int itemTemplateCount)
michael@0 339 {
michael@0 340
michael@0 341 CK_RV crv = CKR_OK;
michael@0 342 CK_ATTRIBUTE templateSpace[SFTK_MAX_ITEM_TEMPLATE];
michael@0 343 CK_ATTRIBUTE *template;
michael@0 344 SFTKTokenObject *tokObject;
michael@0 345 SFTKDBHandle *dbHandle = NULL;
michael@0 346 int i;
michael@0 347
michael@0 348 tokObject = sftk_narrowToTokenObject(object);
michael@0 349
michael@0 350 /* session objects, just loop through the list */
michael@0 351 if (tokObject == NULL) {
michael@0 352 for (i=0; i < itemTemplateCount; i++) {
michael@0 353 crv = sftk_Attribute2SecItem(arena,itemTemplate[i].item, object,
michael@0 354 itemTemplate[i].type);
michael@0 355 if (crv != CKR_OK) {
michael@0 356 return crv;
michael@0 357 }
michael@0 358 }
michael@0 359 return CKR_OK;
michael@0 360 }
michael@0 361
michael@0 362 /* don't do any work if none is required */
michael@0 363 if (itemTemplateCount == 0) {
michael@0 364 return CKR_OK;
michael@0 365 }
michael@0 366
michael@0 367 /* don't allocate the template unless we need it */
michael@0 368 if (itemTemplateCount > SFTK_MAX_ITEM_TEMPLATE) {
michael@0 369 template = PORT_NewArray(CK_ATTRIBUTE, itemTemplateCount);
michael@0 370 } else {
michael@0 371 template = templateSpace;
michael@0 372 }
michael@0 373
michael@0 374 if (template == NULL) {
michael@0 375 crv = CKR_HOST_MEMORY;
michael@0 376 goto loser;
michael@0 377 }
michael@0 378
michael@0 379 dbHandle = sftk_getDBForTokenObject(object->slot, object->handle);
michael@0 380 if (dbHandle == NULL) {
michael@0 381 crv = CKR_OBJECT_HANDLE_INVALID;
michael@0 382 goto loser;
michael@0 383 }
michael@0 384
michael@0 385 /* set up the PKCS #11 template */
michael@0 386 for (i=0; i < itemTemplateCount; i++) {
michael@0 387 template[i].type = itemTemplate[i].type;
michael@0 388 template[i].pValue = NULL;
michael@0 389 template[i].ulValueLen = 0;
michael@0 390 }
michael@0 391
michael@0 392 /* fetch the attribute lengths */
michael@0 393 crv = sftkdb_GetAttributeValue(dbHandle, object->handle,
michael@0 394 template, itemTemplateCount);
michael@0 395 if (crv != CKR_OK) {
michael@0 396 goto loser;
michael@0 397 }
michael@0 398
michael@0 399 /* allocate space for the attributes */
michael@0 400 for (i=0; i < itemTemplateCount ; i++) {
michael@0 401 template[i].pValue = PORT_ArenaAlloc(arena, template[i].ulValueLen);
michael@0 402 if (template[i].pValue == NULL) {
michael@0 403 crv = CKR_HOST_MEMORY;
michael@0 404 goto loser;
michael@0 405 }
michael@0 406 }
michael@0 407
michael@0 408 /* fetch the attributes */
michael@0 409 crv = sftkdb_GetAttributeValue(dbHandle, object->handle,
michael@0 410 template, itemTemplateCount);
michael@0 411 if (crv != CKR_OK) {
michael@0 412 goto loser;
michael@0 413 }
michael@0 414
michael@0 415 /* Fill in the items */
michael@0 416 for (i=0; i < itemTemplateCount; i++) {
michael@0 417 itemTemplate[i].item->data = template[i].pValue;
michael@0 418 itemTemplate[i].item->len = template[i].ulValueLen;
michael@0 419 }
michael@0 420
michael@0 421 loser:
michael@0 422 if (template != templateSpace) {
michael@0 423 PORT_Free(template);
michael@0 424 }
michael@0 425 if (dbHandle) {
michael@0 426 sftk_freeDB(dbHandle);
michael@0 427 }
michael@0 428
michael@0 429 return crv;
michael@0 430 }
michael@0 431
michael@0 432
michael@0 433 /*
michael@0 434 * delete an attribute from an object
michael@0 435 */
michael@0 436 static void
michael@0 437 sftk_DeleteAttribute(SFTKObject *object, SFTKAttribute *attribute)
michael@0 438 {
michael@0 439 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
michael@0 440
michael@0 441 if (sessObject == NULL) {
michael@0 442 return ;
michael@0 443 }
michael@0 444 PZ_Lock(sessObject->attributeLock);
michael@0 445 if (sftkqueue_is_queued(attribute,attribute->handle,
michael@0 446 sessObject->head, sessObject->hashSize)) {
michael@0 447 sftkqueue_delete(attribute,attribute->handle,
michael@0 448 sessObject->head, sessObject->hashSize);
michael@0 449 }
michael@0 450 PZ_Unlock(sessObject->attributeLock);
michael@0 451 }
michael@0 452
michael@0 453 /*
michael@0 454 * this is only valid for CK_BBOOL type attributes. Return the state
michael@0 455 * of that attribute.
michael@0 456 */
michael@0 457 PRBool
michael@0 458 sftk_isTrue(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
michael@0 459 {
michael@0 460 SFTKAttribute *attribute;
michael@0 461 PRBool tok = PR_FALSE;
michael@0 462
michael@0 463 attribute=sftk_FindAttribute(object,type);
michael@0 464 if (attribute == NULL) { return PR_FALSE; }
michael@0 465 tok = (PRBool)(*(CK_BBOOL *)attribute->attrib.pValue);
michael@0 466 sftk_FreeAttribute(attribute);
michael@0 467
michael@0 468 return tok;
michael@0 469 }
michael@0 470
michael@0 471 /*
michael@0 472 * force an attribute to null.
michael@0 473 * this is for sensitive keys which are stored in the database, we don't
michael@0 474 * want to keep this info around in memory in the clear.
michael@0 475 */
michael@0 476 void
michael@0 477 sftk_nullAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
michael@0 478 {
michael@0 479 SFTKAttribute *attribute;
michael@0 480
michael@0 481 attribute=sftk_FindAttribute(object,type);
michael@0 482 if (attribute == NULL) return;
michael@0 483
michael@0 484 if (attribute->attrib.pValue != NULL) {
michael@0 485 PORT_Memset(attribute->attrib.pValue,0,attribute->attrib.ulValueLen);
michael@0 486 if (attribute->freeData) {
michael@0 487 PORT_Free(attribute->attrib.pValue);
michael@0 488 }
michael@0 489 attribute->freeData = PR_FALSE;
michael@0 490 attribute->attrib.pValue = NULL;
michael@0 491 attribute->attrib.ulValueLen = 0;
michael@0 492 }
michael@0 493 sftk_FreeAttribute(attribute);
michael@0 494 }
michael@0 495
michael@0 496
michael@0 497 static CK_RV
michael@0 498 sftk_forceTokenAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type,
michael@0 499 const void *value, unsigned int len)
michael@0 500 {
michael@0 501 CK_ATTRIBUTE attribute;
michael@0 502 SFTKDBHandle *dbHandle = NULL;
michael@0 503 SFTKTokenObject *to = sftk_narrowToTokenObject(object);
michael@0 504 CK_RV crv;
michael@0 505
michael@0 506 PORT_Assert(to);
michael@0 507 if (to == NULL) {
michael@0 508 return CKR_DEVICE_ERROR;
michael@0 509 }
michael@0 510
michael@0 511 dbHandle = sftk_getDBForTokenObject(object->slot, object->handle);
michael@0 512
michael@0 513 attribute.type = type;
michael@0 514 attribute.pValue = (void *)value;
michael@0 515 attribute.ulValueLen = len;
michael@0 516
michael@0 517 crv = sftkdb_SetAttributeValue(dbHandle, object, &attribute, 1);
michael@0 518 sftk_freeDB(dbHandle);
michael@0 519 return crv;
michael@0 520 }
michael@0 521
michael@0 522 /*
michael@0 523 * force an attribute to a specifc value.
michael@0 524 */
michael@0 525 CK_RV
michael@0 526 sftk_forceAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type,
michael@0 527 const void *value, unsigned int len)
michael@0 528 {
michael@0 529 SFTKAttribute *attribute;
michael@0 530 void *att_val = NULL;
michael@0 531 PRBool freeData = PR_FALSE;
michael@0 532
michael@0 533 PORT_Assert(object);
michael@0 534 PORT_Assert(object->refCount);
michael@0 535 PORT_Assert(object->slot);
michael@0 536 if (!object ||
michael@0 537 !object->refCount ||
michael@0 538 !object->slot) {
michael@0 539 return CKR_DEVICE_ERROR;
michael@0 540 }
michael@0 541 if (sftk_isToken(object->handle)) {
michael@0 542 return sftk_forceTokenAttribute(object,type,value,len);
michael@0 543 }
michael@0 544 attribute=sftk_FindAttribute(object,type);
michael@0 545 if (attribute == NULL) return sftk_AddAttributeType(object,type,value,len);
michael@0 546
michael@0 547
michael@0 548 if (value) {
michael@0 549 if (len <= ATTR_SPACE) {
michael@0 550 att_val = attribute->space;
michael@0 551 } else {
michael@0 552 att_val = PORT_Alloc(len);
michael@0 553 freeData = PR_TRUE;
michael@0 554 }
michael@0 555 if (att_val == NULL) {
michael@0 556 return CKR_HOST_MEMORY;
michael@0 557 }
michael@0 558 if (attribute->attrib.pValue == att_val) {
michael@0 559 PORT_Memset(attribute->attrib.pValue,0,
michael@0 560 attribute->attrib.ulValueLen);
michael@0 561 }
michael@0 562 PORT_Memcpy(att_val,value,len);
michael@0 563 }
michael@0 564 if (attribute->attrib.pValue != NULL) {
michael@0 565 if (attribute->attrib.pValue != att_val) {
michael@0 566 PORT_Memset(attribute->attrib.pValue,0,
michael@0 567 attribute->attrib.ulValueLen);
michael@0 568 }
michael@0 569 if (attribute->freeData) {
michael@0 570 PORT_Free(attribute->attrib.pValue);
michael@0 571 }
michael@0 572 attribute->freeData = PR_FALSE;
michael@0 573 attribute->attrib.pValue = NULL;
michael@0 574 attribute->attrib.ulValueLen = 0;
michael@0 575 }
michael@0 576 if (att_val) {
michael@0 577 attribute->attrib.pValue = att_val;
michael@0 578 attribute->attrib.ulValueLen = len;
michael@0 579 attribute->freeData = freeData;
michael@0 580 }
michael@0 581 sftk_FreeAttribute(attribute);
michael@0 582 return CKR_OK;
michael@0 583 }
michael@0 584
michael@0 585 /*
michael@0 586 * return a null terminated string from attribute 'type'. This string
michael@0 587 * is allocated and needs to be freed with PORT_Free() When complete.
michael@0 588 */
michael@0 589 char *
michael@0 590 sftk_getString(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
michael@0 591 {
michael@0 592 SFTKAttribute *attribute;
michael@0 593 char *label = NULL;
michael@0 594
michael@0 595 attribute=sftk_FindAttribute(object,type);
michael@0 596 if (attribute == NULL) return NULL;
michael@0 597
michael@0 598 if (attribute->attrib.pValue != NULL) {
michael@0 599 label = (char *) PORT_Alloc(attribute->attrib.ulValueLen+1);
michael@0 600 if (label == NULL) {
michael@0 601 sftk_FreeAttribute(attribute);
michael@0 602 return NULL;
michael@0 603 }
michael@0 604
michael@0 605 PORT_Memcpy(label,attribute->attrib.pValue,
michael@0 606 attribute->attrib.ulValueLen);
michael@0 607 label[attribute->attrib.ulValueLen] = 0;
michael@0 608 }
michael@0 609 sftk_FreeAttribute(attribute);
michael@0 610 return label;
michael@0 611 }
michael@0 612
michael@0 613 /*
michael@0 614 * decode when a particular attribute may be modified
michael@0 615 * SFTK_NEVER: This attribute must be set at object creation time and
michael@0 616 * can never be modified.
michael@0 617 * SFTK_ONCOPY: This attribute may be modified only when you copy the
michael@0 618 * object.
michael@0 619 * SFTK_SENSITIVE: The CKA_SENSITIVE attribute can only be changed from
michael@0 620 * CK_FALSE to CK_TRUE.
michael@0 621 * SFTK_ALWAYS: This attribute can always be modified.
michael@0 622 * Some attributes vary their modification type based on the class of the
michael@0 623 * object.
michael@0 624 */
michael@0 625 SFTKModifyType
michael@0 626 sftk_modifyType(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
michael@0 627 {
michael@0 628 /* if we don't know about it, user user defined, always allow modify */
michael@0 629 SFTKModifyType mtype = SFTK_ALWAYS;
michael@0 630
michael@0 631 switch(type) {
michael@0 632 /* NEVER */
michael@0 633 case CKA_CLASS:
michael@0 634 case CKA_CERTIFICATE_TYPE:
michael@0 635 case CKA_KEY_TYPE:
michael@0 636 case CKA_MODULUS:
michael@0 637 case CKA_MODULUS_BITS:
michael@0 638 case CKA_PUBLIC_EXPONENT:
michael@0 639 case CKA_PRIVATE_EXPONENT:
michael@0 640 case CKA_PRIME:
michael@0 641 case CKA_SUBPRIME:
michael@0 642 case CKA_BASE:
michael@0 643 case CKA_PRIME_1:
michael@0 644 case CKA_PRIME_2:
michael@0 645 case CKA_EXPONENT_1:
michael@0 646 case CKA_EXPONENT_2:
michael@0 647 case CKA_COEFFICIENT:
michael@0 648 case CKA_VALUE_LEN:
michael@0 649 case CKA_ALWAYS_SENSITIVE:
michael@0 650 case CKA_NEVER_EXTRACTABLE:
michael@0 651 case CKA_NETSCAPE_DB:
michael@0 652 mtype = SFTK_NEVER;
michael@0 653 break;
michael@0 654
michael@0 655 /* ONCOPY */
michael@0 656 case CKA_TOKEN:
michael@0 657 case CKA_PRIVATE:
michael@0 658 case CKA_MODIFIABLE:
michael@0 659 mtype = SFTK_ONCOPY;
michael@0 660 break;
michael@0 661
michael@0 662 /* SENSITIVE */
michael@0 663 case CKA_SENSITIVE:
michael@0 664 case CKA_EXTRACTABLE:
michael@0 665 mtype = SFTK_SENSITIVE;
michael@0 666 break;
michael@0 667
michael@0 668 /* ALWAYS */
michael@0 669 case CKA_LABEL:
michael@0 670 case CKA_APPLICATION:
michael@0 671 case CKA_ID:
michael@0 672 case CKA_SERIAL_NUMBER:
michael@0 673 case CKA_START_DATE:
michael@0 674 case CKA_END_DATE:
michael@0 675 case CKA_DERIVE:
michael@0 676 case CKA_ENCRYPT:
michael@0 677 case CKA_DECRYPT:
michael@0 678 case CKA_SIGN:
michael@0 679 case CKA_VERIFY:
michael@0 680 case CKA_SIGN_RECOVER:
michael@0 681 case CKA_VERIFY_RECOVER:
michael@0 682 case CKA_WRAP:
michael@0 683 case CKA_UNWRAP:
michael@0 684 mtype = SFTK_ALWAYS;
michael@0 685 break;
michael@0 686
michael@0 687 /* DEPENDS ON CLASS */
michael@0 688 case CKA_VALUE:
michael@0 689 mtype = (inClass == CKO_DATA) ? SFTK_ALWAYS : SFTK_NEVER;
michael@0 690 break;
michael@0 691
michael@0 692 case CKA_SUBJECT:
michael@0 693 mtype = (inClass == CKO_CERTIFICATE) ? SFTK_NEVER : SFTK_ALWAYS;
michael@0 694 break;
michael@0 695 default:
michael@0 696 break;
michael@0 697 }
michael@0 698 return mtype;
michael@0 699 }
michael@0 700
michael@0 701 /* decode if a particular attribute is sensitive (cannot be read
michael@0 702 * back to the user of if the object is set to SENSITIVE) */
michael@0 703 PRBool
michael@0 704 sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)
michael@0 705 {
michael@0 706 switch(type) {
michael@0 707 /* ALWAYS */
michael@0 708 case CKA_PRIVATE_EXPONENT:
michael@0 709 case CKA_PRIME_1:
michael@0 710 case CKA_PRIME_2:
michael@0 711 case CKA_EXPONENT_1:
michael@0 712 case CKA_EXPONENT_2:
michael@0 713 case CKA_COEFFICIENT:
michael@0 714 return PR_TRUE;
michael@0 715
michael@0 716 /* DEPENDS ON CLASS */
michael@0 717 case CKA_VALUE:
michael@0 718 /* PRIVATE and SECRET KEYS have SENSITIVE values */
michael@0 719 return (PRBool)((inClass == CKO_PRIVATE_KEY) || (inClass == CKO_SECRET_KEY));
michael@0 720
michael@0 721 default:
michael@0 722 break;
michael@0 723 }
michael@0 724 return PR_FALSE;
michael@0 725 }
michael@0 726
michael@0 727 /*
michael@0 728 * copy an attribute into a SECItem. Secitem is allocated in the specified
michael@0 729 * arena.
michael@0 730 */
michael@0 731 CK_RV
michael@0 732 sftk_Attribute2SecItem(PLArenaPool *arena,SECItem *item,SFTKObject *object,
michael@0 733 CK_ATTRIBUTE_TYPE type)
michael@0 734 {
michael@0 735 int len;
michael@0 736 SFTKAttribute *attribute;
michael@0 737
michael@0 738 attribute = sftk_FindAttribute(object, type);
michael@0 739 if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
michael@0 740 len = attribute->attrib.ulValueLen;
michael@0 741
michael@0 742 if (arena) {
michael@0 743 item->data = (unsigned char *) PORT_ArenaAlloc(arena,len);
michael@0 744 } else {
michael@0 745 item->data = (unsigned char *) PORT_Alloc(len);
michael@0 746 }
michael@0 747 if (item->data == NULL) {
michael@0 748 sftk_FreeAttribute(attribute);
michael@0 749 return CKR_HOST_MEMORY;
michael@0 750 }
michael@0 751 item->len = len;
michael@0 752 PORT_Memcpy(item->data,attribute->attrib.pValue, len);
michael@0 753 sftk_FreeAttribute(attribute);
michael@0 754 return CKR_OK;
michael@0 755 }
michael@0 756
michael@0 757 CK_RV
michael@0 758 sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
michael@0 759 CK_ULONG *longData)
michael@0 760 {
michael@0 761 SFTKAttribute *attribute;
michael@0 762
michael@0 763 attribute = sftk_FindAttribute(object, type);
michael@0 764 if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
michael@0 765
michael@0 766 if (attribute->attrib.ulValueLen != sizeof(CK_ULONG)) {
michael@0 767 return CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 768 }
michael@0 769
michael@0 770 *longData = *(CK_ULONG *)attribute->attrib.pValue;
michael@0 771 sftk_FreeAttribute(attribute);
michael@0 772 return CKR_OK;
michael@0 773 }
michael@0 774
michael@0 775 void
michael@0 776 sftk_DeleteAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type)
michael@0 777 {
michael@0 778 SFTKAttribute *attribute;
michael@0 779 attribute = sftk_FindAttribute(object, type);
michael@0 780 if (attribute == NULL) return ;
michael@0 781 sftk_DeleteAttribute(object,attribute);
michael@0 782 sftk_FreeAttribute(attribute);
michael@0 783 }
michael@0 784
michael@0 785 CK_RV
michael@0 786 sftk_AddAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type,
michael@0 787 const void *valPtr, CK_ULONG length)
michael@0 788 {
michael@0 789 SFTKAttribute *attribute;
michael@0 790 attribute = sftk_NewAttribute(object,type,valPtr,length);
michael@0 791 if (attribute == NULL) { return CKR_HOST_MEMORY; }
michael@0 792 sftk_AddAttribute(object,attribute);
michael@0 793 return CKR_OK;
michael@0 794 }
michael@0 795
michael@0 796 /*
michael@0 797 * ******************** Object Utilities *******************************
michael@0 798 */
michael@0 799
michael@0 800 /* must be called holding sftk_tokenKeyLock(slot) */
michael@0 801 static SECItem *
michael@0 802 sftk_lookupTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle)
michael@0 803 {
michael@0 804 return (SECItem *)PL_HashTableLookup(slot->tokObjHashTable, (void *)handle);
michael@0 805 }
michael@0 806
michael@0 807 /*
michael@0 808 * use the refLock. This operations should be very rare, so the added
michael@0 809 * contention on the ref lock should be lower than the overhead of adding
michael@0 810 * a new lock. We use separate functions for this just in case I'm wrong.
michael@0 811 */
michael@0 812 static void
michael@0 813 sftk_tokenKeyLock(SFTKSlot *slot) {
michael@0 814 SKIP_AFTER_FORK(PZ_Lock(slot->objectLock));
michael@0 815 }
michael@0 816
michael@0 817 static void
michael@0 818 sftk_tokenKeyUnlock(SFTKSlot *slot) {
michael@0 819 SKIP_AFTER_FORK(PZ_Unlock(slot->objectLock));
michael@0 820 }
michael@0 821
michael@0 822 static PRIntn
michael@0 823 sftk_freeHashItem(PLHashEntry* entry, PRIntn index, void *arg)
michael@0 824 {
michael@0 825 SECItem *item = (SECItem *)entry->value;
michael@0 826
michael@0 827 SECITEM_FreeItem(item, PR_TRUE);
michael@0 828 return HT_ENUMERATE_NEXT;
michael@0 829 }
michael@0 830
michael@0 831 CK_RV
michael@0 832 SFTK_ClearTokenKeyHashTable(SFTKSlot *slot)
michael@0 833 {
michael@0 834 sftk_tokenKeyLock(slot);
michael@0 835 PORT_Assert(!slot->present);
michael@0 836 PL_HashTableEnumerateEntries(slot->tokObjHashTable, sftk_freeHashItem, NULL);
michael@0 837 sftk_tokenKeyUnlock(slot);
michael@0 838 return CKR_OK;
michael@0 839 }
michael@0 840
michael@0 841
michael@0 842 /* allocation hooks that allow us to recycle old object structures */
michael@0 843 static SFTKObjectFreeList sessionObjectList = { NULL, NULL, 0 };
michael@0 844 static SFTKObjectFreeList tokenObjectList = { NULL, NULL, 0 };
michael@0 845
michael@0 846 SFTKObject *
michael@0 847 sftk_GetObjectFromList(PRBool *hasLocks, PRBool optimizeSpace,
michael@0 848 SFTKObjectFreeList *list, unsigned int hashSize, PRBool isSessionObject)
michael@0 849 {
michael@0 850 SFTKObject *object;
michael@0 851 int size = 0;
michael@0 852
michael@0 853 if (!optimizeSpace) {
michael@0 854 PZ_Lock(list->lock);
michael@0 855 object = list->head;
michael@0 856 if (object) {
michael@0 857 list->head = object->next;
michael@0 858 list->count--;
michael@0 859 }
michael@0 860 PZ_Unlock(list->lock);
michael@0 861 if (object) {
michael@0 862 object->next = object->prev = NULL;
michael@0 863 *hasLocks = PR_TRUE;
michael@0 864 return object;
michael@0 865 }
michael@0 866 }
michael@0 867 size = isSessionObject ? sizeof(SFTKSessionObject)
michael@0 868 + hashSize *sizeof(SFTKAttribute *) : sizeof(SFTKTokenObject);
michael@0 869
michael@0 870 object = (SFTKObject*)PORT_ZAlloc(size);
michael@0 871 if (isSessionObject && object) {
michael@0 872 ((SFTKSessionObject *)object)->hashSize = hashSize;
michael@0 873 }
michael@0 874 *hasLocks = PR_FALSE;
michael@0 875 return object;
michael@0 876 }
michael@0 877
michael@0 878 static void
michael@0 879 sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list,
michael@0 880 PRBool isSessionObject) {
michael@0 881
michael@0 882 /* the code below is equivalent to :
michael@0 883 * optimizeSpace = isSessionObject ? object->optimizeSpace : PR_FALSE;
michael@0 884 * just faster.
michael@0 885 */
michael@0 886 PRBool optimizeSpace = isSessionObject &&
michael@0 887 ((SFTKSessionObject *)object)->optimizeSpace;
michael@0 888 if (object->refLock && !optimizeSpace
michael@0 889 && (list->count < MAX_OBJECT_LIST_SIZE)) {
michael@0 890 PZ_Lock(list->lock);
michael@0 891 object->next = list->head;
michael@0 892 list->head = object;
michael@0 893 list->count++;
michael@0 894 PZ_Unlock(list->lock);
michael@0 895 return;
michael@0 896 }
michael@0 897 if (isSessionObject) {
michael@0 898 SFTKSessionObject *so = (SFTKSessionObject *)object;
michael@0 899 PZ_DestroyLock(so->attributeLock);
michael@0 900 so->attributeLock = NULL;
michael@0 901 }
michael@0 902 if (object->refLock) {
michael@0 903 PZ_DestroyLock(object->refLock);
michael@0 904 object->refLock = NULL;
michael@0 905 }
michael@0 906 PORT_Free(object);
michael@0 907 }
michael@0 908
michael@0 909 static SFTKObject *
michael@0 910 sftk_freeObjectData(SFTKObject *object) {
michael@0 911 SFTKObject *next = object->next;
michael@0 912
michael@0 913 PORT_Free(object);
michael@0 914 return next;
michael@0 915 }
michael@0 916
michael@0 917 static void
michael@0 918 sftk_InitFreeList(SFTKObjectFreeList *list)
michael@0 919 {
michael@0 920 list->lock = PZ_NewLock(nssILockObject);
michael@0 921 }
michael@0 922
michael@0 923 void sftk_InitFreeLists(void)
michael@0 924 {
michael@0 925 sftk_InitFreeList(&sessionObjectList);
michael@0 926 sftk_InitFreeList(&tokenObjectList);
michael@0 927 }
michael@0 928
michael@0 929 static void
michael@0 930 sftk_CleanupFreeList(SFTKObjectFreeList *list, PRBool isSessionList)
michael@0 931 {
michael@0 932 SFTKObject *object;
michael@0 933
michael@0 934 if (!list->lock) {
michael@0 935 return;
michael@0 936 }
michael@0 937 SKIP_AFTER_FORK(PZ_Lock(list->lock));
michael@0 938 for (object= list->head; object != NULL;
michael@0 939 object = sftk_freeObjectData(object)) {
michael@0 940 PZ_DestroyLock(object->refLock);
michael@0 941 if (isSessionList) {
michael@0 942 PZ_DestroyLock(((SFTKSessionObject *)object)->attributeLock);
michael@0 943 }
michael@0 944 }
michael@0 945 list->count = 0;
michael@0 946 list->head = NULL;
michael@0 947 SKIP_AFTER_FORK(PZ_Unlock(list->lock));
michael@0 948 SKIP_AFTER_FORK(PZ_DestroyLock(list->lock));
michael@0 949 list->lock = NULL;
michael@0 950 }
michael@0 951
michael@0 952 void
michael@0 953 sftk_CleanupFreeLists(void)
michael@0 954 {
michael@0 955 sftk_CleanupFreeList(&sessionObjectList, PR_TRUE);
michael@0 956 sftk_CleanupFreeList(&tokenObjectList, PR_FALSE);
michael@0 957 }
michael@0 958
michael@0 959
michael@0 960 /*
michael@0 961 * Create a new object
michael@0 962 */
michael@0 963 SFTKObject *
michael@0 964 sftk_NewObject(SFTKSlot *slot)
michael@0 965 {
michael@0 966 SFTKObject *object;
michael@0 967 SFTKSessionObject *sessObject;
michael@0 968 PRBool hasLocks = PR_FALSE;
michael@0 969 unsigned int i;
michael@0 970 unsigned int hashSize = 0;
michael@0 971
michael@0 972 hashSize = (slot->optimizeSpace) ? SPACE_ATTRIBUTE_HASH_SIZE :
michael@0 973 TIME_ATTRIBUTE_HASH_SIZE;
michael@0 974
michael@0 975 object = sftk_GetObjectFromList(&hasLocks, slot->optimizeSpace,
michael@0 976 &sessionObjectList, hashSize, PR_TRUE);
michael@0 977 if (object == NULL) {
michael@0 978 return NULL;
michael@0 979 }
michael@0 980 sessObject = (SFTKSessionObject *)object;
michael@0 981 sessObject->nextAttr = 0;
michael@0 982
michael@0 983 for (i=0; i < MAX_OBJS_ATTRS; i++) {
michael@0 984 sessObject->attrList[i].attrib.pValue = NULL;
michael@0 985 sessObject->attrList[i].freeData = PR_FALSE;
michael@0 986 }
michael@0 987 sessObject->optimizeSpace = slot->optimizeSpace;
michael@0 988
michael@0 989 object->handle = 0;
michael@0 990 object->next = object->prev = NULL;
michael@0 991 object->slot = slot;
michael@0 992
michael@0 993 object->refCount = 1;
michael@0 994 sessObject->sessionList.next = NULL;
michael@0 995 sessObject->sessionList.prev = NULL;
michael@0 996 sessObject->sessionList.parent = object;
michael@0 997 sessObject->session = NULL;
michael@0 998 sessObject->wasDerived = PR_FALSE;
michael@0 999 if (!hasLocks) object->refLock = PZ_NewLock(nssILockRefLock);
michael@0 1000 if (object->refLock == NULL) {
michael@0 1001 PORT_Free(object);
michael@0 1002 return NULL;
michael@0 1003 }
michael@0 1004 if (!hasLocks) sessObject->attributeLock = PZ_NewLock(nssILockAttribute);
michael@0 1005 if (sessObject->attributeLock == NULL) {
michael@0 1006 PZ_DestroyLock(object->refLock);
michael@0 1007 PORT_Free(object);
michael@0 1008 return NULL;
michael@0 1009 }
michael@0 1010 for (i=0; i < sessObject->hashSize; i++) {
michael@0 1011 sessObject->head[i] = NULL;
michael@0 1012 }
michael@0 1013 object->objectInfo = NULL;
michael@0 1014 object->infoFree = NULL;
michael@0 1015 return object;
michael@0 1016 }
michael@0 1017
michael@0 1018 static CK_RV
michael@0 1019 sftk_DestroySessionObjectData(SFTKSessionObject *so)
michael@0 1020 {
michael@0 1021 int i;
michael@0 1022
michael@0 1023 for (i=0; i < MAX_OBJS_ATTRS; i++) {
michael@0 1024 unsigned char *value = so->attrList[i].attrib.pValue;
michael@0 1025 if (value) {
michael@0 1026 PORT_Memset(value,0,so->attrList[i].attrib.ulValueLen);
michael@0 1027 if (so->attrList[i].freeData) {
michael@0 1028 PORT_Free(value);
michael@0 1029 }
michael@0 1030 so->attrList[i].attrib.pValue = NULL;
michael@0 1031 so->attrList[i].freeData = PR_FALSE;
michael@0 1032 }
michael@0 1033 }
michael@0 1034 /* PZ_DestroyLock(so->attributeLock);*/
michael@0 1035 return CKR_OK;
michael@0 1036 }
michael@0 1037
michael@0 1038 /*
michael@0 1039 * free all the data associated with an object. Object reference count must
michael@0 1040 * be 'zero'.
michael@0 1041 */
michael@0 1042 static CK_RV
michael@0 1043 sftk_DestroyObject(SFTKObject *object)
michael@0 1044 {
michael@0 1045 CK_RV crv = CKR_OK;
michael@0 1046 SFTKSessionObject *so = sftk_narrowToSessionObject(object);
michael@0 1047 SFTKTokenObject *to = sftk_narrowToTokenObject(object);
michael@0 1048
michael@0 1049 PORT_Assert(object->refCount == 0);
michael@0 1050
michael@0 1051 /* delete the database value */
michael@0 1052 if (to) {
michael@0 1053 if (to->dbKey.data) {
michael@0 1054 PORT_Free(to->dbKey.data);
michael@0 1055 to->dbKey.data = NULL;
michael@0 1056 }
michael@0 1057 }
michael@0 1058 if (so) {
michael@0 1059 sftk_DestroySessionObjectData(so);
michael@0 1060 }
michael@0 1061 if (object->objectInfo) {
michael@0 1062 (*object->infoFree)(object->objectInfo);
michael@0 1063 object->objectInfo = NULL;
michael@0 1064 object->infoFree = NULL;
michael@0 1065 }
michael@0 1066 if (so) {
michael@0 1067 sftk_PutObjectToList(object,&sessionObjectList,PR_TRUE);
michael@0 1068 } else {
michael@0 1069 sftk_PutObjectToList(object,&tokenObjectList,PR_FALSE);
michael@0 1070 }
michael@0 1071 return crv;
michael@0 1072 }
michael@0 1073
michael@0 1074 void
michael@0 1075 sftk_ReferenceObject(SFTKObject *object)
michael@0 1076 {
michael@0 1077 PZ_Lock(object->refLock);
michael@0 1078 object->refCount++;
michael@0 1079 PZ_Unlock(object->refLock);
michael@0 1080 }
michael@0 1081
michael@0 1082 static SFTKObject *
michael@0 1083 sftk_ObjectFromHandleOnSlot(CK_OBJECT_HANDLE handle, SFTKSlot *slot)
michael@0 1084 {
michael@0 1085 SFTKObject *object;
michael@0 1086 PRUint32 index = sftk_hash(handle, slot->sessObjHashSize);
michael@0 1087
michael@0 1088 if (sftk_isToken(handle)) {
michael@0 1089 return sftk_NewTokenObject(slot, NULL, handle);
michael@0 1090 }
michael@0 1091
michael@0 1092 PZ_Lock(slot->objectLock);
michael@0 1093 sftkqueue_find2(object, handle, index, slot->sessObjHashTable);
michael@0 1094 if (object) {
michael@0 1095 sftk_ReferenceObject(object);
michael@0 1096 }
michael@0 1097 PZ_Unlock(slot->objectLock);
michael@0 1098
michael@0 1099 return(object);
michael@0 1100 }
michael@0 1101 /*
michael@0 1102 * look up and object structure from a handle. OBJECT_Handles only make
michael@0 1103 * sense in terms of a given session. make a reference to that object
michael@0 1104 * structure returned.
michael@0 1105 */
michael@0 1106 SFTKObject *
michael@0 1107 sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle, SFTKSession *session)
michael@0 1108 {
michael@0 1109 SFTKSlot *slot = sftk_SlotFromSession(session);
michael@0 1110
michael@0 1111 return sftk_ObjectFromHandleOnSlot(handle,slot);
michael@0 1112 }
michael@0 1113
michael@0 1114
michael@0 1115 /*
michael@0 1116 * release a reference to an object handle
michael@0 1117 */
michael@0 1118 SFTKFreeStatus
michael@0 1119 sftk_FreeObject(SFTKObject *object)
michael@0 1120 {
michael@0 1121 PRBool destroy = PR_FALSE;
michael@0 1122 CK_RV crv;
michael@0 1123
michael@0 1124 PZ_Lock(object->refLock);
michael@0 1125 if (object->refCount == 1) destroy = PR_TRUE;
michael@0 1126 object->refCount--;
michael@0 1127 PZ_Unlock(object->refLock);
michael@0 1128
michael@0 1129 if (destroy) {
michael@0 1130 crv = sftk_DestroyObject(object);
michael@0 1131 if (crv != CKR_OK) {
michael@0 1132 return SFTK_DestroyFailure;
michael@0 1133 }
michael@0 1134 return SFTK_Destroyed;
michael@0 1135 }
michael@0 1136 return SFTK_Busy;
michael@0 1137 }
michael@0 1138
michael@0 1139 /*
michael@0 1140 * add an object to a slot and session queue. These two functions
michael@0 1141 * adopt the object.
michael@0 1142 */
michael@0 1143 void
michael@0 1144 sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object)
michael@0 1145 {
michael@0 1146 PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize);
michael@0 1147 sftkqueue_init_element(object);
michael@0 1148 PZ_Lock(slot->objectLock);
michael@0 1149 sftkqueue_add2(object, object->handle, index, slot->sessObjHashTable);
michael@0 1150 PZ_Unlock(slot->objectLock);
michael@0 1151 }
michael@0 1152
michael@0 1153 void
michael@0 1154 sftk_AddObject(SFTKSession *session, SFTKObject *object)
michael@0 1155 {
michael@0 1156 SFTKSlot *slot = sftk_SlotFromSession(session);
michael@0 1157 SFTKSessionObject *so = sftk_narrowToSessionObject(object);
michael@0 1158
michael@0 1159 if (so) {
michael@0 1160 PZ_Lock(session->objectLock);
michael@0 1161 sftkqueue_add(&so->sessionList,0,session->objects,0);
michael@0 1162 so->session = session;
michael@0 1163 PZ_Unlock(session->objectLock);
michael@0 1164 }
michael@0 1165 sftk_AddSlotObject(slot,object);
michael@0 1166 sftk_ReferenceObject(object);
michael@0 1167 }
michael@0 1168
michael@0 1169 /*
michael@0 1170 * delete an object from a slot and session queue
michael@0 1171 */
michael@0 1172 CK_RV
michael@0 1173 sftk_DeleteObject(SFTKSession *session, SFTKObject *object)
michael@0 1174 {
michael@0 1175 SFTKSlot *slot = sftk_SlotFromSession(session);
michael@0 1176 SFTKSessionObject *so = sftk_narrowToSessionObject(object);
michael@0 1177 SFTKTokenObject *to = sftk_narrowToTokenObject(object);
michael@0 1178 CK_RV crv = CKR_OK;
michael@0 1179 PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize);
michael@0 1180
michael@0 1181 /* Handle Token case */
michael@0 1182 if (so && so->session) {
michael@0 1183 SFTKSession *session = so->session;
michael@0 1184 PZ_Lock(session->objectLock);
michael@0 1185 sftkqueue_delete(&so->sessionList,0,session->objects,0);
michael@0 1186 PZ_Unlock(session->objectLock);
michael@0 1187 PZ_Lock(slot->objectLock);
michael@0 1188 sftkqueue_delete2(object, object->handle, index, slot->sessObjHashTable);
michael@0 1189 PZ_Unlock(slot->objectLock);
michael@0 1190 sftkqueue_clear_deleted_element(object);
michael@0 1191 sftk_FreeObject(object); /* free the reference owned by the queue */
michael@0 1192 } else {
michael@0 1193 SFTKDBHandle *handle = sftk_getDBForTokenObject(slot, object->handle);
michael@0 1194
michael@0 1195 PORT_Assert(to);
michael@0 1196 crv = sftkdb_DestroyObject(handle, object->handle);
michael@0 1197 sftk_freeDB(handle);
michael@0 1198 }
michael@0 1199 return crv;
michael@0 1200 }
michael@0 1201
michael@0 1202 /*
michael@0 1203 * Token objects don't explicitly store their attributes, so we need to know
michael@0 1204 * what attributes make up a particular token object before we can copy it.
michael@0 1205 * below are the tables by object type.
michael@0 1206 */
michael@0 1207 static const CK_ATTRIBUTE_TYPE commonAttrs[] = {
michael@0 1208 CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_MODIFIABLE
michael@0 1209 };
michael@0 1210 static const CK_ULONG commonAttrsCount =
michael@0 1211 sizeof(commonAttrs)/sizeof(commonAttrs[0]);
michael@0 1212
michael@0 1213 static const CK_ATTRIBUTE_TYPE commonKeyAttrs[] = {
michael@0 1214 CKA_ID, CKA_START_DATE, CKA_END_DATE, CKA_DERIVE, CKA_LOCAL, CKA_KEY_TYPE
michael@0 1215 };
michael@0 1216 static const CK_ULONG commonKeyAttrsCount =
michael@0 1217 sizeof(commonKeyAttrs)/sizeof(commonKeyAttrs[0]);
michael@0 1218
michael@0 1219 static const CK_ATTRIBUTE_TYPE secretKeyAttrs[] = {
michael@0 1220 CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN,
michael@0 1221 CKA_VERIFY, CKA_WRAP, CKA_UNWRAP, CKA_VALUE
michael@0 1222 };
michael@0 1223 static const CK_ULONG secretKeyAttrsCount =
michael@0 1224 sizeof(secretKeyAttrs)/sizeof(secretKeyAttrs[0]);
michael@0 1225
michael@0 1226 static const CK_ATTRIBUTE_TYPE commonPubKeyAttrs[] = {
michael@0 1227 CKA_ENCRYPT, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_WRAP, CKA_SUBJECT
michael@0 1228 };
michael@0 1229 static const CK_ULONG commonPubKeyAttrsCount =
michael@0 1230 sizeof(commonPubKeyAttrs)/sizeof(commonPubKeyAttrs[0]);
michael@0 1231
michael@0 1232 static const CK_ATTRIBUTE_TYPE rsaPubKeyAttrs[] = {
michael@0 1233 CKA_MODULUS, CKA_PUBLIC_EXPONENT
michael@0 1234 };
michael@0 1235 static const CK_ULONG rsaPubKeyAttrsCount =
michael@0 1236 sizeof(rsaPubKeyAttrs)/sizeof(rsaPubKeyAttrs[0]);
michael@0 1237
michael@0 1238 static const CK_ATTRIBUTE_TYPE dsaPubKeyAttrs[] = {
michael@0 1239 CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
michael@0 1240 };
michael@0 1241 static const CK_ULONG dsaPubKeyAttrsCount =
michael@0 1242 sizeof(dsaPubKeyAttrs)/sizeof(dsaPubKeyAttrs[0]);
michael@0 1243
michael@0 1244 static const CK_ATTRIBUTE_TYPE dhPubKeyAttrs[] = {
michael@0 1245 CKA_PRIME, CKA_BASE, CKA_VALUE
michael@0 1246 };
michael@0 1247 static const CK_ULONG dhPubKeyAttrsCount =
michael@0 1248 sizeof(dhPubKeyAttrs)/sizeof(dhPubKeyAttrs[0]);
michael@0 1249 #ifndef NSS_DISABLE_ECC
michael@0 1250 static const CK_ATTRIBUTE_TYPE ecPubKeyAttrs[] = {
michael@0 1251 CKA_EC_PARAMS, CKA_EC_POINT
michael@0 1252 };
michael@0 1253 static const CK_ULONG ecPubKeyAttrsCount =
michael@0 1254 sizeof(ecPubKeyAttrs)/sizeof(ecPubKeyAttrs[0]);
michael@0 1255 #endif
michael@0 1256
michael@0 1257 static const CK_ATTRIBUTE_TYPE commonPrivKeyAttrs[] = {
michael@0 1258 CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_SUBJECT,
michael@0 1259 CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NETSCAPE_DB
michael@0 1260 };
michael@0 1261 static const CK_ULONG commonPrivKeyAttrsCount =
michael@0 1262 sizeof(commonPrivKeyAttrs)/sizeof(commonPrivKeyAttrs[0]);
michael@0 1263
michael@0 1264 static const CK_ATTRIBUTE_TYPE rsaPrivKeyAttrs[] = {
michael@0 1265 CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT,
michael@0 1266 CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT
michael@0 1267 };
michael@0 1268 static const CK_ULONG rsaPrivKeyAttrsCount =
michael@0 1269 sizeof(rsaPrivKeyAttrs)/sizeof(rsaPrivKeyAttrs[0]);
michael@0 1270
michael@0 1271 static const CK_ATTRIBUTE_TYPE dsaPrivKeyAttrs[] = {
michael@0 1272 CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE
michael@0 1273 };
michael@0 1274 static const CK_ULONG dsaPrivKeyAttrsCount =
michael@0 1275 sizeof(dsaPrivKeyAttrs)/sizeof(dsaPrivKeyAttrs[0]);
michael@0 1276
michael@0 1277 static const CK_ATTRIBUTE_TYPE dhPrivKeyAttrs[] = {
michael@0 1278 CKA_PRIME, CKA_BASE, CKA_VALUE
michael@0 1279 };
michael@0 1280 static const CK_ULONG dhPrivKeyAttrsCount =
michael@0 1281 sizeof(dhPrivKeyAttrs)/sizeof(dhPrivKeyAttrs[0]);
michael@0 1282 #ifndef NSS_DISABLE_ECC
michael@0 1283 static const CK_ATTRIBUTE_TYPE ecPrivKeyAttrs[] = {
michael@0 1284 CKA_EC_PARAMS, CKA_VALUE
michael@0 1285 };
michael@0 1286 static const CK_ULONG ecPrivKeyAttrsCount =
michael@0 1287 sizeof(ecPrivKeyAttrs)/sizeof(ecPrivKeyAttrs[0]);
michael@0 1288 #endif
michael@0 1289
michael@0 1290 static const CK_ATTRIBUTE_TYPE certAttrs[] = {
michael@0 1291 CKA_CERTIFICATE_TYPE, CKA_VALUE, CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER
michael@0 1292 };
michael@0 1293 static const CK_ULONG certAttrsCount =
michael@0 1294 sizeof(certAttrs)/sizeof(certAttrs[0]);
michael@0 1295
michael@0 1296 static const CK_ATTRIBUTE_TYPE trustAttrs[] = {
michael@0 1297 CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
michael@0 1298 CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_EMAIL_PROTECTION,
michael@0 1299 CKA_TRUST_CODE_SIGNING, CKA_TRUST_STEP_UP_APPROVED
michael@0 1300 };
michael@0 1301 static const CK_ULONG trustAttrsCount =
michael@0 1302 sizeof(trustAttrs)/sizeof(trustAttrs[0]);
michael@0 1303
michael@0 1304 static const CK_ATTRIBUTE_TYPE smimeAttrs[] = {
michael@0 1305 CKA_SUBJECT, CKA_NETSCAPE_EMAIL, CKA_NETSCAPE_SMIME_TIMESTAMP, CKA_VALUE
michael@0 1306 };
michael@0 1307 static const CK_ULONG smimeAttrsCount =
michael@0 1308 sizeof(smimeAttrs)/sizeof(smimeAttrs[0]);
michael@0 1309
michael@0 1310 static const CK_ATTRIBUTE_TYPE crlAttrs[] = {
michael@0 1311 CKA_SUBJECT, CKA_VALUE, CKA_NETSCAPE_URL, CKA_NETSCAPE_KRL
michael@0 1312 };
michael@0 1313 static const CK_ULONG crlAttrsCount =
michael@0 1314 sizeof(crlAttrs)/sizeof(crlAttrs[0]);
michael@0 1315
michael@0 1316 /* copy an object based on it's table */
michael@0 1317 CK_RV
michael@0 1318 stfk_CopyTokenAttributes(SFTKObject *destObject,SFTKTokenObject *src_to,
michael@0 1319 const CK_ATTRIBUTE_TYPE *attrArray, CK_ULONG attrCount)
michael@0 1320 {
michael@0 1321 SFTKAttribute *attribute;
michael@0 1322 SFTKAttribute *newAttribute;
michael@0 1323 CK_RV crv = CKR_OK;
michael@0 1324 unsigned int i;
michael@0 1325
michael@0 1326 for (i=0; i < attrCount; i++) {
michael@0 1327 if (!sftk_hasAttribute(destObject,attrArray[i])) {
michael@0 1328 attribute =sftk_FindAttribute(&src_to->obj, attrArray[i]);
michael@0 1329 if (!attribute) {
michael@0 1330 continue; /* return CKR_ATTRIBUTE_VALUE_INVALID; */
michael@0 1331 }
michael@0 1332 /* we need to copy the attribute since each attribute
michael@0 1333 * only has one set of link list pointers */
michael@0 1334 newAttribute = sftk_NewAttribute( destObject,
michael@0 1335 sftk_attr_expand(&attribute->attrib));
michael@0 1336 sftk_FreeAttribute(attribute); /* free the old attribute */
michael@0 1337 if (!newAttribute) {
michael@0 1338 return CKR_HOST_MEMORY;
michael@0 1339 }
michael@0 1340 sftk_AddAttribute(destObject,newAttribute);
michael@0 1341 }
michael@0 1342 }
michael@0 1343 return crv;
michael@0 1344 }
michael@0 1345
michael@0 1346 CK_RV
michael@0 1347 stfk_CopyTokenPrivateKey(SFTKObject *destObject,SFTKTokenObject *src_to)
michael@0 1348 {
michael@0 1349 CK_RV crv;
michael@0 1350 CK_KEY_TYPE key_type;
michael@0 1351 SFTKAttribute *attribute;
michael@0 1352
michael@0 1353 /* copy the common attributes for all keys first */
michael@0 1354 crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
michael@0 1355 commonKeyAttrsCount);
michael@0 1356 if (crv != CKR_OK) {
michael@0 1357 goto fail;
michael@0 1358 }
michael@0 1359 /* copy the common attributes for all private keys next */
michael@0 1360 crv = stfk_CopyTokenAttributes(destObject, src_to, commonPrivKeyAttrs,
michael@0 1361 commonPrivKeyAttrsCount);
michael@0 1362 if (crv != CKR_OK) {
michael@0 1363 goto fail;
michael@0 1364 }
michael@0 1365 attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
michael@0 1366 PORT_Assert(attribute); /* if it wasn't here, ww should have failed
michael@0 1367 * copying the common attributes */
michael@0 1368 if (!attribute) {
michael@0 1369 /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
michael@0 1370 * the fact is, the only reason we couldn't get the attribute would
michael@0 1371 * be a memory error or database error (an error in the 'device').
michael@0 1372 * if we have a database error code, we could return it here */
michael@0 1373 crv = CKR_DEVICE_ERROR;
michael@0 1374 goto fail;
michael@0 1375 }
michael@0 1376 key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
michael@0 1377 sftk_FreeAttribute(attribute);
michael@0 1378
michael@0 1379 /* finally copy the attributes for various private key types */
michael@0 1380 switch (key_type) {
michael@0 1381 case CKK_RSA:
michael@0 1382 crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPrivKeyAttrs,
michael@0 1383 rsaPrivKeyAttrsCount);
michael@0 1384 break;
michael@0 1385 case CKK_DSA:
michael@0 1386 crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPrivKeyAttrs,
michael@0 1387 dsaPrivKeyAttrsCount);
michael@0 1388 break;
michael@0 1389 case CKK_DH:
michael@0 1390 crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs,
michael@0 1391 dhPrivKeyAttrsCount);
michael@0 1392 break;
michael@0 1393 #ifndef NSS_DISABLE_ECC
michael@0 1394 case CKK_EC:
michael@0 1395 crv = stfk_CopyTokenAttributes(destObject, src_to, ecPrivKeyAttrs,
michael@0 1396 ecPrivKeyAttrsCount);
michael@0 1397 break;
michael@0 1398 #endif
michael@0 1399 default:
michael@0 1400 crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
michael@0 1401 * of token keys into our database. */
michael@0 1402 }
michael@0 1403 fail:
michael@0 1404 return crv;
michael@0 1405 }
michael@0 1406
michael@0 1407 CK_RV
michael@0 1408 stfk_CopyTokenPublicKey(SFTKObject *destObject,SFTKTokenObject *src_to)
michael@0 1409 {
michael@0 1410 CK_RV crv;
michael@0 1411 CK_KEY_TYPE key_type;
michael@0 1412 SFTKAttribute *attribute;
michael@0 1413
michael@0 1414 /* copy the common attributes for all keys first */
michael@0 1415 crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
michael@0 1416 commonKeyAttrsCount);
michael@0 1417 if (crv != CKR_OK) {
michael@0 1418 goto fail;
michael@0 1419 }
michael@0 1420
michael@0 1421 /* copy the common attributes for all public keys next */
michael@0 1422 crv = stfk_CopyTokenAttributes(destObject, src_to, commonPubKeyAttrs,
michael@0 1423 commonPubKeyAttrsCount);
michael@0 1424 if (crv != CKR_OK) {
michael@0 1425 goto fail;
michael@0 1426 }
michael@0 1427 attribute =sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);
michael@0 1428 PORT_Assert(attribute); /* if it wasn't here, ww should have failed
michael@0 1429 * copying the common attributes */
michael@0 1430 if (!attribute) {
michael@0 1431 /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but
michael@0 1432 * the fact is, the only reason we couldn't get the attribute would
michael@0 1433 * be a memory error or database error (an error in the 'device').
michael@0 1434 * if we have a database error code, we could return it here */
michael@0 1435 crv = CKR_DEVICE_ERROR;
michael@0 1436 goto fail;
michael@0 1437 }
michael@0 1438 key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
michael@0 1439 sftk_FreeAttribute(attribute);
michael@0 1440
michael@0 1441 /* finally copy the attributes for various public key types */
michael@0 1442 switch (key_type) {
michael@0 1443 case CKK_RSA:
michael@0 1444 crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPubKeyAttrs,
michael@0 1445 rsaPubKeyAttrsCount);
michael@0 1446 break;
michael@0 1447 case CKK_DSA:
michael@0 1448 crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPubKeyAttrs,
michael@0 1449 dsaPubKeyAttrsCount);
michael@0 1450 break;
michael@0 1451 case CKK_DH:
michael@0 1452 crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs,
michael@0 1453 dhPubKeyAttrsCount);
michael@0 1454 break;
michael@0 1455 #ifndef NSS_DISABLE_ECC
michael@0 1456 case CKK_EC:
michael@0 1457 crv = stfk_CopyTokenAttributes(destObject, src_to, ecPubKeyAttrs,
michael@0 1458 ecPubKeyAttrsCount);
michael@0 1459 break;
michael@0 1460 #endif
michael@0 1461 default:
michael@0 1462 crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
michael@0 1463 * of token keys into our database. */
michael@0 1464 }
michael@0 1465 fail:
michael@0 1466 return crv;
michael@0 1467 }
michael@0 1468 CK_RV
michael@0 1469 stfk_CopyTokenSecretKey(SFTKObject *destObject,SFTKTokenObject *src_to)
michael@0 1470 {
michael@0 1471 CK_RV crv;
michael@0 1472 crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,
michael@0 1473 commonKeyAttrsCount);
michael@0 1474 if (crv != CKR_OK) {
michael@0 1475 goto fail;
michael@0 1476 }
michael@0 1477 crv = stfk_CopyTokenAttributes(destObject, src_to, secretKeyAttrs,
michael@0 1478 secretKeyAttrsCount);
michael@0 1479 fail:
michael@0 1480 return crv;
michael@0 1481 }
michael@0 1482
michael@0 1483 /*
michael@0 1484 * Copy a token object. We need to explicitly copy the relevant
michael@0 1485 * attributes since token objects don't store those attributes in
michael@0 1486 * the token itself.
michael@0 1487 */
michael@0 1488 CK_RV
michael@0 1489 sftk_CopyTokenObject(SFTKObject *destObject,SFTKObject *srcObject)
michael@0 1490 {
michael@0 1491 SFTKTokenObject *src_to = sftk_narrowToTokenObject(srcObject);
michael@0 1492 CK_RV crv;
michael@0 1493
michael@0 1494 PORT_Assert(src_to);
michael@0 1495 if (src_to == NULL) {
michael@0 1496 return CKR_DEVICE_ERROR; /* internal state inconsistant */
michael@0 1497 }
michael@0 1498
michael@0 1499 crv = stfk_CopyTokenAttributes(destObject, src_to, commonAttrs,
michael@0 1500 commonAttrsCount);
michael@0 1501 if (crv != CKR_OK) {
michael@0 1502 goto fail;
michael@0 1503 }
michael@0 1504 switch (src_to->obj.objclass) {
michael@0 1505 case CKO_CERTIFICATE:
michael@0 1506 crv = stfk_CopyTokenAttributes(destObject, src_to, certAttrs,
michael@0 1507 certAttrsCount);
michael@0 1508 break;
michael@0 1509 case CKO_NETSCAPE_TRUST:
michael@0 1510 crv = stfk_CopyTokenAttributes(destObject, src_to, trustAttrs,
michael@0 1511 trustAttrsCount);
michael@0 1512 break;
michael@0 1513 case CKO_NETSCAPE_SMIME:
michael@0 1514 crv = stfk_CopyTokenAttributes(destObject, src_to, smimeAttrs,
michael@0 1515 smimeAttrsCount);
michael@0 1516 break;
michael@0 1517 case CKO_NETSCAPE_CRL:
michael@0 1518 crv = stfk_CopyTokenAttributes(destObject, src_to, crlAttrs,
michael@0 1519 crlAttrsCount);
michael@0 1520 break;
michael@0 1521 case CKO_PRIVATE_KEY:
michael@0 1522 crv = stfk_CopyTokenPrivateKey(destObject,src_to);
michael@0 1523 break;
michael@0 1524 case CKO_PUBLIC_KEY:
michael@0 1525 crv = stfk_CopyTokenPublicKey(destObject,src_to);
michael@0 1526 break;
michael@0 1527 case CKO_SECRET_KEY:
michael@0 1528 crv = stfk_CopyTokenSecretKey(destObject,src_to);
michael@0 1529 break;
michael@0 1530 default:
michael@0 1531 crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types
michael@0 1532 * of token keys into our database. */
michael@0 1533 }
michael@0 1534 fail:
michael@0 1535 return crv;
michael@0 1536 }
michael@0 1537
michael@0 1538 /*
michael@0 1539 * copy the attributes from one object to another. Don't overwrite existing
michael@0 1540 * attributes. NOTE: This is a pretty expensive operation since it
michael@0 1541 * grabs the attribute locks for the src object for a *long* time.
michael@0 1542 */
michael@0 1543 CK_RV
michael@0 1544 sftk_CopyObject(SFTKObject *destObject,SFTKObject *srcObject)
michael@0 1545 {
michael@0 1546 SFTKAttribute *attribute;
michael@0 1547 SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);
michael@0 1548 unsigned int i;
michael@0 1549
michael@0 1550 if (src_so == NULL) {
michael@0 1551 return sftk_CopyTokenObject(destObject,srcObject);
michael@0 1552 }
michael@0 1553
michael@0 1554 PZ_Lock(src_so->attributeLock);
michael@0 1555 for(i=0; i < src_so->hashSize; i++) {
michael@0 1556 attribute = src_so->head[i];
michael@0 1557 do {
michael@0 1558 if (attribute) {
michael@0 1559 if (!sftk_hasAttribute(destObject,attribute->handle)) {
michael@0 1560 /* we need to copy the attribute since each attribute
michael@0 1561 * only has one set of link list pointers */
michael@0 1562 SFTKAttribute *newAttribute = sftk_NewAttribute(
michael@0 1563 destObject,sftk_attr_expand(&attribute->attrib));
michael@0 1564 if (newAttribute == NULL) {
michael@0 1565 PZ_Unlock(src_so->attributeLock);
michael@0 1566 return CKR_HOST_MEMORY;
michael@0 1567 }
michael@0 1568 sftk_AddAttribute(destObject,newAttribute);
michael@0 1569 }
michael@0 1570 attribute=attribute->next;
michael@0 1571 }
michael@0 1572 } while (attribute != NULL);
michael@0 1573 }
michael@0 1574 PZ_Unlock(src_so->attributeLock);
michael@0 1575
michael@0 1576 return CKR_OK;
michael@0 1577 }
michael@0 1578
michael@0 1579 /*
michael@0 1580 * ******************** Search Utilities *******************************
michael@0 1581 */
michael@0 1582
michael@0 1583 /* add an object to a search list */
michael@0 1584 CK_RV
michael@0 1585 AddToList(SFTKObjectListElement **list,SFTKObject *object)
michael@0 1586 {
michael@0 1587 SFTKObjectListElement *newElem =
michael@0 1588 (SFTKObjectListElement *)PORT_Alloc(sizeof(SFTKObjectListElement));
michael@0 1589
michael@0 1590 if (newElem == NULL) return CKR_HOST_MEMORY;
michael@0 1591
michael@0 1592 newElem->next = *list;
michael@0 1593 newElem->object = object;
michael@0 1594 sftk_ReferenceObject(object);
michael@0 1595
michael@0 1596 *list = newElem;
michael@0 1597 return CKR_OK;
michael@0 1598 }
michael@0 1599
michael@0 1600
michael@0 1601 /* return true if the object matches the template */
michael@0 1602 PRBool
michael@0 1603 sftk_objectMatch(SFTKObject *object,CK_ATTRIBUTE_PTR theTemplate,int count)
michael@0 1604 {
michael@0 1605 int i;
michael@0 1606
michael@0 1607 for (i=0; i < count; i++) {
michael@0 1608 SFTKAttribute *attribute = sftk_FindAttribute(object,theTemplate[i].type);
michael@0 1609 if (attribute == NULL) {
michael@0 1610 return PR_FALSE;
michael@0 1611 }
michael@0 1612 if (attribute->attrib.ulValueLen == theTemplate[i].ulValueLen) {
michael@0 1613 if (PORT_Memcmp(attribute->attrib.pValue,theTemplate[i].pValue,
michael@0 1614 theTemplate[i].ulValueLen) == 0) {
michael@0 1615 sftk_FreeAttribute(attribute);
michael@0 1616 continue;
michael@0 1617 }
michael@0 1618 }
michael@0 1619 sftk_FreeAttribute(attribute);
michael@0 1620 return PR_FALSE;
michael@0 1621 }
michael@0 1622 return PR_TRUE;
michael@0 1623 }
michael@0 1624
michael@0 1625 /* search through all the objects in the queue and return the template matches
michael@0 1626 * in the object list.
michael@0 1627 */
michael@0 1628 CK_RV
michael@0 1629 sftk_searchObjectList(SFTKSearchResults *search,SFTKObject **head,
michael@0 1630 unsigned int size, PZLock *lock, CK_ATTRIBUTE_PTR theTemplate,
michael@0 1631 int count, PRBool isLoggedIn)
michael@0 1632 {
michael@0 1633 unsigned int i;
michael@0 1634 SFTKObject *object;
michael@0 1635 CK_RV crv = CKR_OK;
michael@0 1636
michael@0 1637 for(i=0; i < size; i++) {
michael@0 1638 /* We need to hold the lock to copy a consistant version of
michael@0 1639 * the linked list. */
michael@0 1640 PZ_Lock(lock);
michael@0 1641 for (object = head[i]; object != NULL; object= object->next) {
michael@0 1642 if (sftk_objectMatch(object,theTemplate,count)) {
michael@0 1643 /* don't return objects that aren't yet visible */
michael@0 1644 if ((!isLoggedIn) && sftk_isTrue(object,CKA_PRIVATE)) continue;
michael@0 1645 sftk_addHandle(search,object->handle);
michael@0 1646 }
michael@0 1647 }
michael@0 1648 PZ_Unlock(lock);
michael@0 1649 }
michael@0 1650 return crv;
michael@0 1651 }
michael@0 1652
michael@0 1653 /*
michael@0 1654 * free a single list element. Return the Next object in the list.
michael@0 1655 */
michael@0 1656 SFTKObjectListElement *
michael@0 1657 sftk_FreeObjectListElement(SFTKObjectListElement *objectList)
michael@0 1658 {
michael@0 1659 SFTKObjectListElement *ol = objectList->next;
michael@0 1660
michael@0 1661 sftk_FreeObject(objectList->object);
michael@0 1662 PORT_Free(objectList);
michael@0 1663 return ol;
michael@0 1664 }
michael@0 1665
michael@0 1666 /* free an entire object list */
michael@0 1667 void
michael@0 1668 sftk_FreeObjectList(SFTKObjectListElement *objectList)
michael@0 1669 {
michael@0 1670 SFTKObjectListElement *ol;
michael@0 1671
michael@0 1672 for (ol= objectList; ol != NULL; ol = sftk_FreeObjectListElement(ol)) {}
michael@0 1673 }
michael@0 1674
michael@0 1675 /*
michael@0 1676 * free a search structure
michael@0 1677 */
michael@0 1678 void
michael@0 1679 sftk_FreeSearch(SFTKSearchResults *search)
michael@0 1680 {
michael@0 1681 if (search->handles) {
michael@0 1682 PORT_Free(search->handles);
michael@0 1683 }
michael@0 1684 PORT_Free(search);
michael@0 1685 }
michael@0 1686
michael@0 1687 /*
michael@0 1688 * ******************** Session Utilities *******************************
michael@0 1689 */
michael@0 1690
michael@0 1691 /* update the sessions state based in it's flags and wether or not it's
michael@0 1692 * logged in */
michael@0 1693 void
michael@0 1694 sftk_update_state(SFTKSlot *slot,SFTKSession *session)
michael@0 1695 {
michael@0 1696 if (slot->isLoggedIn) {
michael@0 1697 if (slot->ssoLoggedIn) {
michael@0 1698 session->info.state = CKS_RW_SO_FUNCTIONS;
michael@0 1699 } else if (session->info.flags & CKF_RW_SESSION) {
michael@0 1700 session->info.state = CKS_RW_USER_FUNCTIONS;
michael@0 1701 } else {
michael@0 1702 session->info.state = CKS_RO_USER_FUNCTIONS;
michael@0 1703 }
michael@0 1704 } else {
michael@0 1705 if (session->info.flags & CKF_RW_SESSION) {
michael@0 1706 session->info.state = CKS_RW_PUBLIC_SESSION;
michael@0 1707 } else {
michael@0 1708 session->info.state = CKS_RO_PUBLIC_SESSION;
michael@0 1709 }
michael@0 1710 }
michael@0 1711 }
michael@0 1712
michael@0 1713 /* update the state of all the sessions on a slot */
michael@0 1714 void
michael@0 1715 sftk_update_all_states(SFTKSlot *slot)
michael@0 1716 {
michael@0 1717 unsigned int i;
michael@0 1718 SFTKSession *session;
michael@0 1719
michael@0 1720 for (i=0; i < slot->sessHashSize; i++) {
michael@0 1721 PZLock *lock = SFTK_SESSION_LOCK(slot,i);
michael@0 1722 PZ_Lock(lock);
michael@0 1723 for (session = slot->head[i]; session; session = session->next) {
michael@0 1724 sftk_update_state(slot,session);
michael@0 1725 }
michael@0 1726 PZ_Unlock(lock);
michael@0 1727 }
michael@0 1728 }
michael@0 1729
michael@0 1730 /*
michael@0 1731 * context are cipher and digest contexts that are associated with a session
michael@0 1732 */
michael@0 1733 void
michael@0 1734 sftk_FreeContext(SFTKSessionContext *context)
michael@0 1735 {
michael@0 1736 if (context->cipherInfo) {
michael@0 1737 (*context->destroy)(context->cipherInfo,PR_TRUE);
michael@0 1738 }
michael@0 1739 if (context->hashInfo) {
michael@0 1740 (*context->hashdestroy)(context->hashInfo,PR_TRUE);
michael@0 1741 }
michael@0 1742 if (context->key) {
michael@0 1743 sftk_FreeObject(context->key);
michael@0 1744 context->key = NULL;
michael@0 1745 }
michael@0 1746 PORT_Free(context);
michael@0 1747 }
michael@0 1748
michael@0 1749 /*
michael@0 1750 * create a new nession. NOTE: The session handle is not set, and the
michael@0 1751 * session is not added to the slot's session queue.
michael@0 1752 */
michael@0 1753 SFTKSession *
michael@0 1754 sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,
michael@0 1755 CK_FLAGS flags)
michael@0 1756 {
michael@0 1757 SFTKSession *session;
michael@0 1758 SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
michael@0 1759
michael@0 1760 if (slot == NULL) return NULL;
michael@0 1761
michael@0 1762 session = (SFTKSession*)PORT_Alloc(sizeof(SFTKSession));
michael@0 1763 if (session == NULL) return NULL;
michael@0 1764
michael@0 1765 session->next = session->prev = NULL;
michael@0 1766 session->refCount = 1;
michael@0 1767 session->enc_context = NULL;
michael@0 1768 session->hash_context = NULL;
michael@0 1769 session->sign_context = NULL;
michael@0 1770 session->search = NULL;
michael@0 1771 session->objectIDCount = 1;
michael@0 1772 session->objectLock = PZ_NewLock(nssILockObject);
michael@0 1773 if (session->objectLock == NULL) {
michael@0 1774 PORT_Free(session);
michael@0 1775 return NULL;
michael@0 1776 }
michael@0 1777 session->objects[0] = NULL;
michael@0 1778
michael@0 1779 session->slot = slot;
michael@0 1780 session->notify = notify;
michael@0 1781 session->appData = pApplication;
michael@0 1782 session->info.flags = flags;
michael@0 1783 session->info.slotID = slotID;
michael@0 1784 session->info.ulDeviceError = 0;
michael@0 1785 sftk_update_state(slot,session);
michael@0 1786 return session;
michael@0 1787 }
michael@0 1788
michael@0 1789
michael@0 1790 /* free all the data associated with a session. */
michael@0 1791 static void
michael@0 1792 sftk_DestroySession(SFTKSession *session)
michael@0 1793 {
michael@0 1794 SFTKObjectList *op,*next;
michael@0 1795 PORT_Assert(session->refCount == 0);
michael@0 1796
michael@0 1797 /* clean out the attributes */
michael@0 1798 /* since no one is referencing us, it's safe to walk the chain
michael@0 1799 * without a lock */
michael@0 1800 for (op = session->objects[0]; op != NULL; op = next) {
michael@0 1801 next = op->next;
michael@0 1802 /* paranoia */
michael@0 1803 op->next = op->prev = NULL;
michael@0 1804 sftk_DeleteObject(session,op->parent);
michael@0 1805 }
michael@0 1806 PZ_DestroyLock(session->objectLock);
michael@0 1807 if (session->enc_context) {
michael@0 1808 sftk_FreeContext(session->enc_context);
michael@0 1809 }
michael@0 1810 if (session->hash_context) {
michael@0 1811 sftk_FreeContext(session->hash_context);
michael@0 1812 }
michael@0 1813 if (session->sign_context) {
michael@0 1814 sftk_FreeContext(session->sign_context);
michael@0 1815 }
michael@0 1816 if (session->search) {
michael@0 1817 sftk_FreeSearch(session->search);
michael@0 1818 }
michael@0 1819 PORT_Free(session);
michael@0 1820 }
michael@0 1821
michael@0 1822
michael@0 1823 /*
michael@0 1824 * look up a session structure from a session handle
michael@0 1825 * generate a reference to it.
michael@0 1826 */
michael@0 1827 SFTKSession *
michael@0 1828 sftk_SessionFromHandle(CK_SESSION_HANDLE handle)
michael@0 1829 {
michael@0 1830 SFTKSlot *slot = sftk_SlotFromSessionHandle(handle);
michael@0 1831 SFTKSession *session;
michael@0 1832 PZLock *lock;
michael@0 1833
michael@0 1834 if (!slot) return NULL;
michael@0 1835 lock = SFTK_SESSION_LOCK(slot,handle);
michael@0 1836
michael@0 1837 PZ_Lock(lock);
michael@0 1838 sftkqueue_find(session,handle,slot->head,slot->sessHashSize);
michael@0 1839 if (session) session->refCount++;
michael@0 1840 PZ_Unlock(lock);
michael@0 1841
michael@0 1842 return (session);
michael@0 1843 }
michael@0 1844
michael@0 1845 /*
michael@0 1846 * release a reference to a session handle
michael@0 1847 */
michael@0 1848 void
michael@0 1849 sftk_FreeSession(SFTKSession *session)
michael@0 1850 {
michael@0 1851 PRBool destroy = PR_FALSE;
michael@0 1852 SFTKSlot *slot = sftk_SlotFromSession(session);
michael@0 1853 PZLock *lock = SFTK_SESSION_LOCK(slot,session->handle);
michael@0 1854
michael@0 1855 PZ_Lock(lock);
michael@0 1856 if (session->refCount == 1) destroy = PR_TRUE;
michael@0 1857 session->refCount--;
michael@0 1858 PZ_Unlock(lock);
michael@0 1859
michael@0 1860 if (destroy) sftk_DestroySession(session);
michael@0 1861 }
michael@0 1862
michael@0 1863 void
michael@0 1864 sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle)
michael@0 1865 {
michael@0 1866 if (search->handles == NULL) {
michael@0 1867 return;
michael@0 1868 }
michael@0 1869 if (search->size >= search->array_size) {
michael@0 1870 search->array_size += NSC_SEARCH_BLOCK_SIZE;
michael@0 1871 search->handles = (CK_OBJECT_HANDLE *) PORT_Realloc(search->handles,
michael@0 1872 sizeof(CK_OBJECT_HANDLE)* search->array_size);
michael@0 1873 if (search->handles == NULL) {
michael@0 1874 return;
michael@0 1875 }
michael@0 1876 }
michael@0 1877 search->handles[search->size] = handle;
michael@0 1878 search->size++;
michael@0 1879 }
michael@0 1880
michael@0 1881 static CK_RV
michael@0 1882 handleToClass(SFTKSlot *slot, CK_OBJECT_HANDLE handle,
michael@0 1883 CK_OBJECT_CLASS *objClass)
michael@0 1884 {
michael@0 1885 SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, handle);
michael@0 1886 CK_ATTRIBUTE objClassTemplate;
michael@0 1887 CK_RV crv;
michael@0 1888
michael@0 1889 *objClass = CKO_DATA;
michael@0 1890 objClassTemplate.type = CKA_CLASS;
michael@0 1891 objClassTemplate.pValue = objClass;
michael@0 1892 objClassTemplate.ulValueLen = sizeof(*objClass);
michael@0 1893 crv = sftkdb_GetAttributeValue(dbHandle, handle, &objClassTemplate, 1);
michael@0 1894 sftk_freeDB(dbHandle);
michael@0 1895 return crv;
michael@0 1896 }
michael@0 1897
michael@0 1898 SFTKObject *
michael@0 1899 sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle)
michael@0 1900 {
michael@0 1901 SFTKObject *object = NULL;
michael@0 1902 SFTKTokenObject *tokObject = NULL;
michael@0 1903 PRBool hasLocks = PR_FALSE;
michael@0 1904 CK_RV crv;
michael@0 1905
michael@0 1906 object = sftk_GetObjectFromList(&hasLocks, PR_FALSE, &tokenObjectList, 0,
michael@0 1907 PR_FALSE);
michael@0 1908 if (object == NULL) {
michael@0 1909 return NULL;
michael@0 1910 }
michael@0 1911 tokObject = (SFTKTokenObject *) object;
michael@0 1912
michael@0 1913 object->handle = handle;
michael@0 1914 /* every object must have a class, if we can't get it, the object
michael@0 1915 * doesn't exist */
michael@0 1916 crv = handleToClass(slot, handle, &object->objclass);
michael@0 1917 if (crv != CKR_OK) {
michael@0 1918 goto loser;
michael@0 1919 }
michael@0 1920 object->slot = slot;
michael@0 1921 object->objectInfo = NULL;
michael@0 1922 object->infoFree = NULL;
michael@0 1923 if (!hasLocks) {
michael@0 1924 object->refLock = PZ_NewLock(nssILockRefLock);
michael@0 1925 }
michael@0 1926 if (object->refLock == NULL) {
michael@0 1927 goto loser;
michael@0 1928 }
michael@0 1929 object->refCount = 1;
michael@0 1930
michael@0 1931 return object;
michael@0 1932 loser:
michael@0 1933 if (object) {
michael@0 1934 (void) sftk_DestroyObject(object);
michael@0 1935 }
michael@0 1936 return NULL;
michael@0 1937
michael@0 1938 }
michael@0 1939
michael@0 1940 SFTKTokenObject *
michael@0 1941 sftk_convertSessionToToken(SFTKObject *obj)
michael@0 1942 {
michael@0 1943 SECItem *key;
michael@0 1944 SFTKSessionObject *so = (SFTKSessionObject *)obj;
michael@0 1945 SFTKTokenObject *to = sftk_narrowToTokenObject(obj);
michael@0 1946 SECStatus rv;
michael@0 1947
michael@0 1948 sftk_DestroySessionObjectData(so);
michael@0 1949 PZ_DestroyLock(so->attributeLock);
michael@0 1950 if (to == NULL) {
michael@0 1951 return NULL;
michael@0 1952 }
michael@0 1953 sftk_tokenKeyLock(so->obj.slot);
michael@0 1954 key = sftk_lookupTokenKeyByHandle(so->obj.slot,so->obj.handle);
michael@0 1955 if (key == NULL) {
michael@0 1956 sftk_tokenKeyUnlock(so->obj.slot);
michael@0 1957 return NULL;
michael@0 1958 }
michael@0 1959 rv = SECITEM_CopyItem(NULL,&to->dbKey,key);
michael@0 1960 sftk_tokenKeyUnlock(so->obj.slot);
michael@0 1961 if (rv == SECFailure) {
michael@0 1962 return NULL;
michael@0 1963 }
michael@0 1964
michael@0 1965 return to;
michael@0 1966 }
michael@0 1967
michael@0 1968 SFTKSessionObject *
michael@0 1969 sftk_narrowToSessionObject(SFTKObject *obj)
michael@0 1970 {
michael@0 1971 return !sftk_isToken(obj->handle) ? (SFTKSessionObject *)obj : NULL;
michael@0 1972 }
michael@0 1973
michael@0 1974 SFTKTokenObject *
michael@0 1975 sftk_narrowToTokenObject(SFTKObject *obj)
michael@0 1976 {
michael@0 1977 return sftk_isToken(obj->handle) ? (SFTKTokenObject *)obj : NULL;
michael@0 1978 }
michael@0 1979

mercurial