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 /* Can't create token objects in a read-only session. */ 152 if ((IS_READ_ONLY_SESSION(session->session_flags)) && object->isToken) { 153 rv = CKR_SESSION_READ_ONLY; 154 goto cleanup; 155 } 156 157 /* 158 * Set to true (private object) if template has CKA_PRIVATE=true; 159 * otherwise, it is false (public object). 160 */ 161 (void) get_template_boolean(CKA_PRIVATE, pTemplate, ulCount, 162 &(object->isPrivate)); 163 164 /* Assume object is extractable unless template has otherwise */ 165 object->isExtractable = B_TRUE; 166 (void) get_template_boolean(CKA_EXTRACTABLE, pTemplate, ulCount, 167 &(object->isExtractable)); 168 169 /* 170 * Set to true (sensitive object) if template has CKA_SENSITIVE=true; 171 * otherwise, it is false. 172 */ 173 (void) get_template_boolean(CKA_SENSITIVE, pTemplate, ulCount, 174 &(object->isSensitive)); 175 176 /* 177 * Check if this can be a FreeObject. 178 * 179 * For creating objects, this check is mostly for preventing 180 * non-keystore hardware from creating CKA_PRIVATE objects without 181 * logging in. 182 */ 183 184 if (meta_freeobject_check(session, object, NULL, pTemplate, ulCount, 185 NULL)) { 186 /* 187 * Make sure we are logged into the keystore if this is a 188 * private freetoken object. 189 */ 190 if (object->isPrivate && !metaslot_logged_in()) 191 return (CKR_USER_NOT_LOGGED_IN); 192 193 if (!meta_freeobject_set(object, pTemplate, ulCount, B_TRUE)) 194 goto cleanup; 195 } 196 197 198 keystore_slotnum = get_keystore_slotnum(); 199 200 if (object->isToken || object->isFreeToken == FREE_ENABLED) { 201 202 /* 203 * If this is a token object or a FreeToken then create it 204 * on the keystore slot. 205 */ 206 207 slot_num = keystore_slotnum; 208 rv = meta_get_slot_session(slot_num, &slot_session, 209 session->session_flags); 210 if (rv != CKR_OK) 211 goto cleanup; 212 213 object->tried_create_clone[slot_num] = B_TRUE; 214 rv = FUNCLIST(slot_session->fw_st_id)->C_CreateObject( 215 slot_session->hSession, pTemplate, ulCount, &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 if (src_object->isFreeToken == FREE_ENABLED) 382 dst_object->isToken = TRUE; 383 else 384 dst_object->isToken = src_object->isToken; 385 } 386 387 /* Can't create token objects in a read-only session. */ 388 if ((IS_READ_ONLY_SESSION(session->session_flags)) && 389 (dst_object->isToken)) { 390 rv = CKR_SESSION_READ_ONLY; 391 goto finish; 392 } 393 394 if (dst_object->isToken) { 395 396 /* 397 * if the dst object is a token object, and the source 398 * object is not, the source object needs to be extractable. 399 * Otherwise, the source object needs to reside in the 400 * token object slot 401 */ 402 if ((!src_object->isExtractable) && 403 (src_object->master_clone_slotnum 404 != get_keystore_slotnum())) { 405 rv = CKR_FUNCTION_FAILED; 406 goto finish; 407 } 408 409 /* determine if dst is going to be private object or not */ 410 found = get_template_boolean(CKA_PRIVATE, 411 pTemplate, ulCount, &(dst_object->isPrivate)); 412 if (!found) { 413 /* will be the same as the source object */ 414 dst_object->isPrivate = src_object->isPrivate; 415 } 416 417 slotnum = get_keystore_slotnum(); 418 } else { 419 420 /* try create the obj in the same slot as the source obj */ 421 slotnum = src_object->master_clone_slotnum; 422 } 423 424 rv = meta_slot_object_alloc(&dst_slot_object); 425 if (rv != CKR_OK) 426 goto finish; 427 428 rv = meta_get_slot_session(slotnum, &slot_session, 429 session->session_flags); 430 if (rv != CKR_OK) 431 goto finish; 432 433 rv = meta_object_get_clone(src_object, slotnum, 434 slot_session, &src_slot_object); 435 if (rv != CKR_OK) 436 goto finish; 437 438 dst_object->tried_create_clone[slotnum] = B_TRUE; 439 rv = FUNCLIST(slot_session->fw_st_id)->C_CopyObject( 440 slot_session->hSession, src_slot_object->hObject, pTemplate, 441 ulCount, &(dst_slot_object->hObject)); 442 443 if (rv != CKR_OK) { 444 if (dst_object->isToken) { 445 /* 446 * token obj can only be created in the 447 * token slot. No need to try anywhere else 448 */ 449 goto finish; 450 } 451 if ((!src_object->isExtractable) || 452 ((src_object->isSensitive) && (src_object->isToken) && 453 (!metaslot_auto_key_migrate))) { 454 /* source object isn't clonable in another slot */ 455 goto finish; 456 } 457 458 if (!try_again(rv)) { 459 goto finish; 460 } 461 462 first_rv = rv; 463 464 meta_release_slot_session(slot_session); 465 slot_session = NULL; 466 467 num_slots = meta_slotManager_get_slotcount(); 468 469 /* Try operation on other slots if the object is clonable */ 470 for (slotnum = 0; slotnum < num_slots; slotnum++) { 471 472 if (slotnum == src_object->master_clone_slotnum) { 473 /* already tried, don't need to try again */ 474 continue; 475 } 476 477 rv = meta_get_slot_session(slotnum, &slot_session, 478 session->session_flags); 479 if (rv != CKR_OK) { 480 goto finish; 481 } 482 483 rv = meta_object_get_clone(src_object, slotnum, 484 slot_session, &src_slot_object); 485 if (rv != CKR_OK) 486 goto finish; 487 488 dst_object->tried_create_clone[slotnum] = B_TRUE; 489 490 rv = FUNCLIST(slot_session->fw_st_id)->C_CopyObject( 491 slot_session->hSession, src_slot_object->hObject, 492 pTemplate, ulCount, &dst_slot_object->hObject); 493 494 if (rv == CKR_OK) { 495 break; 496 } 497 498 if (!try_again(rv)) { 499 goto finish; 500 } 501 meta_release_slot_session(slot_session); 502 slot_session = NULL; 503 } 504 } 505 506 if (rv == CKR_OK) { 507 508 rv = meta_object_get_attr(slot_session, 509 dst_slot_object->hObject, dst_object); 510 if (rv != CKR_OK) { 511 goto finish; 512 } 513 514 if (src_object->attributes != NULL) { 515 516 /* Keep a copy of the template for the future */ 517 518 /* 519 * Don't allow attributes to change while 520 * we look at them. 521 */ 522 (void) pthread_rwlock_rdlock( 523 &src_object->attribute_lock); 524 525 rv = get_master_attributes_by_duplication( 526 src_object->attributes, 527 src_object->num_attributes, 528 &dst_object->attributes, 529 &dst_object->num_attributes); 530 531 (void) pthread_rwlock_unlock( 532 &src_object->attribute_lock); 533 534 if (rv != CKR_OK) 535 goto finish; 536 537 for (i = 0; i < ulCount; i++) { 538 rv = attribute_set_value(pTemplate + i, 539 dst_object->attributes, 540 dst_object->num_attributes); 541 542 if (rv != CKR_OK) 543 goto finish; 544 } 545 } 546 547 meta_slot_object_activate(dst_slot_object, 548 slot_session, dst_object->isToken); 549 550 dst_object->clones[slotnum] = dst_slot_object; 551 dst_object->master_clone_slotnum = slotnum; 552 dst_slot_object = NULL; /* for error cleanup */ 553 554 meta_release_slot_session(slot_session); 555 slot_session = NULL; /* for error cleanup */ 556 557 } else { 558 /* 559 * return either first error code or 560 * CKR_FUNCTION_FAILED depending on the failure 561 */ 562 int j; 563 for (j = 0; j < num_other_rv; j++) { 564 if (rv == other_rv[j]) { 565 rv = CKR_FUNCTION_FAILED; 566 goto finish; 567 } 568 } 569 /* need to return first rv */ 570 rv = first_rv; 571 goto finish; 572 } 573 meta_object_activate(dst_object); 574 *phNewObject = (CK_OBJECT_HANDLE) dst_object; 575 576 finish: 577 if (rv != CKR_OK) { 578 if (dst_slot_object) 579 meta_slot_object_dealloc(dst_slot_object); 580 581 if (dst_object) 582 (void) meta_object_dealloc(dst_object, B_TRUE); 583 584 if (slot_session) 585 meta_release_slot_session(slot_session); 586 } 587 588 OBJRELEASE(src_object); 589 REFRELEASE(session); 590 591 return (rv); 592 } 593 594 595 /* 596 * meta_DestroyObject 597 * 598 * This function destroys an object by first removing it from the 599 * list of valid objects for a given session (if session object) or 600 * the global token object list. And then, calling C_DestroyObject 601 * on all the slots on which we have created a clone of this object. 602 */ 603 CK_RV 604 meta_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) 605 { 606 CK_RV rv; 607 meta_session_t *session; 608 meta_object_t *object; 609 610 rv = meta_handle2session(hSession, &session); 611 if (rv != CKR_OK) 612 return (rv); 613 614 rv = meta_handle2object(hObject, &object); 615 if (rv != CKR_OK) { 616 REFRELEASE(session); 617 return (rv); 618 } 619 620 /* Can't delete token objects from a read-only session. */ 621 if ((IS_READ_ONLY_SESSION(session->session_flags)) && 622 (object->isToken || object->isFreeToken == FREE_ENABLED)) { 623 OBJRELEASE(object); 624 REFRELEASE(session); 625 return (CKR_SESSION_READ_ONLY); 626 } 627 628 /* Remove object from list of valid meta_objects */ 629 rv = meta_object_deactivate(object, B_FALSE, B_TRUE); 630 631 /* 632 * Actually call C_DestroyObject on all the slots on which we have 633 * created a clone of this object. 634 */ 635 if (rv == CKR_OK) 636 rv = meta_object_dealloc(object, B_TRUE); 637 638 REFRELEASE(session); 639 640 return (rv); 641 } 642 643 644 /* 645 * meta_GetObjectSize 646 * 647 * NOTES: 648 * 1) Because the "size" is so poorly defined in the spec, we have deemed 649 * it useless and won't support it. This is especially true for the 650 * metaslot, because the mulitple providers it uses may each interpret 651 * the size differently. 652 */ 653 /* ARGSUSED */ 654 CK_RV 655 meta_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 656 CK_ULONG_PTR pulSize) 657 { 658 return (CKR_FUNCTION_NOT_SUPPORTED); 659 } 660 661 662 /* 663 * meta_GetAttributeValue 664 * 665 */ 666 CK_RV 667 meta_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 668 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) 669 { 670 CK_RV rv; 671 meta_session_t *session; 672 meta_object_t *object; 673 CK_ULONG slotnum; 674 slot_session_t *slot_session; 675 676 if (pTemplate == NULL || ulCount < 1) 677 return (CKR_ARGUMENTS_BAD); 678 679 rv = meta_handle2session(hSession, &session); 680 if (rv != CKR_OK) 681 return (rv); 682 683 rv = meta_handle2object(hObject, &object); 684 if (rv != CKR_OK) { 685 REFRELEASE(session); 686 return (rv); 687 } 688 689 slotnum = object->master_clone_slotnum; 690 691 rv = meta_get_slot_session(slotnum, &slot_session, 692 session->session_flags); 693 if (rv == CKR_OK) { 694 rv = FUNCLIST(slot_session->fw_st_id)->C_GetAttributeValue( 695 slot_session->hSession, object->clones[slotnum]->hObject, 696 pTemplate, ulCount); 697 698 meta_release_slot_session(slot_session); 699 } 700 701 OBJRELEASE(object); 702 REFRELEASE(session); 703 704 return (rv); 705 706 } 707 708 709 /* 710 * meta_SetAttributeValue 711 * 712 * Call C_SetAttributeValue on all the clones. If the operation fails on 713 * all clones, return the failure. 714 * 715 * If the operation fails on some clones and not the others, delete all the 716 * clones that have failed the operation. If any of the deleted clone is the 717 * master clone, use one of the remaining clone as the master clone. 718 * 719 * If the operation is successful and the master template already exists, 720 * update the master template with new values. 721 */ 722 CK_RV 723 meta_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 724 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) 725 { 726 CK_RV rv = CKR_OK, save_rv = CKR_OK; 727 meta_session_t *session; 728 meta_object_t *object; 729 CK_ULONG slotnum, num_slots; 730 /* Keep track of which slot's SetAttributeValue failed */ 731 boolean_t *clone_failed_op = NULL; 732 int num_clones = 0, num_clones_failed = 0; 733 slot_session_t *slot_session; 734 slot_object_t *slot_object; 735 boolean_t need_update_master_clone = B_FALSE; 736 737 if (pTemplate == NULL || ulCount < 1) 738 return (CKR_ARGUMENTS_BAD); 739 740 rv = meta_handle2session(hSession, &session); 741 if (rv != CKR_OK) 742 return (rv); 743 744 rv = meta_handle2object(hObject, &object); 745 if (rv != CKR_OK) { 746 REFRELEASE(session); 747 return (rv); 748 } 749 750 if ((IS_READ_ONLY_SESSION(session->session_flags)) && 751 (object->isToken || object->isFreeToken == FREE_ENABLED)) { 752 rv = CKR_SESSION_READ_ONLY; 753 goto finish; 754 } 755 756 if ((!object->isExtractable) && (object->attributes == NULL)) { 757 /* 758 * object has no clone, just need to do the operation 759 * in the master clone slot 760 */ 761 slot_session_t *slot_session; 762 slotnum = object->master_clone_slotnum; 763 764 rv = meta_get_slot_session(slotnum, &slot_session, 765 session->session_flags); 766 if (rv == CKR_OK) { 767 rv = FUNCLIST(slot_session->fw_st_id)->\ 768 C_SetAttributeValue(slot_session->hSession, 769 object->clones[slotnum]->hObject, pTemplate, 770 ulCount); 771 772 meta_release_slot_session(slot_session); 773 } 774 goto finish; 775 } 776 777 778 num_slots = meta_slotManager_get_slotcount(); 779 780 /* 781 * object might have clones, need to do operation in all clones 782 * 783 * If the C_SetAttributeValue() call fails in a clone, the 784 * clone that failed the operation can not be deleted right 785 * away. The clone with the failed operation is recorded, and 786 * the deletion will happen in a separate loop. 787 * 788 * This is necessary because if ALL the clones failed 789 * C_SetAttributeVAlue(), then, the app's call to C_SetAttributeValue() 790 * is considered failed, and there shouldn't be any changes to the 791 * object, none of the clones should be deleted. 792 * On the other hand, if C_SetAttributeValue() fails in some clones 793 * and succeeds in other clones, the C_SetAttributeValue() operation 794 * is considered successful, and those clones that failed the 795 * operation is deleted. 796 */ 797 clone_failed_op = calloc(num_slots, sizeof (boolean_t)); 798 if (clone_failed_op == NULL) { 799 rv = CKR_HOST_MEMORY; 800 goto finish; 801 } 802 for (slotnum = 0; slotnum < num_slots; slotnum++) { 803 if (object->clones[slotnum] != NULL) { 804 num_clones++; 805 rv = meta_get_slot_session(slotnum, &slot_session, 806 session->session_flags); 807 if (rv != CKR_OK) { 808 goto finish; 809 } 810 811 rv = FUNCLIST(slot_session->fw_st_id)->\ 812 C_SetAttributeValue(slot_session->hSession, 813 object->clones[slotnum]->hObject, pTemplate, 814 ulCount); 815 816 if (rv != CKR_OK) { 817 num_clones_failed++; 818 clone_failed_op[slotnum] = B_TRUE; 819 if (save_rv == CKR_OK) { 820 save_rv = rv; 821 } 822 } 823 meta_release_slot_session(slot_session); 824 } 825 } 826 827 if (num_clones_failed == num_clones) { 828 /* all operations failed */ 829 rv = save_rv; 830 goto finish; 831 } 832 833 if (num_clones_failed > 0) { 834 /* 835 * C_SetAttributeValue in some of the clones failed. 836 * Find out which ones failed, and delete the clones 837 * in those failed slots 838 */ 839 for (slotnum = 0; slotnum < num_slots; slotnum++) { 840 if (clone_failed_op[slotnum]) { 841 842 slot_object_t *clone = object->clones[slotnum]; 843 844 rv = meta_get_slot_session(slotnum, 845 &slot_session, session->session_flags); 846 if (rv == CKR_OK) { 847 (void) FUNCLIST( 848 slot_session->fw_st_id)-> 849 C_DestroyObject( 850 slot_session->hSession, 851 clone->hObject); 852 853 meta_release_slot_session(slot_session); 854 855 } 856 857 meta_slot_object_deactivate(clone); 858 meta_slot_object_dealloc(clone); 859 object->clones[slotnum] = NULL; 860 861 if (slotnum == object->master_clone_slotnum) { 862 need_update_master_clone = B_TRUE; 863 } 864 } 865 } 866 867 if (need_update_master_clone) { 868 /* make first available clone the master */ 869 for (slotnum = 0; slotnum < num_slots; slotnum++) { 870 if (object->clones[slotnum]) { 871 object->master_clone_slotnum = slotnum; 872 need_update_master_clone = B_FALSE; 873 break; 874 } 875 } 876 877 } 878 if (need_update_master_clone) { 879 /* 880 * something is very wrong, can't continue 881 * it should never be this case. 882 */ 883 rv = CKR_FUNCTION_FAILED; 884 goto finish; 885 } 886 rv = CKR_OK; 887 } 888 889 /* 890 * Update the attribute information we keep in our metaslot object 891 */ 892 slot_object = object->clones[object->master_clone_slotnum]; 893 rv = meta_get_slot_session(object->master_clone_slotnum, 894 &slot_session, session->session_flags); 895 if (rv == CKR_OK) { 896 (void) meta_object_get_attr(slot_session, 897 slot_object->hObject, object); 898 meta_release_slot_session(slot_session); 899 } 900 901 /* if there's a copy of the attributes, keep it up to date */ 902 if (object->attributes != NULL) { 903 904 CK_ULONG i; 905 906 /* Make sure no one else is looking at attributes. */ 907 (void) pthread_rwlock_wrlock(&object->attribute_lock); 908 909 for (i = 0; i < ulCount; i++) { 910 (void) attribute_set_value(pTemplate + i, 911 object->attributes, object->num_attributes); 912 913 } 914 (void) pthread_rwlock_unlock(&object->attribute_lock); 915 } 916 917 finish: 918 if (clone_failed_op) { 919 free(clone_failed_op); 920 } 921 OBJRELEASE(object); 922 REFRELEASE(session); 923 924 return (rv); 925 } 926 927 static boolean_t 928 meta_object_in_list(meta_object_t *obj, meta_object_t **objs_list, int num_objs) 929 { 930 int i; 931 932 for (i = 0; i < num_objs; i++) { 933 if (objs_list[i] == obj) { 934 return (B_TRUE); 935 } 936 } 937 return (B_FALSE); 938 } 939 940 static CK_RV 941 add_to_search_result(meta_object_t *object, find_objs_info_t *info, 942 int *num_results_alloc) 943 { 944 /* 945 * allocate space for storing results if the currently 946 * allocated space is not enough 947 */ 948 if (*num_results_alloc <= info->num_matched_objs) { 949 *num_results_alloc += FIND_OBJ_BUF_SIZE; 950 info->matched_objs = realloc(info->matched_objs, 951 sizeof (meta_object_t *) * (*num_results_alloc)); 952 if (info->matched_objs == NULL) { 953 return (CKR_HOST_MEMORY); 954 } 955 } 956 (info->matched_objs)[(info->num_matched_objs)++] = object; 957 return (CKR_OK); 958 } 959 960 static CK_RV 961 process_find_results(CK_OBJECT_HANDLE *results, CK_ULONG num_results, 962 int *num_results_allocated, find_objs_info_t *info, CK_ULONG slotnum, 963 boolean_t token_only, slot_session_t *slot_session, 964 meta_session_t *session) 965 { 966 CK_ULONG i; 967 meta_object_t *object; 968 CK_RV rv; 969 970 for (i = 0; i < num_results; i++) { 971 972 object = meta_object_find_by_handle(results[i], slotnum, 973 token_only); 974 975 /* 976 * a token object is found from the keystore, 977 * need to create a meta object for it 978 */ 979 if (object == NULL) { 980 slot_object_t *slot_object; 981 982 rv = meta_object_alloc(session, &object); 983 if (rv != CKR_OK) { 984 return (rv); 985 } 986 987 rv = meta_slot_object_alloc(&slot_object); 988 if (rv != CKR_OK) { 989 (void) meta_object_dealloc(object, B_TRUE); 990 return (rv); 991 } 992 993 slot_object->hObject = results[i]; 994 object->master_clone_slotnum = slotnum; 995 object->clones[slotnum] = slot_object; 996 997 /* get in the attributes we keep in meta_object */ 998 999 rv = meta_object_get_attr(slot_session, 1000 slot_object->hObject, object); 1001 if (rv != CKR_OK) { 1002 (void) meta_object_dealloc(object, B_TRUE); 1003 return (rv); 1004 } 1005 1006 meta_slot_object_activate(slot_object, slot_session, 1007 B_TRUE); 1008 meta_object_activate(object); 1009 slot_object = NULL; 1010 } 1011 1012 if (!meta_object_in_list(object, info->matched_objs, 1013 info->num_matched_objs)) { 1014 rv = add_to_search_result(object, info, 1015 num_results_allocated); 1016 if (rv != CKR_OK) { 1017 return (rv); 1018 } 1019 } 1020 } 1021 return (CKR_OK); 1022 } 1023 1024 static CK_RV 1025 meta_search_for_objects(meta_session_t *session, find_objs_info_t *info, 1026 slot_session_t *slot_session, CK_ATTRIBUTE_PTR pTemplate, 1027 CK_ULONG ulCount, CK_ULONG slotnum, boolean_t token_only, 1028 int *num_results_alloc) 1029 { 1030 CK_ULONG tmp_num_results; 1031 CK_OBJECT_HANDLE tmp_results[FIND_OBJ_BUF_SIZE]; 1032 CK_SESSION_HANDLE hSession = slot_session->hSession; 1033 CK_RV rv; 1034 CK_SLOT_ID fw_st_id = slot_session->fw_st_id; 1035 1036 rv = FUNCLIST(fw_st_id)->C_FindObjectsInit(hSession, 1037 pTemplate, ulCount); 1038 1039 if (rv != CKR_OK) { 1040 return (rv); 1041 } 1042 1043 tmp_num_results = 0; 1044 rv = FUNCLIST(fw_st_id)->C_FindObjects(hSession, tmp_results, 1045 FIND_OBJ_BUF_SIZE, &tmp_num_results); 1046 if (rv != CKR_OK) { 1047 return (rv); 1048 } 1049 1050 rv = process_find_results(tmp_results, tmp_num_results, 1051 num_results_alloc, info, slotnum, token_only, 1052 slot_session, session); 1053 if (rv != CKR_OK) { 1054 return (rv); 1055 } 1056 1057 while (tmp_num_results == FIND_OBJ_BUF_SIZE) { 1058 /* might be more results, need to call C_FindObjects again */ 1059 rv = FUNCLIST(fw_st_id)->C_FindObjects(hSession, tmp_results, 1060 FIND_OBJ_BUF_SIZE, &tmp_num_results); 1061 if (rv != CKR_OK) { 1062 return (rv); 1063 } 1064 1065 rv = process_find_results(tmp_results, tmp_num_results, 1066 num_results_alloc, info, slotnum, token_only, 1067 slot_session, session); 1068 if (rv != CKR_OK) { 1069 return (rv); 1070 } 1071 } 1072 1073 rv = FUNCLIST(fw_st_id)->C_FindObjectsFinal(hSession); 1074 return (rv); 1075 } 1076 1077 1078 /* 1079 * meta_FindObjectsInit 1080 * 1081 * This function actually will do ALL the work of searching for objects 1082 * that match all requirements specified in the template. 1083 * 1084 * Objects that matched the template will be stored in the 1085 * session's data structure. When the subsequent C_FindObjects() 1086 * calls are made, results saved will be returned. 1087 * 1088 */ 1089 CK_RV 1090 meta_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, 1091 CK_ULONG ulCount) 1092 { 1093 CK_RV rv; 1094 meta_session_t *session; 1095 CK_ULONG slot_num = 0; 1096 boolean_t have_token_attr, tokenTrue = B_FALSE; 1097 slot_session_t *slot_find_session = NULL; 1098 int num_results_allocated = 0; 1099 CK_ULONG keystore_slotnum; 1100 1101 rv = meta_handle2session(hSession, &session); 1102 if (rv != CKR_OK) 1103 return (rv); 1104 1105 if ((session->find_objs_info).op_active) { 1106 REFRELEASE(session); 1107 return (CKR_OPERATION_ACTIVE); 1108 } 1109 1110 (session->find_objs_info).op_active = B_TRUE; 1111 1112 REFRELEASE(session); 1113 1114 /* see if the template indicates token object only or not */ 1115 have_token_attr = get_template_boolean(CKA_TOKEN, pTemplate, ulCount, 1116 &tokenTrue); 1117 1118 keystore_slotnum = get_keystore_slotnum(); 1119 1120 if (have_token_attr && tokenTrue) { 1121 1122 1123 /* 1124 * only interested in token objects, just need to search 1125 * token object slot 1126 */ 1127 rv = meta_get_slot_session(keystore_slotnum, 1128 &slot_find_session, session->session_flags); 1129 if (rv != CKR_OK) { 1130 goto finish; 1131 } 1132 rv = meta_search_for_objects(session, 1133 &(session->find_objs_info), slot_find_session, pTemplate, 1134 ulCount, keystore_slotnum, B_TRUE, &num_results_allocated); 1135 if (rv != CKR_OK) { 1136 goto finish; 1137 } 1138 } else { 1139 CK_ULONG num_slots = meta_slotManager_get_slotcount(); 1140 for (slot_num = 0; slot_num < num_slots; slot_num++) { 1141 rv = meta_get_slot_session(slot_num, 1142 &slot_find_session, session->session_flags); 1143 if (rv != CKR_OK) { 1144 goto finish; 1145 } 1146 1147 /* 1148 * if the slot is NOT the token object slot, and 1149 * CKA_TOKEN is not specified, need to specified 1150 * it to be false explicitly. This will prevent 1151 * us from using token objects that doesn't 1152 * belong to the token slot in the case that 1153 * more than one slot supports token objects. 1154 */ 1155 1156 if ((slot_num != keystore_slotnum) && 1157 (!have_token_attr)) { 1158 CK_BBOOL false = FALSE; 1159 CK_ATTRIBUTE_PTR newTemplate; 1160 1161 newTemplate = malloc((ulCount + 1) * 1162 sizeof (CK_ATTRIBUTE)); 1163 if (newTemplate == NULL) { 1164 rv = CKR_HOST_MEMORY; 1165 goto finish; 1166 } 1167 (void) memcpy(newTemplate + 1, pTemplate, 1168 ulCount * sizeof (CK_ATTRIBUTE)); 1169 newTemplate[0].type = CKA_TOKEN; 1170 newTemplate[0].pValue = &false; 1171 newTemplate[0].ulValueLen = sizeof (false); 1172 1173 rv = meta_search_for_objects(session, 1174 &(session->find_objs_info), 1175 slot_find_session, newTemplate, 1176 ulCount+1, slot_num, B_FALSE, 1177 &num_results_allocated); 1178 free(newTemplate); 1179 } else { 1180 rv = meta_search_for_objects(session, 1181 &(session->find_objs_info), 1182 slot_find_session, pTemplate, ulCount, 1183 slot_num, B_FALSE, 1184 &num_results_allocated); 1185 } 1186 1187 if (rv != CKR_OK) { 1188 goto finish; 1189 } 1190 meta_release_slot_session(slot_find_session); 1191 slot_find_session = NULL; 1192 } 1193 } 1194 1195 finish: 1196 if (slot_find_session != NULL) { 1197 meta_release_slot_session(slot_find_session); 1198 } 1199 if (rv != CKR_OK) { 1200 (void) pthread_rwlock_wrlock(&session->session_lock); 1201 if (((session->find_objs_info).matched_objs) != NULL) { 1202 free((session->find_objs_info).matched_objs); 1203 } 1204 bzero(&(session->find_objs_info), sizeof (find_objs_info_t)); 1205 (void) pthread_rwlock_unlock(&(session->session_lock)); 1206 } 1207 1208 return (rv); 1209 } 1210 1211 /* 1212 * meta_FindObjects 1213 * 1214 * This function actually doesn't do any real work in search for the 1215 * matching object. All the work is done in FindObjectsInit(). This 1216 * function will only return the matching objects store in the session's 1217 * "find_objs_info" variable. 1218 * 1219 */ 1220 CK_RV 1221 meta_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, 1222 CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) 1223 { 1224 CK_RV rv; 1225 find_objs_info_t *info; 1226 CK_ULONG num_objs_found = 0; 1227 meta_object_t *obj; 1228 meta_session_t *session; 1229 int i; 1230 1231 rv = meta_handle2session(hSession, &session); 1232 if (rv != CKR_OK) 1233 return (rv); 1234 1235 info = &(session->find_objs_info); 1236 1237 if (!(info->op_active)) { 1238 REFRELEASE(session); 1239 return (CKR_OPERATION_NOT_INITIALIZED); 1240 } 1241 1242 for (i = info->next_result_index; 1243 ((num_objs_found < ulMaxObjectCount) && 1244 (i < info->num_matched_objs)); 1245 i++) { 1246 obj = info->matched_objs[i]; 1247 if (obj != NULL) { 1248 /* sanity check to see if object is still valid */ 1249 (void) pthread_rwlock_rdlock(&obj->object_lock); 1250 if (obj->magic_marker == METASLOT_OBJECT_MAGIC) { 1251 phObject[num_objs_found++] = 1252 (CK_OBJECT_HANDLE)obj; 1253 } 1254 (void) pthread_rwlock_unlock(&obj->object_lock); 1255 } 1256 } 1257 info->next_result_index = i; 1258 *pulObjectCount = num_objs_found; 1259 REFRELEASE(session); 1260 return (rv); 1261 } 1262 1263 1264 /* 1265 * meta_FindObjectsFinal 1266 * 1267 */ 1268 CK_RV 1269 meta_FindObjectsFinal(CK_SESSION_HANDLE hSession) 1270 { 1271 CK_RV rv; 1272 find_objs_info_t *info; 1273 meta_session_t *session; 1274 1275 rv = meta_handle2session(hSession, &session); 1276 if (rv != CKR_OK) 1277 return (rv); 1278 1279 info = &(session->find_objs_info); 1280 1281 if (!info->op_active) { 1282 REFRELEASE(session); 1283 return (CKR_OPERATION_NOT_INITIALIZED); 1284 } 1285 1286 if (info->matched_objs) { 1287 free(info->matched_objs); 1288 } 1289 1290 bzero(info, sizeof (find_objs_info_t)); 1291 REFRELEASE(session); 1292 return (rv); 1293 } 1294