pkcs11u.c (85233B)
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 #include "secoid.h" 17 #include "softkver.h" 18 19 #if !defined(NSS_FIPS_DISABLED) && defined(NSS_ENABLE_FIPS_INDICATORS) 20 /* this file should be supplied by the vendor and include all the 21 * algorithms which have Algorithm certs and have been reviewed by 22 * the lab. A blank file is included for the base so that FIPS mode 23 * will still be compiled and run, but FIPS indicators will always 24 * return PR_FALSE 25 */ 26 #include "fips_algorithms.h" 27 #define NSS_HAS_FIPS_INDICATORS 1 28 #endif 29 30 /* 31 * ******************** Error mapping ******************************* 32 */ 33 /* 34 * map all the SEC_ERROR_xxx error codes that may be returned by freebl 35 * functions to CKR_xxx. return CKR_DEVICE_ERROR by default for backward 36 * compatibility. 37 */ 38 CK_RV 39 sftk_MapCryptError(int error) 40 { 41 switch (error) { 42 case SEC_ERROR_INVALID_ARGS: 43 case SEC_ERROR_BAD_DATA: /* MP_RANGE gets mapped to this */ 44 return CKR_ARGUMENTS_BAD; 45 case SEC_ERROR_INPUT_LEN: 46 return CKR_DATA_LEN_RANGE; 47 case SEC_ERROR_OUTPUT_LEN: 48 return CKR_BUFFER_TOO_SMALL; 49 case SEC_ERROR_LIBRARY_FAILURE: 50 return CKR_GENERAL_ERROR; 51 case SEC_ERROR_NO_MEMORY: 52 return CKR_HOST_MEMORY; 53 case SEC_ERROR_BAD_SIGNATURE: 54 return CKR_SIGNATURE_INVALID; 55 case SEC_ERROR_INVALID_KEY: 56 return CKR_KEY_SIZE_RANGE; 57 case SEC_ERROR_BAD_KEY: /* an EC public key that fails validation */ 58 return CKR_KEY_SIZE_RANGE; /* the closest error code */ 59 case SEC_ERROR_UNSUPPORTED_EC_POINT_FORM: 60 return CKR_TEMPLATE_INCONSISTENT; 61 case SEC_ERROR_UNSUPPORTED_KEYALG: 62 return CKR_MECHANISM_INVALID; 63 case SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE: 64 return CKR_DOMAIN_PARAMS_INVALID; 65 /* key pair generation failed after max number of attempts */ 66 case SEC_ERROR_NEED_RANDOM: 67 return CKR_FUNCTION_FAILED; 68 } 69 return CKR_DEVICE_ERROR; 70 } 71 72 /* 73 * functions which adjust the mapping based on different contexts 74 * (Decrypt or Verify). 75 */ 76 77 /* used by Decrypt and UnwrapKey (indirectly) and Decrypt message */ 78 CK_RV 79 sftk_MapDecryptError(int error) 80 { 81 switch (error) { 82 /* usually a padding error, or aead tag mismatch */ 83 case SEC_ERROR_BAD_DATA: 84 return CKR_ENCRYPTED_DATA_INVALID; 85 default: 86 return sftk_MapCryptError(error); 87 } 88 } 89 90 /* 91 * return CKR_SIGNATURE_INVALID instead of CKR_DEVICE_ERROR by default for 92 * backward compatibilty. 93 */ 94 CK_RV 95 sftk_MapVerifyError(int error) 96 { 97 CK_RV crv = sftk_MapCryptError(error); 98 if (crv == CKR_DEVICE_ERROR) 99 crv = CKR_SIGNATURE_INVALID; 100 return crv; 101 } 102 103 /* 104 * ******************** Attribute Utilities ******************************* 105 */ 106 107 /* 108 * create a new attribute with type, value, and length. Space is allocated 109 * to hold value. 110 */ 111 static SFTKAttribute * 112 sftk_NewAttribute(SFTKObject *object, 113 CK_ATTRIBUTE_TYPE type, const void *value, CK_ULONG len) 114 { 115 SFTKAttribute *attribute; 116 117 SFTKSessionObject *so = sftk_narrowToSessionObject(object); 118 int index; 119 120 if (so == NULL) { 121 /* allocate new attribute in a buffer */ 122 PORT_Assert(0); 123 return NULL; 124 } 125 /* 126 * We attempt to keep down contention on Malloc and Arena locks by 127 * limiting the number of these calls on high traversed paths. This 128 * is done for attributes by 'allocating' them from a pool already 129 * allocated by the parent object. 130 */ 131 PZ_Lock(so->attributeLock); 132 index = so->nextAttr++; 133 PZ_Unlock(so->attributeLock); 134 PORT_Assert(index < MAX_OBJS_ATTRS); 135 if (index >= MAX_OBJS_ATTRS) 136 return NULL; 137 138 attribute = &so->attrList[index]; 139 attribute->attrib.type = type; 140 attribute->freeAttr = PR_FALSE; 141 attribute->freeData = PR_FALSE; 142 if (value) { 143 if (len <= ATTR_SPACE) { 144 attribute->attrib.pValue = attribute->space; 145 } else { 146 attribute->attrib.pValue = PORT_Alloc(len); 147 attribute->freeData = PR_TRUE; 148 } 149 if (attribute->attrib.pValue == NULL) { 150 return NULL; 151 } 152 PORT_Memcpy(attribute->attrib.pValue, value, len); 153 attribute->attrib.ulValueLen = len; 154 } else { 155 attribute->attrib.pValue = NULL; 156 attribute->attrib.ulValueLen = 0; 157 } 158 attribute->attrib.type = type; 159 attribute->handle = type; 160 attribute->next = attribute->prev = NULL; 161 return attribute; 162 } 163 164 /* 165 * Free up all the memory associated with an attribute. Reference count 166 * must be zero to call this. 167 */ 168 static void 169 sftk_DestroyAttribute(SFTKAttribute *attribute) 170 { 171 if (attribute->attrib.pValue) { 172 /* clear out the data in the attribute value... it may have been 173 * sensitive data */ 174 PORT_Memset(attribute->attrib.pValue, 0, attribute->attrib.ulValueLen); 175 if (attribute->freeData) { 176 PORT_Free(attribute->attrib.pValue); 177 attribute->attrib.pValue = NULL; 178 attribute->freeData = PR_FALSE; 179 } 180 } 181 if (attribute->freeAttr) { 182 PORT_Free(attribute); 183 } 184 } 185 186 /* 187 * release a reference to an attribute structure 188 */ 189 void 190 sftk_FreeAttribute(SFTKAttribute *attribute) 191 { 192 if (attribute && attribute->freeAttr) { 193 sftk_DestroyAttribute(attribute); 194 return; 195 } 196 } 197 198 static SFTKAttribute * 199 sftk_FindTokenAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) 200 { 201 SFTKAttribute *myattribute = NULL; 202 SFTKDBHandle *dbHandle = NULL; 203 CK_RV crv = CKR_HOST_MEMORY; 204 205 myattribute = (SFTKAttribute *)PORT_Alloc(sizeof(SFTKAttribute)); 206 if (myattribute == NULL) { 207 goto loser; 208 } 209 210 dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle); 211 212 myattribute->handle = type; 213 myattribute->attrib.type = type; 214 myattribute->attrib.pValue = myattribute->space; 215 myattribute->attrib.ulValueLen = ATTR_SPACE; 216 myattribute->next = myattribute->prev = NULL; 217 myattribute->freeAttr = PR_TRUE; 218 myattribute->freeData = PR_FALSE; 219 220 crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, 221 &myattribute->attrib, 1); 222 223 /* attribute is bigger than our attribute space buffer, malloc it */ 224 if (crv == CKR_BUFFER_TOO_SMALL) { 225 myattribute->attrib.pValue = NULL; 226 crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, 227 &myattribute->attrib, 1); 228 if (crv != CKR_OK) { 229 goto loser; 230 } 231 myattribute->attrib.pValue = PORT_Alloc(myattribute->attrib.ulValueLen); 232 if (myattribute->attrib.pValue == NULL) { 233 crv = CKR_HOST_MEMORY; 234 goto loser; 235 } 236 myattribute->freeData = PR_TRUE; 237 crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, 238 &myattribute->attrib, 1); 239 } 240 loser: 241 if (dbHandle) { 242 sftk_freeDB(dbHandle); 243 } 244 if (crv != CKR_OK) { 245 if (myattribute) { 246 myattribute->attrib.ulValueLen = 0; 247 sftk_FreeAttribute(myattribute); 248 myattribute = NULL; 249 } 250 } 251 return myattribute; 252 } 253 254 /* 255 * look up and attribute structure from a type and Object structure. 256 * The returned attribute is referenced and needs to be freed when 257 * it is no longer needed. 258 */ 259 SFTKAttribute * 260 sftk_FindAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type) 261 { 262 SFTKAttribute *attribute; 263 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); 264 265 /* validation flags are stored as FIPS indicators */ 266 if (type == CKA_OBJECT_VALIDATION_FLAGS) { 267 return &object->validation_attribute; 268 } 269 270 if (sessObject == NULL) { 271 return sftk_FindTokenAttribute(sftk_narrowToTokenObject(object), type); 272 } 273 274 PZ_Lock(sessObject->attributeLock); 275 sftkqueue_find(attribute, type, sessObject->head, sessObject->hashSize); 276 PZ_Unlock(sessObject->attributeLock); 277 278 return (attribute); 279 } 280 281 /* 282 * Take a buffer and it's length and return it's true size in bits; 283 */ 284 unsigned int 285 sftk_GetLengthInBits(unsigned char *buf, unsigned int bufLen) 286 { 287 unsigned int size = bufLen * 8; 288 unsigned int i; 289 290 /* Get the real length in bytes */ 291 for (i = 0; i < bufLen; i++) { 292 unsigned char c = *buf++; 293 if (c != 0) { 294 unsigned char m; 295 for (m = 0x80; m > 0; m = m >> 1) { 296 if ((c & m) != 0) { 297 break; 298 } 299 size--; 300 } 301 break; 302 } 303 size -= 8; 304 } 305 return size; 306 } 307 308 /* 309 * Constrain a big num attribute. to size and padding 310 * minLength means length of the object must be greater than equal to minLength 311 * maxLength means length of the object must be less than equal to maxLength 312 * minMultiple means that object length mod minMultiple must equal 0. 313 * all input sizes are in bits. 314 * if any constraint is '0' that constraint is not checked. 315 */ 316 CK_RV 317 sftk_ConstrainAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, 318 int minLength, int maxLength, int minMultiple) 319 { 320 SFTKAttribute *attribute; 321 int size; 322 unsigned char *ptr; 323 324 attribute = sftk_FindAttribute(object, type); 325 if (!attribute) { 326 return CKR_TEMPLATE_INCOMPLETE; 327 } 328 ptr = (unsigned char *)attribute->attrib.pValue; 329 if (ptr == NULL) { 330 sftk_FreeAttribute(attribute); 331 return CKR_ATTRIBUTE_VALUE_INVALID; 332 } 333 size = sftk_GetLengthInBits(ptr, attribute->attrib.ulValueLen); 334 sftk_FreeAttribute(attribute); 335 336 if ((minLength != 0) && (size < minLength)) { 337 return CKR_ATTRIBUTE_VALUE_INVALID; 338 } 339 if ((maxLength != 0) && (size > maxLength)) { 340 return CKR_ATTRIBUTE_VALUE_INVALID; 341 } 342 if ((minMultiple != 0) && ((size % minMultiple) != 0)) { 343 return CKR_ATTRIBUTE_VALUE_INVALID; 344 } 345 return CKR_OK; 346 } 347 348 PRBool 349 sftk_hasAttributeToken(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) 350 { 351 CK_ATTRIBUTE template; 352 CK_RV crv; 353 SFTKDBHandle *dbHandle; 354 355 dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle); 356 template.type = type; 357 template.pValue = NULL; 358 template.ulValueLen = 0; 359 360 crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, &template, 1); 361 sftk_freeDB(dbHandle); 362 363 /* attribute is bigger than our attribute space buffer, malloc it */ 364 return (crv == CKR_OK) ? PR_TRUE : PR_FALSE; 365 } 366 367 /* 368 * return true if object has attribute 369 */ 370 PRBool 371 sftk_hasAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type) 372 { 373 SFTKAttribute *attribute; 374 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); 375 376 if (sessObject == NULL) { 377 return sftk_hasAttributeToken(sftk_narrowToTokenObject(object), type); 378 } 379 380 PZ_Lock(sessObject->attributeLock); 381 sftkqueue_find(attribute, type, sessObject->head, sessObject->hashSize); 382 PZ_Unlock(sessObject->attributeLock); 383 384 return (PRBool)(attribute != NULL); 385 } 386 387 /* 388 * add an attribute to an object 389 */ 390 static void 391 sftk_AddAttribute(SFTKObject *object, SFTKAttribute *attribute) 392 { 393 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); 394 395 if (sessObject == NULL) 396 return; 397 PZ_Lock(sessObject->attributeLock); 398 sftkqueue_add(attribute, attribute->handle, 399 sessObject->head, sessObject->hashSize); 400 PZ_Unlock(sessObject->attributeLock); 401 } 402 403 /* 404 * copy an unsigned attribute into a SECItem. Secitem is allocated in 405 * the specified arena. 406 */ 407 CK_RV 408 sftk_Attribute2SSecItem(PLArenaPool *arena, SECItem *item, SFTKObject *object, 409 CK_ATTRIBUTE_TYPE type) 410 { 411 SFTKAttribute *attribute; 412 413 item->data = NULL; 414 415 attribute = sftk_FindAttribute(object, type); 416 if (attribute == NULL) 417 return CKR_TEMPLATE_INCOMPLETE; 418 419 (void)SECITEM_AllocItem(arena, item, attribute->attrib.ulValueLen); 420 if (item->data == NULL) { 421 sftk_FreeAttribute(attribute); 422 return CKR_HOST_MEMORY; 423 } 424 PORT_Memcpy(item->data, attribute->attrib.pValue, item->len); 425 sftk_FreeAttribute(attribute); 426 return CKR_OK; 427 } 428 429 /* 430 * fetch multiple attributes into SECItems. Secitem data is allocated in 431 * the specified arena. 432 */ 433 CK_RV 434 sftk_MultipleAttribute2SecItem(PLArenaPool *arena, SFTKObject *object, 435 SFTKItemTemplate *itemTemplate, int itemTemplateCount) 436 { 437 438 CK_RV crv = CKR_OK; 439 CK_ATTRIBUTE templateSpace[SFTK_MAX_ITEM_TEMPLATE]; 440 CK_ATTRIBUTE *template; 441 SFTKTokenObject *tokObject; 442 SFTKDBHandle *dbHandle = NULL; 443 int i; 444 445 tokObject = sftk_narrowToTokenObject(object); 446 447 /* session objects, just loop through the list */ 448 if (tokObject == NULL) { 449 for (i = 0; i < itemTemplateCount; i++) { 450 crv = sftk_Attribute2SecItem(arena, itemTemplate[i].item, object, 451 itemTemplate[i].type); 452 if (crv != CKR_OK) { 453 return crv; 454 } 455 } 456 return CKR_OK; 457 } 458 459 /* don't do any work if none is required */ 460 if (itemTemplateCount == 0) { 461 return CKR_OK; 462 } 463 464 /* don't allocate the template unless we need it */ 465 if (itemTemplateCount > SFTK_MAX_ITEM_TEMPLATE) { 466 template = PORT_NewArray(CK_ATTRIBUTE, itemTemplateCount); 467 } else { 468 template = templateSpace; 469 } 470 471 if (template == NULL) { 472 crv = CKR_HOST_MEMORY; 473 goto loser; 474 } 475 476 dbHandle = sftk_getDBForTokenObject(object->slot, object->handle); 477 if (dbHandle == NULL) { 478 crv = CKR_OBJECT_HANDLE_INVALID; 479 goto loser; 480 } 481 482 /* set up the PKCS #11 template */ 483 for (i = 0; i < itemTemplateCount; i++) { 484 template[i].type = itemTemplate[i].type; 485 template[i].pValue = NULL; 486 template[i].ulValueLen = 0; 487 } 488 489 /* fetch the attribute lengths */ 490 crv = sftkdb_GetAttributeValue(dbHandle, object->handle, 491 template, itemTemplateCount); 492 if (crv != CKR_OK) { 493 goto loser; 494 } 495 496 /* allocate space for the attributes */ 497 for (i = 0; i < itemTemplateCount; i++) { 498 template[i].pValue = PORT_ArenaAlloc(arena, template[i].ulValueLen); 499 if (template[i].pValue == NULL) { 500 crv = CKR_HOST_MEMORY; 501 goto loser; 502 } 503 } 504 505 /* fetch the attributes */ 506 crv = sftkdb_GetAttributeValue(dbHandle, object->handle, 507 template, itemTemplateCount); 508 if (crv != CKR_OK) { 509 goto loser; 510 } 511 512 /* Fill in the items */ 513 for (i = 0; i < itemTemplateCount; i++) { 514 itemTemplate[i].item->data = template[i].pValue; 515 itemTemplate[i].item->len = template[i].ulValueLen; 516 } 517 518 loser: 519 if (template != templateSpace) { 520 PORT_Free(template); 521 } 522 if (dbHandle) { 523 sftk_freeDB(dbHandle); 524 } 525 526 return crv; 527 } 528 529 /* 530 * delete an attribute from an object 531 */ 532 static void 533 sftk_DeleteAttribute(SFTKObject *object, SFTKAttribute *attribute) 534 { 535 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); 536 537 if (sessObject == NULL) { 538 return; 539 } 540 PZ_Lock(sessObject->attributeLock); 541 if (sftkqueue_is_queued(attribute, attribute->handle, 542 sessObject->head, sessObject->hashSize)) { 543 sftkqueue_delete(attribute, attribute->handle, 544 sessObject->head, sessObject->hashSize); 545 } 546 PZ_Unlock(sessObject->attributeLock); 547 } 548 549 /* 550 * this is only valid for CK_BBOOL type attributes. Return the state 551 * of that attribute. 552 */ 553 PRBool 554 sftk_isTrue(SFTKObject *object, CK_ATTRIBUTE_TYPE type) 555 { 556 SFTKAttribute *attribute; 557 PRBool tok = PR_FALSE; 558 559 attribute = sftk_FindAttribute(object, type); 560 if (attribute == NULL) { 561 return PR_FALSE; 562 } 563 tok = (PRBool)(*(CK_BBOOL *)attribute->attrib.pValue); 564 sftk_FreeAttribute(attribute); 565 566 return tok; 567 } 568 569 /* 570 * force an attribute to null. 571 * this is for sensitive keys which are stored in the database, we don't 572 * want to keep this info around in memory in the clear. 573 */ 574 void 575 sftk_nullAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type) 576 { 577 SFTKAttribute *attribute; 578 579 attribute = sftk_FindAttribute(object, type); 580 if (attribute == NULL) 581 return; 582 583 if (attribute->attrib.pValue != NULL) { 584 PORT_Memset(attribute->attrib.pValue, 0, attribute->attrib.ulValueLen); 585 if (attribute->freeData) { 586 PORT_Free(attribute->attrib.pValue); 587 } 588 attribute->freeData = PR_FALSE; 589 attribute->attrib.pValue = NULL; 590 attribute->attrib.ulValueLen = 0; 591 } 592 sftk_FreeAttribute(attribute); 593 } 594 595 static CK_RV 596 sftk_forceTokenAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, 597 const void *value, unsigned int len) 598 { 599 CK_ATTRIBUTE attribute; 600 SFTKDBHandle *dbHandle = NULL; 601 SFTKTokenObject *to = sftk_narrowToTokenObject(object); 602 CK_RV crv; 603 604 PORT_Assert(to); 605 if (to == NULL) { 606 return CKR_DEVICE_ERROR; 607 } 608 609 dbHandle = sftk_getDBForTokenObject(object->slot, object->handle); 610 611 attribute.type = type; 612 attribute.pValue = (void *)value; 613 attribute.ulValueLen = len; 614 615 crv = sftkdb_SetAttributeValue(dbHandle, object, &attribute, 1); 616 sftk_freeDB(dbHandle); 617 return crv; 618 } 619 620 /* 621 * force an attribute to a specifc value. 622 */ 623 CK_RV 624 sftk_forceAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, 625 const void *value, unsigned int len) 626 { 627 SFTKAttribute *attribute; 628 void *att_val = NULL; 629 PRBool freeData = PR_FALSE; 630 631 PORT_Assert(object); 632 PORT_Assert(object->refCount); 633 PORT_Assert(object->slot); 634 if (!object || 635 !object->refCount || 636 !object->slot) { 637 return CKR_DEVICE_ERROR; 638 } 639 /* validation flags are stored as FIPS indicators, 640 * don't send them through the general attribute 641 * parsing */ 642 if (type == CKA_OBJECT_VALIDATION_FLAGS) { 643 CK_FLAGS validation; 644 if (len != sizeof(CK_FLAGS)) { 645 return CKR_ATTRIBUTE_VALUE_INVALID; 646 } 647 validation = *(CK_FLAGS *)value; 648 /* we only understand FIPS currently, don't allow setting 649 * other flags */ 650 if ((validation & ~SFTK_VALIDATION_FIPS_FLAG) != 0) { 651 return CKR_ATTRIBUTE_VALUE_INVALID; 652 } 653 object->validation_value = validation; 654 return CKR_OK; 655 } 656 if (sftk_isToken(object->handle)) { 657 return sftk_forceTokenAttribute(object, type, value, len); 658 } 659 attribute = sftk_FindAttribute(object, type); 660 if (attribute == NULL) 661 return sftk_AddAttributeType(object, type, value, len); 662 663 if (value) { 664 if (len <= ATTR_SPACE) { 665 att_val = attribute->space; 666 } else { 667 att_val = PORT_Alloc(len); 668 freeData = PR_TRUE; 669 } 670 if (att_val == NULL) { 671 return CKR_HOST_MEMORY; 672 } 673 if (attribute->attrib.pValue == att_val) { 674 PORT_Memset(attribute->attrib.pValue, 0, 675 attribute->attrib.ulValueLen); 676 } 677 PORT_Memcpy(att_val, value, len); 678 } 679 if (attribute->attrib.pValue != NULL) { 680 if (attribute->attrib.pValue != att_val) { 681 PORT_Memset(attribute->attrib.pValue, 0, 682 attribute->attrib.ulValueLen); 683 } 684 if (attribute->freeData) { 685 PORT_Free(attribute->attrib.pValue); 686 } 687 attribute->freeData = PR_FALSE; 688 attribute->attrib.pValue = NULL; 689 attribute->attrib.ulValueLen = 0; 690 } 691 if (att_val) { 692 attribute->attrib.pValue = att_val; 693 attribute->attrib.ulValueLen = len; 694 attribute->freeData = freeData; 695 } 696 sftk_FreeAttribute(attribute); 697 return CKR_OK; 698 } 699 700 /* 701 * return a null terminated string from attribute 'type'. This string 702 * is allocated and needs to be freed with PORT_Free() When complete. 703 */ 704 char * 705 sftk_getString(SFTKObject *object, CK_ATTRIBUTE_TYPE type) 706 { 707 SFTKAttribute *attribute; 708 char *label = NULL; 709 710 attribute = sftk_FindAttribute(object, type); 711 if (attribute == NULL) 712 return NULL; 713 714 if (attribute->attrib.pValue != NULL) { 715 label = (char *)PORT_Alloc(attribute->attrib.ulValueLen + 1); 716 if (label == NULL) { 717 sftk_FreeAttribute(attribute); 718 return NULL; 719 } 720 721 PORT_Memcpy(label, attribute->attrib.pValue, 722 attribute->attrib.ulValueLen); 723 label[attribute->attrib.ulValueLen] = 0; 724 } 725 sftk_FreeAttribute(attribute); 726 return label; 727 } 728 729 /* 730 * decode when a particular attribute may be modified 731 * SFTK_NEVER: This attribute must be set at object creation time and 732 * can never be modified. 733 * SFTK_ONCOPY: This attribute may be modified only when you copy the 734 * object. 735 * SFTK_SENSITIVE: The CKA_SENSITIVE attribute can only be changed from 736 * CK_FALSE to CK_TRUE. 737 * SFTK_ALWAYS: This attribute can always be modified. 738 * Some attributes vary their modification type based on the class of the 739 * object. 740 */ 741 SFTKModifyType 742 sftk_modifyType(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass) 743 { 744 /* if we don't know about it, user user defined, always allow modify */ 745 SFTKModifyType mtype = SFTK_ALWAYS; 746 747 switch (type) { 748 /* NEVER */ 749 case CKA_CLASS: 750 case CKA_CERTIFICATE_TYPE: 751 case CKA_KEY_TYPE: 752 case CKA_MODULUS: 753 case CKA_MODULUS_BITS: 754 case CKA_PUBLIC_EXPONENT: 755 case CKA_PRIVATE_EXPONENT: 756 case CKA_PRIME: 757 case CKA_BASE: 758 case CKA_PRIME_1: 759 case CKA_PRIME_2: 760 case CKA_EXPONENT_1: 761 case CKA_EXPONENT_2: 762 case CKA_COEFFICIENT: 763 case CKA_SEED: 764 case CKA_PARAMETER_SET: 765 case CKA_VALUE_LEN: 766 case CKA_ALWAYS_SENSITIVE: 767 case CKA_NEVER_EXTRACTABLE: 768 case CKA_NSS_DB: 769 mtype = SFTK_NEVER; 770 break; 771 772 /* ONCOPY */ 773 case CKA_TOKEN: 774 case CKA_PRIVATE: 775 case CKA_MODIFIABLE: 776 mtype = SFTK_ONCOPY; 777 break; 778 779 /* SENSITIVE */ 780 case CKA_SENSITIVE: 781 case CKA_EXTRACTABLE: 782 mtype = SFTK_SENSITIVE; 783 break; 784 785 /* ALWAYS */ 786 case CKA_LABEL: 787 case CKA_APPLICATION: 788 case CKA_ID: 789 case CKA_SERIAL_NUMBER: 790 case CKA_START_DATE: 791 case CKA_END_DATE: 792 case CKA_DERIVE: 793 case CKA_ENCRYPT: 794 case CKA_DECRYPT: 795 case CKA_SIGN: 796 case CKA_VERIFY: 797 case CKA_SIGN_RECOVER: 798 case CKA_VERIFY_RECOVER: 799 case CKA_WRAP: 800 case CKA_UNWRAP: 801 mtype = SFTK_ALWAYS; 802 break; 803 804 /* DEPENDS ON CLASS */ 805 case CKA_VALUE: 806 mtype = (inClass == CKO_DATA) ? SFTK_ALWAYS : SFTK_NEVER; 807 break; 808 809 case CKA_SUBPRIME: 810 /* allow the CKA_SUBPRIME to be added to dh private keys */ 811 mtype = (inClass == CKO_PRIVATE_KEY) ? SFTK_ALWAYS : SFTK_NEVER; 812 break; 813 814 case CKA_SUBJECT: 815 mtype = (inClass == CKO_CERTIFICATE) ? SFTK_NEVER : SFTK_ALWAYS; 816 break; 817 default: 818 break; 819 } 820 return mtype; 821 } 822 823 /* decode if a particular attribute is sensitive (cannot be read 824 * back to the user of if the object is set to SENSITIVE) */ 825 PRBool 826 sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass) 827 { 828 switch (type) { 829 /* ALWAYS */ 830 case CKA_PRIVATE_EXPONENT: 831 case CKA_PRIME_1: 832 case CKA_PRIME_2: 833 case CKA_EXPONENT_1: 834 case CKA_EXPONENT_2: 835 case CKA_COEFFICIENT: 836 case CKA_SEED: 837 return PR_TRUE; 838 839 /* DEPENDS ON CLASS */ 840 case CKA_VALUE: 841 /* PRIVATE and SECRET KEYS have SENSITIVE values */ 842 return (PRBool)((inClass == CKO_PRIVATE_KEY) || (inClass == CKO_SECRET_KEY)); 843 844 default: 845 break; 846 } 847 return PR_FALSE; 848 } 849 850 /* 851 * copy an attribute into a SECItem. Secitem is allocated in the specified 852 * arena. 853 */ 854 CK_RV 855 sftk_Attribute2SecItem(PLArenaPool *arena, SECItem *item, SFTKObject *object, 856 CK_ATTRIBUTE_TYPE type) 857 { 858 int len; 859 SFTKAttribute *attribute; 860 861 attribute = sftk_FindAttribute(object, type); 862 if (attribute == NULL) 863 return CKR_TEMPLATE_INCOMPLETE; 864 len = attribute->attrib.ulValueLen; 865 866 if (arena) { 867 item->data = (unsigned char *)PORT_ArenaAlloc(arena, len); 868 } else { 869 item->data = (unsigned char *)PORT_Alloc(len); 870 } 871 if (item->data == NULL) { 872 sftk_FreeAttribute(attribute); 873 return CKR_HOST_MEMORY; 874 } 875 item->len = len; 876 PORT_Memcpy(item->data, attribute->attrib.pValue, len); 877 sftk_FreeAttribute(attribute); 878 return CKR_OK; 879 } 880 881 CK_RV 882 sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, 883 CK_ULONG *longData) 884 { 885 SFTKAttribute *attribute; 886 887 attribute = sftk_FindAttribute(object, type); 888 if (attribute == NULL) 889 return CKR_TEMPLATE_INCOMPLETE; 890 891 if (attribute->attrib.ulValueLen != sizeof(CK_ULONG)) { 892 return CKR_ATTRIBUTE_VALUE_INVALID; 893 } 894 895 *longData = *(CK_ULONG *)attribute->attrib.pValue; 896 sftk_FreeAttribute(attribute); 897 return CKR_OK; 898 } 899 900 CK_RV 901 sftk_ReadAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, 902 unsigned char *data, unsigned int maxLen, unsigned int *lenp) 903 { 904 SFTKAttribute *attribute; 905 906 attribute = sftk_FindAttribute(object, type); 907 if (attribute == NULL) 908 return CKR_TEMPLATE_INCOMPLETE; 909 910 *lenp = attribute->attrib.ulValueLen; 911 if (*lenp > maxLen) { 912 /* normally would be CKR_BUFFER_TOO_SMALL, but 913 * it used with internal buffers, so if the value is 914 * to long, the original attribute was invalid */ 915 return CKR_ATTRIBUTE_VALUE_INVALID; 916 } 917 PORT_Memcpy(data, attribute->attrib.pValue, *lenp); 918 sftk_FreeAttribute(attribute); 919 return CKR_OK; 920 } 921 922 void 923 sftk_DeleteAttributeType(SFTKObject *object, CK_ATTRIBUTE_TYPE type) 924 { 925 SFTKAttribute *attribute; 926 attribute = sftk_FindAttribute(object, type); 927 if (attribute == NULL) 928 return; 929 sftk_DeleteAttribute(object, attribute); 930 sftk_DestroyAttribute(attribute); 931 } 932 933 CK_RV 934 sftk_AddAttributeType(SFTKObject *object, CK_ATTRIBUTE_TYPE type, 935 const void *valPtr, CK_ULONG length) 936 { 937 SFTKAttribute *attribute; 938 attribute = sftk_NewAttribute(object, type, valPtr, length); 939 if (attribute == NULL) { 940 return CKR_HOST_MEMORY; 941 } 942 sftk_AddAttribute(object, attribute); 943 return CKR_OK; 944 } 945 946 /* 947 * ******************** Object Utilities ******************************* 948 */ 949 950 /* must be called holding sftk_tokenKeyLock(slot) */ 951 static SECItem * 952 sftk_lookupTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle) 953 { 954 return (SECItem *)PL_HashTableLookup(slot->tokObjHashTable, (void *)(uintptr_t)handle); 955 } 956 957 /* 958 * use the refLock. This operations should be very rare, so the added 959 * contention on the ref lock should be lower than the overhead of adding 960 * a new lock. We use separate functions for this just in case I'm wrong. 961 */ 962 static void 963 sftk_tokenKeyLock(SFTKSlot *slot) 964 { 965 SKIP_AFTER_FORK(PZ_Lock(slot->objectLock)); 966 } 967 968 static void 969 sftk_tokenKeyUnlock(SFTKSlot *slot) 970 { 971 SKIP_AFTER_FORK(PZ_Unlock(slot->objectLock)); 972 } 973 974 static PRIntn 975 sftk_freeHashItem(PLHashEntry *entry, PRIntn index, void *arg) 976 { 977 SECItem *item = (SECItem *)entry->value; 978 979 SECITEM_FreeItem(item, PR_TRUE); 980 return HT_ENUMERATE_NEXT; 981 } 982 983 CK_RV 984 SFTK_ClearTokenKeyHashTable(SFTKSlot *slot) 985 { 986 sftk_tokenKeyLock(slot); 987 PORT_Assert(!slot->present); 988 PL_HashTableEnumerateEntries(slot->tokObjHashTable, sftk_freeHashItem, NULL); 989 sftk_tokenKeyUnlock(slot); 990 return CKR_OK; 991 } 992 993 /* allocation hooks that allow us to recycle old object structures */ 994 static SFTKObjectFreeList sessionObjectList = { NULL, NULL, 0 }; 995 static SFTKObjectFreeList tokenObjectList = { NULL, NULL, 0 }; 996 997 SFTKObject * 998 sftk_GetObjectFromList(PRBool *hasLocks, PRBool optimizeSpace, 999 SFTKObjectFreeList *list, unsigned int hashSize, PRBool isSessionObject) 1000 { 1001 SFTKObject *object; 1002 int size = 0; 1003 1004 if (!optimizeSpace) { 1005 PZ_Lock(list->lock); 1006 object = list->head; 1007 if (object) { 1008 list->head = object->next; 1009 list->count--; 1010 } 1011 PZ_Unlock(list->lock); 1012 if (object) { 1013 // As a safeguard against misuse of the library, ensure we don't 1014 // hand out live objects that somehow land in the free list. 1015 PORT_Assert(object->refCount == 0); 1016 if (object->refCount == 0) { 1017 object->next = object->prev = NULL; 1018 *hasLocks = PR_TRUE; 1019 return object; 1020 } 1021 } 1022 } 1023 size = isSessionObject ? sizeof(SFTKSessionObject) + hashSize * sizeof(SFTKAttribute *) : sizeof(SFTKTokenObject); 1024 1025 object = (SFTKObject *)PORT_ZAlloc(size); 1026 if (isSessionObject && object) { 1027 ((SFTKSessionObject *)object)->hashSize = hashSize; 1028 } 1029 *hasLocks = PR_FALSE; 1030 return object; 1031 } 1032 1033 static void 1034 sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list, 1035 PRBool isSessionObject) 1036 { 1037 1038 /* the code below is equivalent to : 1039 * optimizeSpace = isSessionObject ? object->optimizeSpace : PR_FALSE; 1040 * just faster. 1041 */ 1042 PRBool optimizeSpace = isSessionObject && 1043 ((SFTKSessionObject *)object)->optimizeSpace; 1044 if (object->refLock && !optimizeSpace) { 1045 PZ_Lock(list->lock); 1046 if (list->count < MAX_OBJECT_LIST_SIZE) { 1047 object->next = list->head; 1048 list->head = object; 1049 list->count++; 1050 PZ_Unlock(list->lock); 1051 return; 1052 } 1053 PZ_Unlock(list->lock); 1054 } 1055 if (isSessionObject) { 1056 SFTKSessionObject *so = (SFTKSessionObject *)object; 1057 PZ_DestroyLock(so->attributeLock); 1058 so->attributeLock = NULL; 1059 } 1060 if (object->refLock) { 1061 PZ_DestroyLock(object->refLock); 1062 object->refLock = NULL; 1063 } 1064 PORT_Free(object); 1065 } 1066 1067 static SFTKObject * 1068 sftk_freeObjectData(SFTKObject *object) 1069 { 1070 SFTKObject *next = object->next; 1071 1072 PORT_Free(object); 1073 return next; 1074 } 1075 1076 static void 1077 sftk_InitFreeList(SFTKObjectFreeList *list) 1078 { 1079 if (!list->lock) { 1080 list->lock = PZ_NewLock(nssILockObject); 1081 } 1082 } 1083 1084 void 1085 sftk_InitFreeLists(void) 1086 { 1087 sftk_InitFreeList(&sessionObjectList); 1088 sftk_InitFreeList(&tokenObjectList); 1089 } 1090 1091 static void 1092 sftk_CleanupFreeList(SFTKObjectFreeList *list, PRBool isSessionList) 1093 { 1094 SFTKObject *object; 1095 1096 if (!list->lock) { 1097 return; 1098 } 1099 SKIP_AFTER_FORK(PZ_Lock(list->lock)); 1100 for (object = list->head; object != NULL; 1101 object = sftk_freeObjectData(object)) { 1102 PZ_DestroyLock(object->refLock); 1103 if (isSessionList) { 1104 PZ_DestroyLock(((SFTKSessionObject *)object)->attributeLock); 1105 } 1106 } 1107 list->count = 0; 1108 list->head = NULL; 1109 SKIP_AFTER_FORK(PZ_Unlock(list->lock)); 1110 SKIP_AFTER_FORK(PZ_DestroyLock(list->lock)); 1111 list->lock = NULL; 1112 } 1113 1114 void 1115 sftk_CleanupFreeLists(void) 1116 { 1117 sftk_CleanupFreeList(&sessionObjectList, PR_TRUE); 1118 sftk_CleanupFreeList(&tokenObjectList, PR_FALSE); 1119 } 1120 1121 /* 1122 * Create a new object 1123 */ 1124 SFTKObject * 1125 sftk_NewObject(SFTKSlot *slot) 1126 { 1127 SFTKObject *object; 1128 SFTKSessionObject *sessObject; 1129 PRBool hasLocks = PR_FALSE; 1130 unsigned int i; 1131 unsigned int hashSize = 0; 1132 1133 hashSize = (slot->optimizeSpace) ? SPACE_ATTRIBUTE_HASH_SIZE : TIME_ATTRIBUTE_HASH_SIZE; 1134 1135 object = sftk_GetObjectFromList(&hasLocks, slot->optimizeSpace, 1136 &sessionObjectList, hashSize, PR_TRUE); 1137 if (object == NULL) { 1138 return NULL; 1139 } 1140 sessObject = (SFTKSessionObject *)object; 1141 sessObject->nextAttr = 0; 1142 1143 for (i = 0; i < MAX_OBJS_ATTRS; i++) { 1144 sessObject->attrList[i].attrib.pValue = NULL; 1145 sessObject->attrList[i].freeData = PR_FALSE; 1146 } 1147 sessObject->optimizeSpace = slot->optimizeSpace; 1148 1149 object->handle = 0; 1150 object->next = object->prev = NULL; 1151 object->slot = slot; 1152 /* set up the validation flags */ 1153 object->validation_value = 0; 1154 object->validation_attribute.next = NULL; 1155 object->validation_attribute.prev = NULL; 1156 object->validation_attribute.freeAttr = PR_FALSE; 1157 object->validation_attribute.freeData = PR_FALSE; 1158 object->validation_attribute.handle = CKA_OBJECT_VALIDATION_FLAGS; 1159 object->validation_attribute.attrib.type = CKA_OBJECT_VALIDATION_FLAGS; 1160 object->validation_attribute.attrib.pValue = &object->validation_value; 1161 object->validation_attribute.attrib.ulValueLen = sizeof(object->validation_value); 1162 /* initialize the FIPS flag properly */ 1163 sftk_setFIPS(object, sftk_isFIPS(slot->slotID)); 1164 1165 object->refCount = 1; 1166 sessObject->sessionList.next = NULL; 1167 sessObject->sessionList.prev = NULL; 1168 sessObject->sessionList.parent = object; 1169 sessObject->session = NULL; 1170 sessObject->wasDerived = PR_FALSE; 1171 if (!hasLocks) 1172 object->refLock = PZ_NewLock(nssILockRefLock); 1173 if (object->refLock == NULL) { 1174 PORT_Free(object); 1175 return NULL; 1176 } 1177 if (!hasLocks) 1178 sessObject->attributeLock = PZ_NewLock(nssILockAttribute); 1179 if (sessObject->attributeLock == NULL) { 1180 PZ_DestroyLock(object->refLock); 1181 PORT_Free(object); 1182 return NULL; 1183 } 1184 for (i = 0; i < sessObject->hashSize; i++) { 1185 sessObject->head[i] = NULL; 1186 } 1187 object->objectInfo = NULL; 1188 object->infoFree = NULL; 1189 return object; 1190 } 1191 1192 static CK_RV 1193 sftk_DestroySessionObjectData(SFTKSessionObject *so) 1194 { 1195 int i; 1196 1197 for (i = 0; i < MAX_OBJS_ATTRS; i++) { 1198 unsigned char *value = so->attrList[i].attrib.pValue; 1199 if (value) { 1200 PORT_Memset(value, 0, so->attrList[i].attrib.ulValueLen); 1201 if (so->attrList[i].freeData) { 1202 PORT_Free(value); 1203 } 1204 so->attrList[i].attrib.pValue = NULL; 1205 so->attrList[i].freeData = PR_FALSE; 1206 } 1207 } 1208 /* PZ_DestroyLock(so->attributeLock);*/ 1209 return CKR_OK; 1210 } 1211 1212 /* 1213 * free all the data associated with an object. Object reference count must 1214 * be 'zero'. 1215 */ 1216 static CK_RV 1217 sftk_DestroyObject(SFTKObject *object) 1218 { 1219 CK_RV crv = CKR_OK; 1220 SFTKSessionObject *so = sftk_narrowToSessionObject(object); 1221 SFTKTokenObject *to = sftk_narrowToTokenObject(object); 1222 1223 PORT_Assert(object->refCount == 0); 1224 1225 /* delete the database value */ 1226 if (to) { 1227 if (to->dbKey.data) { 1228 PORT_Free(to->dbKey.data); 1229 to->dbKey.data = NULL; 1230 } 1231 } 1232 if (so) { 1233 sftk_DestroySessionObjectData(so); 1234 } 1235 if (object->objectInfo) { 1236 (*object->infoFree)(object->objectInfo); 1237 object->objectInfo = NULL; 1238 object->infoFree = NULL; 1239 } 1240 if (so) { 1241 sftk_PutObjectToList(object, &sessionObjectList, PR_TRUE); 1242 } else { 1243 sftk_PutObjectToList(object, &tokenObjectList, PR_FALSE); 1244 } 1245 return crv; 1246 } 1247 1248 void 1249 sftk_ReferenceObject(SFTKObject *object) 1250 { 1251 PZ_Lock(object->refLock); 1252 PORT_Assert(object->refCount > 0); 1253 object->refCount++; 1254 PZ_Unlock(object->refLock); 1255 } 1256 1257 static SFTKObject * 1258 sftk_ObjectFromHandleOnSlot(CK_OBJECT_HANDLE handle, SFTKSlot *slot) 1259 { 1260 SFTKObject *object; 1261 PRUint32 index = sftk_hash(handle, slot->sessObjHashSize); 1262 1263 if (sftk_isToken(handle)) { 1264 return sftk_NewTokenObject(slot, NULL, handle); 1265 } 1266 1267 PZ_Lock(slot->objectLock); 1268 sftkqueue_find2(object, handle, index, slot->sessObjHashTable); 1269 if (object) { 1270 sftk_ReferenceObject(object); 1271 } 1272 PZ_Unlock(slot->objectLock); 1273 1274 return (object); 1275 } 1276 /* 1277 * look up and object structure from a handle. OBJECT_Handles only make 1278 * sense in terms of a given session. make a reference to that object 1279 * structure returned. 1280 */ 1281 SFTKObject * 1282 sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle, SFTKSession *session) 1283 { 1284 SFTKSlot *slot = sftk_SlotFromSession(session); 1285 1286 return sftk_ObjectFromHandleOnSlot(handle, slot); 1287 } 1288 1289 /* 1290 * release a reference to an object handle 1291 */ 1292 SFTKFreeStatus 1293 sftk_FreeObject(SFTKObject *object) 1294 { 1295 PRBool destroy = PR_FALSE; 1296 CK_RV crv; 1297 1298 PZ_Lock(object->refLock); 1299 if (object->refCount == 1) 1300 destroy = PR_TRUE; 1301 object->refCount--; 1302 PZ_Unlock(object->refLock); 1303 1304 if (destroy) { 1305 crv = sftk_DestroyObject(object); 1306 if (crv != CKR_OK) { 1307 return SFTK_DestroyFailure; 1308 } 1309 return SFTK_Destroyed; 1310 } 1311 return SFTK_Busy; 1312 } 1313 1314 /* find the next available object handle that isn't currently in use */ 1315 /* NOTE: This function could loop forever if we've exhausted all 1316 * 3^31-1 handles. This is highly unlikely (NSS has been running for 1317 * decades with this code) uless we start increasing the size of the 1318 * SFTK_TOKEN_MASK (which is just the high bit currently). */ 1319 CK_OBJECT_HANDLE 1320 sftk_getNextHandle(SFTKSlot *slot) 1321 { 1322 CK_OBJECT_HANDLE handle; 1323 SFTKObject *duplicateObject = NULL; 1324 do { 1325 PRUint32 wrappedAround; 1326 1327 duplicateObject = NULL; 1328 PZ_Lock(slot->objectLock); 1329 wrappedAround = slot->sessionObjectHandleCount & SFTK_TOKEN_MASK; 1330 handle = slot->sessionObjectHandleCount & ~SFTK_TOKEN_MASK; 1331 if (!handle) /* don't allow zero handle */ 1332 handle = NSC_MIN_SESSION_OBJECT_HANDLE; 1333 slot->sessionObjectHandleCount = (handle + 1U) | wrappedAround; 1334 /* Is there already a session object with this handle? */ 1335 if (wrappedAround) { 1336 sftkqueue_find(duplicateObject, handle, slot->sessObjHashTable, 1337 slot->sessObjHashSize); 1338 } 1339 PZ_Unlock(slot->objectLock); 1340 } while (duplicateObject != NULL); 1341 return handle; 1342 } 1343 1344 /* 1345 * add an object to a slot and session queue. These two functions 1346 * adopt the object. 1347 */ 1348 void 1349 sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object) 1350 { 1351 PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize); 1352 sftkqueue_init_element(object); 1353 PZ_Lock(slot->objectLock); 1354 sftkqueue_add2(object, object->handle, index, slot->sessObjHashTable); 1355 PZ_Unlock(slot->objectLock); 1356 } 1357 1358 void 1359 sftk_AddObject(SFTKSession *session, SFTKObject *object) 1360 { 1361 SFTKSlot *slot = sftk_SlotFromSession(session); 1362 SFTKSessionObject *so = sftk_narrowToSessionObject(object); 1363 1364 if (so) { 1365 PZ_Lock(session->objectLock); 1366 sftkqueue_add(&so->sessionList, 0, session->objects, 0); 1367 so->session = session; 1368 PZ_Unlock(session->objectLock); 1369 } 1370 sftk_AddSlotObject(slot, object); 1371 sftk_ReferenceObject(object); 1372 } 1373 1374 /* 1375 * delete an object from a slot and session queue 1376 */ 1377 CK_RV 1378 sftk_DeleteObject(SFTKSession *session, SFTKObject *object) 1379 { 1380 SFTKSlot *slot = sftk_SlotFromSession(session); 1381 SFTKSessionObject *so = sftk_narrowToSessionObject(object); 1382 CK_RV crv = CKR_OK; 1383 PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize); 1384 1385 /* Handle Token case */ 1386 if (so && so->session) { 1387 session = so->session; 1388 PZ_Lock(session->objectLock); 1389 sftkqueue_delete(&so->sessionList, 0, session->objects, 0); 1390 PZ_Unlock(session->objectLock); 1391 PZ_Lock(slot->objectLock); 1392 sftkqueue_delete2(object, object->handle, index, slot->sessObjHashTable); 1393 PZ_Unlock(slot->objectLock); 1394 sftkqueue_clear_deleted_element(object); 1395 sftk_FreeObject(object); /* free the reference owned by the queue */ 1396 } else { 1397 SFTKDBHandle *handle = sftk_getDBForTokenObject(slot, object->handle); 1398 #ifdef DEBUG 1399 SFTKTokenObject *to = sftk_narrowToTokenObject(object); 1400 PORT_Assert(to); 1401 #endif 1402 crv = sftkdb_DestroyObject(handle, object->handle, object->objclass); 1403 sftk_freeDB(handle); 1404 } 1405 return crv; 1406 } 1407 1408 /* 1409 * Token objects don't explicitly store their attributes, so we need to know 1410 * what attributes make up a particular token object before we can copy it. 1411 * below are the tables by object type. 1412 */ 1413 static const CK_ATTRIBUTE_TYPE commonAttrs[] = { 1414 CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_MODIFIABLE 1415 }; 1416 static const CK_ULONG commonAttrsCount = 1417 sizeof(commonAttrs) / sizeof(commonAttrs[0]); 1418 1419 static const CK_ATTRIBUTE_TYPE commonKeyAttrs[] = { 1420 CKA_ID, CKA_START_DATE, CKA_END_DATE, CKA_DERIVE, CKA_LOCAL, CKA_KEY_TYPE 1421 }; 1422 static const CK_ULONG commonKeyAttrsCount = 1423 sizeof(commonKeyAttrs) / sizeof(commonKeyAttrs[0]); 1424 1425 static const CK_ATTRIBUTE_TYPE secretKeyAttrs[] = { 1426 CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN, 1427 CKA_VERIFY, CKA_WRAP, CKA_UNWRAP, CKA_VALUE 1428 }; 1429 static const CK_ULONG secretKeyAttrsCount = 1430 sizeof(secretKeyAttrs) / sizeof(secretKeyAttrs[0]); 1431 1432 static const CK_ATTRIBUTE_TYPE commonPubKeyAttrs[] = { 1433 CKA_ENCRYPT, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_WRAP, CKA_SUBJECT 1434 }; 1435 static const CK_ULONG commonPubKeyAttrsCount = 1436 sizeof(commonPubKeyAttrs) / sizeof(commonPubKeyAttrs[0]); 1437 1438 static const CK_ATTRIBUTE_TYPE rsaPubKeyAttrs[] = { 1439 CKA_MODULUS, CKA_PUBLIC_EXPONENT 1440 }; 1441 static const CK_ULONG rsaPubKeyAttrsCount = 1442 sizeof(rsaPubKeyAttrs) / sizeof(rsaPubKeyAttrs[0]); 1443 1444 static const CK_ATTRIBUTE_TYPE dsaPubKeyAttrs[] = { 1445 CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE 1446 }; 1447 static const CK_ULONG dsaPubKeyAttrsCount = 1448 sizeof(dsaPubKeyAttrs) / sizeof(dsaPubKeyAttrs[0]); 1449 1450 static const CK_ATTRIBUTE_TYPE dhPubKeyAttrs[] = { 1451 CKA_PRIME, CKA_BASE, CKA_VALUE 1452 }; 1453 static const CK_ULONG dhPubKeyAttrsCount = 1454 sizeof(dhPubKeyAttrs) / sizeof(dhPubKeyAttrs[0]); 1455 static const CK_ATTRIBUTE_TYPE ecPubKeyAttrs[] = { 1456 CKA_EC_PARAMS, CKA_EC_POINT 1457 }; 1458 static const CK_ULONG ecPubKeyAttrsCount = 1459 sizeof(ecPubKeyAttrs) / sizeof(ecPubKeyAttrs[0]); 1460 1461 static const CK_ATTRIBUTE_TYPE mldsaPubKeyAttrs[] = { 1462 CKA_PARAMETER_SET, CKA_VALUE 1463 }; 1464 static const CK_ULONG mldsaPubKeyAttrsCount = PR_ARRAY_SIZE(mldsaPubKeyAttrs); 1465 1466 static const CK_ATTRIBUTE_TYPE commonPrivKeyAttrs[] = { 1467 CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_SUBJECT, 1468 CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NSS_DB, CKA_PUBLIC_KEY_INFO 1469 }; 1470 static const CK_ULONG commonPrivKeyAttrsCount = 1471 sizeof(commonPrivKeyAttrs) / sizeof(commonPrivKeyAttrs[0]); 1472 1473 static const CK_ATTRIBUTE_TYPE rsaPrivKeyAttrs[] = { 1474 CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, 1475 CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT 1476 }; 1477 static const CK_ULONG rsaPrivKeyAttrsCount = 1478 sizeof(rsaPrivKeyAttrs) / sizeof(rsaPrivKeyAttrs[0]); 1479 1480 static const CK_ATTRIBUTE_TYPE dsaPrivKeyAttrs[] = { 1481 CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE 1482 }; 1483 static const CK_ULONG dsaPrivKeyAttrsCount = 1484 sizeof(dsaPrivKeyAttrs) / sizeof(dsaPrivKeyAttrs[0]); 1485 1486 static const CK_ATTRIBUTE_TYPE dhPrivKeyAttrs[] = { 1487 CKA_PRIME, CKA_BASE, CKA_VALUE 1488 }; 1489 static const CK_ULONG dhPrivKeyAttrsCount = 1490 sizeof(dhPrivKeyAttrs) / sizeof(dhPrivKeyAttrs[0]); 1491 static const CK_ATTRIBUTE_TYPE ecPrivKeyAttrs[] = { 1492 CKA_EC_PARAMS, CKA_VALUE 1493 }; 1494 static const CK_ULONG ecPrivKeyAttrsCount = 1495 sizeof(ecPrivKeyAttrs) / sizeof(ecPrivKeyAttrs[0]); 1496 1497 static const CK_ATTRIBUTE_TYPE mldsaPrivKeyAttrs[] = { 1498 CKA_PARAMETER_SET, CKA_VALUE, CKA_SEED 1499 }; 1500 static const CK_ULONG mldsaPrivKeyAttrsCount = PR_ARRAY_SIZE(mldsaPrivKeyAttrs); 1501 1502 static const CK_ATTRIBUTE_TYPE certAttrs[] = { 1503 CKA_CERTIFICATE_TYPE, CKA_VALUE, CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER 1504 }; 1505 static const CK_ULONG certAttrsCount = 1506 sizeof(certAttrs) / sizeof(certAttrs[0]); 1507 1508 static const CK_ATTRIBUTE_TYPE nssTrustAttrs[] = { 1509 CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_NSS_CERT_SHA1_HASH, 1510 CKA_NSS_CERT_MD5_HASH, CKA_NSS_TRUST_SERVER_AUTH, CKA_NSS_TRUST_CLIENT_AUTH, 1511 CKA_NSS_TRUST_EMAIL_PROTECTION, CKA_NSS_TRUST_CODE_SIGNING, 1512 CKA_NSS_TRUST_STEP_UP_APPROVED 1513 }; 1514 static const CK_ULONG nssTrustAttrsCount = 1515 sizeof(nssTrustAttrs) / sizeof(nssTrustAttrs[0]); 1516 1517 static const CK_ATTRIBUTE_TYPE trustAttrs[] = { 1518 CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_HASH_OF_CERTIFICATE, 1519 CKA_NAME_HASH_ALGORITHM, CKA_PKCS_TRUST_SERVER_AUTH, 1520 CKA_PKCS_TRUST_CLIENT_AUTH, CKA_PKCS_TRUST_EMAIL_PROTECTION, 1521 CKA_PKCS_TRUST_CODE_SIGNING 1522 }; 1523 static const CK_ULONG trustAttrsCount = 1524 sizeof(trustAttrs) / sizeof(trustAttrs[0]); 1525 1526 static const CK_ATTRIBUTE_TYPE smimeAttrs[] = { 1527 CKA_SUBJECT, CKA_NSS_EMAIL, CKA_NSS_SMIME_TIMESTAMP, CKA_VALUE 1528 }; 1529 static const CK_ULONG smimeAttrsCount = 1530 sizeof(smimeAttrs) / sizeof(smimeAttrs[0]); 1531 1532 static const CK_ATTRIBUTE_TYPE crlAttrs[] = { 1533 CKA_SUBJECT, CKA_VALUE, CKA_NSS_URL, CKA_NSS_KRL 1534 }; 1535 static const CK_ULONG crlAttrsCount = 1536 sizeof(crlAttrs) / sizeof(crlAttrs[0]); 1537 1538 /* copy an object based on it's table */ 1539 CK_RV 1540 stfk_CopyTokenAttributes(SFTKObject *destObject, SFTKTokenObject *src_to, 1541 const CK_ATTRIBUTE_TYPE *attrArray, CK_ULONG attrCount) 1542 { 1543 SFTKAttribute *attribute; 1544 SFTKAttribute *newAttribute; 1545 CK_RV crv = CKR_OK; 1546 unsigned int i; 1547 1548 for (i = 0; i < attrCount; i++) { 1549 if (!sftk_hasAttribute(destObject, attrArray[i])) { 1550 attribute = sftk_FindAttribute(&src_to->obj, attrArray[i]); 1551 if (!attribute) { 1552 continue; /* return CKR_ATTRIBUTE_VALUE_INVALID; */ 1553 } 1554 /* we need to copy the attribute since each attribute 1555 * only has one set of link list pointers */ 1556 newAttribute = sftk_NewAttribute(destObject, 1557 sftk_attr_expand(&attribute->attrib)); 1558 sftk_FreeAttribute(attribute); /* free the old attribute */ 1559 if (!newAttribute) { 1560 return CKR_HOST_MEMORY; 1561 } 1562 sftk_AddAttribute(destObject, newAttribute); 1563 } 1564 } 1565 return crv; 1566 } 1567 1568 CK_RV 1569 stfk_CopyTokenPrivateKey(SFTKObject *destObject, SFTKTokenObject *src_to) 1570 { 1571 CK_RV crv; 1572 CK_KEY_TYPE key_type; 1573 SFTKAttribute *attribute; 1574 1575 /* copy the common attributes for all keys first */ 1576 crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs, 1577 commonKeyAttrsCount); 1578 if (crv != CKR_OK) { 1579 goto fail; 1580 } 1581 /* copy the common attributes for all private keys next */ 1582 crv = stfk_CopyTokenAttributes(destObject, src_to, commonPrivKeyAttrs, 1583 commonPrivKeyAttrsCount); 1584 if (crv != CKR_OK) { 1585 goto fail; 1586 } 1587 attribute = sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE); 1588 PORT_Assert(attribute); /* if it wasn't here, ww should have failed 1589 * copying the common attributes */ 1590 if (!attribute) { 1591 /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but 1592 * the fact is, the only reason we couldn't get the attribute would 1593 * be a memory error or database error (an error in the 'device'). 1594 * if we have a database error code, we could return it here */ 1595 crv = CKR_DEVICE_ERROR; 1596 goto fail; 1597 } 1598 key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue; 1599 sftk_FreeAttribute(attribute); 1600 1601 /* finally copy the attributes for various private key types */ 1602 switch (key_type) { 1603 case CKK_RSA: 1604 crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPrivKeyAttrs, 1605 rsaPrivKeyAttrsCount); 1606 break; 1607 case CKK_DSA: 1608 crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPrivKeyAttrs, 1609 dsaPrivKeyAttrsCount); 1610 break; 1611 case CKK_ML_DSA: 1612 crv = stfk_CopyTokenAttributes(destObject, src_to, mldsaPrivKeyAttrs, 1613 mldsaPrivKeyAttrsCount); 1614 break; 1615 case CKK_DH: 1616 crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs, 1617 dhPrivKeyAttrsCount); 1618 break; 1619 case CKK_EC: 1620 crv = stfk_CopyTokenAttributes(destObject, src_to, ecPrivKeyAttrs, 1621 ecPrivKeyAttrsCount); 1622 break; 1623 default: 1624 crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types 1625 * of token keys into our database. */ 1626 } 1627 fail: 1628 return crv; 1629 } 1630 1631 CK_RV 1632 stfk_CopyTokenPublicKey(SFTKObject *destObject, SFTKTokenObject *src_to) 1633 { 1634 CK_RV crv; 1635 CK_KEY_TYPE key_type; 1636 SFTKAttribute *attribute; 1637 1638 /* copy the common attributes for all keys first */ 1639 crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs, 1640 commonKeyAttrsCount); 1641 if (crv != CKR_OK) { 1642 goto fail; 1643 } 1644 1645 /* copy the common attributes for all public keys next */ 1646 crv = stfk_CopyTokenAttributes(destObject, src_to, commonPubKeyAttrs, 1647 commonPubKeyAttrsCount); 1648 if (crv != CKR_OK) { 1649 goto fail; 1650 } 1651 attribute = sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE); 1652 PORT_Assert(attribute); /* if it wasn't here, ww should have failed 1653 * copying the common attributes */ 1654 if (!attribute) { 1655 /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but 1656 * the fact is, the only reason we couldn't get the attribute would 1657 * be a memory error or database error (an error in the 'device'). 1658 * if we have a database error code, we could return it here */ 1659 crv = CKR_DEVICE_ERROR; 1660 goto fail; 1661 } 1662 key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue; 1663 sftk_FreeAttribute(attribute); 1664 1665 /* finally copy the attributes for various public key types */ 1666 switch (key_type) { 1667 case CKK_RSA: 1668 crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPubKeyAttrs, 1669 rsaPubKeyAttrsCount); 1670 break; 1671 case CKK_DSA: 1672 crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPubKeyAttrs, 1673 dsaPubKeyAttrsCount); 1674 break; 1675 case CKK_ML_DSA: 1676 crv = stfk_CopyTokenAttributes(destObject, src_to, mldsaPubKeyAttrs, 1677 mldsaPubKeyAttrsCount); 1678 break; 1679 case CKK_DH: 1680 crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs, 1681 dhPubKeyAttrsCount); 1682 break; 1683 case CKK_EC: 1684 crv = stfk_CopyTokenAttributes(destObject, src_to, ecPubKeyAttrs, 1685 ecPubKeyAttrsCount); 1686 break; 1687 default: 1688 crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types 1689 * of token keys into our database. */ 1690 } 1691 fail: 1692 return crv; 1693 } 1694 CK_RV 1695 stfk_CopyTokenSecretKey(SFTKObject *destObject, SFTKTokenObject *src_to) 1696 { 1697 CK_RV crv; 1698 crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs, 1699 commonKeyAttrsCount); 1700 if (crv != CKR_OK) { 1701 goto fail; 1702 } 1703 crv = stfk_CopyTokenAttributes(destObject, src_to, secretKeyAttrs, 1704 secretKeyAttrsCount); 1705 fail: 1706 return crv; 1707 } 1708 1709 /* 1710 * Copy a token object. We need to explicitly copy the relevant 1711 * attributes since token objects don't store those attributes in 1712 * the token itself. 1713 */ 1714 CK_RV 1715 sftk_CopyTokenObject(SFTKObject *destObject, SFTKObject *srcObject) 1716 { 1717 SFTKTokenObject *src_to = sftk_narrowToTokenObject(srcObject); 1718 CK_RV crv; 1719 1720 PORT_Assert(src_to); 1721 if (src_to == NULL) { 1722 return CKR_DEVICE_ERROR; /* internal state inconsistant */ 1723 } 1724 1725 crv = stfk_CopyTokenAttributes(destObject, src_to, commonAttrs, 1726 commonAttrsCount); 1727 if (crv != CKR_OK) { 1728 goto fail; 1729 } 1730 switch (src_to->obj.objclass) { 1731 case CKO_CERTIFICATE: 1732 crv = stfk_CopyTokenAttributes(destObject, src_to, certAttrs, 1733 certAttrsCount); 1734 break; 1735 case CKO_NSS_TRUST: 1736 crv = stfk_CopyTokenAttributes(destObject, src_to, nssTrustAttrs, 1737 nssTrustAttrsCount); 1738 break; 1739 case CKO_TRUST: 1740 crv = stfk_CopyTokenAttributes(destObject, src_to, trustAttrs, 1741 trustAttrsCount); 1742 break; 1743 case CKO_NSS_SMIME: 1744 crv = stfk_CopyTokenAttributes(destObject, src_to, smimeAttrs, 1745 smimeAttrsCount); 1746 break; 1747 case CKO_NSS_CRL: 1748 crv = stfk_CopyTokenAttributes(destObject, src_to, crlAttrs, 1749 crlAttrsCount); 1750 break; 1751 case CKO_PRIVATE_KEY: 1752 crv = stfk_CopyTokenPrivateKey(destObject, src_to); 1753 break; 1754 case CKO_PUBLIC_KEY: 1755 crv = stfk_CopyTokenPublicKey(destObject, src_to); 1756 break; 1757 case CKO_SECRET_KEY: 1758 crv = stfk_CopyTokenSecretKey(destObject, src_to); 1759 break; 1760 default: 1761 crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types 1762 * of token keys into our database. */ 1763 } 1764 fail: 1765 return crv; 1766 } 1767 1768 /* 1769 * copy the attributes from one object to another. Don't overwrite existing 1770 * attributes. NOTE: This is a pretty expensive operation since it 1771 * grabs the attribute locks for the src object for a *long* time. 1772 */ 1773 CK_RV 1774 sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject) 1775 { 1776 SFTKAttribute *attribute; 1777 SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject); 1778 unsigned int i; 1779 1780 destObject->validation_value = srcObject->validation_value; 1781 if (src_so == NULL) { 1782 return sftk_CopyTokenObject(destObject, srcObject); 1783 } 1784 1785 PZ_Lock(src_so->attributeLock); 1786 for (i = 0; i < src_so->hashSize; i++) { 1787 attribute = src_so->head[i]; 1788 do { 1789 if (attribute) { 1790 if (!sftk_hasAttribute(destObject, attribute->handle)) { 1791 /* we need to copy the attribute since each attribute 1792 * only has one set of link list pointers */ 1793 SFTKAttribute *newAttribute = sftk_NewAttribute( 1794 destObject, sftk_attr_expand(&attribute->attrib)); 1795 if (newAttribute == NULL) { 1796 PZ_Unlock(src_so->attributeLock); 1797 return CKR_HOST_MEMORY; 1798 } 1799 sftk_AddAttribute(destObject, newAttribute); 1800 } 1801 attribute = attribute->next; 1802 } 1803 } while (attribute != NULL); 1804 } 1805 PZ_Unlock(src_so->attributeLock); 1806 1807 return CKR_OK; 1808 } 1809 1810 /* 1811 * ******************** Search Utilities ******************************* 1812 */ 1813 1814 /* add an object to a search list */ 1815 CK_RV 1816 AddToList(SFTKObjectListElement **list, SFTKObject *object) 1817 { 1818 SFTKObjectListElement *newElem = 1819 (SFTKObjectListElement *)PORT_Alloc(sizeof(SFTKObjectListElement)); 1820 1821 if (newElem == NULL) 1822 return CKR_HOST_MEMORY; 1823 1824 newElem->next = *list; 1825 newElem->object = object; 1826 sftk_ReferenceObject(object); 1827 1828 *list = newElem; 1829 return CKR_OK; 1830 } 1831 1832 /* return true if the object matches the template */ 1833 PRBool 1834 sftk_objectMatch(SFTKObject *object, CK_ATTRIBUTE_PTR theTemplate, int count) 1835 { 1836 int i; 1837 1838 for (i = 0; i < count; i++) { 1839 SFTKAttribute *attribute = sftk_FindAttribute(object, theTemplate[i].type); 1840 if (attribute == NULL) { 1841 return PR_FALSE; 1842 } 1843 if (attribute->attrib.ulValueLen == theTemplate[i].ulValueLen) { 1844 if (PORT_Memcmp(attribute->attrib.pValue, theTemplate[i].pValue, 1845 theTemplate[i].ulValueLen) == 0) { 1846 sftk_FreeAttribute(attribute); 1847 continue; 1848 } 1849 } 1850 sftk_FreeAttribute(attribute); 1851 return PR_FALSE; 1852 } 1853 return PR_TRUE; 1854 } 1855 1856 /* search through all the objects in the queue and return the template matches 1857 * in the object list. 1858 */ 1859 CK_RV 1860 sftk_searchObjectList(SFTKSearchResults *search, SFTKObject **head, 1861 unsigned int size, PZLock *lock, CK_ATTRIBUTE_PTR theTemplate, 1862 int count, PRBool isLoggedIn) 1863 { 1864 unsigned int i; 1865 SFTKObject *object; 1866 CK_RV crv = CKR_OK; 1867 1868 PZ_Lock(lock); 1869 for (i = 0; i < size; i++) { 1870 for (object = head[i]; object != NULL; object = object->next) { 1871 if (sftk_objectMatch(object, theTemplate, count)) { 1872 /* don't return objects that aren't yet visible */ 1873 if ((!isLoggedIn) && sftk_isTrue(object, CKA_PRIVATE)) 1874 continue; 1875 sftk_addHandle(search, object->handle); 1876 } 1877 } 1878 } 1879 PZ_Unlock(lock); 1880 return crv; 1881 } 1882 1883 /* 1884 * free a single list element. Return the Next object in the list. 1885 */ 1886 SFTKObjectListElement * 1887 sftk_FreeObjectListElement(SFTKObjectListElement *objectList) 1888 { 1889 SFTKObjectListElement *ol = objectList->next; 1890 1891 sftk_FreeObject(objectList->object); 1892 PORT_Free(objectList); 1893 return ol; 1894 } 1895 1896 /* free an entire object list */ 1897 void 1898 sftk_FreeObjectList(SFTKObjectListElement *objectList) 1899 { 1900 SFTKObjectListElement *ol; 1901 1902 for (ol = objectList; ol != NULL; ol = sftk_FreeObjectListElement(ol)) { 1903 } 1904 } 1905 1906 /* 1907 * free a search structure 1908 */ 1909 void 1910 sftk_FreeSearch(SFTKSearchResults *search) 1911 { 1912 if (search->handles) { 1913 PORT_Free(search->handles); 1914 } 1915 PORT_Free(search); 1916 } 1917 1918 /* 1919 * ******************** Session Utilities ******************************* 1920 */ 1921 1922 /* update the sessions state based in it's flags and wether or not it's 1923 * logged in */ 1924 void 1925 sftk_update_state(SFTKSlot *slot, SFTKSession *session) 1926 { 1927 if (slot->isLoggedIn) { 1928 if (slot->ssoLoggedIn) { 1929 session->info.state = CKS_RW_SO_FUNCTIONS; 1930 } else if (session->info.flags & CKF_RW_SESSION) { 1931 session->info.state = CKS_RW_USER_FUNCTIONS; 1932 } else { 1933 session->info.state = CKS_RO_USER_FUNCTIONS; 1934 } 1935 } else { 1936 if (session->info.flags & CKF_RW_SESSION) { 1937 session->info.state = CKS_RW_PUBLIC_SESSION; 1938 } else { 1939 session->info.state = CKS_RO_PUBLIC_SESSION; 1940 } 1941 } 1942 } 1943 1944 /* update the state of all the sessions on a slot */ 1945 void 1946 sftk_update_all_states(SFTKSlot *slot) 1947 { 1948 unsigned int i; 1949 SFTKSession *session; 1950 1951 for (i = 0; i < slot->sessHashSize; i++) { 1952 PZLock *lock = SFTK_SESSION_LOCK(slot, i); 1953 PZ_Lock(lock); 1954 for (session = slot->head[i]; session; session = session->next) { 1955 sftk_update_state(slot, session); 1956 } 1957 PZ_Unlock(lock); 1958 } 1959 } 1960 1961 /* 1962 * context are cipher and digest contexts that are associated with a session 1963 */ 1964 void 1965 sftk_FreeContext(SFTKSessionContext *context) 1966 { 1967 if (context->cipherInfo) { 1968 (*context->destroy)(context->cipherInfo, PR_TRUE); 1969 } 1970 if (context->hashInfo) { 1971 (*context->hashdestroy)(context->hashInfo, PR_TRUE); 1972 } 1973 if (context->key) { 1974 sftk_FreeObject(context->key); 1975 context->key = NULL; 1976 } 1977 if (context->signature) { 1978 SECITEM_FreeItem(context->signature, PR_TRUE); 1979 context->signature = NULL; 1980 } 1981 PORT_Free(context); 1982 } 1983 1984 /* 1985 * Init a new session. NOTE: The session handle is not set, and the 1986 * session is not added to the slot's session queue. 1987 */ 1988 CK_RV 1989 sftk_InitSession(SFTKSession *session, SFTKSlot *slot, CK_SLOT_ID slotID, 1990 CK_NOTIFY notify, CK_VOID_PTR pApplication, CK_FLAGS flags) 1991 { 1992 session->next = session->prev = NULL; 1993 session->enc_context = NULL; 1994 session->hash_context = NULL; 1995 session->sign_context = NULL; 1996 session->search = NULL; 1997 session->objectIDCount = 1; 1998 session->objectLock = PZ_NewLock(nssILockObject); 1999 if (session->objectLock == NULL) { 2000 return CKR_HOST_MEMORY; 2001 } 2002 session->objects[0] = NULL; 2003 2004 session->slot = slot; 2005 session->notify = notify; 2006 session->appData = pApplication; 2007 session->info.flags = flags; 2008 session->info.slotID = slotID; 2009 session->info.ulDeviceError = 0; 2010 sftk_update_state(slot, session); 2011 /* no ops completed yet, so the last one couldn't be a FIPS op */ 2012 session->lastOpWasFIPS = PR_FALSE; 2013 return CKR_OK; 2014 } 2015 2016 /* 2017 * Create a new session and init it. 2018 */ 2019 SFTKSession * 2020 sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication, 2021 CK_FLAGS flags) 2022 { 2023 SFTKSession *session; 2024 SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE); 2025 CK_RV crv; 2026 2027 if (slot == NULL) 2028 return NULL; 2029 2030 session = (SFTKSession *)PORT_Alloc(sizeof(SFTKSession)); 2031 if (session == NULL) 2032 return NULL; 2033 2034 crv = sftk_InitSession(session, slot, slotID, notify, pApplication, flags); 2035 if (crv != CKR_OK) { 2036 PORT_Free(session); 2037 return NULL; 2038 } 2039 return session; 2040 } 2041 2042 /* free all the data associated with a session. */ 2043 void 2044 sftk_ClearSession(SFTKSession *session) 2045 { 2046 SFTKObjectList *op, *next; 2047 2048 /* clean out the attributes */ 2049 /* since no one is referencing us, it's safe to walk the chain 2050 * without a lock */ 2051 for (op = session->objects[0]; op != NULL; op = next) { 2052 next = op->next; 2053 /* paranoia */ 2054 op->next = op->prev = NULL; 2055 sftk_DeleteObject(session, op->parent); 2056 } 2057 PZ_DestroyLock(session->objectLock); 2058 if (session->enc_context) { 2059 sftk_FreeContext(session->enc_context); 2060 } 2061 if (session->hash_context) { 2062 sftk_FreeContext(session->hash_context); 2063 } 2064 if (session->sign_context) { 2065 sftk_FreeContext(session->sign_context); 2066 } 2067 if (session->search) { 2068 sftk_FreeSearch(session->search); 2069 } 2070 } 2071 2072 /* free the data associated with the session, and the session */ 2073 void 2074 sftk_DestroySession(SFTKSession *session) 2075 { 2076 sftk_ClearSession(session); 2077 PORT_Free(session); 2078 } 2079 2080 /* 2081 * look up a session structure from a session handle 2082 * generate a reference to it. 2083 */ 2084 SFTKSession * 2085 sftk_SessionFromHandle(CK_SESSION_HANDLE handle) 2086 { 2087 SFTKSlot *slot = sftk_SlotFromSessionHandle(handle); 2088 SFTKSession *session; 2089 PZLock *lock; 2090 2091 if (!slot) 2092 return NULL; 2093 lock = SFTK_SESSION_LOCK(slot, handle); 2094 2095 PZ_Lock(lock); 2096 sftkqueue_find(session, handle, slot->head, slot->sessHashSize); 2097 PZ_Unlock(lock); 2098 2099 return (session); 2100 } 2101 2102 /* 2103 * release a reference to a session handle. This method of using SFTKSessions 2104 * is deprecated, but the pattern should be retained until a future effort 2105 * to refactor all SFTKSession users at once is completed. 2106 */ 2107 void 2108 sftk_FreeSession(SFTKSession *session) 2109 { 2110 return; 2111 } 2112 2113 void 2114 sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle) 2115 { 2116 if (search->handles == NULL) { 2117 return; 2118 } 2119 if (search->size >= search->array_size) { 2120 search->array_size += NSC_SEARCH_BLOCK_SIZE; 2121 search->handles = (CK_OBJECT_HANDLE *)PORT_Realloc(search->handles, 2122 sizeof(CK_OBJECT_HANDLE) * search->array_size); 2123 if (search->handles == NULL) { 2124 return; 2125 } 2126 } 2127 search->handles[search->size] = handle; 2128 search->size++; 2129 } 2130 2131 static CK_RV 2132 handleToClass(SFTKSlot *slot, CK_OBJECT_HANDLE handle, 2133 CK_OBJECT_CLASS *objClass) 2134 { 2135 SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, handle); 2136 CK_ATTRIBUTE objClassTemplate; 2137 CK_RV crv; 2138 2139 *objClass = CKO_DATA; 2140 objClassTemplate.type = CKA_CLASS; 2141 objClassTemplate.pValue = objClass; 2142 objClassTemplate.ulValueLen = sizeof(*objClass); 2143 crv = sftkdb_GetAttributeValue(dbHandle, handle, &objClassTemplate, 1); 2144 sftk_freeDB(dbHandle); 2145 return crv; 2146 } 2147 2148 SFTKObject * 2149 sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle) 2150 { 2151 SFTKObject *object = NULL; 2152 PRBool hasLocks = PR_FALSE; 2153 CK_RV crv; 2154 2155 object = sftk_GetObjectFromList(&hasLocks, PR_FALSE, &tokenObjectList, 0, 2156 PR_FALSE); 2157 if (object == NULL) { 2158 return NULL; 2159 } 2160 2161 object->handle = handle; 2162 /* every object must have a class, if we can't get it, the object 2163 * doesn't exist */ 2164 crv = handleToClass(slot, handle, &object->objclass); 2165 if (crv != CKR_OK) { 2166 goto loser; 2167 } 2168 object->slot = slot; 2169 /* set up the validation flags */ 2170 object->validation_value = 0; 2171 object->validation_attribute.next = NULL; 2172 object->validation_attribute.prev = NULL; 2173 object->validation_attribute.freeAttr = PR_FALSE; 2174 object->validation_attribute.freeData = PR_FALSE; 2175 object->validation_attribute.handle = CKA_OBJECT_VALIDATION_FLAGS; 2176 object->validation_attribute.attrib.type = CKA_OBJECT_VALIDATION_FLAGS; 2177 object->validation_attribute.attrib.pValue = &object->validation_value; 2178 object->validation_attribute.attrib.ulValueLen = sizeof(object->validation_value); 2179 /* initialize the FIPS flag properly */ 2180 sftk_setFIPS(object, sftk_isFIPS(slot->slotID)); 2181 object->objectInfo = NULL; 2182 object->infoFree = NULL; 2183 if (!hasLocks) { 2184 object->refLock = PZ_NewLock(nssILockRefLock); 2185 } 2186 if (object->refLock == NULL) { 2187 goto loser; 2188 } 2189 object->refCount = 1; 2190 2191 return object; 2192 loser: 2193 (void)sftk_DestroyObject(object); 2194 return NULL; 2195 } 2196 2197 SFTKTokenObject * 2198 sftk_convertSessionToToken(SFTKObject *obj) 2199 { 2200 SECItem *key; 2201 SFTKSessionObject *so = (SFTKSessionObject *)obj; 2202 SFTKTokenObject *to = sftk_narrowToTokenObject(obj); 2203 SECStatus rv; 2204 2205 sftk_DestroySessionObjectData(so); 2206 PZ_DestroyLock(so->attributeLock); 2207 if (to == NULL) { 2208 return NULL; 2209 } 2210 sftk_tokenKeyLock(so->obj.slot); 2211 key = sftk_lookupTokenKeyByHandle(so->obj.slot, so->obj.handle); 2212 if (key == NULL) { 2213 sftk_tokenKeyUnlock(so->obj.slot); 2214 return NULL; 2215 } 2216 rv = SECITEM_CopyItem(NULL, &to->dbKey, key); 2217 sftk_tokenKeyUnlock(so->obj.slot); 2218 if (rv == SECFailure) { 2219 return NULL; 2220 } 2221 2222 return to; 2223 } 2224 2225 SFTKSessionObject * 2226 sftk_narrowToSessionObject(SFTKObject *obj) 2227 { 2228 return !sftk_isToken(obj->handle) ? (SFTKSessionObject *)obj : NULL; 2229 } 2230 2231 SFTKTokenObject * 2232 sftk_narrowToTokenObject(SFTKObject *obj) 2233 { 2234 return sftk_isToken(obj->handle) ? (SFTKTokenObject *)obj : NULL; 2235 } 2236 2237 /* Constant time helper functions */ 2238 2239 /* sftk_CKRVToMask returns, in constant time, a mask value of 2240 * all ones if rv == CKR_OK. Otherwise it returns zero. */ 2241 unsigned int 2242 sftk_CKRVToMask(CK_RV rv) 2243 { 2244 PR_STATIC_ASSERT(CKR_OK == 0); 2245 return ~PORT_CT_NOT_ZERO(rv); 2246 } 2247 2248 /* sftk_CheckCBCPadding checks, in constant time, the padding validity and 2249 * accordingly sets the pad length. */ 2250 CK_RV 2251 sftk_CheckCBCPadding(CK_BYTE_PTR pBuf, unsigned int bufLen, 2252 unsigned int blockSize, unsigned int *outPadSize) 2253 { 2254 PORT_Assert(outPadSize); 2255 2256 unsigned int padSize = (unsigned int)pBuf[bufLen - 1]; 2257 2258 /* If padSize <= blockSize, set goodPad to all-1s and all-0s otherwise.*/ 2259 unsigned int goodPad = PORT_CT_DUPLICATE_MSB_TO_ALL(~(blockSize - padSize)); 2260 /* padSize should not be 0 */ 2261 goodPad &= PORT_CT_NOT_ZERO(padSize); 2262 2263 unsigned int i; 2264 for (i = 0; i < blockSize; i++) { 2265 /* If i < padSize, set loopMask to all-1s and all-0s otherwise.*/ 2266 unsigned int loopMask = PORT_CT_DUPLICATE_MSB_TO_ALL(~(padSize - 1 - i)); 2267 /* Get the padding value (should be padSize) from buffer */ 2268 unsigned int padVal = pBuf[bufLen - 1 - i]; 2269 /* Update goodPad only if i < padSize */ 2270 goodPad &= PORT_CT_SEL(loopMask, ~(padVal ^ padSize), goodPad); 2271 } 2272 2273 /* If any of the final padding bytes had the wrong value, one or more 2274 * of the lower eight bits of |goodPad| will be cleared. We AND the 2275 * bottom 8 bits together and duplicate the result to all the bits. */ 2276 goodPad &= goodPad >> 4; 2277 goodPad &= goodPad >> 2; 2278 goodPad &= goodPad >> 1; 2279 goodPad <<= sizeof(goodPad) * 8 - 1; 2280 goodPad = PORT_CT_DUPLICATE_MSB_TO_ALL(goodPad); 2281 2282 /* Set outPadSize to padSize or 0 */ 2283 *outPadSize = PORT_CT_SEL(goodPad, padSize, 0); 2284 /* Return OK if the pad is valid */ 2285 return PORT_CT_SEL(goodPad, CKR_OK, CKR_ENCRYPTED_DATA_INVALID); 2286 } 2287 2288 void 2289 sftk_EncodeInteger(PRUint64 integer, CK_ULONG num_bits, CK_BBOOL littleEndian, 2290 CK_BYTE_PTR output, CK_ULONG_PTR output_len) 2291 { 2292 if (output_len) { 2293 *output_len = (num_bits / 8); 2294 } 2295 2296 PR_ASSERT(num_bits > 0 && num_bits <= 64 && (num_bits % 8) == 0); 2297 2298 if (littleEndian == CK_TRUE) { 2299 for (size_t offset = 0; offset < num_bits / 8; offset++) { 2300 output[offset] = (unsigned char)((integer >> (offset * 8)) & 0xFF); 2301 } 2302 } else { 2303 for (size_t offset = 0; offset < num_bits / 8; offset++) { 2304 PRUint64 shift = num_bits - (offset + 1) * 8; 2305 output[offset] = (unsigned char)((integer >> shift) & 0xFF); 2306 } 2307 } 2308 } 2309 2310 CK_FLAGS 2311 sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE op) 2312 { 2313 CK_FLAGS flags = 0; 2314 2315 switch (op) { 2316 case CKA_ENCRYPT: 2317 flags = CKF_ENCRYPT; 2318 break; 2319 case CKA_DECRYPT: 2320 flags = CKF_DECRYPT; 2321 break; 2322 case CKA_WRAP: 2323 flags = CKF_WRAP; 2324 break; 2325 case CKA_UNWRAP: 2326 flags = CKF_UNWRAP; 2327 break; 2328 case CKA_SIGN: 2329 flags = CKF_SIGN; 2330 break; 2331 case CKA_SIGN_RECOVER: 2332 flags = CKF_SIGN_RECOVER; 2333 break; 2334 case CKA_VERIFY: 2335 flags = CKF_VERIFY; 2336 break; 2337 case CKA_VERIFY_RECOVER: 2338 flags = CKF_VERIFY_RECOVER; 2339 break; 2340 case CKA_DERIVE: 2341 flags = CKF_DERIVE; 2342 break; 2343 /* fake attribute to select digesting */ 2344 case CKA_DIGEST: 2345 flags = CKF_DIGEST; 2346 break; 2347 case CKA_NSS_MESSAGE | CKA_ENCRYPT: 2348 flags = CKF_MESSAGE_ENCRYPT; 2349 break; 2350 case CKA_NSS_MESSAGE | CKA_DECRYPT: 2351 flags = CKF_MESSAGE_DECRYPT; 2352 break; 2353 case CKA_NSS_MESSAGE | CKA_SIGN: 2354 flags = CKF_MESSAGE_SIGN; 2355 break; 2356 case CKA_NSS_MESSAGE | CKA_VERIFY: 2357 flags = CKF_MESSAGE_VERIFY; 2358 break; 2359 default: 2360 break; 2361 } 2362 return flags; 2363 } 2364 2365 /* 2366 * ******************** Hash Utilities ************************** 2367 */ 2368 /* 2369 * Utility function for converting PSS/OAEP parameter types into 2370 * HASH_HashTypes. Note: Only SHA family functions are defined in RFC 3447. 2371 */ 2372 HASH_HashType 2373 sftk_GetHashTypeFromMechanism(CK_MECHANISM_TYPE mech) 2374 { 2375 switch (mech) { 2376 case CKM_SHA_1: 2377 case CKG_MGF1_SHA1: 2378 return HASH_AlgSHA1; 2379 case CKM_SHA224: 2380 case CKG_MGF1_SHA224: 2381 return HASH_AlgSHA224; 2382 case CKM_SHA256: 2383 case CKG_MGF1_SHA256: 2384 return HASH_AlgSHA256; 2385 case CKM_SHA384: 2386 case CKG_MGF1_SHA384: 2387 return HASH_AlgSHA384; 2388 case CKM_SHA512: 2389 case CKG_MGF1_SHA512: 2390 return HASH_AlgSHA512; 2391 default: 2392 return HASH_AlgNULL; 2393 } 2394 } 2395 2396 #ifdef NSS_HAS_FIPS_INDICATORS 2397 /**************** FIPS Indicator Utilities *************************/ 2398 /* sigh, we probably need a version of this in secutil so that both 2399 * softoken and NSS can use it */ 2400 static SECOidTag 2401 sftk_quickGetECCCurveOid(SFTKObject *source) 2402 { 2403 SFTKAttribute *attribute = sftk_FindAttribute(source, CKA_EC_PARAMS); 2404 unsigned char *encoded; 2405 int len; 2406 SECItem oid; 2407 SECOidTag tag; 2408 2409 if (attribute == NULL) { 2410 return SEC_OID_UNKNOWN; 2411 } 2412 encoded = attribute->attrib.pValue; 2413 len = attribute->attrib.ulValueLen; 2414 if ((len < 2) || (encoded[0] != SEC_ASN1_OBJECT_ID) || 2415 (len != encoded[1] + 2)) { 2416 sftk_FreeAttribute(attribute); 2417 return SEC_OID_UNKNOWN; 2418 } 2419 oid.data = encoded + 2; 2420 oid.len = len - 2; 2421 tag = SECOID_FindOIDTag(&oid); 2422 sftk_FreeAttribute(attribute); 2423 return tag; 2424 } 2425 2426 /* This function currently only returns valid lengths for 2427 * FIPS approved ECC curves. If we want to make this generic 2428 * in the future, that Curve determination can be done in 2429 * the sftk_handleSpecial. Since it's currently only used 2430 * in FIPS indicators, it's currently only compiled with 2431 * the FIPS indicator code */ 2432 static int 2433 sftk_getKeyLength(SFTKObject *source) 2434 { 2435 CK_KEY_TYPE keyType = CK_INVALID_HANDLE; 2436 CK_ATTRIBUTE_TYPE keyAttribute; 2437 CK_ULONG keyLength = 0; 2438 SFTKAttribute *attribute; 2439 CK_RV crv; 2440 2441 /* If we don't have a key, then it doesn't have a length. 2442 * this may be OK (say we are hashing). The mech info will 2443 * sort this out because algorithms which expect no keys 2444 * will accept zero length for the keys */ 2445 if (source == NULL) { 2446 return 0; 2447 } 2448 2449 crv = sftk_GetULongAttribute(source, CKA_KEY_TYPE, &keyType); 2450 if (crv != CKR_OK) { 2451 /* sometimes we're passed a data object, in that case the 2452 * key length is CKA_VALUE, which is the default */ 2453 keyType = CKK_INVALID_KEY_TYPE; 2454 } 2455 if (keyType == CKK_EC) { 2456 SECOidTag curve = sftk_quickGetECCCurveOid(source); 2457 switch (curve) { 2458 case SEC_OID_CURVE25519: 2459 /* change when we start algorithm testing on curve25519 */ 2460 return 0; 2461 case SEC_OID_SECG_EC_SECP256R1: 2462 return 256; 2463 case SEC_OID_SECG_EC_SECP384R1: 2464 return 384; 2465 case SEC_OID_SECG_EC_SECP521R1: 2466 /* this is a lie, but it makes the table easier. We don't 2467 * have to have a double entry for every ECC mechanism */ 2468 return 512; 2469 default: 2470 break; 2471 } 2472 /* other curves aren't NIST approved, returning 0 will cause these 2473 * curves to fail FIPS length criteria */ 2474 return 0; 2475 } 2476 2477 switch (keyType) { 2478 case CKK_RSA: 2479 keyAttribute = CKA_MODULUS; 2480 break; 2481 case CKK_DSA: 2482 case CKK_DH: 2483 keyAttribute = CKA_PRIME; 2484 break; 2485 default: 2486 keyAttribute = CKA_VALUE; 2487 break; 2488 } 2489 attribute = sftk_FindAttribute(source, keyAttribute); 2490 if (attribute) { 2491 keyLength = attribute->attrib.ulValueLen * 8; 2492 sftk_FreeAttribute(attribute); 2493 } 2494 return keyLength; 2495 } 2496 2497 /* 2498 * handle specialized FIPS semantics that are too complicated to 2499 * handle with just a table. NOTE: this means any additional semantics 2500 * would have to be coded here before they can be added to the table */ 2501 static PRBool 2502 sftk_handleSpecial(SFTKSlot *slot, CK_MECHANISM *mech, 2503 SFTKFIPSAlgorithmList *mechInfo, SFTKObject *source) 2504 { 2505 switch (mechInfo->special) { 2506 case SFTKFIPSDH: { 2507 SECItem dhPrime; 2508 SECItem dhBase; 2509 SECItem dhGenerator; 2510 PRBool fipsOk = PR_FALSE; 2511 const SECItem *dhSubPrime; 2512 CK_RV crv = sftk_Attribute2SecItem(NULL, &dhPrime, 2513 source, CKA_PRIME); 2514 if (crv != CKR_OK) { 2515 return PR_FALSE; 2516 } 2517 crv = sftk_Attribute2SecItem(NULL, &dhBase, source, CKA_BASE); 2518 if (crv != CKR_OK) { 2519 return PR_FALSE; 2520 } 2521 dhSubPrime = sftk_VerifyDH_Prime(&dhPrime, &dhGenerator, PR_TRUE); 2522 fipsOk = (dhSubPrime) ? PR_TRUE : PR_FALSE; 2523 if (fipsOk && (SECITEM_CompareItem(&dhBase, &dhGenerator) != 0)) { 2524 fipsOk = PR_FALSE; 2525 } 2526 2527 SECITEM_ZfreeItem(&dhPrime, PR_FALSE); 2528 SECITEM_ZfreeItem(&dhBase, PR_FALSE); 2529 return fipsOk; 2530 } 2531 case SFTKFIPSNone: 2532 return PR_FALSE; 2533 case SFTKFIPSECC: 2534 /* we've already handled the curve selection in the 'getlength' 2535 * function */ 2536 return PR_TRUE; 2537 case SFTKFIPSAEAD: { 2538 if (mech->ulParameterLen == 0) { 2539 /* AEAD ciphers are only in FIPS mode if we are using the 2540 * MESSAGE interface. This takes an empty parameter 2541 * in the init function */ 2542 return PR_TRUE; 2543 } 2544 return PR_FALSE; 2545 } 2546 case SFTKFIPSRSAPSS: { 2547 /* PSS salt must not be longer than the underlying hash. 2548 * We verify that the underlying hash of the 2549 * parameters matches Hash of the combined hash mechanisms, so 2550 * we don't need to look at the specific PSS mechanism */ 2551 CK_RSA_PKCS_PSS_PARAMS *pss = (CK_RSA_PKCS_PSS_PARAMS *) 2552 mech->pParameter; 2553 const SECHashObject *hashObj = NULL; 2554 if (mech->ulParameterLen != sizeof(*pss)) { 2555 return PR_FALSE; 2556 } 2557 /* we use the existing hash utilities to find the length of 2558 * the hash */ 2559 hashObj = HASH_GetRawHashObject(sftk_GetHashTypeFromMechanism( 2560 pss->hashAlg)); 2561 if (hashObj == NULL) { 2562 return PR_FALSE; 2563 } 2564 if (pss->sLen > hashObj->length) { 2565 return PR_FALSE; 2566 } 2567 return PR_TRUE; 2568 } 2569 default: 2570 break; 2571 } 2572 /* if we didn't understand the special processing, mark it non-fips */ 2573 return PR_FALSE; 2574 } 2575 #endif 2576 2577 PRBool 2578 sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech, CK_ATTRIBUTE_TYPE op, 2579 SFTKObject *source) 2580 { 2581 #ifndef NSS_HAS_FIPS_INDICATORS 2582 return PR_FALSE; 2583 #else 2584 int i; 2585 CK_FLAGS opFlags; 2586 CK_ULONG keyLength; 2587 2588 /* handle all the quick stuff first */ 2589 if (!sftk_isFIPS(slot->slotID)) { 2590 return PR_FALSE; 2591 } 2592 if (source && !sftk_hasFIPS(source)) { 2593 return PR_FALSE; 2594 } 2595 if (mech == NULL) { 2596 return PR_FALSE; 2597 } 2598 2599 /* now get the calculated values */ 2600 opFlags = sftk_AttributeToFlags(op); 2601 if (opFlags == 0) { 2602 return PR_FALSE; 2603 } 2604 keyLength = sftk_getKeyLength(source); 2605 2606 /* check against our algorithm array */ 2607 for (i = 0; i < SFTK_NUMBER_FIPS_ALGORITHMS; i++) { 2608 SFTKFIPSAlgorithmList *mechs = &sftk_fips_mechs[i]; 2609 /* if we match the number of records exactly, then we are an 2610 * approved algorithm in the approved mode with an approved key */ 2611 if (((mech->mechanism == mechs->type) && 2612 (opFlags == (mechs->info.flags & opFlags)) && 2613 (keyLength <= mechs->info.ulMaxKeySize) && 2614 (keyLength >= mechs->info.ulMinKeySize) && 2615 ((keyLength - mechs->info.ulMinKeySize) % mechs->step) == 0) && 2616 ((mechs->special == SFTKFIPSNone) || 2617 sftk_handleSpecial(slot, mech, mechs, source))) { 2618 return PR_TRUE; 2619 } 2620 } 2621 return PR_FALSE; 2622 #endif 2623 } 2624 2625 void 2626 sftk_setFIPS(SFTKObject *obj, PRBool isFIPS) 2627 { 2628 if (isFIPS) { 2629 obj->validation_value |= SFTK_VALIDATION_FIPS_FLAG; 2630 } else { 2631 obj->validation_value &= ~SFTK_VALIDATION_FIPS_FLAG; 2632 } 2633 } 2634 2635 PRBool 2636 sftk_hasFIPS(SFTKObject *obj) 2637 { 2638 return (obj->validation_value & SFTK_VALIDATION_FIPS_FLAG) ? PR_TRUE : PR_FALSE; 2639 } 2640 2641 /* 2642 * create the FIPS Validation objects. If the vendor 2643 * doesn't supply an NSS_FIPS_MODULE_ID, at compile time, 2644 * then we assumethis is an unvalidated module. 2645 */ 2646 CK_RV 2647 sftk_CreateValidationObjects(SFTKSlot *slot) 2648 { 2649 const char *module_id; 2650 int module_id_len; 2651 CK_RV crv = CKR_OK; 2652 /* we currently use both vendor specific values and PKCS #11 v3.2 2653 * values for compatibility for a couple more ESR releases. Then we can 2654 * drop the vendor specific ones */ 2655 CK_OBJECT_CLASS cko_nss_validation = CKO_NSS_VALIDATION; 2656 CK_OBJECT_CLASS cko_validation = CKO_VALIDATION; 2657 CK_NSS_VALIDATION_TYPE ckv_fips = CKV_NSS_FIPS_140; 2658 CK_FLAGS fipsFlag = SFTK_VALIDATION_FIPS_FLAG; 2659 CK_VALIDATION_TYPE swValidationType = CKV_TYPE_SOFTWARE; 2660 CK_VALIDATION_AUTHORITY_TYPE nistValidationAuthority = 2661 CKV_AUTHORITY_TYPE_NIST_CMVP; 2662 CK_UTF8CHAR us[] = { 'U', 'S' }; 2663 CK_VERSION fips_version = { 3, 0 }; /* FIPS-140-3 */ 2664 CK_ULONG fips_level = 1; /* or 2 if you validated at level 2 */ 2665 2666 #ifndef NSS_FIPS_MODULE_ID 2667 #define NSS_FIPS_MODULE_ID "Generic NSS " SOFTOKEN_VERSION " Unvalidated" 2668 #endif 2669 module_id = NSS_FIPS_MODULE_ID; 2670 module_id_len = sizeof(NSS_FIPS_MODULE_ID) - 1; 2671 SFTKObject *object; 2672 2673 object = sftk_NewObject(slot); /* fill in the handle later */ 2674 if (object == NULL) { 2675 return CKR_HOST_MEMORY; 2676 } 2677 sftk_setFIPS(object, PR_FALSE); 2678 2679 crv = sftk_AddAttributeType(object, CKA_CLASS, &cko_nss_validation, 2680 sizeof(cko_nss_validation)); 2681 if (crv != CKR_OK) { 2682 goto loser; 2683 } 2684 crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_TYPE, 2685 &ckv_fips, sizeof(ckv_fips)); 2686 if (crv != CKR_OK) { 2687 goto loser; 2688 } 2689 crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_VERSION, 2690 &fips_version, sizeof(fips_version)); 2691 if (crv != CKR_OK) { 2692 goto loser; 2693 } 2694 crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_LEVEL, 2695 &fips_level, sizeof(fips_level)); 2696 if (crv != CKR_OK) { 2697 goto loser; 2698 } 2699 crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_MODULE_ID, 2700 module_id, module_id_len); 2701 if (crv != CKR_OK) { 2702 goto loser; 2703 } 2704 2705 object->handle = sftk_getNextHandle(slot); 2706 object->slot = slot; 2707 sftk_AddObject(&slot->moduleObjects, object); 2708 sftk_FreeObject(object); 2709 2710 object = sftk_NewObject(slot); /* fill in the handle later */ 2711 if (object == NULL) { 2712 return CKR_HOST_MEMORY; 2713 } 2714 sftk_setFIPS(object, PR_FALSE); 2715 crv = sftk_AddAttributeType(object, CKA_CLASS, &cko_validation, 2716 sizeof(cko_validation)); 2717 if (crv != CKR_OK) { 2718 goto loser; 2719 } 2720 crv = sftk_AddAttributeType(object, CKA_VALIDATION_TYPE, 2721 &swValidationType, sizeof(swValidationType)); 2722 if (crv != CKR_OK) { 2723 goto loser; 2724 } 2725 crv = sftk_AddAttributeType(object, CKA_VALIDATION_VERSION, 2726 &fips_version, sizeof(fips_version)); 2727 if (crv != CKR_OK) { 2728 goto loser; 2729 } 2730 crv = sftk_AddAttributeType(object, CKA_VALIDATION_LEVEL, 2731 &fips_level, sizeof(fips_level)); 2732 if (crv != CKR_OK) { 2733 goto loser; 2734 } 2735 crv = sftk_AddAttributeType(object, CKA_VALIDATION_MODULE_ID, 2736 module_id, module_id_len); 2737 if (crv != CKR_OK) { 2738 goto loser; 2739 } 2740 crv = sftk_AddAttributeType(object, CKA_VALIDATION_FLAG, 2741 &fipsFlag, sizeof(fipsFlag)); 2742 if (crv != CKR_OK) { 2743 goto loser; 2744 } 2745 crv = sftk_AddAttributeType(object, CKA_VALIDATION_AUTHORITY_TYPE, 2746 &nistValidationAuthority, 2747 sizeof(nistValidationAuthority)); 2748 if (crv != CKR_OK) { 2749 goto loser; 2750 } 2751 crv = sftk_AddAttributeType(object, CKA_VALIDATION_COUNTRY, us, sizeof(us)); 2752 if (crv != CKR_OK) { 2753 goto loser; 2754 } 2755 crv = sftk_AddAttributeType(object, CKA_VALIDATION_CERTIFICATE_IDENTIFIER, 2756 NULL, 0); 2757 if (crv != CKR_OK) { 2758 goto loser; 2759 } 2760 crv = sftk_AddAttributeType(object, CKA_VALIDATION_CERTIFICATE_URI, 2761 NULL, 0); 2762 if (crv != CKR_OK) { 2763 goto loser; 2764 } 2765 crv = sftk_AddAttributeType(object, CKA_VALIDATION_PROFILE, 2766 NULL, 0); 2767 if (crv != CKR_OK) { 2768 goto loser; 2769 } 2770 crv = sftk_AddAttributeType(object, CKA_VALIDATION_VENDOR_URI, 2771 NULL, 0); 2772 if (crv != CKR_OK) { 2773 goto loser; 2774 } 2775 /* future, fill in validation certificate information from a supplied 2776 * pointer to a config file */ 2777 object->handle = sftk_getNextHandle(slot); 2778 object->slot = slot; 2779 sftk_AddObject(&slot->moduleObjects, object); 2780 loser: 2781 sftk_FreeObject(object); 2782 2783 return crv; 2784 }