1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <pthread.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <security/cryptoki.h> 31 #include "softGlobal.h" 32 #include "softObject.h" 33 #include "softSession.h" 34 #include "softKeystore.h" 35 #include "softKeystoreUtil.h" 36 37 /* 38 * Add an object to the session's object list. 39 * 40 * This function will acquire the lock on the session, and release 41 * that lock after adding the object to the session's object list. 42 */ 43 void 44 soft_add_object_to_session(soft_object_t *objp, soft_session_t *sp) 45 { 46 47 /* Acquire the session lock. */ 48 (void) pthread_mutex_lock(&sp->session_mutex); 49 50 /* Insert the new object in front of session's object list. */ 51 if (sp->object_list == NULL) { 52 sp->object_list = objp; 53 objp->next = NULL; 54 objp->prev = NULL; 55 } else { 56 sp->object_list->prev = objp; 57 objp->next = sp->object_list; 58 objp->prev = NULL; 59 sp->object_list = objp; 60 } 61 62 /* Release the session lock. */ 63 (void) pthread_mutex_unlock(&sp->session_mutex); 64 } 65 66 67 /* 68 * Clean up and release the storage allocated to the object. 69 * 70 * The function is called either with the object lock being held 71 * (by caller soft_delete_object()), or there is no object lock 72 * yet (by soft_build_XXX_object() during creating an object). 73 */ 74 void 75 soft_cleanup_object(soft_object_t *objp) 76 { 77 /* 78 * Free the storage allocated to big integer attributes. 79 */ 80 soft_cleanup_object_bigint_attrs(objp); 81 82 /* 83 * Free the storage allocated to the extra attribute list. 84 */ 85 soft_cleanup_extra_attr(objp); 86 87 /* 88 * Free the storage allocated to certificate attributes. 89 */ 90 soft_cleanup_cert_object(objp); 91 } 92 93 94 /* 95 * Create a new object. Copy the attributes that can be modified 96 * (in the boolean attribute mask field and extra attribute list) 97 * from the old object to the new object. 98 * 99 * The caller of this function holds the lock on the old object. 100 */ 101 CK_RV 102 soft_copy_object(soft_object_t *old_object, soft_object_t **new_object, 103 CK_ULONG object_func, soft_session_t *sp) 104 { 105 106 CK_RV rv = CKR_OK; 107 soft_object_t *new_objp = NULL; 108 CK_ATTRIBUTE_INFO_PTR attrp; 109 110 /* Allocate new object. */ 111 new_objp = calloc(1, sizeof (soft_object_t)); 112 if (new_objp == NULL) 113 return (CKR_HOST_MEMORY); 114 115 new_objp->class = old_object->class; 116 new_objp->bool_attr_mask = old_object->bool_attr_mask; 117 new_objp->cert_type = old_object->cert_type; 118 new_objp->object_type = old_object->object_type; 119 120 attrp = old_object->extra_attrlistp; 121 while (attrp) { 122 /* 123 * Copy the attribute_info struct from the old 124 * object to a new attribute_info struct, and add 125 * that new struct to the extra attribute list 126 * of the new object. 127 */ 128 rv = soft_copy_extra_attr(attrp, new_objp); 129 if (rv != CKR_OK) { 130 soft_cleanup_extra_attr(new_objp); 131 free(new_objp); 132 return (rv); 133 } 134 attrp = attrp->next; 135 } 136 137 *new_object = new_objp; 138 139 if (object_func == SOFT_SET_ATTR_VALUE) { 140 /* done with copying all information that can be modified */ 141 return (CKR_OK); 142 } 143 144 /* 145 * Copy the rest of the object. 146 * Certain fields that are not appropriate for coping will be 147 * initialized. 148 */ 149 new_objp->key_type = old_object->key_type; 150 new_objp->magic_marker = old_object->magic_marker; 151 new_objp->mechanism = old_object->mechanism; 152 153 switch (object_func) { 154 case SOFT_COPY_OBJ_ORIG_SH: 155 new_objp->session_handle = old_object->session_handle; 156 break; 157 case SOFT_COPY_OBJECT: 158 /* 159 * Save the session handle of the C_CopyObject function 160 * in the new copy of the session object. 161 */ 162 new_objp->session_handle = (CK_SESSION_HANDLE)sp; 163 break; 164 } 165 166 (void) pthread_cond_init(&(new_objp->obj_free_cond), NULL); 167 (void) pthread_mutex_init(&(new_objp->object_mutex), NULL); 168 /* copy key related information */ 169 switch (new_objp->class) { 170 case CKO_PUBLIC_KEY: 171 rv = soft_copy_public_key_attr(OBJ_PUB(old_object), 172 &(OBJ_PUB(new_objp)), new_objp->key_type); 173 break; 174 case CKO_PRIVATE_KEY: 175 rv = soft_copy_private_key_attr(OBJ_PRI(old_object), 176 &(OBJ_PRI(new_objp)), new_objp->key_type); 177 break; 178 case CKO_SECRET_KEY: 179 rv = soft_copy_secret_key_attr(OBJ_SEC(old_object), 180 &(OBJ_SEC(new_objp))); 181 break; 182 case CKO_DOMAIN_PARAMETERS: 183 rv = soft_copy_domain_attr(OBJ_DOM(old_object), 184 &(OBJ_DOM(new_objp)), new_objp->key_type); 185 break; 186 case CKO_CERTIFICATE: 187 rv = soft_copy_certificate(OBJ_CERT(old_object), 188 &(OBJ_CERT(new_objp)), new_objp->cert_type); 189 break; 190 default: 191 /* should never be this case */ 192 break; 193 } 194 if (rv != CKR_OK) { 195 /* 196 * don't need to cleanup the memory from failure of copying 197 * any key related stuff. Each individual function for 198 * copying key attr will free the memory if it fails 199 */ 200 soft_cleanup_extra_attr(new_objp); 201 free(new_objp); 202 } 203 return (rv); 204 } 205 206 207 /* 208 * Copy the attributes (in the boolean attribute mask field and 209 * extra attribute list) from the new object back to the original 210 * object. Also, clean up and release all the storage in the extra 211 * attribute list of the original object. 212 * 213 * The caller of this function holds the lock on the old object. 214 */ 215 void 216 soft_merge_object(soft_object_t *old_object, soft_object_t *new_object) 217 { 218 old_object->bool_attr_mask = new_object->bool_attr_mask; 219 soft_cleanup_extra_attr(old_object); 220 old_object->extra_attrlistp = new_object->extra_attrlistp; 221 } 222 223 224 /* 225 * Create a new object struct, and add it to the session's object list. 226 */ 227 CK_RV 228 soft_add_object(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, 229 CK_ULONG *objecthandle_p, soft_session_t *sp) 230 { 231 232 CK_RV rv = CKR_OK; 233 soft_object_t *new_objp = NULL; 234 235 new_objp = calloc(1, sizeof (soft_object_t)); 236 if (new_objp == NULL) { 237 return (CKR_HOST_MEMORY); 238 } 239 240 new_objp->extra_attrlistp = NULL; 241 242 /* 243 * Validate attribute template and fill in the attributes 244 * in the soft_object_t. 245 */ 246 rv = soft_build_object(pTemplate, ulCount, new_objp); 247 if (rv != CKR_OK) { 248 goto fail_cleanup1; 249 } 250 251 rv = soft_pin_expired_check(new_objp); 252 if (rv != CKR_OK) { 253 goto fail_cleanup2; 254 } 255 256 rv = soft_object_write_access_check(sp, new_objp); 257 if (rv != CKR_OK) { 258 goto fail_cleanup2; 259 } 260 261 /* Initialize the rest of stuffs in soft_object_t. */ 262 (void) pthread_cond_init(&new_objp->obj_free_cond, NULL); 263 (void) pthread_mutex_init(&new_objp->object_mutex, NULL); 264 new_objp->magic_marker = SOFTTOKEN_OBJECT_MAGIC; 265 new_objp->obj_refcnt = 0; 266 new_objp->obj_delete_sync = 0; 267 268 /* Write the new token object to the keystore */ 269 if (IS_TOKEN_OBJECT(new_objp)) { 270 if (!soft_keystore_status(KEYSTORE_INITIALIZED)) { 271 rv = CKR_DEVICE_REMOVED; 272 goto fail_cleanup2; 273 } 274 new_objp->version = 1; 275 rv = soft_put_object_to_keystore(new_objp); 276 if (rv != CKR_OK) { 277 (void) pthread_cond_destroy(&new_objp->obj_free_cond); 278 (void) pthread_mutex_destroy(&new_objp->object_mutex); 279 goto fail_cleanup2; 280 } 281 new_objp->session_handle = (CK_SESSION_HANDLE)NULL; 282 soft_add_token_object_to_slot(new_objp); 283 /* 284 * Type casting the address of an object struct to 285 * an object handle. 286 */ 287 *objecthandle_p = (CK_ULONG)new_objp; 288 289 return (CKR_OK); 290 } 291 292 new_objp->session_handle = (CK_SESSION_HANDLE)sp; 293 294 /* Add the new object to the session's object list. */ 295 soft_add_object_to_session(new_objp, sp); 296 297 /* Type casting the address of an object struct to an object handle. */ 298 *objecthandle_p = (CK_ULONG)new_objp; 299 300 return (CKR_OK); 301 302 fail_cleanup2: 303 /* 304 * When any error occurs after soft_build_object(), we will need to 305 * clean up the memory allocated by the soft_build_object(). 306 */ 307 soft_cleanup_object(new_objp); 308 309 fail_cleanup1: 310 if (new_objp) { 311 /* 312 * The storage allocated inside of this object should have 313 * been cleaned up by the soft_build_object() if it failed. 314 * Therefore, we can safely free the object. 315 */ 316 free(new_objp); 317 } 318 319 return (rv); 320 321 } 322 323 324 /* 325 * Remove an object from the session's object list. 326 * 327 * The caller of this function holds the session lock. 328 */ 329 CK_RV 330 soft_remove_object_from_session(soft_object_t *objp, soft_session_t *sp) 331 { 332 soft_object_t *tmp_objp; 333 boolean_t found = B_FALSE; 334 335 /* 336 * Remove the object from the session's object list. 337 */ 338 if ((sp == NULL) || 339 (sp->magic_marker != SOFTTOKEN_SESSION_MAGIC)) { 340 return (CKR_SESSION_HANDLE_INVALID); 341 } 342 343 if ((sp->object_list == NULL) || (objp == NULL) || 344 (objp->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) { 345 return (CKR_OBJECT_HANDLE_INVALID); 346 } 347 348 tmp_objp = sp->object_list; 349 while (tmp_objp) { 350 if (tmp_objp == objp) { 351 found = B_TRUE; 352 break; 353 } 354 tmp_objp = tmp_objp->next; 355 } 356 if (!found) 357 return (CKR_OBJECT_HANDLE_INVALID); 358 359 if (sp->object_list == objp) { 360 /* Object is the first one in the list. */ 361 if (objp->next) { 362 sp->object_list = objp->next; 363 objp->next->prev = NULL; 364 } else { 365 /* Object is the only one in the list. */ 366 sp->object_list = NULL; 367 } 368 } else { 369 /* Object is not the first one in the list. */ 370 if (objp->next) { 371 /* Object is in the middle of the list. */ 372 objp->prev->next = objp->next; 373 objp->next->prev = objp->prev; 374 } else { 375 /* Object is the last one in the list. */ 376 objp->prev->next = NULL; 377 } 378 } 379 return (CKR_OK); 380 } 381 382 /* 383 * This function adds the to-be-freed session object to a linked list. 384 * When the number of objects queued in the linked list reaches the 385 * maximum threshold MAX_OBJ_TO_BE_FREED, it will free the first 386 * object (FIFO) in the list. 387 */ 388 void 389 object_delay_free(soft_object_t *objp) 390 { 391 soft_object_t *tmp; 392 393 (void) pthread_mutex_lock(&obj_delay_freed.obj_to_be_free_mutex); 394 395 /* Add the newly deleted object at the end of the list */ 396 objp->next = NULL; 397 if (obj_delay_freed.first == NULL) { 398 obj_delay_freed.last = objp; 399 obj_delay_freed.first = objp; 400 } else { 401 obj_delay_freed.last->next = objp; 402 obj_delay_freed.last = objp; 403 } 404 405 if (++obj_delay_freed.count >= MAX_OBJ_TO_BE_FREED) { 406 /* 407 * Free the first object in the list only if 408 * the total count reaches maximum threshold. 409 */ 410 obj_delay_freed.count--; 411 tmp = obj_delay_freed.first->next; 412 free(obj_delay_freed.first); 413 obj_delay_freed.first = tmp; 414 } 415 (void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex); 416 } 417 418 static void 419 soft_delete_object_cleanup(soft_object_t *objp) 420 { 421 /* Acquire the lock on the object. */ 422 (void) pthread_mutex_lock(&objp->object_mutex); 423 424 /* 425 * Make sure another thread hasn't freed the object. 426 */ 427 if (objp->magic_marker != SOFTTOKEN_OBJECT_MAGIC) { 428 (void) pthread_mutex_unlock(&objp->object_mutex); 429 return; 430 } 431 432 /* 433 * The deletion of an object must be blocked when the object 434 * reference count is not zero. This means if any object related 435 * operation starts prior to the delete object operation gets in, 436 * the object deleting thread must wait for the non-deleting 437 * operation to be completed before it can proceed the delete 438 * operation. 439 */ 440 while (objp->obj_refcnt != 0) { 441 /* 442 * We set the OBJECT_REFCNT_WAITING flag before we put 443 * this deleting thread in a wait state, so other non-deleting 444 * operation thread will signal to wake it up only when 445 * the object reference count becomes zero and this flag 446 * is set. 447 */ 448 objp->obj_delete_sync |= OBJECT_REFCNT_WAITING; 449 (void) pthread_cond_wait(&objp->obj_free_cond, 450 &objp->object_mutex); 451 } 452 453 objp->obj_delete_sync &= ~OBJECT_REFCNT_WAITING; 454 455 /* Mark object as no longer valid. */ 456 objp->magic_marker = 0; 457 458 (void) pthread_cond_destroy(&objp->obj_free_cond); 459 460 /* 461 * Cleanup the contents of this object such as free all the 462 * storage allocated for this object. 463 */ 464 soft_cleanup_object(objp); 465 466 /* Reset OBJECT_IS_DELETING flag. */ 467 objp->obj_delete_sync &= ~OBJECT_IS_DELETING; 468 469 (void) pthread_mutex_unlock(&objp->object_mutex); 470 /* Destroy the object lock */ 471 (void) pthread_mutex_destroy(&objp->object_mutex); 472 473 /* Free the object itself */ 474 if (IS_TOKEN_OBJECT(objp)) 475 free(objp); 476 else 477 /* 478 * Delay freeing the session object as S1WS/NSS uses session 479 * objects for its SSL Handshake. 480 */ 481 (void) object_delay_free(objp); 482 } 483 484 /* 485 * Delete an object: 486 * - Remove the object from the session's object list. 487 * Holding the lock on the session which the object was created at 488 * is needed to do this. 489 * - Release the storage allocated to the object. 490 * 491 * The boolean argument lock_held is used to indicate that whether 492 * the caller holds the session lock or not. 493 * - When called by soft_delete_all_objects_in_session() -- the 494 * lock_held = TRUE. 495 * 496 * When the caller does not hold the session lock, this function 497 * will acquire that lock in order to proceed, and also release 498 * that lock before returning to caller. 499 */ 500 void 501 soft_delete_object(soft_session_t *sp, soft_object_t *objp, boolean_t lock_held) 502 { 503 504 /* 505 * Check to see if the caller holds the lock on the session. 506 * If not, we need to acquire that lock in order to proceed. 507 */ 508 if (!lock_held) { 509 /* Acquire the session lock. */ 510 (void) pthread_mutex_lock(&sp->session_mutex); 511 } 512 513 /* Remove the object from the session's object list first. */ 514 if (soft_remove_object_from_session(objp, sp) != CKR_OK) { 515 if (!lock_held) { 516 (void) pthread_mutex_unlock(&sp->session_mutex); 517 } 518 return; 519 } 520 521 if (!lock_held) { 522 /* 523 * If the session lock is obtained by this function, 524 * then release that lock after removing the object 525 * from session's object list. 526 * We want the releasing of the object storage to 527 * be done without holding the session lock. 528 */ 529 (void) pthread_mutex_unlock(&sp->session_mutex); 530 } 531 532 soft_delete_object_cleanup(objp); 533 } 534 535 536 /* 537 * Delete all the objects in a session. The caller holds the lock 538 * on the session. 539 */ 540 void 541 soft_delete_all_objects_in_session(soft_session_t *sp) 542 { 543 soft_object_t *objp = sp->object_list; 544 soft_object_t *objp1; 545 546 /* Delete all the objects in the session. */ 547 while (objp) { 548 objp1 = objp->next; 549 550 /* 551 * Delete an object by calling soft_delete_object() 552 * with a TRUE boolean argument indicating that 553 * the caller holds the lock on the session. 554 */ 555 soft_delete_object(sp, objp, B_TRUE); 556 557 objp = objp1; 558 } 559 } 560 561 static CK_RV 562 add_to_search_result(soft_object_t *obj, find_context_t *fcontext, 563 CK_ULONG *num_result_alloc) 564 { 565 /* 566 * allocate space for storing results if the currently 567 * allocated space is not enough 568 */ 569 if (*num_result_alloc <= fcontext->num_results) { 570 fcontext->objs_found = realloc(fcontext->objs_found, 571 sizeof (soft_object_t *) * (*num_result_alloc + BUFSIZ)); 572 if (fcontext->objs_found == NULL) { 573 return (CKR_HOST_MEMORY); 574 } 575 *num_result_alloc += BUFSIZ; 576 } 577 578 (fcontext->objs_found)[(fcontext->num_results)++] = obj; 579 return (CKR_OK); 580 } 581 582 static CK_RV 583 search_for_objects(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, 584 find_context_t *fcontext) 585 { 586 soft_session_t *session_p; 587 soft_object_t *obj; 588 CK_OBJECT_CLASS pclasses[6]; /* classes attrs possibly exist */ 589 CK_ULONG num_pclasses; /* number of possible classes */ 590 CK_ULONG num_result_alloc = 0; /* spaces allocated for results */ 591 CK_RV rv = CKR_OK; 592 /* whether CKA_TOKEN flag specified or not */ 593 boolean_t token_specified = B_FALSE; 594 /* value of CKA_TOKEN flag, if specified */ 595 boolean_t token_flag_val = B_FALSE; 596 CK_ULONG i; 597 598 if (ulCount > 0) { 599 /* there are some search requirement */ 600 soft_process_find_attr(pclasses, &num_pclasses, 601 pTemplate, ulCount); 602 } 603 604 for (i = 0; i < ulCount; i++) { 605 if (pTemplate[i].type == CKA_PRIVATE) { 606 (void) pthread_mutex_lock(&soft_giant_mutex); 607 if (soft_slot.userpin_change_needed) { 608 (void) pthread_mutex_unlock(&soft_giant_mutex); 609 return (CKR_PIN_EXPIRED); 610 } 611 (void) pthread_mutex_unlock(&soft_giant_mutex); 612 } 613 } 614 615 /* 616 * look through template and see if it explicitly specifies 617 * whether we need to look for token objects or not 618 */ 619 for (i = 0; i < ulCount; i++) { 620 if (pTemplate[i].type == CKA_TOKEN) { 621 token_specified = B_TRUE; 622 token_flag_val = *((CK_BBOOL *)pTemplate[i].pValue); 623 break; 624 } 625 } 626 627 /* 628 * Need go through token objects if it explicitly say so, or 629 * it is not mentioned in the template. And this will ONLY be 630 * done when the keystore exists. Otherwise, we will skip re-loading 631 * the token objects. 632 * 633 * If a session has not logged into the token, only public 634 * objects, if any, will be searched. If a session is logged 635 * into the token, all public and private objects in the keystore 636 * are searched. 637 */ 638 if (((token_flag_val) || (!token_specified)) && 639 soft_keystore_status(KEYSTORE_INITIALIZED)) { 640 /* acquire token session lock */ 641 (void) pthread_mutex_lock(&soft_slot.slot_mutex); 642 rv = refresh_token_objects(); 643 if (rv != CKR_OK) { 644 (void) pthread_mutex_unlock(&soft_slot.slot_mutex); 645 return (rv); 646 } 647 obj = soft_slot.token_object_list; 648 while (obj) { 649 (void) pthread_mutex_lock(&obj->object_mutex); 650 if (((token_specified) && (ulCount > 1)) || 651 ((!token_specified) && (ulCount > 0))) { 652 if (soft_find_match_attrs(obj, pclasses, 653 num_pclasses, pTemplate, ulCount)) { 654 rv = add_to_search_result( 655 obj, fcontext, &num_result_alloc); 656 } 657 } else { 658 /* no search criteria, just record the object */ 659 rv = add_to_search_result(obj, fcontext, 660 &num_result_alloc); 661 } 662 (void) pthread_mutex_unlock(&obj->object_mutex); 663 if (rv != CKR_OK) { 664 (void) pthread_mutex_unlock 665 (&soft_slot.slot_mutex); 666 return (rv); 667 } 668 obj = obj->next; 669 } 670 (void) pthread_mutex_unlock(&soft_slot.slot_mutex); 671 } 672 673 if (token_flag_val) { 674 /* no need to look through session objects */ 675 return (rv); 676 } 677 678 /* Acquire the global session list lock */ 679 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 680 681 /* 682 * Go through all objects in each session. 683 * Acquire individual session lock for the session 684 * we are searching. 685 */ 686 session_p = soft_session_list; 687 while (session_p) { 688 (void) pthread_mutex_lock(&session_p->session_mutex); 689 690 obj = session_p->object_list; 691 while (obj) { 692 (void) pthread_mutex_lock(&obj->object_mutex); 693 if (ulCount > 0) { 694 if (soft_find_match_attrs(obj, pclasses, 695 num_pclasses, pTemplate, ulCount)) { 696 rv = add_to_search_result( 697 obj, fcontext, &num_result_alloc); 698 } 699 } else { 700 /* no search criteria, just record the object */ 701 rv = add_to_search_result(obj, fcontext, 702 &num_result_alloc); 703 } 704 (void) pthread_mutex_unlock(&obj->object_mutex); 705 if (rv != CKR_OK) { 706 (void) pthread_mutex_unlock( 707 &session_p->session_mutex); 708 goto cleanup; 709 } 710 obj = obj->next; 711 } 712 (void) pthread_mutex_unlock(&session_p->session_mutex); 713 session_p = session_p->next; 714 } 715 716 cleanup: 717 /* Release the global session list lock */ 718 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 719 return (rv); 720 } 721 722 /* 723 * Initialize the context for C_FindObjects() calls 724 */ 725 CK_RV 726 soft_find_objects_init(soft_session_t *sp, CK_ATTRIBUTE_PTR pTemplate, 727 CK_ULONG ulCount) 728 { 729 730 CK_RV rv = CKR_OK; 731 CK_OBJECT_CLASS class; /* for soft_validate_attr(). Value unused */ 732 find_context_t *fcontext; 733 734 if (ulCount) { 735 rv = soft_validate_attr(pTemplate, ulCount, &class); 736 /* Make sure all attributes in template are valid */ 737 if (rv != CKR_OK) { 738 return (rv); 739 } 740 } 741 742 743 /* prepare the find context */ 744 fcontext = calloc(1, sizeof (find_context_t)); 745 if (fcontext == NULL) { 746 return (CKR_HOST_MEMORY); 747 } 748 749 rv = search_for_objects(pTemplate, ulCount, fcontext); 750 if (rv != CKR_OK) { 751 free(fcontext); 752 return (rv); 753 } 754 755 /* store the find_context in the session */ 756 sp->find_objects.context = (CK_VOID_PTR)fcontext; 757 758 return (rv); 759 } 760 761 void 762 soft_find_objects_final(soft_session_t *sp) 763 { 764 find_context_t *fcontext; 765 766 fcontext = sp->find_objects.context; 767 sp->find_objects.context = NULL; 768 sp->find_objects.flags = 0; 769 if (fcontext->objs_found != NULL) { 770 free(fcontext->objs_found); 771 } 772 773 free(fcontext); 774 } 775 776 void 777 soft_find_objects(soft_session_t *sp, CK_OBJECT_HANDLE *obj_found, 778 CK_ULONG max_obj_requested, CK_ULONG *found_obj_count) 779 { 780 find_context_t *fcontext; 781 CK_ULONG num_obj_found = 0; 782 CK_ULONG i; 783 soft_object_t *obj; 784 785 fcontext = sp->find_objects.context; 786 787 for (i = fcontext->next_result_index; 788 ((num_obj_found < max_obj_requested) && 789 (i < fcontext->num_results)); 790 i++) { 791 obj = fcontext->objs_found[i]; 792 if (obj != NULL) { 793 (void) pthread_mutex_lock(&obj->object_mutex); 794 /* a sanity check to make sure the obj is still valid */ 795 if (obj->magic_marker == SOFTTOKEN_OBJECT_MAGIC) { 796 obj_found[num_obj_found] = 797 (CK_OBJECT_HANDLE)obj; 798 num_obj_found++; 799 } 800 (void) pthread_mutex_unlock(&obj->object_mutex); 801 } 802 } 803 fcontext->next_result_index = i; 804 *found_obj_count = num_obj_found; 805 } 806 807 /* 808 * Below are the token object related functions 809 */ 810 void 811 soft_add_token_object_to_slot(soft_object_t *objp) 812 { 813 814 (void) pthread_mutex_lock(&soft_slot.slot_mutex); 815 816 /* Insert the new object in front of slot's token object list. */ 817 if (soft_slot.token_object_list == NULL) { 818 soft_slot.token_object_list = objp; 819 objp->next = NULL; 820 objp->prev = NULL; 821 } else { 822 soft_slot.token_object_list->prev = objp; 823 objp->next = soft_slot.token_object_list; 824 objp->prev = NULL; 825 soft_slot.token_object_list = objp; 826 } 827 828 (void) pthread_mutex_unlock(&soft_slot.slot_mutex); 829 830 } 831 832 void 833 soft_remove_token_object_from_slot(soft_object_t *objp, boolean_t lock_held) 834 { 835 836 if (!lock_held) 837 (void) pthread_mutex_lock(&soft_slot.slot_mutex); 838 839 /* 840 * Remove the object from the slot's token object list. 841 */ 842 if (soft_slot.token_object_list == objp) { 843 /* Object is the first one in the list. */ 844 if (objp->next) { 845 soft_slot.token_object_list = objp->next; 846 objp->next->prev = NULL; 847 } else { 848 /* Object is the only one in the list. */ 849 soft_slot.token_object_list = NULL; 850 } 851 } else { 852 /* Object is not the first one in the list. */ 853 if (objp->next) { 854 /* Object is in the middle of the list. */ 855 objp->prev->next = objp->next; 856 objp->next->prev = objp->prev; 857 } else { 858 /* Object is the last one in the list. */ 859 objp->prev->next = NULL; 860 } 861 } 862 863 if (!lock_held) 864 (void) pthread_mutex_unlock(&soft_slot.slot_mutex); 865 } 866 867 void 868 soft_delete_token_object(soft_object_t *objp, boolean_t persistent, 869 boolean_t lock_held) 870 { 871 872 if (!lock_held) 873 (void) pthread_mutex_lock(&soft_slot.slot_mutex); 874 if (persistent) 875 /* Delete the object from the keystore. */ 876 (void) soft_keystore_del_obj(&objp->ks_handle, B_FALSE); 877 878 /* Remove the object from the slot's token object list. */ 879 soft_remove_token_object_from_slot(objp, B_TRUE); 880 if (!lock_held) 881 (void) pthread_mutex_unlock(&soft_slot.slot_mutex); 882 883 soft_delete_object_cleanup(objp); 884 } 885 886 void 887 soft_delete_all_in_core_token_objects(token_obj_type_t type) 888 { 889 890 soft_object_t *objp; 891 soft_object_t *objp1; 892 893 (void) pthread_mutex_lock(&soft_slot.slot_mutex); 894 objp = soft_slot.token_object_list; 895 896 switch (type) { 897 case PRIVATE_TOKEN: 898 while (objp) { 899 objp1 = objp->next; 900 if (objp->object_type == TOKEN_PRIVATE) { 901 soft_delete_token_object(objp, B_FALSE, B_TRUE); 902 } 903 objp = objp1; 904 } 905 break; 906 907 case PUBLIC_TOKEN: 908 while (objp) { 909 objp1 = objp->next; 910 if (objp->object_type == TOKEN_PUBLIC) { 911 soft_delete_token_object(objp, B_FALSE, B_TRUE); 912 } 913 objp = objp1; 914 } 915 break; 916 917 case ALL_TOKEN: 918 while (objp) { 919 objp1 = objp->next; 920 soft_delete_token_object(objp, B_FALSE, B_TRUE); 921 objp = objp1; 922 } 923 break; 924 } 925 926 (void) pthread_mutex_unlock(&soft_slot.slot_mutex); 927 928 } 929 930 /* 931 * Mark all the token objects in the global list to be valid. 932 */ 933 void 934 soft_validate_token_objects(boolean_t validate) 935 { 936 937 soft_object_t *objp; 938 939 (void) pthread_mutex_lock(&soft_slot.slot_mutex); 940 941 objp = soft_slot.token_object_list; 942 943 while (objp) { 944 if (validate) 945 objp->magic_marker = SOFTTOKEN_OBJECT_MAGIC; 946 else 947 objp->magic_marker = 0; 948 949 objp = objp->next; 950 } 951 952 (void) pthread_mutex_unlock(&soft_slot.slot_mutex); 953 954 } 955 956 /* 957 * Verify user's write access rule to the token object. 958 */ 959 CK_RV 960 soft_object_write_access_check(soft_session_t *sp, soft_object_t *objp) 961 { 962 963 /* 964 * This function is called by C_CreateObject, C_CopyObject, 965 * C_DestroyObject, C_SetAttributeValue, C_GenerateKey, 966 * C_GenerateKeyPairs, C_DeriveKey. All of them will write 967 * the token object to the keystore. 968 */ 969 (void) pthread_mutex_lock(&soft_giant_mutex); 970 if (!soft_slot.authenticated) { 971 (void) pthread_mutex_unlock(&soft_giant_mutex); 972 /* User is not logged in */ 973 if (sp->flags & CKF_RW_SESSION) { 974 /* 975 * For R/W Public Session: 976 * we allow write access to public session or token 977 * object, but not for private token/session object. 978 */ 979 if ((objp->object_type == TOKEN_PRIVATE) || 980 (objp->object_type == SESSION_PRIVATE)) { 981 return (CKR_USER_NOT_LOGGED_IN); 982 } 983 } else { 984 /* 985 * For R/O Public Session: 986 * we allow write access to public session object. 987 */ 988 if (objp->object_type != SESSION_PUBLIC) 989 return (CKR_SESSION_READ_ONLY); 990 } 991 } else { 992 (void) pthread_mutex_unlock(&soft_giant_mutex); 993 /* User is logged in */ 994 if (!(sp->flags & CKF_RW_SESSION)) { 995 /* 996 * For R/O User Function Session: 997 * we allow write access to public or private 998 * session object, but not for public or private 999 * token object. 1000 */ 1001 if ((objp->object_type == TOKEN_PUBLIC) || 1002 (objp->object_type == TOKEN_PRIVATE)) { 1003 return (CKR_SESSION_READ_ONLY); 1004 } 1005 } 1006 } 1007 1008 return (CKR_OK); 1009 } 1010 1011 /* 1012 * Verify if user is required to setpin when accessing the 1013 * private token/session object. 1014 */ 1015 CK_RV 1016 soft_pin_expired_check(soft_object_t *objp) 1017 { 1018 1019 /* 1020 * This function is called by C_CreateObject, C_CopyObject, 1021 * C_DestroyObject, C_GenerateKey, 1022 * C_GenerateKeyPairs, C_DeriveKey. 1023 * All of them will return CKR_PIN_EXPIRED if the 1024 * "userpin_change_needed" is set. 1025 * 1026 * The following functions will not be necessary to call 1027 * this routine even though CKR_PIN_EXPIRED is one of the 1028 * valid error code they might return. These functions are: 1029 * C_EncryptInit, C_DecryptInit, C_DigestInit, C_SignInit, 1030 * C_SignRecoverInit, C_VerifyInit, C_VerifyRecoverInit. 1031 * This is because they will not get the object handle 1032 * before the above functions are called. 1033 */ 1034 1035 (void) pthread_mutex_lock(&soft_giant_mutex); 1036 if (soft_slot.userpin_change_needed) { 1037 /* 1038 * Access private token/session object but user's 1039 * PIN is expired or never set. 1040 */ 1041 if ((objp->object_type == TOKEN_PRIVATE) || 1042 (objp->object_type == SESSION_PRIVATE)) { 1043 (void) pthread_mutex_unlock(&soft_giant_mutex); 1044 return (CKR_PIN_EXPIRED); 1045 } 1046 } 1047 1048 (void) pthread_mutex_unlock(&soft_giant_mutex); 1049 return (CKR_OK); 1050 } 1051 1052 /* 1053 * Copy the selected fields from new token object to old 1054 * token object. 1055 */ 1056 CK_RV 1057 soft_copy_to_old_object(soft_object_t *new, soft_object_t *old) 1058 { 1059 1060 CK_RV rv = CKR_OK; 1061 CK_ATTRIBUTE_INFO_PTR attrp; 1062 1063 old->class = new->class; 1064 old->bool_attr_mask = new->bool_attr_mask; 1065 soft_cleanup_extra_attr(old); 1066 attrp = new->extra_attrlistp; 1067 while (attrp) { 1068 rv = soft_copy_extra_attr(attrp, old); 1069 if (rv != CKR_OK) { 1070 soft_cleanup_extra_attr(old); 1071 return (rv); 1072 } 1073 attrp = attrp->next; 1074 } 1075 1076 /* Done with copying all information that can be modified */ 1077 return (CKR_OK); 1078 } 1079 1080 /* 1081 * Update an existing object with new data from keystore. 1082 */ 1083 CK_RV 1084 soft_update_object(ks_obj_t *ks_obj, soft_object_t *old_obj) 1085 { 1086 1087 soft_object_t *new_object; 1088 CK_RV rv; 1089 1090 new_object = calloc(1, sizeof (soft_object_t)); 1091 if (new_object == NULL) 1092 return (CKR_HOST_MEMORY); 1093 1094 rv = soft_keystore_unpack_obj(new_object, ks_obj); 1095 if (rv != CKR_OK) { 1096 soft_cleanup_object(new_object); 1097 free(new_object); 1098 return (rv); 1099 } 1100 rv = soft_copy_to_old_object(new_object, old_obj); 1101 1102 soft_cleanup_object(new_object); 1103 free(new_object); 1104 return (CKR_OK); 1105 } 1106 1107 1108 CK_RV 1109 soft_keystore_load_latest_object(soft_object_t *old_obj) 1110 { 1111 1112 uint_t version; 1113 ks_obj_t *ks_obj = NULL; 1114 CK_RV rv = CKR_OK; 1115 1116 /* 1117 * Get the current version number from the keystore for 1118 * the specified token object. 1119 */ 1120 if (soft_keystore_get_object_version(&old_obj->ks_handle, &version, 1121 B_FALSE) == 1) 1122 return (CKR_FUNCTION_FAILED); 1123 1124 /* 1125 * If the keystore version is newer than the in-core version, 1126 * re-read the token object from the keystore. 1127 */ 1128 if (old_obj->version != version) { 1129 rv = soft_keystore_get_single_obj(&old_obj->ks_handle, 1130 &ks_obj, B_FALSE); 1131 if (rv != CKR_OK) 1132 return (rv); 1133 old_obj->version = version; 1134 1135 /* 1136 * Update an existing object with new data from keystore. 1137 */ 1138 rv = soft_update_object(ks_obj, old_obj); 1139 free(ks_obj->buf); 1140 free(ks_obj); 1141 } 1142 1143 return (rv); 1144 } 1145 1146 /* 1147 * Insert an object into a list of soft_object_t objects. It is assumed 1148 * that the object to be inserted doesn't previously belong to any list 1149 */ 1150 static void 1151 insert_into_list(soft_object_t **list, soft_object_t **end_of_list, 1152 soft_object_t *objp) 1153 { 1154 if (*list == NULL) { 1155 *list = objp; 1156 objp->next = NULL; 1157 objp->prev = NULL; 1158 *end_of_list = objp; 1159 } else { 1160 (*list)->prev = objp; 1161 objp->next = *list; 1162 objp->prev = NULL; 1163 *list = objp; 1164 } 1165 } 1166 1167 /* 1168 * Move an object from an existing list into a new list of 1169 * soft_object_t objects. 1170 */ 1171 static void 1172 move_into_list(soft_object_t **existing_list, soft_object_t **new_list, 1173 soft_object_t **end_of_list, soft_object_t *objp) 1174 { 1175 1176 /* first, remove object from existing list */ 1177 if (objp == *existing_list) { 1178 /* first item in list */ 1179 if (objp->next) { 1180 *existing_list = objp->next; 1181 objp->next->prev = NULL; 1182 } else { 1183 *existing_list = NULL; 1184 } 1185 } else { 1186 if (objp->next) { 1187 objp->prev->next = objp->next; 1188 objp->next->prev = objp->prev; 1189 } else { 1190 objp->prev->next = NULL; 1191 } 1192 } 1193 1194 /* then, add into new list */ 1195 insert_into_list(new_list, end_of_list, objp); 1196 } 1197 1198 /* 1199 * Insert "new_list" into "existing_list", new list will always be inserted 1200 * into the front of existing list 1201 */ 1202 static void 1203 insert_list_into_list(soft_object_t **existing_list, 1204 soft_object_t *new_list, soft_object_t *end_new_list) 1205 { 1206 1207 if (new_list == NULL) { 1208 return; 1209 } 1210 1211 if (*existing_list == NULL) { 1212 *existing_list = new_list; 1213 } else { 1214 (*existing_list)->prev = end_new_list; 1215 end_new_list->next = *existing_list; 1216 *existing_list = new_list; 1217 } 1218 } 1219 1220 static void 1221 delete_all_objs_in_list(soft_object_t *list) 1222 { 1223 soft_object_t *objp, *objp_next; 1224 1225 if (list == NULL) { 1226 return; 1227 } 1228 1229 objp = list; 1230 while (objp) { 1231 objp_next = objp->next; 1232 soft_delete_object_cleanup(objp); 1233 objp = objp_next; 1234 } 1235 } 1236 1237 /* 1238 * Makes sure that the list of in-core token objects are up to date 1239 * with respect to the on disk keystore. Other process/applications 1240 * might have modified the keystore since the objects are last loaded 1241 * 1242 * If there's any error from refreshing the token object list (eg: unable 1243 * to read, unable to unpack and object...etc), the in-core list 1244 * will be restored back to the state before the refresh. An error 1245 * will be returned to indicate the failure. 1246 * 1247 * It is assumed that the caller holds the lock for the token slot 1248 */ 1249 CK_RV 1250 refresh_token_objects() 1251 { 1252 uint_t on_disk_ks_version; 1253 ks_obj_t *on_disk_list = NULL, *tmp_on_disk, *next_on_disk; 1254 soft_object_t *in_core_obj, *tmp_incore_obj, *new_objp = NULL; 1255 CK_RV rv = CKR_OK; 1256 1257 /* deleted in-core objects */ 1258 soft_object_t *del_objs_list = NULL; 1259 soft_object_t *end_del_objs_list = NULL; 1260 1261 /* modified in-core objects */ 1262 soft_object_t *mod_objs_list = NULL; 1263 soft_object_t *end_mod_objs_list = NULL; 1264 1265 /* 1266 * copy of modified in-core objects, in case we need 1267 * undo the change 1268 */ 1269 soft_object_t *copy_of_mod_objs_list = NULL; 1270 soft_object_t *end_copy_of_mod_objs_list = NULL; 1271 1272 /* objects to be added to the in-core list */ 1273 soft_object_t *added_objs_list = NULL; 1274 soft_object_t *end_added_objs_list = NULL; 1275 1276 if (soft_keystore_get_version(&on_disk_ks_version, B_FALSE) != 0) { 1277 return (CKR_FUNCTION_FAILED); 1278 } 1279 1280 (void) pthread_mutex_lock(&soft_giant_mutex); 1281 if (on_disk_ks_version == soft_slot.ks_version) { 1282 /* no change */ 1283 (void) pthread_mutex_unlock(&soft_giant_mutex); 1284 return (CKR_OK); 1285 } 1286 1287 if (soft_slot.authenticated) { 1288 /* get both public and private objects */ 1289 (void) pthread_mutex_unlock(&soft_giant_mutex); 1290 rv = soft_keystore_get_objs(ALL_TOKENOBJS, &on_disk_list, 1291 B_FALSE); 1292 } else { 1293 /* get both public objects only */ 1294 (void) pthread_mutex_unlock(&soft_giant_mutex); 1295 rv = soft_keystore_get_objs(PUB_TOKENOBJS, &on_disk_list, 1296 B_FALSE); 1297 } 1298 if (rv != CKR_OK) { 1299 return (rv); 1300 } 1301 1302 /* 1303 * The in-core tokens list will be updated as follows: 1304 * 1305 * Go through each item in the in-core tokens list. 1306 * Try to match the in-core object with one of the 1307 * objects from the on-disk list. If a match is made, 1308 * check the version number, and update in-core object 1309 * as necessary. 1310 * 1311 * If there's no match between in-core object with on-disk 1312 * object, that means the object is deleted since 1313 * last loaded. Will remove object from in-core list. 1314 * 1315 * When doing the matching of on-disk object list above, 1316 * Delete every matched on-disk object from the on-disk list 1317 * regardless the in-core object need to be deleted or not 1318 * 1319 * At the end of matching the in-core tokens list, if 1320 * any object is still left on the on-disk object list, 1321 * those are all new objects added since last load, 1322 * include all of them to the in-core list 1323 * 1324 * Since we need to be able to revert the in-core list 1325 * back to original state if there's any error with the refresh, 1326 * we need to do the following. 1327 * When an in-core object is "deleted", it is not immediately 1328 * deleted. It is moved to the list of "deleted_objects". 1329 * When an in-core object is "modified", a copy of the 1330 * unmodified object is made. After the object is modified, 1331 * it is temporarily moved to the "mod_objects" list 1332 * from the in-core list. 1333 * When the refresh is completed without any error, 1334 * the actual deleted objects and unmodified objects is deleted. 1335 */ 1336 in_core_obj = soft_slot.token_object_list; 1337 while (in_core_obj) { 1338 /* try to match object with on_disk_list */ 1339 ks_obj_t *ondisk_obj, *prev_ondisk_obj; 1340 boolean_t found = B_FALSE; 1341 soft_object_t *obj_copy; 1342 1343 ondisk_obj = on_disk_list; 1344 prev_ondisk_obj = NULL; 1345 1346 /* larval object that has not been written to disk */ 1347 if (in_core_obj->ks_handle.name[0] == '\0') { 1348 in_core_obj = in_core_obj->next; 1349 continue; 1350 } 1351 1352 while ((!found) && (ondisk_obj != NULL)) { 1353 1354 if (strcmp((char *)((ondisk_obj->ks_handle).name), 1355 (char *)((in_core_obj->ks_handle).name)) == 0) { 1356 1357 /* found a match */ 1358 found = B_TRUE; 1359 1360 /* update in-core obj if necessary */ 1361 if (ondisk_obj->obj_version != 1362 in_core_obj->version) { 1363 /* make a copy of before updating */ 1364 rv = soft_copy_object(in_core_obj, 1365 &obj_copy, SOFT_COPY_OBJ_ORIG_SH, 1366 NULL); 1367 if (rv != CKR_OK) { 1368 goto cleanup; 1369 } 1370 insert_into_list( 1371 ©_of_mod_objs_list, 1372 &end_copy_of_mod_objs_list, 1373 obj_copy); 1374 1375 rv = soft_update_object(ondisk_obj, 1376 in_core_obj); 1377 if (rv != CKR_OK) { 1378 goto cleanup; 1379 } 1380 move_into_list( 1381 &(soft_slot.token_object_list), 1382 &mod_objs_list, &end_mod_objs_list, 1383 in_core_obj); 1384 } 1385 1386 /* remove processed obj from on disk list */ 1387 if (ondisk_obj == on_disk_list) { 1388 /* first item */ 1389 on_disk_list = ondisk_obj->next; 1390 } else { 1391 prev_ondisk_obj->next = 1392 ondisk_obj->next; 1393 } 1394 free(ondisk_obj->buf); 1395 free(ondisk_obj); 1396 } else { 1397 prev_ondisk_obj = ondisk_obj; 1398 ondisk_obj = ondisk_obj->next; 1399 } 1400 } 1401 1402 if (!found) { 1403 tmp_incore_obj = in_core_obj->next; 1404 move_into_list(&(soft_slot.token_object_list), 1405 &del_objs_list, &end_del_objs_list, in_core_obj); 1406 in_core_obj = tmp_incore_obj; 1407 } else { 1408 in_core_obj = in_core_obj->next; 1409 } 1410 } 1411 1412 /* 1413 * At this point, if there's still anything on the on_disk_list, they 1414 * are all newly added objects since in-core list last loaded. 1415 * include all of them into the in-core list 1416 */ 1417 next_on_disk = on_disk_list; 1418 while (next_on_disk) { 1419 new_objp = calloc(1, sizeof (soft_object_t)); 1420 if (new_objp == NULL) { 1421 rv = CKR_HOST_MEMORY; 1422 goto cleanup; 1423 } 1424 1425 /* Convert the keystore format to memory format */ 1426 rv = soft_keystore_unpack_obj(new_objp, next_on_disk); 1427 if (rv != CKR_OK) { 1428 soft_cleanup_object(new_objp); 1429 free(new_objp); 1430 goto cleanup; 1431 } 1432 1433 insert_into_list(&added_objs_list, &end_added_objs_list, 1434 new_objp); 1435 1436 /* free the on_disk object */ 1437 tmp_on_disk = next_on_disk; 1438 next_on_disk = tmp_on_disk->next; 1439 free(tmp_on_disk->buf); 1440 free(tmp_on_disk); 1441 } 1442 1443 if (rv == CKR_OK) { 1444 (void) pthread_mutex_lock(&soft_giant_mutex); 1445 soft_slot.ks_version = on_disk_ks_version; 1446 (void) pthread_mutex_unlock(&soft_giant_mutex); 1447 1448 /* add the new objects into in-core list */ 1449 insert_list_into_list(&(soft_slot.token_object_list), 1450 added_objs_list, end_added_objs_list); 1451 1452 /* add modified objects back into the in-core list */ 1453 insert_list_into_list(&(soft_slot.token_object_list), 1454 mod_objs_list, end_mod_objs_list); 1455 1456 /* actually remove deleted objs, and copy of modified objs */ 1457 delete_all_objs_in_list(copy_of_mod_objs_list); 1458 delete_all_objs_in_list(del_objs_list); 1459 } 1460 1461 return (rv); 1462 1463 cleanup: 1464 next_on_disk = on_disk_list; 1465 while (next_on_disk) { 1466 tmp_on_disk = next_on_disk; 1467 next_on_disk = tmp_on_disk->next; 1468 free(tmp_on_disk->buf); 1469 free(tmp_on_disk); 1470 } 1471 1472 /* 1473 * restore the in-core list back to the original state by adding 1474 * copy of original objects and deleted objects back to list 1475 */ 1476 insert_list_into_list(&(soft_slot.token_object_list), 1477 del_objs_list, end_del_objs_list); 1478 insert_list_into_list(&(soft_slot.token_object_list), 1479 copy_of_mod_objs_list, end_copy_of_mod_objs_list); 1480 1481 /* 1482 * remove the modified objects, and newly objects list 1483 */ 1484 delete_all_objs_in_list(mod_objs_list); 1485 delete_all_objs_in_list(added_objs_list); 1486 return (rv); 1487 } 1488