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