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