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