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