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 2006 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 (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, lock_held); 880 881 soft_delete_object_cleanup(objp); 882 } 883 884 void 885 soft_delete_all_in_core_token_objects(token_obj_type_t type) 886 { 887 888 soft_object_t *objp; 889 soft_object_t *objp1; 890 891 (void) pthread_mutex_lock(&soft_slot.slot_mutex); 892 objp = soft_slot.token_object_list; 893 894 switch (type) { 895 case PRIVATE_TOKEN: 896 while (objp) { 897 objp1 = objp->next; 898 if (objp->object_type == TOKEN_PRIVATE) { 899 soft_delete_token_object(objp, B_FALSE, B_TRUE); 900 } 901 objp = objp1; 902 } 903 break; 904 905 case PUBLIC_TOKEN: 906 while (objp) { 907 objp1 = objp->next; 908 if (objp->object_type == TOKEN_PUBLIC) { 909 soft_delete_token_object(objp, B_FALSE, B_TRUE); 910 } 911 objp = objp1; 912 } 913 break; 914 915 case ALL_TOKEN: 916 while (objp) { 917 objp1 = objp->next; 918 soft_delete_token_object(objp, B_FALSE, B_TRUE); 919 objp = objp1; 920 } 921 break; 922 } 923 924 (void) pthread_mutex_unlock(&soft_slot.slot_mutex); 925 926 } 927 928 /* 929 * Mark all the token objects in the global list to be valid. 930 */ 931 void 932 soft_validate_token_objects(boolean_t validate) 933 { 934 935 soft_object_t *objp; 936 937 (void) pthread_mutex_lock(&soft_slot.slot_mutex); 938 939 objp = soft_slot.token_object_list; 940 941 while (objp) { 942 if (validate) 943 objp->magic_marker = SOFTTOKEN_OBJECT_MAGIC; 944 else 945 objp->magic_marker = 0; 946 947 objp = objp->next; 948 } 949 950 (void) pthread_mutex_unlock(&soft_slot.slot_mutex); 951 952 } 953 954 /* 955 * Verify user's write access rule to the token object. 956 */ 957 CK_RV 958 soft_object_write_access_check(soft_session_t *sp, soft_object_t *objp) 959 { 960 961 /* 962 * This function is called by C_CreateObject, C_CopyObject, 963 * C_DestroyObject, C_SetAttributeValue, C_GenerateKey, 964 * C_GenerateKeyPairs, C_DeriveKey. All of them will write 965 * the token object to the keystore. 966 */ 967 (void) pthread_mutex_lock(&soft_giant_mutex); 968 if (!soft_slot.authenticated) { 969 (void) pthread_mutex_unlock(&soft_giant_mutex); 970 /* User is not logged in */ 971 if (sp->flags & CKF_RW_SESSION) { 972 /* 973 * For R/W Public Session: 974 * we allow write access to public session or token 975 * object, but not for private token/session object. 976 */ 977 if ((objp->object_type == TOKEN_PRIVATE) || 978 (objp->object_type == SESSION_PRIVATE)) { 979 return (CKR_USER_NOT_LOGGED_IN); 980 } 981 } else { 982 /* 983 * For R/O Public Session: 984 * we allow write access to public session object. 985 */ 986 if (objp->object_type != SESSION_PUBLIC) 987 return (CKR_SESSION_READ_ONLY); 988 } 989 } else { 990 (void) pthread_mutex_unlock(&soft_giant_mutex); 991 /* User is logged in */ 992 if (!(sp->flags & CKF_RW_SESSION)) { 993 /* 994 * For R/O User Function Session: 995 * we allow write access to public or private 996 * session object, but not for public or private 997 * token object. 998 */ 999 if ((objp->object_type == TOKEN_PUBLIC) || 1000 (objp->object_type == TOKEN_PRIVATE)) { 1001 return (CKR_SESSION_READ_ONLY); 1002 } 1003 } 1004 } 1005 1006 return (CKR_OK); 1007 } 1008 1009 /* 1010 * Verify if user is required to setpin when accessing the 1011 * private token/session object. 1012 */ 1013 CK_RV 1014 soft_pin_expired_check(soft_object_t *objp) 1015 { 1016 1017 /* 1018 * This function is called by C_CreateObject, C_CopyObject, 1019 * C_DestroyObject, C_GenerateKey, 1020 * C_GenerateKeyPairs, C_DeriveKey. 1021 * All of them will return CKR_PIN_EXPIRED if the 1022 * "userpin_change_needed" is set. 1023 * 1024 * The following functions will not be necessary to call 1025 * this routine even though CKR_PIN_EXPIRED is one of the 1026 * valid error code they might return. These functions are: 1027 * C_EncryptInit, C_DecryptInit, C_DigestInit, C_SignInit, 1028 * C_SignRecoverInit, C_VerifyInit, C_VerifyRecoverInit. 1029 * This is because they will not get the object handle 1030 * before the above functions are called. 1031 */ 1032 1033 (void) pthread_mutex_lock(&soft_giant_mutex); 1034 if (soft_slot.userpin_change_needed) { 1035 /* 1036 * Access private token/session object but user's 1037 * PIN is expired or never set. 1038 */ 1039 if ((objp->object_type == TOKEN_PRIVATE) || 1040 (objp->object_type == SESSION_PRIVATE)) { 1041 (void) pthread_mutex_unlock(&soft_giant_mutex); 1042 return (CKR_PIN_EXPIRED); 1043 } 1044 } 1045 1046 (void) pthread_mutex_unlock(&soft_giant_mutex); 1047 return (CKR_OK); 1048 } 1049 1050 /* 1051 * Copy the selected fields from new token object to old 1052 * token object. 1053 */ 1054 CK_RV 1055 soft_copy_to_old_object(soft_object_t *new, soft_object_t *old) 1056 { 1057 1058 CK_RV rv = CKR_OK; 1059 CK_ATTRIBUTE_INFO_PTR attrp; 1060 1061 old->class = new->class; 1062 old->bool_attr_mask = new->bool_attr_mask; 1063 soft_cleanup_extra_attr(old); 1064 attrp = new->extra_attrlistp; 1065 while (attrp) { 1066 rv = soft_copy_extra_attr(attrp, old); 1067 if (rv != CKR_OK) { 1068 soft_cleanup_extra_attr(old); 1069 return (rv); 1070 } 1071 attrp = attrp->next; 1072 } 1073 1074 /* Done with copying all information that can be modified */ 1075 return (CKR_OK); 1076 } 1077 1078 /* 1079 * Update an existing object with new data from keystore. 1080 */ 1081 CK_RV 1082 soft_update_object(ks_obj_t *ks_obj, soft_object_t *old_obj) 1083 { 1084 1085 soft_object_t *new_object; 1086 CK_RV rv; 1087 1088 new_object = calloc(1, sizeof (soft_object_t)); 1089 if (new_object == NULL) 1090 return (CKR_HOST_MEMORY); 1091 1092 rv = soft_keystore_unpack_obj(new_object, ks_obj); 1093 if (rv != CKR_OK) { 1094 soft_cleanup_object(new_object); 1095 free(new_object); 1096 return (rv); 1097 } 1098 rv = soft_copy_to_old_object(new_object, old_obj); 1099 1100 soft_cleanup_object(new_object); 1101 free(new_object); 1102 return (CKR_OK); 1103 } 1104 1105 1106 CK_RV 1107 soft_keystore_load_latest_object(soft_object_t *old_obj) 1108 { 1109 1110 uint_t version; 1111 ks_obj_t *ks_obj = NULL; 1112 CK_RV rv = CKR_OK; 1113 1114 /* 1115 * Get the current version number from the keystore for 1116 * the specified token object. 1117 */ 1118 if (soft_keystore_get_object_version(&old_obj->ks_handle, &version, 1119 B_FALSE) == 1) 1120 return (CKR_FUNCTION_FAILED); 1121 1122 /* 1123 * If the keystore version is newer than the in-core version, 1124 * re-read the token object from the keystore. 1125 */ 1126 if (old_obj->version != version) { 1127 rv = soft_keystore_get_single_obj(&old_obj->ks_handle, 1128 &ks_obj, B_FALSE); 1129 if (rv != CKR_OK) 1130 return (rv); 1131 old_obj->version = version; 1132 1133 /* 1134 * Update an existing object with new data from keystore. 1135 */ 1136 rv = soft_update_object(ks_obj, old_obj); 1137 free(ks_obj->buf); 1138 free(ks_obj); 1139 } 1140 1141 return (rv); 1142 } 1143 1144 /* 1145 * Insert an object into a list of soft_object_t objects. It is assumed 1146 * that the object to be inserted doesn't previously belong to any list 1147 */ 1148 static void 1149 insert_into_list(soft_object_t **list, soft_object_t **end_of_list, 1150 soft_object_t *objp) 1151 { 1152 if (*list == NULL) { 1153 *list = objp; 1154 objp->next = NULL; 1155 objp->prev = NULL; 1156 *end_of_list = objp; 1157 } else { 1158 (*list)->prev = objp; 1159 objp->next = *list; 1160 objp->prev = NULL; 1161 *list = objp; 1162 } 1163 } 1164 1165 /* 1166 * Move an object from an existing list into a new list of 1167 * soft_object_t objects. 1168 */ 1169 static void 1170 move_into_list(soft_object_t **existing_list, soft_object_t **new_list, 1171 soft_object_t **end_of_list, soft_object_t *objp) 1172 { 1173 1174 /* first, remove object from existing list */ 1175 if (objp == *existing_list) { 1176 /* first item in list */ 1177 if (objp->next) { 1178 *existing_list = objp->next; 1179 objp->next->prev = NULL; 1180 } else { 1181 *existing_list = NULL; 1182 } 1183 } else { 1184 if (objp->next) { 1185 objp->prev->next = objp->next; 1186 objp->next->prev = objp->prev; 1187 } else { 1188 objp->prev->next = NULL; 1189 } 1190 } 1191 1192 /* then, add into new list */ 1193 insert_into_list(new_list, end_of_list, objp); 1194 } 1195 1196 /* 1197 * Insert "new_list" into "existing_list", new list will always be inserted 1198 * into the front of existing list 1199 */ 1200 static void 1201 insert_list_into_list(soft_object_t **existing_list, 1202 soft_object_t *new_list, soft_object_t *end_new_list) 1203 { 1204 1205 if (new_list == NULL) { 1206 return; 1207 } 1208 1209 if (*existing_list == NULL) { 1210 *existing_list = new_list; 1211 } else { 1212 (*existing_list)->prev = end_new_list; 1213 end_new_list->next = *existing_list; 1214 *existing_list = new_list; 1215 } 1216 } 1217 1218 static void 1219 delete_all_objs_in_list(soft_object_t *list) 1220 { 1221 soft_object_t *objp, *objp_next; 1222 1223 if (list == NULL) { 1224 return; 1225 } 1226 1227 objp = list; 1228 while (objp) { 1229 objp_next = objp->next; 1230 soft_delete_object_cleanup(objp); 1231 objp = objp_next; 1232 } 1233 } 1234 1235 /* 1236 * Makes sure that the list of in-core token objects are up to date 1237 * with respect to the on disk keystore. Other process/applications 1238 * might have modified the keystore since the objects are last loaded 1239 * 1240 * If there's any error from refreshing the token object list (eg: unable 1241 * to read, unable to unpack and object...etc), the in-core list 1242 * will be restored back to the state before the refresh. An error 1243 * will be returned to indicate the failure. 1244 * 1245 * It is assumed that the caller holds the lock for the token slot 1246 */ 1247 CK_RV 1248 refresh_token_objects() 1249 { 1250 uint_t on_disk_ks_version; 1251 ks_obj_t *on_disk_list = NULL, *tmp_on_disk, *next_on_disk; 1252 soft_object_t *in_core_obj, *tmp_incore_obj, *new_objp = NULL; 1253 CK_RV rv = CKR_OK; 1254 1255 /* deleted in-core objects */ 1256 soft_object_t *del_objs_list = NULL, 1257 *end_del_objs_list = NULL, 1258 1259 /* modified in-core objects */ 1260 *mod_objs_list = NULL, 1261 *end_mod_objs_list = NULL, 1262 1263 /* 1264 * copy of modified in-core objects, in case we need 1265 * undo the change 1266 */ 1267 *copy_of_mod_objs_list = NULL, 1268 *end_copy_of_mod_objs_list = NULL, 1269 1270 /* objects to be added to the in-core list */ 1271 *added_objs_list = NULL, 1272 *end_added_objs_list = NULL; 1273 1274 if (soft_keystore_get_version(&on_disk_ks_version, B_FALSE) != 0) { 1275 return (CKR_FUNCTION_FAILED); 1276 } 1277 1278 (void) pthread_mutex_lock(&soft_giant_mutex); 1279 if (on_disk_ks_version == soft_slot.ks_version) { 1280 /* no change */ 1281 (void) pthread_mutex_unlock(&soft_giant_mutex); 1282 return (CKR_OK); 1283 } 1284 1285 if (soft_slot.authenticated) { 1286 /* get both public and private objects */ 1287 (void) pthread_mutex_unlock(&soft_giant_mutex); 1288 rv = soft_keystore_get_objs(ALL_TOKENOBJS, &on_disk_list, 1289 B_FALSE); 1290 } else { 1291 /* get both public objects only */ 1292 (void) pthread_mutex_unlock(&soft_giant_mutex); 1293 rv = soft_keystore_get_objs(PUB_TOKENOBJS, &on_disk_list, 1294 B_FALSE); 1295 } 1296 if (rv != CKR_OK) { 1297 return (rv); 1298 } 1299 1300 /* 1301 * The in-core tokens list will be updated as follows: 1302 * 1303 * Go through each item in the in-core tokens list. 1304 * Try to match the in-core object with one of the 1305 * objects from the on-disk list. If a match is made, 1306 * check the version number, and update in-core object 1307 * as necessary. 1308 * 1309 * If there's no match between in-core object with on-disk 1310 * object, that means the object is deleted since 1311 * last loaded. Will remove object from in-core list. 1312 * 1313 * When doing the matching of on-disk object list above, 1314 * Delete every matched on-disk object from the on-disk list 1315 * regardless the in-core object need to be deleted or not 1316 * 1317 * At the end of matching the in-core tokens list, if 1318 * any object is still left on the on-disk object list, 1319 * those are all new objects added since last load, 1320 * include all of them to the in-core list 1321 * 1322 * Since we need to be able to revert the in-core list 1323 * back to original state if there's any error with the refresh, 1324 * we need to do the following. 1325 * When an in-core object is "deleted", it is not immediately 1326 * deleted. It is moved to the list of "deleted_objects". 1327 * When an in-core object is "modified", a copy of the 1328 * unmodified object is made. After the object is modified, 1329 * it is temporarily moved to the "mod_objects" list 1330 * from the in-core list. 1331 * When the refresh is completed without any error, 1332 * the actual deleted objects and unmodified objects is deleted. 1333 */ 1334 in_core_obj = soft_slot.token_object_list; 1335 while (in_core_obj) { 1336 /* try to match object with on_disk_list */ 1337 ks_obj_t *ondisk_obj, *prev_ondisk_obj; 1338 boolean_t found = B_FALSE; 1339 soft_object_t *obj_copy; 1340 1341 ondisk_obj = on_disk_list; 1342 prev_ondisk_obj = NULL; 1343 1344 while ((!found) && (ondisk_obj != NULL)) { 1345 1346 if (strcmp((char *)((ondisk_obj->ks_handle).name), 1347 (char *)((in_core_obj->ks_handle).name)) == 0) { 1348 1349 /* found a match */ 1350 found = B_TRUE; 1351 1352 /* update in-core obj if necessary */ 1353 if (ondisk_obj->obj_version != 1354 in_core_obj->version) { 1355 /* make a copy of before updating */ 1356 rv = soft_copy_object(in_core_obj, 1357 &obj_copy, SOFT_COPY_OBJ_ORIG_SH, 1358 NULL); 1359 if (rv != CKR_OK) { 1360 goto cleanup; 1361 } 1362 insert_into_list( 1363 ©_of_mod_objs_list, 1364 &end_copy_of_mod_objs_list, 1365 obj_copy); 1366 1367 rv = soft_update_object(ondisk_obj, 1368 in_core_obj); 1369 if (rv != CKR_OK) { 1370 goto cleanup; 1371 } 1372 move_into_list( 1373 &(soft_slot.token_object_list), 1374 &mod_objs_list, &end_mod_objs_list, 1375 in_core_obj); 1376 } 1377 1378 /* remove processed obj from on disk list */ 1379 if (ondisk_obj == on_disk_list) { 1380 /* first item */ 1381 on_disk_list = ondisk_obj->next; 1382 } else { 1383 prev_ondisk_obj->next = 1384 ondisk_obj->next; 1385 } 1386 free(ondisk_obj->buf); 1387 free(ondisk_obj); 1388 } else { 1389 prev_ondisk_obj = ondisk_obj; 1390 ondisk_obj = ondisk_obj->next; 1391 } 1392 } 1393 1394 if (!found) { 1395 tmp_incore_obj = in_core_obj->next; 1396 move_into_list(&(soft_slot.token_object_list), 1397 &del_objs_list, &end_del_objs_list, in_core_obj); 1398 in_core_obj = tmp_incore_obj; 1399 } else { 1400 in_core_obj = in_core_obj->next; 1401 } 1402 } 1403 1404 /* 1405 * At this point, if there's still anything on the on_disk_list, they 1406 * are all newly added objects since in-core list last loaded. 1407 * include all of them into the in-core list 1408 */ 1409 next_on_disk = on_disk_list; 1410 while (next_on_disk) { 1411 new_objp = calloc(1, sizeof (soft_object_t)); 1412 if (new_objp == NULL) { 1413 rv = CKR_HOST_MEMORY; 1414 goto cleanup; 1415 } 1416 1417 /* Convert the keystore format to memory format */ 1418 rv = soft_keystore_unpack_obj(new_objp, next_on_disk); 1419 if (rv != CKR_OK) { 1420 soft_cleanup_object(new_objp); 1421 free(new_objp); 1422 goto cleanup; 1423 } 1424 1425 insert_into_list(&added_objs_list, &end_added_objs_list, 1426 new_objp); 1427 1428 /* free the on_disk object */ 1429 tmp_on_disk = next_on_disk; 1430 next_on_disk = tmp_on_disk->next; 1431 free(tmp_on_disk->buf); 1432 free(tmp_on_disk); 1433 } 1434 1435 if (rv == CKR_OK) { 1436 (void) pthread_mutex_lock(&soft_giant_mutex); 1437 soft_slot.ks_version = on_disk_ks_version; 1438 (void) pthread_mutex_unlock(&soft_giant_mutex); 1439 1440 /* add the new objects into in-core list */ 1441 insert_list_into_list(&(soft_slot.token_object_list), 1442 added_objs_list, end_added_objs_list); 1443 1444 /* add modified objects back into the in-core list */ 1445 insert_list_into_list(&(soft_slot.token_object_list), 1446 mod_objs_list, end_mod_objs_list); 1447 1448 /* actually remove deleted objs, and copy of modified objs */ 1449 delete_all_objs_in_list(copy_of_mod_objs_list); 1450 delete_all_objs_in_list(del_objs_list); 1451 } 1452 1453 return (rv); 1454 1455 cleanup: 1456 next_on_disk = on_disk_list; 1457 while (next_on_disk) { 1458 tmp_on_disk = next_on_disk; 1459 next_on_disk = tmp_on_disk->next; 1460 free(tmp_on_disk->buf); 1461 free(tmp_on_disk); 1462 } 1463 1464 /* 1465 * restore the in-core list back to the original state by adding 1466 * copy of original objects and deleted objects back to list 1467 */ 1468 insert_list_into_list(&(soft_slot.token_object_list), 1469 del_objs_list, end_del_objs_list); 1470 insert_list_into_list(&(soft_slot.token_object_list), 1471 copy_of_mod_objs_list, end_copy_of_mod_objs_list); 1472 1473 /* 1474 * remove the modified objects, and newly objects list 1475 */ 1476 delete_all_objs_in_list(mod_objs_list); 1477 delete_all_objs_in_list(added_objs_list); 1478 return (rv); 1479 } 1480