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 #include <pthread.h> 27 #include <stdlib.h> 28 #include <security/cryptoki.h> 29 #include "softGlobal.h" 30 #include "softObject.h" 31 #include "softSession.h" 32 #include "softKeystore.h" 33 #include "softKeystoreUtil.h" 34 35 36 CK_RV 37 C_CreateObject(CK_SESSION_HANDLE hSession, 38 CK_ATTRIBUTE_PTR pTemplate, 39 CK_ULONG ulCount, 40 CK_OBJECT_HANDLE_PTR phObject) 41 { 42 43 CK_RV rv; 44 soft_session_t *session_p; 45 boolean_t lock_held = B_FALSE; 46 47 if (!softtoken_initialized) 48 return (CKR_CRYPTOKI_NOT_INITIALIZED); 49 50 /* 51 * Obtain the session pointer. Also, increment the session 52 * reference count. 53 */ 54 rv = handle2session(hSession, &session_p); 55 if (rv != CKR_OK) 56 return (rv); 57 58 if ((pTemplate == NULL) || (ulCount == 0) || 59 (phObject == NULL)) { 60 rv = CKR_ARGUMENTS_BAD; 61 goto clean_exit; 62 } 63 64 /* Create a new object. */ 65 rv = soft_add_object(pTemplate, ulCount, phObject, session_p); 66 67 clean_exit: 68 /* 69 * Decrement the session reference count. 70 * We do not hold the session lock. 71 */ 72 SES_REFRELE(session_p, lock_held); 73 return (rv); 74 } 75 76 CK_RV 77 C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 78 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, 79 CK_OBJECT_HANDLE_PTR phNewObject) 80 { 81 82 CK_RV rv; 83 soft_session_t *session_p; 84 boolean_t lock_held = B_FALSE; 85 soft_object_t *old_object, *new_object = NULL; 86 ulong_t i; 87 88 if (!softtoken_initialized) 89 return (CKR_CRYPTOKI_NOT_INITIALIZED); 90 91 /* 92 * Obtain the session pointer. Also, increment the session 93 * reference count. 94 */ 95 rv = handle2session(hSession, &session_p); 96 if (rv != CKR_OK) 97 return (rv); 98 99 /* Check arguments */ 100 if (((ulCount > 0) && (pTemplate == NULL)) || 101 (phNewObject == NULL)) { 102 rv = CKR_ARGUMENTS_BAD; 103 goto clean_exit; 104 } 105 106 /* Obtain the object pointer. */ 107 HANDLE2OBJECT(hObject, old_object, rv); 108 if (rv != CKR_OK) { 109 goto clean_exit; 110 } 111 112 /* 113 * Copy the old object to a new object. 114 * The 3rd argument with SOFT_COPY_OBJ value indicates that 115 * everything in the object will be duplicated for C_CopyObject. 116 * The 4th argument has the session pointer that will be 117 * saved in the new copy of the session object. 118 */ 119 (void) pthread_mutex_lock(&old_object->object_mutex); 120 rv = soft_copy_object(old_object, &new_object, SOFT_COPY_OBJECT, 121 session_p); 122 123 if ((rv != CKR_OK) || (new_object == NULL)) { 124 /* Most likely we ran out of space. */ 125 (void) pthread_mutex_unlock(&old_object->object_mutex); 126 goto clean_exit1; 127 } 128 129 /* No need to hold the lock on the old object. */ 130 (void) pthread_mutex_unlock(&old_object->object_mutex); 131 132 /* Modifiy the objects if requested */ 133 for (i = 0; i < ulCount; i++) { 134 /* Set the requested attribute into the new object. */ 135 rv = soft_set_attribute(new_object, &pTemplate[i], B_TRUE); 136 if (rv != CKR_OK) { 137 goto fail; 138 } 139 } 140 141 rv = soft_pin_expired_check(new_object); 142 if (rv != CKR_OK) { 143 goto fail; 144 } 145 146 /* 147 * Does the new object violate the creation rule or access rule? 148 */ 149 rv = soft_object_write_access_check(session_p, new_object); 150 if (rv != CKR_OK) { 151 goto fail; 152 } 153 154 /* 155 * If the new object is a token object, it will be added 156 * to token object list and write to disk. 157 */ 158 if (IS_TOKEN_OBJECT(new_object)) { 159 new_object->version = 1; 160 /* 161 * Write to the keystore file. 162 */ 163 rv = soft_put_object_to_keystore(new_object); 164 if (rv != CKR_OK) { 165 goto fail; 166 } 167 168 new_object->session_handle = (CK_SESSION_HANDLE)NULL; 169 /* 170 * Add the newly created token object to the global 171 * token object list in the slot struct. 172 */ 173 soft_add_token_object_to_slot(new_object); 174 OBJ_REFRELE(old_object); 175 SES_REFRELE(session_p, lock_held); 176 *phNewObject = (CK_ULONG)new_object; 177 178 return (CKR_OK); 179 } 180 181 /* Insert new object into this session's object list */ 182 soft_add_object_to_session(new_object, session_p); 183 184 /* 185 * Decrement the session reference count. 186 * We do not hold the session lock. 187 */ 188 OBJ_REFRELE(old_object); 189 SES_REFRELE(session_p, lock_held); 190 191 /* set handle of the new object */ 192 *phNewObject = (CK_ULONG)new_object; 193 194 return (rv); 195 196 fail: 197 soft_cleanup_object(new_object); 198 free(new_object); 199 200 clean_exit1: 201 OBJ_REFRELE(old_object); 202 clean_exit: 203 SES_REFRELE(session_p, lock_held); 204 return (rv); 205 } 206 207 CK_RV 208 C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) 209 { 210 211 CK_RV rv; 212 soft_object_t *object_p; 213 soft_session_t *session_p = (soft_session_t *)(hSession); 214 boolean_t lock_held = B_FALSE; 215 CK_SESSION_HANDLE creating_session; 216 217 218 if (!softtoken_initialized) 219 return (CKR_CRYPTOKI_NOT_INITIALIZED); 220 221 /* 222 * The reason that we don't call handle2session is because 223 * the argument hSession may not be the creating_session of 224 * the object to be destroyed, and we want to avoid the lock 225 * contention. The handle2session will be called later for 226 * the creating_session. 227 */ 228 if ((session_p == NULL) || 229 (session_p->magic_marker != SOFTTOKEN_SESSION_MAGIC)) { 230 return (CKR_SESSION_HANDLE_INVALID); 231 } 232 233 /* Obtain the object pointer. */ 234 HANDLE2OBJECT_DESTROY(hObject, object_p, rv); 235 if (rv != CKR_OK) { 236 return (rv); 237 } 238 239 /* Obtain the session handle which object belongs to. */ 240 creating_session = object_p->session_handle; 241 242 if (creating_session == NULL) { 243 /* 244 * This is a token object to be deleted. 245 * For token object, there is no creating session concept, 246 * therefore, creating_session is always NULL. 247 */ 248 rv = soft_pin_expired_check(object_p); 249 if (rv != CKR_OK) { 250 return (rv); 251 } 252 253 /* Obtain the session pointer just for validity check. */ 254 rv = handle2session(hSession, &session_p); 255 if (rv != CKR_OK) { 256 return (rv); 257 } 258 259 rv = soft_object_write_access_check(session_p, object_p); 260 if (rv != CKR_OK) { 261 SES_REFRELE(session_p, lock_held); 262 return (rv); 263 } 264 265 /* 266 * Set OBJECT_IS_DELETING flag so any access to this 267 * object will be rejected. 268 */ 269 (void) pthread_mutex_lock(&object_p->object_mutex); 270 if (object_p->obj_delete_sync & OBJECT_IS_DELETING) { 271 (void) pthread_mutex_unlock(&object_p->object_mutex); 272 SES_REFRELE(session_p, lock_held); 273 return (CKR_OBJECT_HANDLE_INVALID); 274 } 275 object_p->obj_delete_sync |= OBJECT_IS_DELETING; 276 (void) pthread_mutex_unlock(&object_p->object_mutex); 277 SES_REFRELE(session_p, lock_held); 278 279 /* 280 * Delete a token object by calling soft_delete_token_object() 281 * with the second argument B_TRUE indicating to delete the 282 * object from keystore and the third argument B_FALSE 283 * indicating that the caller does not hold the slot mutex. 284 */ 285 soft_delete_token_object(object_p, B_TRUE, B_FALSE); 286 return (CKR_OK); 287 } 288 289 /* 290 * Obtain the session pointer. Also, increment the session 291 * reference count. 292 */ 293 rv = handle2session(creating_session, &session_p); 294 if (rv != CKR_OK) { 295 return (rv); 296 } 297 298 /* 299 * Set OBJECT_IS_DELETING flag so any access to this 300 * object will be rejected. 301 */ 302 (void) pthread_mutex_lock(&object_p->object_mutex); 303 if (object_p->obj_delete_sync & OBJECT_IS_DELETING) { 304 (void) pthread_mutex_unlock(&object_p->object_mutex); 305 SES_REFRELE(session_p, lock_held); 306 return (CKR_OBJECT_HANDLE_INVALID); 307 } 308 object_p->obj_delete_sync |= OBJECT_IS_DELETING; 309 (void) pthread_mutex_unlock(&object_p->object_mutex); 310 311 /* 312 * Delete an object by calling soft_delete_object() 313 * with a FALSE boolean argument indicating that 314 * the caller does not hold the session lock. 315 */ 316 soft_delete_object(session_p, object_p, B_FALSE, B_FALSE); 317 318 /* 319 * Decrement the session reference count. 320 * We do not hold the session lock. 321 */ 322 SES_REFRELE(session_p, lock_held); 323 324 return (rv); 325 } 326 327 328 CK_RV 329 C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 330 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) 331 { 332 333 CK_RV rv = CKR_OK, rv1 = CKR_OK; 334 soft_object_t *object_p; 335 soft_session_t *session_p; 336 boolean_t lock_held = B_FALSE; 337 ulong_t i; 338 339 if (!softtoken_initialized) 340 return (CKR_CRYPTOKI_NOT_INITIALIZED); 341 342 /* 343 * Obtain the session pointer. Also, increment the session 344 * reference count. 345 */ 346 rv = handle2session(hSession, &session_p); 347 if (rv != CKR_OK) 348 return (rv); 349 350 if ((pTemplate == NULL) || (ulCount == 0)) { 351 /* 352 * Decrement the session reference count. 353 * We do not hold the session lock. 354 */ 355 SES_REFRELE(session_p, lock_held); 356 return (CKR_ARGUMENTS_BAD); 357 } 358 359 /* Obtain the object pointer. */ 360 HANDLE2OBJECT(hObject, object_p, rv); 361 if (rv != CKR_OK) { 362 /* 363 * Decrement the session reference count. 364 * We do not hold the session lock. 365 */ 366 SES_REFRELE(session_p, lock_held); 367 return (rv); 368 } 369 370 if (IS_TOKEN_OBJECT(object_p)) { 371 372 rv = soft_keystore_load_latest_object(object_p); 373 if (rv != CKR_OK) { 374 OBJ_REFRELE(object_p); 375 SES_REFRELE(session_p, lock_held); 376 return (rv); 377 } 378 } 379 380 /* Acquire the lock on the object. */ 381 (void) pthread_mutex_lock(&object_p->object_mutex); 382 383 for (i = 0; i < ulCount; i++) { 384 /* 385 * Get the value of each attribute in the template. 386 * (We must process EVERY attribute in the template.) 387 */ 388 rv = soft_get_attribute(object_p, &pTemplate[i]); 389 if (rv != CKR_OK) 390 /* At least we catch some type of error. */ 391 rv1 = rv; 392 } 393 394 /* Release the object lock */ 395 (void) pthread_mutex_unlock(&object_p->object_mutex); 396 397 /* 398 * Decrement the session reference count. 399 * We do not hold the session lock. 400 */ 401 OBJ_REFRELE(object_p); 402 SES_REFRELE(session_p, lock_held); 403 404 rv = rv1; 405 return (rv); 406 } 407 408 409 CK_RV 410 C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 411 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) 412 { 413 CK_RV rv = CKR_OK; 414 soft_object_t *object_p; 415 soft_object_t *new_object = NULL; 416 soft_session_t *session_p; 417 boolean_t lock_held = B_FALSE; 418 ulong_t i; 419 420 if (!softtoken_initialized) 421 return (CKR_CRYPTOKI_NOT_INITIALIZED); 422 423 /* 424 * Obtain the session pointer. Also, increment the session 425 * reference count. 426 */ 427 rv = handle2session(hSession, &session_p); 428 if (rv != CKR_OK) 429 return (rv); 430 431 if ((pTemplate == NULL) || (ulCount == 0)) { 432 /* 433 * Decrement the session reference count. 434 * We do not hold the session lock. 435 */ 436 SES_REFRELE(session_p, lock_held); 437 return (CKR_ARGUMENTS_BAD); 438 } 439 440 /* Obtain the object pointer. */ 441 HANDLE2OBJECT(hObject, object_p, rv); 442 if (rv != CKR_OK) { 443 /* 444 * Decrement the session reference count. 445 * We do not hold the session lock. 446 */ 447 SES_REFRELE(session_p, lock_held); 448 return (rv); 449 } 450 451 if (object_p->bool_attr_mask & NOT_MODIFIABLE_BOOL_ON) { 452 rv = CKR_ATTRIBUTE_READ_ONLY; 453 goto fail_1; 454 } 455 456 /* 457 * Start working on the object, so we need to set the write lock so that 458 * no one can write to it but still can read it. 459 */ 460 if (IS_TOKEN_OBJECT(object_p)) { 461 rv = soft_keystore_load_latest_object(object_p); 462 if (rv != CKR_OK) { 463 goto fail_1; 464 } 465 } 466 467 /* 468 * Copy the old object to a new object. We work on the copied 469 * version because in case of error we still keep the old one 470 * intact. 471 * The 3rd argument with SOFT_SET_ATTR_VALUE value indicates that 472 * not everything will be duplicated for C_SetAttributeValue. 473 * Information not duplicated are those attributes that are not 474 * modifiable. 475 */ 476 (void) pthread_mutex_lock(&object_p->object_mutex); 477 rv = soft_copy_object(object_p, &new_object, SOFT_SET_ATTR_VALUE, NULL); 478 479 if ((rv != CKR_OK) || (new_object == NULL)) { 480 /* Most likely we ran out of space. */ 481 (void) pthread_mutex_unlock(&object_p->object_mutex); 482 /* 483 * Decrement the session reference count. 484 * We do not hold the session lock. 485 */ 486 goto fail_1; 487 } 488 489 /* 490 * No need to hold the lock on the old object, because we 491 * will be working on the new scratch object. 492 */ 493 (void) pthread_mutex_unlock(&object_p->object_mutex); 494 495 rv = soft_object_write_access_check(session_p, new_object); 496 if (rv != CKR_OK) { 497 goto fail; 498 } 499 500 for (i = 0; i < ulCount; i++) { 501 /* Set the requested attribute into the new object. */ 502 rv = soft_set_attribute(new_object, &pTemplate[i], B_FALSE); 503 504 if (rv != CKR_OK) { 505 goto fail; 506 } 507 } 508 509 /* 510 * We've successfully set all the requested attributes. 511 * Merge the new object with the old object, then destory 512 * the new one. The reason to do the merging is because we 513 * have to keep the original object handle (address of object). 514 */ 515 (void) pthread_mutex_lock(&object_p->object_mutex); 516 517 soft_merge_object(object_p, new_object); 518 519 /* 520 * The object has been modified, so we write it back to keystore. 521 */ 522 if (IS_TOKEN_OBJECT(object_p)) { 523 object_p->version++; 524 rv = soft_modify_object_to_keystore(object_p); 525 } 526 527 (void) pthread_mutex_unlock(&object_p->object_mutex); 528 free(new_object); 529 530 /* 531 * Decrement the session reference count. 532 * We do not hold the session lock. 533 */ 534 OBJ_REFRELE(object_p); 535 SES_REFRELE(session_p, lock_held); 536 return (rv); 537 538 fail: 539 soft_cleanup_object(new_object); 540 free(new_object); 541 542 fail_1: 543 OBJ_REFRELE(object_p); 544 SES_REFRELE(session_p, lock_held); 545 546 return (rv); 547 } 548 549 /*ARGSUSED*/ 550 CK_RV 551 C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 552 CK_ULONG_PTR pulSize) 553 { 554 if (!softtoken_initialized) 555 return (CKR_CRYPTOKI_NOT_INITIALIZED); 556 557 return (CKR_FUNCTION_NOT_SUPPORTED); 558 } 559 560 CK_RV 561 C_FindObjectsInit(CK_SESSION_HANDLE sh, CK_ATTRIBUTE_PTR pTemplate, 562 CK_ULONG ulCount) 563 { 564 565 CK_RV rv; 566 soft_session_t *session_p; 567 boolean_t lock_held = B_TRUE; 568 569 if (!softtoken_initialized) 570 return (CKR_CRYPTOKI_NOT_INITIALIZED); 571 572 /* 573 * Obtain the session pointer. Also, increment the session 574 * reference count. 575 */ 576 rv = handle2session(sh, &session_p); 577 if (rv != CKR_OK) 578 return (rv); 579 580 /* Check the arguments */ 581 if ((ulCount > 0) && (pTemplate == NULL)) { 582 /* decrement the session count, we do not hold the lock */ 583 lock_held = B_FALSE; 584 SES_REFRELE(session_p, lock_held); 585 return (CKR_ARGUMENTS_BAD); 586 } 587 588 /* Acquire the session lock */ 589 (void) pthread_mutex_lock(&session_p->session_mutex); 590 591 /* Check to see if find operation is already active */ 592 if (session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE) { 593 /* decrement the session count, and unlock the mutex */ 594 SES_REFRELE(session_p, lock_held); 595 return (CKR_OPERATION_ACTIVE); 596 } else { 597 /* 598 * This active flag will remain ON until application calls 599 * C_FindObjectsFinal. 600 */ 601 session_p->find_objects.flags = CRYPTO_OPERATION_ACTIVE; 602 } 603 604 (void) pthread_mutex_unlock(&session_p->session_mutex); 605 606 rv = soft_find_objects_init(session_p, pTemplate, ulCount); 607 608 if (rv != CKR_OK) { 609 (void) pthread_mutex_lock(&session_p->session_mutex); 610 session_p->find_objects.flags = 0; 611 (void) pthread_mutex_unlock(&session_p->session_mutex); 612 } 613 614 /* decrement the session count, and unlock the mutex */ 615 lock_held = B_FALSE; 616 SES_REFRELE(session_p, lock_held); 617 return (rv); 618 } 619 620 CK_RV 621 C_FindObjects(CK_SESSION_HANDLE sh, 622 CK_OBJECT_HANDLE_PTR phObject, 623 CK_ULONG ulMaxObjectCount, 624 CK_ULONG_PTR pulObjectCount) 625 { 626 soft_session_t *session_p; 627 CK_RV rv = CKR_OK; 628 boolean_t lock_held = B_TRUE; 629 630 if (!softtoken_initialized) 631 return (CKR_CRYPTOKI_NOT_INITIALIZED); 632 633 /* 634 * Obtain the session pointer. Also, increment the session 635 * reference count. 636 */ 637 rv = handle2session(sh, &session_p); 638 if (rv != CKR_OK) 639 return (rv); 640 641 /* check for invalid arguments */ 642 if (((phObject == NULL) && (ulMaxObjectCount != 0)) || 643 (pulObjectCount == NULL)) { 644 /* decrement the session count, we do not hold the lock */ 645 lock_held = B_FALSE; 646 SES_REFRELE(session_p, lock_held); 647 return (CKR_ARGUMENTS_BAD); 648 } 649 650 if (ulMaxObjectCount == 0) { 651 /* don't need to do anything, just return */ 652 *pulObjectCount = 0; 653 /* decrement the session count, we do not hold the lock */ 654 lock_held = B_FALSE; 655 SES_REFRELE(session_p, lock_held); 656 return (CKR_OK); 657 } 658 659 /* Acquire the session lock */ 660 (void) pthread_mutex_lock(&session_p->session_mutex); 661 662 /* Check to see if find operation is active */ 663 if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) { 664 SES_REFRELE(session_p, lock_held); 665 return (CKR_OPERATION_NOT_INITIALIZED); 666 } 667 668 soft_find_objects(session_p, phObject, ulMaxObjectCount, 669 pulObjectCount); 670 671 /* decrement the session count, and release the lock */ 672 SES_REFRELE(session_p, lock_held); 673 return (rv); 674 } 675 676 CK_RV 677 C_FindObjectsFinal(CK_SESSION_HANDLE sh) 678 { 679 soft_session_t *session_p; 680 CK_RV rv; 681 boolean_t lock_held = B_TRUE; 682 683 if (!softtoken_initialized) 684 return (CKR_CRYPTOKI_NOT_INITIALIZED); 685 686 /* 687 * Obtain the session pointer. Also, increment the session 688 * reference count. 689 */ 690 rv = handle2session(sh, &session_p); 691 if (rv != CKR_OK) 692 return (rv); 693 694 /* Acquire the session lock */ 695 (void) pthread_mutex_lock(&session_p->session_mutex); 696 697 /* Check to see if find operation is active */ 698 if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) { 699 SES_REFRELE(session_p, lock_held); 700 return (CKR_OPERATION_NOT_INITIALIZED); 701 } 702 703 soft_find_objects_final(session_p); 704 705 /* decrement the session count, and release the lock */ 706 SES_REFRELE(session_p, lock_held); 707 return (rv); 708 } 709