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 /* 29 * Object Management Functions 30 * (as defined in PKCS#11 spec section 11.7) 31 */ 32 33 #include <strings.h> 34 #include "metaGlobal.h" 35 #include <stdio.h> 36 37 #define FIND_OBJ_BUF_SIZE 512 /* size of buf used for C_FindObjects */ 38 39 /* 40 * Argument related return codes. Will return to the caller immediately, 41 * and not try the operation on another slot. 42 */ 43 static CK_RV stop_rv[] = { 44 CKR_ARGUMENTS_BAD, 45 CKR_ATTRIBUTE_TYPE_INVALID, 46 CKR_DOMAIN_PARAMS_INVALID, 47 CKR_TEMPLATE_INCOMPLETE 48 }; 49 static int num_stop_rv = sizeof (stop_rv) / sizeof (CK_RV); 50 51 /* 52 * Return codes that are related to a specific slot. 53 * Will try to perform the operation in the next available slot. 54 * If all attempts failed, will return the error code from the first slot. 55 * 56 * This list is here for reference only, it is commented out because 57 * it doesn't need to be used by the code at this point. 58 * 59 * static CK_RV try_again_rv[] = { 60 * CKR_DEVICE_ERROR, 61 * CKR_DEVICE_MEMORY, 62 * CKR_DEVICE_REMOVED, 63 * CKR_FUNCTION_FAILED, 64 * CKR_GENERAL_ERROR, 65 * CKR_HOST_MEMORY, 66 * CKR_TEMPLATE_INCONSISTENT, 67 * CKR_ATTRIBUTE_READ_ONLY, 68 * CKR_ATTRIBUTE_VALUE_INVALID 69 * }; 70 * static int num_try_again_rv = sizeof (try_again_rv) / sizeof (CK_RV); 71 */ 72 73 /* 74 * We should never get these return codes because 75 * MetaSlot is the one that actually created the 76 * sessions. When we get these errors in C_CreateObject, 77 * will try to create the object in the next available slot. 78 * If all attempts failed, will return CKR_FUNCTION_FAILED 79 * to the caller. 80 */ 81 static CK_RV other_rv[] = { 82 CKR_CRYPTOKI_NOT_INITIALIZED, 83 CKR_SESSION_CLOSED, 84 CKR_SESSION_HANDLE_INVALID, 85 CKR_SESSION_READ_ONLY 86 }; 87 static int num_other_rv = sizeof (other_rv) / sizeof (CK_RV); 88 89 /* 90 * This function is only used by the C_CreateObject and C_CopyObject. 91 * 92 * It is used to determine if the operation should be tried on another slot 93 * based on the return code 94 */ 95 static boolean_t 96 try_again(CK_RV rv) 97 { 98 int i; 99 100 for (i = 0; i < num_stop_rv; i++) { 101 if (rv == stop_rv[i]) { 102 return (B_FALSE); 103 } 104 } 105 return (B_TRUE); 106 } 107 108 109 /* 110 * meta_CreateObject 111 * 112 */ 113 CK_RV 114 meta_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, 115 CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) 116 { 117 CK_RV rv; 118 meta_session_t *session; 119 slot_session_t *slot_session = NULL; 120 meta_object_t *object = NULL; 121 slot_object_t *slot_object = NULL; 122 CK_OBJECT_HANDLE hNewObject; 123 CK_ULONG slot_num, keystore_slotnum; 124 CK_RV first_rv; 125 126 if (pTemplate == NULL || ulCount < 1 || phObject == NULL) 127 return (CKR_ARGUMENTS_BAD); 128 129 rv = meta_handle2session(hSession, &session); 130 if (rv != CKR_OK) 131 return (rv); 132 133 rv = meta_object_alloc(session, &object); 134 if (rv != CKR_OK) 135 goto cleanup; 136 137 /* 138 * Create a clone of the object 139 */ 140 rv = meta_slot_object_alloc(&slot_object); 141 if (rv != CKR_OK) 142 goto cleanup; 143 144 /* 145 * Set to true (token object) if template has CKA_TOKEN=true; 146 * otherwise, it is false (session object). 147 */ 148 (void) get_template_boolean(CKA_TOKEN, pTemplate, ulCount, 149 &(object->isToken)); 150 151 /* 152 * Set to true (private object) if template has CKA_PRIVATE=true; 153 * otherwise, it is false (public object). 154 */ 155 (void) get_template_boolean(CKA_PRIVATE, pTemplate, ulCount, 156 &(object->isPrivate)); 157 158 /* Assume object is extractable unless template has otherwise */ 159 object->isExtractable = B_TRUE; 160 (void) get_template_boolean(CKA_EXTRACTABLE, pTemplate, ulCount, 161 &(object->isExtractable)); 162 163 /* 164 * Set to true (sensitive object) if template has CKA_SENSITIVE=true; 165 * otherwise, it is false. 166 */ 167 (void) get_template_boolean(CKA_SENSITIVE, pTemplate, ulCount, 168 &(object->isSensitive)); 169 170 /* 171 * Check if this can be a FreeObject. 172 * 173 * For creating objects, this check is mostly for preventing 174 * non-keystore hardware from creating CKA_PRIVATE objects without 175 * logging in. 176 */ 177 178 if (meta_freeobject_check(session, object, NULL, pTemplate, ulCount, 179 NULL)) { 180 /* 181 * Make sure we are logged into the keystore if this is a 182 * private freetoken object. 183 */ 184 if (object->isPrivate && !metaslot_logged_in()) 185 return (CKR_USER_NOT_LOGGED_IN); 186 187 if (!meta_freeobject_set(object, pTemplate, ulCount, B_TRUE)) 188 goto cleanup; 189 } 190 191 /* Can't create token objects in a read-only session. */ 192 if ((IS_READ_ONLY_SESSION(session->session_flags)) && object->isToken) { 193 rv = CKR_SESSION_READ_ONLY; 194 goto cleanup; 195 } 196 197 keystore_slotnum = get_keystore_slotnum(); 198 199 if (object->isToken || object->isFreeToken == FREE_ENABLED) { 200 201 /* 202 * If this is a token object or a FreeToken then create it 203 * on the keystore slot. 204 */ 205 206 slot_num = keystore_slotnum; 207 rv = meta_get_slot_session(slot_num, &slot_session, 208 session->session_flags); 209 if (rv != CKR_OK) 210 goto cleanup; 211 212 object->tried_create_clone[slot_num] = B_TRUE; 213 rv = FUNCLIST(slot_session->fw_st_id)->C_CreateObject( 214 slot_session->hSession, pTemplate, ulCount, 215 &hNewObject); 216 217 if (rv != CKR_OK) 218 goto cleanup; 219 220 } else { 221 222 /* 223 * Create a clone of the object in the first available slot. 224 * 225 * If creating a clone in a specific slot failed, it will 226 * either stop and return the error to the user, or try 227 * again in the next available slot until it succeeds. The 228 * decision to stop or continue is made based on the return 229 * code. 230 */ 231 CK_ULONG num_slots = meta_slotManager_get_slotcount(); 232 233 for (slot_num = 0; slot_num < num_slots; slot_num++) { 234 /* 235 * If this is a free token and we are on the keystore 236 * slot, bypass this because it was already created 237 */ 238 239 rv = meta_get_slot_session(slot_num, &slot_session, 240 session->session_flags); 241 if (rv != CKR_OK) 242 goto cleanup; 243 244 object->tried_create_clone[slot_num] = B_TRUE; 245 rv = FUNCLIST(slot_session->fw_st_id)->C_CreateObject( 246 slot_session->hSession, pTemplate, ulCount, 247 &hNewObject); 248 if (rv == CKR_OK) 249 break; 250 251 if (!try_again(rv)) 252 goto cleanup; 253 254 /* save first rv for other errors */ 255 if (slot_num == 0) 256 first_rv = rv; 257 258 meta_release_slot_session(slot_session); 259 slot_session = NULL; 260 261 } 262 } 263 264 if (rv == CKR_OK) { 265 slot_object->hObject = hNewObject; 266 object->clones[slot_num] = slot_object; 267 object->master_clone_slotnum = slot_num; 268 269 if (object->isToken || object->isFreeToken == FREE_ENABLED) 270 meta_slot_object_activate(slot_object, 271 slot_session, B_TRUE); 272 else 273 meta_slot_object_activate(slot_object, 274 slot_session, B_FALSE); 275 276 slot_object = NULL; 277 meta_release_slot_session(slot_session); 278 slot_session = NULL; 279 280 } else { 281 /* 282 * return either first error code or 283 * CKR_FUNCTION_FAILED depending on the failure 284 */ 285 int i; 286 for (i = 0; i < num_other_rv; i++) { 287 if (rv == other_rv[i]) { 288 rv = CKR_FUNCTION_FAILED; 289 goto cleanup; 290 } 291 } 292 /* need to return first rv */ 293 rv = first_rv; 294 goto cleanup; 295 } 296 297 298 /* 299 * always keep a copy of the template for C_CreateObject, 300 * so clones can be created on other slots if necessary. 301 * This is done even when the CKA_EXTRACTABLE=FALSE flag 302 * is set for the object. The supplied template is 303 * "owned" by metaslot. The application should not be 304 * penalized just because metaslot choose to try creating 305 * the object in a slot that's not capable of performing 306 * any future operation. 307 */ 308 rv = get_master_attributes_by_template(pTemplate, ulCount, 309 &object->attributes, &object->num_attributes); 310 if (rv == CKR_OK) { 311 CK_ULONG i; 312 for (i = 0; i < ulCount; i++) { 313 rv = attribute_set_value(&(pTemplate[i]), 314 object->attributes, object->num_attributes); 315 } 316 } 317 318 meta_object_activate(object); 319 *phObject = (CK_OBJECT_HANDLE) object; 320 321 REFRELEASE(session); 322 323 return (CKR_OK); 324 325 cleanup: 326 if (slot_object) 327 meta_slot_object_dealloc(slot_object); 328 if (slot_session) 329 meta_release_slot_session(slot_session); 330 if (object) 331 (void) meta_object_dealloc(object, B_TRUE); 332 333 REFRELEASE(session); 334 335 return (rv); 336 } 337 338 339 /* 340 * meta_CopyObject 341 * 342 */ 343 CK_RV 344 meta_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 345 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, 346 CK_OBJECT_HANDLE_PTR phNewObject) 347 { 348 CK_RV rv, first_rv; 349 meta_session_t *session; 350 meta_object_t *src_object, *dst_object = NULL; 351 slot_session_t *slot_session = NULL; 352 slot_object_t *dst_slot_object = NULL; 353 CK_ULONG i; 354 slot_object_t *src_slot_object; 355 CK_ULONG slotnum, num_slots; 356 boolean_t found; 357 358 if (pTemplate == NULL && ulCount != 0) 359 return (CKR_ARGUMENTS_BAD); 360 if (phNewObject == NULL) 361 return (CKR_ARGUMENTS_BAD); 362 363 rv = meta_handle2session(hSession, &session); 364 if (rv != CKR_OK) 365 return (rv); 366 367 rv = meta_handle2object(hObject, &src_object); 368 if (rv != CKR_OK) { 369 REFRELEASE(session); 370 return (rv); 371 } 372 373 rv = meta_object_alloc(session, &dst_object); 374 if (rv != CKR_OK) 375 goto finish; 376 377 found = get_template_boolean(CKA_TOKEN, 378 pTemplate, ulCount, &(dst_object->isToken)); 379 if (!found) { 380 dst_object->isToken = src_object->isToken; 381 } 382 383 /* Can't create token objects in a read-only session. */ 384 if ((IS_READ_ONLY_SESSION(session->session_flags)) && 385 (dst_object->isToken)) { 386 rv = CKR_SESSION_READ_ONLY; 387 goto finish; 388 } 389 390 if (dst_object->isToken) { 391 392 /* 393 * if the dst object is a token object, and the source 394 * object is not, the source object needs to be extractable. 395 * Otherwise, the source object needs to reside in the 396 * token object slot 397 */ 398 if ((!src_object->isExtractable) && 399 (src_object->master_clone_slotnum 400 != get_keystore_slotnum())) { 401 rv = CKR_FUNCTION_FAILED; 402 goto finish; 403 } 404 405 /* determine if dst is going to be private object or not */ 406 found = get_template_boolean(CKA_PRIVATE, 407 pTemplate, ulCount, &(dst_object->isPrivate)); 408 if (!found) { 409 /* will be the same as the source object */ 410 dst_object->isPrivate = src_object->isPrivate; 411 } 412 413 slotnum = get_keystore_slotnum(); 414 } else { 415 416 /* try create the obj in the same slot as the source obj */ 417 slotnum = src_object->master_clone_slotnum; 418 } 419 420 rv = meta_slot_object_alloc(&dst_slot_object); 421 if (rv != CKR_OK) 422 goto finish; 423 424 rv = meta_get_slot_session(slotnum, &slot_session, 425 session->session_flags); 426 if (rv != CKR_OK) 427 goto finish; 428 429 rv = meta_object_get_clone(src_object, slotnum, 430 slot_session, &src_slot_object); 431 if (rv != CKR_OK) 432 goto finish; 433 434 dst_object->tried_create_clone[slotnum] = B_TRUE; 435 rv = FUNCLIST(slot_session->fw_st_id)->C_CopyObject( 436 slot_session->hSession, src_slot_object->hObject, pTemplate, 437 ulCount, &(dst_slot_object->hObject)); 438 439 if (rv != CKR_OK) { 440 if (dst_object->isToken) { 441 /* 442 * token obj can only be created in the 443 * token slot. No need to try anywhere else 444 */ 445 goto finish; 446 } 447 if ((!src_object->isExtractable) || 448 ((src_object->isSensitive) && (src_object->isToken) && 449 (!metaslot_auto_key_migrate))) { 450 /* source object isn't clonable in another slot */ 451 goto finish; 452 } 453 454 if (!try_again(rv)) { 455 goto finish; 456 } 457 458 first_rv = rv; 459 460 meta_release_slot_session(slot_session); 461 slot_session = NULL; 462 463 num_slots = meta_slotManager_get_slotcount(); 464 465 /* Try operation on other slots if the object is clonable */ 466 for (slotnum = 0; slotnum < num_slots; slotnum++) { 467 468 if (slotnum == src_object->master_clone_slotnum) { 469 /* already tried, don't need to try again */ 470 continue; 471 } 472 473 rv = meta_get_slot_session(slotnum, &slot_session, 474 session->session_flags); 475 if (rv != CKR_OK) { 476 goto finish; 477 } 478 479 rv = meta_object_get_clone(src_object, slotnum, 480 slot_session, &src_slot_object); 481 if (rv != CKR_OK) 482 goto finish; 483 484 dst_object->tried_create_clone[slotnum] = B_TRUE; 485 486 rv = FUNCLIST(slot_session->fw_st_id)->C_CopyObject( 487 slot_session->hSession, src_slot_object->hObject, 488 pTemplate, ulCount, &dst_slot_object->hObject); 489 490 if (rv == CKR_OK) { 491 break; 492 } 493 494 if (!try_again(rv)) { 495 goto finish; 496 } 497 meta_release_slot_session(slot_session); 498 slot_session = NULL; 499 } 500 } 501 502 if (rv == CKR_OK) { 503 504 rv = meta_object_get_attr(slot_session, 505 dst_slot_object->hObject, dst_object); 506 if (rv != CKR_OK) { 507 goto finish; 508 } 509 510 if (src_object->attributes != NULL) { 511 512 /* Keep a copy of the template for the future */ 513 514 /* 515 * Don't allow attributes to change while 516 * we look at them. 517 */ 518 (void) pthread_rwlock_rdlock( 519 &src_object->attribute_lock); 520 521 rv = get_master_attributes_by_duplication( 522 src_object->attributes, 523 src_object->num_attributes, 524 &dst_object->attributes, 525 &dst_object->num_attributes); 526 527 (void) pthread_rwlock_unlock( 528 &src_object->attribute_lock); 529 530 if (rv != CKR_OK) 531 goto finish; 532 533 for (i = 0; i < ulCount; i++) { 534 rv = attribute_set_value(pTemplate + i, 535 dst_object->attributes, 536 dst_object->num_attributes); 537 538 if (rv != CKR_OK) 539 goto finish; 540 } 541 } 542 543 meta_slot_object_activate(dst_slot_object, 544 slot_session, dst_object->isToken); 545 546 dst_object->clones[slotnum] = dst_slot_object; 547 dst_object->master_clone_slotnum = slotnum; 548 dst_slot_object = NULL; /* for error cleanup */ 549 550 meta_release_slot_session(slot_session); 551 slot_session = NULL; /* for error cleanup */ 552 553 } else { 554 /* 555 * return either first error code or 556 * CKR_FUNCTION_FAILED depending on the failure 557 */ 558 int j; 559 for (j = 0; j < num_other_rv; j++) { 560 if (rv == other_rv[j]) { 561 rv = CKR_FUNCTION_FAILED; 562 goto finish; 563 } 564 } 565 /* need to return first rv */ 566 rv = first_rv; 567 goto finish; 568 } 569 meta_object_activate(dst_object); 570 *phNewObject = (CK_OBJECT_HANDLE) dst_object; 571 572 finish: 573 if (rv != CKR_OK) { 574 if (dst_slot_object) 575 meta_slot_object_dealloc(dst_slot_object); 576 577 if (dst_object) 578 (void) meta_object_dealloc(dst_object, B_TRUE); 579 580 if (slot_session) 581 meta_release_slot_session(slot_session); 582 } 583 584 OBJRELEASE(src_object); 585 REFRELEASE(session); 586 587 return (rv); 588 } 589 590 591 /* 592 * meta_DestroyObject 593 * 594 * This function destroys an object by first removing it from the 595 * list of valid objects for a given session (if session object) or 596 * the global token object list. And then, calling C_DestroyObject 597 * on all the slots on which we have created a clone of this object. 598 */ 599 CK_RV 600 meta_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) 601 { 602 CK_RV rv; 603 meta_session_t *session; 604 meta_object_t *object; 605 606 rv = meta_handle2session(hSession, &session); 607 if (rv != CKR_OK) 608 return (rv); 609 610 rv = meta_handle2object(hObject, &object); 611 if (rv != CKR_OK) { 612 REFRELEASE(session); 613 return (rv); 614 } 615 616 /* Can't delete token objects from a read-only session. */ 617 if ((IS_READ_ONLY_SESSION(session->session_flags)) && object->isToken) { 618 OBJRELEASE(object); 619 REFRELEASE(session); 620 return (CKR_SESSION_READ_ONLY); 621 } 622 623 /* Remove object from list of valid meta_objects */ 624 rv = meta_object_deactivate(object, B_FALSE, B_TRUE); 625 626 /* 627 * Actually call C_DestroyObject on all the slots on which we have 628 * created a clone of this object. 629 */ 630 if (rv == CKR_OK) 631 rv = meta_object_dealloc(object, B_TRUE); 632 633 REFRELEASE(session); 634 635 return (rv); 636 } 637 638 639 /* 640 * meta_GetObjectSize 641 * 642 * NOTES: 643 * 1) Because the "size" is so poorly defined in the spec, we have deemed 644 * it useless and won't support it. This is especially true for the 645 * metaslot, because the mulitple providers it uses may each interpret 646 * the size differently. 647 */ 648 /* ARGSUSED */ 649 CK_RV 650 meta_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 651 CK_ULONG_PTR pulSize) 652 { 653 return (CKR_FUNCTION_NOT_SUPPORTED); 654 } 655 656 657 /* 658 * meta_GetAttributeValue 659 * 660 */ 661 CK_RV 662 meta_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 663 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) 664 { 665 CK_RV rv; 666 meta_session_t *session; 667 meta_object_t *object; 668 CK_ULONG slotnum; 669 slot_session_t *slot_session; 670 671 if (pTemplate == NULL || ulCount < 1) 672 return (CKR_ARGUMENTS_BAD); 673 674 rv = meta_handle2session(hSession, &session); 675 if (rv != CKR_OK) 676 return (rv); 677 678 rv = meta_handle2object(hObject, &object); 679 if (rv != CKR_OK) { 680 REFRELEASE(session); 681 return (rv); 682 } 683 684 slotnum = object->master_clone_slotnum; 685 686 rv = meta_get_slot_session(slotnum, &slot_session, 687 session->session_flags); 688 if (rv == CKR_OK) { 689 rv = FUNCLIST(slot_session->fw_st_id)->C_GetAttributeValue( 690 slot_session->hSession, object->clones[slotnum]->hObject, 691 pTemplate, ulCount); 692 693 meta_release_slot_session(slot_session); 694 } 695 696 OBJRELEASE(object); 697 REFRELEASE(session); 698 699 return (rv); 700 701 } 702 703 704 /* 705 * meta_SetAttributeValue 706 * 707 * Call C_SetAttributeValue on all the clones. If the operation fails on 708 * all clones, return the failure. 709 * 710 * If the operation fails on some clones and not the others, delete all the 711 * clones that have failed the operation. If any of the deleted clone is the 712 * master clone, use one of the remaining clone as the master clone. 713 * 714 * If the operation is successful and the master template already exists, 715 * update the master template with new values. 716 */ 717 CK_RV 718 meta_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 719 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) 720 { 721 CK_RV rv = CKR_OK, save_rv = CKR_OK; 722 meta_session_t *session; 723 meta_object_t *object; 724 CK_ULONG slotnum, num_slots; 725 /* Keep track of which slot's SetAttributeValue failed */ 726 boolean_t *clone_failed_op = NULL; 727 int num_clones = 0, num_clones_failed = 0; 728 slot_session_t *slot_session; 729 slot_object_t *slot_object; 730 boolean_t need_update_master_clone = B_FALSE; 731 732 if (pTemplate == NULL || ulCount < 1) 733 return (CKR_ARGUMENTS_BAD); 734 735 rv = meta_handle2session(hSession, &session); 736 if (rv != CKR_OK) 737 return (rv); 738 739 rv = meta_handle2object(hObject, &object); 740 if (rv != CKR_OK) { 741 REFRELEASE(session); 742 return (rv); 743 } 744 745 if ((IS_READ_ONLY_SESSION(session->session_flags)) && 746 (object->isToken)) { 747 rv = CKR_SESSION_READ_ONLY; 748 goto finish; 749 } 750 751 if ((!object->isExtractable) && (object->attributes == NULL)) { 752 /* 753 * object has no clone, just need to do the operation 754 * in the master clone slot 755 */ 756 slot_session_t *slot_session; 757 slotnum = object->master_clone_slotnum; 758 759 rv = meta_get_slot_session(slotnum, &slot_session, 760 session->session_flags); 761 if (rv == CKR_OK) { 762 rv = FUNCLIST(slot_session->fw_st_id)->\ 763 C_SetAttributeValue(slot_session->hSession, 764 object->clones[slotnum]->hObject, pTemplate, 765 ulCount); 766 767 meta_release_slot_session(slot_session); 768 } 769 goto finish; 770 } 771 772 773 num_slots = meta_slotManager_get_slotcount(); 774 775 /* 776 * object might have clones, need to do operation in all clones 777 * 778 * If the C_SetAttributeValue() call fails in a clone, the 779 * clone that failed the operation can not be deleted right 780 * away. The clone with the failed operation is recorded, and 781 * the deletion will happen in a separate loop. 782 * 783 * This is necessary because if ALL the clones failed 784 * C_SetAttributeVAlue(), then, the app's call to C_SetAttributeValue() 785 * is considered failed, and there shouldn't be any changes to the 786 * object, none of the clones should be deleted. 787 * On the other hand, if C_SetAttributeValue() fails in some clones 788 * and succeeds in other clones, the C_SetAttributeValue() operation 789 * is considered successful, and those clones that failed the 790 * operation is deleted. 791 */ 792 clone_failed_op = calloc(num_slots, sizeof (boolean_t)); 793 if (clone_failed_op == NULL) { 794 rv = CKR_HOST_MEMORY; 795 goto finish; 796 } 797 for (slotnum = 0; slotnum < num_slots; slotnum++) { 798 if (object->clones[slotnum] != NULL) { 799 num_clones++; 800 rv = meta_get_slot_session(slotnum, &slot_session, 801 session->session_flags); 802 if (rv != CKR_OK) { 803 goto finish; 804 } 805 806 rv = FUNCLIST(slot_session->fw_st_id)->\ 807 C_SetAttributeValue(slot_session->hSession, 808 object->clones[slotnum]->hObject, pTemplate, 809 ulCount); 810 811 if (rv != CKR_OK) { 812 num_clones_failed++; 813 clone_failed_op[slotnum] = B_TRUE; 814 if (save_rv == CKR_OK) { 815 save_rv = rv; 816 } 817 } 818 meta_release_slot_session(slot_session); 819 } 820 } 821 822 if (num_clones_failed == num_clones) { 823 /* all operations failed */ 824 rv = save_rv; 825 goto finish; 826 } 827 828 if (num_clones_failed > 0) { 829 /* 830 * C_SetAttributeValue in some of the clones failed. 831 * Find out which ones failed, and delete the clones 832 * in those failed slots 833 */ 834 for (slotnum = 0; slotnum < num_slots; slotnum++) { 835 if (clone_failed_op[slotnum]) { 836 837 slot_object_t *clone = object->clones[slotnum]; 838 839 rv = meta_get_slot_session(slotnum, 840 &slot_session, session->session_flags); 841 if (rv == CKR_OK) { 842 (void) FUNCLIST( 843 slot_session->fw_st_id)-> 844 C_DestroyObject( 845 slot_session->hSession, 846 clone->hObject); 847 848 meta_release_slot_session(slot_session); 849 850 } 851 852 meta_slot_object_deactivate(clone); 853 meta_slot_object_dealloc(clone); 854 object->clones[slotnum] = NULL; 855 856 if (slotnum == object->master_clone_slotnum) { 857 need_update_master_clone = B_TRUE; 858 } 859 } 860 } 861 862 if (need_update_master_clone) { 863 /* make first available clone the master */ 864 for (slotnum = 0; slotnum < num_slots; slotnum++) { 865 if (object->clones[slotnum]) { 866 object->master_clone_slotnum = slotnum; 867 need_update_master_clone = B_FALSE; 868 break; 869 } 870 } 871 872 } 873 if (need_update_master_clone) { 874 /* 875 * something is very wrong, can't continue 876 * it should never be this case. 877 */ 878 rv = CKR_FUNCTION_FAILED; 879 goto finish; 880 } 881 rv = CKR_OK; 882 } 883 884 /* 885 * Update the attribute information we keep in our metaslot object 886 */ 887 slot_object = object->clones[object->master_clone_slotnum]; 888 rv = meta_get_slot_session(object->master_clone_slotnum, 889 &slot_session, session->session_flags); 890 if (rv == CKR_OK) { 891 (void) meta_object_get_attr(slot_session, 892 slot_object->hObject, object); 893 meta_release_slot_session(slot_session); 894 } 895 896 /* if there's a copy of the attributes, keep it up to date */ 897 if (object->attributes != NULL) { 898 899 CK_ULONG i; 900 901 /* Make sure no one else is looking at attributes. */ 902 (void) pthread_rwlock_wrlock(&object->attribute_lock); 903 904 for (i = 0; i < ulCount; i++) { 905 (void) attribute_set_value(pTemplate + i, 906 object->attributes, object->num_attributes); 907 908 } 909 (void) pthread_rwlock_unlock(&object->attribute_lock); 910 } 911 912 finish: 913 if (clone_failed_op) { 914 free(clone_failed_op); 915 } 916 OBJRELEASE(object); 917 REFRELEASE(session); 918 919 return (rv); 920 } 921 922 static boolean_t 923 meta_object_in_list(meta_object_t *obj, meta_object_t **objs_list, int num_objs) 924 { 925 int i; 926 927 for (i = 0; i < num_objs; i++) { 928 if (objs_list[i] == obj) { 929 return (B_TRUE); 930 } 931 } 932 return (B_FALSE); 933 } 934 935 static CK_RV 936 add_to_search_result(meta_object_t *object, find_objs_info_t *info, 937 int *num_results_alloc) 938 { 939 /* 940 * allocate space for storing results if the currently 941 * allocated space is not enough 942 */ 943 if (*num_results_alloc <= info->num_matched_objs) { 944 *num_results_alloc += FIND_OBJ_BUF_SIZE; 945 info->matched_objs = realloc(info->matched_objs, 946 sizeof (meta_object_t *) * (*num_results_alloc)); 947 if (info->matched_objs == NULL) { 948 return (CKR_HOST_MEMORY); 949 } 950 } 951 (info->matched_objs)[(info->num_matched_objs)++] = object; 952 return (CKR_OK); 953 } 954 955 static CK_RV 956 process_find_results(CK_OBJECT_HANDLE *results, CK_ULONG num_results, 957 int *num_results_allocated, find_objs_info_t *info, CK_ULONG slotnum, 958 boolean_t token_only, slot_session_t *slot_session, 959 meta_session_t *session) 960 { 961 CK_ULONG i; 962 meta_object_t *object; 963 CK_RV rv; 964 965 for (i = 0; i < num_results; i++) { 966 967 object = meta_object_find_by_handle(results[i], slotnum, 968 token_only); 969 970 /* 971 * a token object is found from the keystore, 972 * need to create a meta object for it 973 */ 974 if (object == NULL) { 975 slot_object_t *slot_object; 976 977 rv = meta_object_alloc(session, &object); 978 if (rv != CKR_OK) { 979 return (rv); 980 } 981 982 rv = meta_slot_object_alloc(&slot_object); 983 if (rv != CKR_OK) { 984 (void) meta_object_dealloc(object, B_TRUE); 985 return (rv); 986 } 987 988 slot_object->hObject = results[i]; 989 object->master_clone_slotnum = slotnum; 990 object->clones[slotnum] = slot_object; 991 992 /* get in the attributes we keep in meta_object */ 993 994 rv = meta_object_get_attr(slot_session, 995 slot_object->hObject, object); 996 if (rv != CKR_OK) { 997 (void) meta_object_dealloc(object, B_TRUE); 998 return (rv); 999 } 1000 1001 meta_slot_object_activate(slot_object, slot_session, 1002 B_TRUE); 1003 meta_object_activate(object); 1004 slot_object = NULL; 1005 } 1006 1007 if (!meta_object_in_list(object, info->matched_objs, 1008 info->num_matched_objs)) { 1009 rv = add_to_search_result(object, info, 1010 num_results_allocated); 1011 if (rv != CKR_OK) { 1012 return (rv); 1013 } 1014 } 1015 } 1016 return (CKR_OK); 1017 } 1018 1019 static CK_RV 1020 meta_search_for_objects(meta_session_t *session, find_objs_info_t *info, 1021 slot_session_t *slot_session, CK_ATTRIBUTE_PTR pTemplate, 1022 CK_ULONG ulCount, CK_ULONG slotnum, boolean_t token_only, 1023 int *num_results_alloc) 1024 { 1025 CK_ULONG tmp_num_results; 1026 CK_OBJECT_HANDLE tmp_results[FIND_OBJ_BUF_SIZE]; 1027 CK_SESSION_HANDLE hSession = slot_session->hSession; 1028 CK_RV rv; 1029 CK_SLOT_ID fw_st_id = slot_session->fw_st_id; 1030 1031 rv = FUNCLIST(fw_st_id)->C_FindObjectsInit(hSession, 1032 pTemplate, ulCount); 1033 1034 if (rv != CKR_OK) { 1035 return (rv); 1036 } 1037 1038 tmp_num_results = 0; 1039 rv = FUNCLIST(fw_st_id)->C_FindObjects(hSession, tmp_results, 1040 FIND_OBJ_BUF_SIZE, &tmp_num_results); 1041 if (rv != CKR_OK) { 1042 return (rv); 1043 } 1044 1045 rv = process_find_results(tmp_results, tmp_num_results, 1046 num_results_alloc, info, slotnum, token_only, 1047 slot_session, session); 1048 if (rv != CKR_OK) { 1049 return (rv); 1050 } 1051 1052 while (tmp_num_results == FIND_OBJ_BUF_SIZE) { 1053 /* might be more results, need to call C_FindObjects again */ 1054 rv = FUNCLIST(fw_st_id)->C_FindObjects(hSession, tmp_results, 1055 FIND_OBJ_BUF_SIZE, &tmp_num_results); 1056 if (rv != CKR_OK) { 1057 return (rv); 1058 } 1059 1060 rv = process_find_results(tmp_results, tmp_num_results, 1061 num_results_alloc, info, slotnum, token_only, 1062 slot_session, session); 1063 if (rv != CKR_OK) { 1064 return (rv); 1065 } 1066 } 1067 1068 rv = FUNCLIST(fw_st_id)->C_FindObjectsFinal(hSession); 1069 return (rv); 1070 } 1071 1072 1073 /* 1074 * meta_FindObjectsInit 1075 * 1076 * This function actually will do ALL the work of searching for objects 1077 * that match all requirements specified in the template. 1078 * 1079 * Objects that matched the template will be stored in the 1080 * session's data structure. When the subsequent C_FindObjects() 1081 * calls are made, results saved will be returned. 1082 * 1083 */ 1084 CK_RV 1085 meta_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, 1086 CK_ULONG ulCount) 1087 { 1088 CK_RV rv; 1089 meta_session_t *session; 1090 CK_ULONG slot_num = 0; 1091 boolean_t have_token_attr, tokenTrue = B_FALSE; 1092 slot_session_t *slot_find_session = NULL; 1093 int num_results_allocated = 0; 1094 CK_ULONG keystore_slotnum; 1095 1096 rv = meta_handle2session(hSession, &session); 1097 if (rv != CKR_OK) 1098 return (rv); 1099 1100 if ((session->find_objs_info).op_active) { 1101 REFRELEASE(session); 1102 return (CKR_OPERATION_ACTIVE); 1103 } 1104 1105 (session->find_objs_info).op_active = B_TRUE; 1106 1107 REFRELEASE(session); 1108 1109 /* see if the template indicates token object only or not */ 1110 have_token_attr = get_template_boolean(CKA_TOKEN, pTemplate, ulCount, 1111 &tokenTrue); 1112 1113 keystore_slotnum = get_keystore_slotnum(); 1114 1115 if (have_token_attr && tokenTrue) { 1116 1117 1118 /* 1119 * only interested in token objects, just need to search 1120 * token object slot 1121 */ 1122 rv = meta_get_slot_session(keystore_slotnum, 1123 &slot_find_session, session->session_flags); 1124 if (rv != CKR_OK) { 1125 goto finish; 1126 } 1127 rv = meta_search_for_objects(session, 1128 &(session->find_objs_info), slot_find_session, pTemplate, 1129 ulCount, keystore_slotnum, B_TRUE, &num_results_allocated); 1130 if (rv != CKR_OK) { 1131 goto finish; 1132 } 1133 } else { 1134 CK_ULONG num_slots = meta_slotManager_get_slotcount(); 1135 for (slot_num = 0; slot_num < num_slots; slot_num++) { 1136 rv = meta_get_slot_session(slot_num, 1137 &slot_find_session, session->session_flags); 1138 if (rv != CKR_OK) { 1139 goto finish; 1140 } 1141 1142 /* 1143 * if the slot is NOT the token object slot, and 1144 * CKA_TOKEN is not specified, need to specified 1145 * it to be false explicitly. This will prevent 1146 * us from using token objects that doesn't 1147 * belong to the token slot in the case that 1148 * more than one slot supports token objects. 1149 */ 1150 1151 if ((slot_num != keystore_slotnum) && 1152 (!have_token_attr)) { 1153 CK_BBOOL false = FALSE; 1154 CK_ATTRIBUTE_PTR newTemplate; 1155 1156 newTemplate = malloc((ulCount + 1) * 1157 sizeof (CK_ATTRIBUTE)); 1158 if (newTemplate == NULL) { 1159 rv = CKR_HOST_MEMORY; 1160 goto finish; 1161 } 1162 (void) memcpy(newTemplate + 1, pTemplate, 1163 ulCount * sizeof (CK_ATTRIBUTE)); 1164 newTemplate[0].type = CKA_TOKEN; 1165 newTemplate[0].pValue = &false; 1166 newTemplate[0].ulValueLen = sizeof (false); 1167 1168 rv = meta_search_for_objects(session, 1169 &(session->find_objs_info), 1170 slot_find_session, newTemplate, 1171 ulCount+1, slot_num, B_FALSE, 1172 &num_results_allocated); 1173 free(newTemplate); 1174 } else { 1175 rv = meta_search_for_objects(session, 1176 &(session->find_objs_info), 1177 slot_find_session, pTemplate, ulCount, 1178 slot_num, B_FALSE, 1179 &num_results_allocated); 1180 } 1181 1182 if (rv != CKR_OK) { 1183 goto finish; 1184 } 1185 meta_release_slot_session(slot_find_session); 1186 slot_find_session = NULL; 1187 } 1188 } 1189 1190 finish: 1191 if (slot_find_session != NULL) { 1192 meta_release_slot_session(slot_find_session); 1193 } 1194 if (rv != CKR_OK) { 1195 (void) pthread_rwlock_wrlock(&session->session_lock); 1196 if (((session->find_objs_info).matched_objs) != NULL) { 1197 free((session->find_objs_info).matched_objs); 1198 } 1199 bzero(&(session->find_objs_info), sizeof (find_objs_info_t)); 1200 (void) pthread_rwlock_unlock(&(session->session_lock)); 1201 } 1202 1203 return (rv); 1204 } 1205 1206 /* 1207 * meta_FindObjects 1208 * 1209 * This function actually doesn't do any real work in search for the 1210 * matching object. All the work is done in FindObjectsInit(). This 1211 * function will only return the matching objects store in the session's 1212 * "find_objs_info" variable. 1213 * 1214 */ 1215 CK_RV 1216 meta_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, 1217 CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) 1218 { 1219 CK_RV rv; 1220 find_objs_info_t *info; 1221 CK_ULONG num_objs_found = 0; 1222 meta_object_t *obj; 1223 meta_session_t *session; 1224 int i; 1225 1226 rv = meta_handle2session(hSession, &session); 1227 if (rv != CKR_OK) 1228 return (rv); 1229 1230 info = &(session->find_objs_info); 1231 1232 if (!(info->op_active)) { 1233 REFRELEASE(session); 1234 return (CKR_OPERATION_NOT_INITIALIZED); 1235 } 1236 1237 for (i = info->next_result_index; 1238 ((num_objs_found < ulMaxObjectCount) && 1239 (i < info->num_matched_objs)); 1240 i++) { 1241 obj = info->matched_objs[i]; 1242 if (obj != NULL) { 1243 /* sanity check to see if object is still valid */ 1244 (void) pthread_rwlock_rdlock(&obj->object_lock); 1245 if (obj->magic_marker == METASLOT_OBJECT_MAGIC) { 1246 phObject[num_objs_found++] = 1247 (CK_OBJECT_HANDLE)obj; 1248 } 1249 (void) pthread_rwlock_unlock(&obj->object_lock); 1250 } 1251 } 1252 info->next_result_index = i; 1253 *pulObjectCount = num_objs_found; 1254 REFRELEASE(session); 1255 return (rv); 1256 } 1257 1258 1259 /* 1260 * meta_FindObjectsFinal 1261 * 1262 */ 1263 CK_RV 1264 meta_FindObjectsFinal(CK_SESSION_HANDLE hSession) 1265 { 1266 CK_RV rv; 1267 find_objs_info_t *info; 1268 meta_session_t *session; 1269 1270 rv = meta_handle2session(hSession, &session); 1271 if (rv != CKR_OK) 1272 return (rv); 1273 1274 info = &(session->find_objs_info); 1275 1276 if (!info->op_active) { 1277 REFRELEASE(session); 1278 return (CKR_OPERATION_NOT_INITIALIZED); 1279 } 1280 1281 if (info->matched_objs) { 1282 free(info->matched_objs); 1283 } 1284 1285 bzero(info, sizeof (find_objs_info_t)); 1286 REFRELEASE(session); 1287 return (rv); 1288 } 1289