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