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 2004 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 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 277 /* 278 * Delete a token object by calling soft_delete_token_object() 279 * with the second argument B_TRUE indicating to delete the 280 * object from keystore and the third argument B_FALSE 281 * indicating that the caller does not hold the slot mutex. 282 */ 283 soft_delete_token_object(object_p, B_TRUE, B_FALSE); 284 return (CKR_OK); 285 } 286 287 /* 288 * Obtain the session pointer. Also, increment the session 289 * reference count. 290 */ 291 rv = handle2session(creating_session, &session_p); 292 if (rv != CKR_OK) { 293 return (rv); 294 } 295 296 /* 297 * Set OBJECT_IS_DELETING flag so any access to this 298 * object will be rejected. 299 */ 300 (void) pthread_mutex_lock(&object_p->object_mutex); 301 object_p->obj_delete_sync |= OBJECT_IS_DELETING; 302 (void) pthread_mutex_unlock(&object_p->object_mutex); 303 304 /* 305 * Delete an object by calling soft_delete_object() 306 * with a FALSE boolean argument indicating that 307 * the caller does not hold the session lock. 308 */ 309 soft_delete_object(session_p, object_p, B_FALSE); 310 311 /* 312 * Decrement the session reference count. 313 * We do not hold the session lock. 314 */ 315 SES_REFRELE(session_p, lock_held); 316 317 return (rv); 318 } 319 320 321 CK_RV 322 C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 323 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) 324 { 325 326 CK_RV rv = CKR_OK, rv1 = CKR_OK; 327 soft_object_t *object_p; 328 soft_session_t *session_p; 329 boolean_t lock_held = B_FALSE; 330 ulong_t i; 331 332 if (!softtoken_initialized) 333 return (CKR_CRYPTOKI_NOT_INITIALIZED); 334 335 /* 336 * Obtain the session pointer. Also, increment the session 337 * reference count. 338 */ 339 rv = handle2session(hSession, &session_p); 340 if (rv != CKR_OK) 341 return (rv); 342 343 if ((pTemplate == NULL) || (ulCount == 0)) { 344 /* 345 * Decrement the session reference count. 346 * We do not hold the session lock. 347 */ 348 SES_REFRELE(session_p, lock_held); 349 return (CKR_ARGUMENTS_BAD); 350 } 351 352 /* Obtain the object pointer. */ 353 HANDLE2OBJECT(hObject, object_p, rv); 354 if (rv != CKR_OK) { 355 /* 356 * Decrement the session reference count. 357 * We do not hold the session lock. 358 */ 359 SES_REFRELE(session_p, lock_held); 360 return (rv); 361 } 362 363 if (IS_TOKEN_OBJECT(object_p)) { 364 365 rv = soft_keystore_load_latest_object(object_p); 366 if (rv != CKR_OK) { 367 OBJ_REFRELE(object_p); 368 SES_REFRELE(session_p, lock_held); 369 return (rv); 370 } 371 } 372 373 /* Acquire the lock on the object. */ 374 (void) pthread_mutex_lock(&object_p->object_mutex); 375 376 for (i = 0; i < ulCount; i++) { 377 /* 378 * Get the value of each attribute in the template. 379 * (We must process EVERY attribute in the template.) 380 */ 381 rv = soft_get_attribute(object_p, &pTemplate[i]); 382 if (rv != CKR_OK) 383 /* At least we catch some type of error. */ 384 rv1 = rv; 385 } 386 387 /* Release the object lock */ 388 (void) pthread_mutex_unlock(&object_p->object_mutex); 389 390 /* 391 * Decrement the session reference count. 392 * We do not hold the session lock. 393 */ 394 OBJ_REFRELE(object_p); 395 SES_REFRELE(session_p, lock_held); 396 397 rv = rv1; 398 return (rv); 399 } 400 401 402 CK_RV 403 C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 404 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) 405 { 406 CK_RV rv = CKR_OK; 407 soft_object_t *object_p; 408 soft_object_t *new_object = NULL; 409 soft_session_t *session_p; 410 boolean_t lock_held = B_FALSE; 411 ulong_t i; 412 413 if (!softtoken_initialized) 414 return (CKR_CRYPTOKI_NOT_INITIALIZED); 415 416 /* 417 * Obtain the session pointer. Also, increment the session 418 * reference count. 419 */ 420 rv = handle2session(hSession, &session_p); 421 if (rv != CKR_OK) 422 return (rv); 423 424 if ((pTemplate == NULL) || (ulCount == 0)) { 425 /* 426 * Decrement the session reference count. 427 * We do not hold the session lock. 428 */ 429 SES_REFRELE(session_p, lock_held); 430 return (CKR_ARGUMENTS_BAD); 431 } 432 433 /* Obtain the object pointer. */ 434 HANDLE2OBJECT(hObject, object_p, rv); 435 if (rv != CKR_OK) { 436 /* 437 * Decrement the session reference count. 438 * We do not hold the session lock. 439 */ 440 SES_REFRELE(session_p, lock_held); 441 return (rv); 442 } 443 444 if (object_p->bool_attr_mask & NOT_MODIFIABLE_BOOL_ON) { 445 rv = CKR_ATTRIBUTE_READ_ONLY; 446 goto fail_1; 447 } 448 449 /* 450 * Start working on the object, so we need to set the write lock so that 451 * no one can write to it but still can read it. 452 */ 453 if (IS_TOKEN_OBJECT(object_p)) { 454 rv = soft_keystore_load_latest_object(object_p); 455 if (rv != CKR_OK) { 456 goto fail_1; 457 } 458 } 459 460 /* 461 * Copy the old object to a new object. We work on the copied 462 * version because in case of error we still keep the old one 463 * intact. 464 * The 3rd argument with SOFT_SET_ATTR_VALUE value indicates that 465 * not everything will be duplicated for C_SetAttributeValue. 466 * Information not duplicated are those attributes that are not 467 * modifiable. 468 */ 469 (void) pthread_mutex_lock(&object_p->object_mutex); 470 rv = soft_copy_object(object_p, &new_object, SOFT_SET_ATTR_VALUE, NULL); 471 472 if ((rv != CKR_OK) || (new_object == NULL)) { 473 /* Most likely we ran out of space. */ 474 (void) pthread_mutex_unlock(&object_p->object_mutex); 475 /* 476 * Decrement the session reference count. 477 * We do not hold the session lock. 478 */ 479 goto fail_1; 480 } 481 482 /* 483 * No need to hold the lock on the old object, because we 484 * will be working on the new scratch object. 485 */ 486 (void) pthread_mutex_unlock(&object_p->object_mutex); 487 488 rv = soft_object_write_access_check(session_p, new_object); 489 if (rv != CKR_OK) { 490 goto fail; 491 } 492 493 for (i = 0; i < ulCount; i++) { 494 /* Set the requested attribute into the new object. */ 495 rv = soft_set_attribute(new_object, &pTemplate[i], B_FALSE); 496 497 if (rv != CKR_OK) { 498 goto fail; 499 } 500 } 501 502 /* 503 * We've successfully set all the requested attributes. 504 * Merge the new object with the old object, then destory 505 * the new one. The reason to do the merging is because we 506 * have to keep the original object handle (address of object). 507 */ 508 (void) pthread_mutex_lock(&object_p->object_mutex); 509 510 soft_merge_object(object_p, new_object); 511 512 /* 513 * The object has been modified, so we write it back to keystore. 514 */ 515 if (IS_TOKEN_OBJECT(object_p)) { 516 object_p->version++; 517 rv = soft_modify_object_to_keystore(object_p); 518 } 519 520 (void) pthread_mutex_unlock(&object_p->object_mutex); 521 free(new_object); 522 523 /* 524 * Decrement the session reference count. 525 * We do not hold the session lock. 526 */ 527 OBJ_REFRELE(object_p); 528 SES_REFRELE(session_p, lock_held); 529 return (rv); 530 531 fail: 532 soft_cleanup_object(new_object); 533 free(new_object); 534 535 fail_1: 536 OBJ_REFRELE(object_p); 537 SES_REFRELE(session_p, lock_held); 538 539 return (rv); 540 } 541 542 /*ARGSUSED*/ 543 CK_RV 544 C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, 545 CK_ULONG_PTR pulSize) 546 { 547 if (!softtoken_initialized) 548 return (CKR_CRYPTOKI_NOT_INITIALIZED); 549 550 return (CKR_FUNCTION_NOT_SUPPORTED); 551 } 552 553 CK_RV 554 C_FindObjectsInit(CK_SESSION_HANDLE sh, CK_ATTRIBUTE_PTR pTemplate, 555 CK_ULONG ulCount) 556 { 557 558 CK_RV rv; 559 soft_session_t *session_p; 560 boolean_t lock_held = B_TRUE; 561 562 if (!softtoken_initialized) 563 return (CKR_CRYPTOKI_NOT_INITIALIZED); 564 565 /* 566 * Obtain the session pointer. Also, increment the session 567 * reference count. 568 */ 569 rv = handle2session(sh, &session_p); 570 if (rv != CKR_OK) 571 return (rv); 572 573 /* Check the arguments */ 574 if ((ulCount > 0) && (pTemplate == NULL)) { 575 /* decrement the session count, we do not hold the lock */ 576 lock_held = B_FALSE; 577 SES_REFRELE(session_p, lock_held); 578 return (CKR_ARGUMENTS_BAD); 579 } 580 581 /* Acquire the session lock */ 582 (void) pthread_mutex_lock(&session_p->session_mutex); 583 584 /* Check to see if find operation is already active */ 585 if (session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE) { 586 /* decrement the session count, and unlock the mutex */ 587 SES_REFRELE(session_p, lock_held); 588 return (CKR_OPERATION_ACTIVE); 589 } else { 590 /* 591 * This active flag will remain ON until application calls 592 * C_FindObjectsFinal. 593 */ 594 session_p->find_objects.flags = CRYPTO_OPERATION_ACTIVE; 595 } 596 597 (void) pthread_mutex_unlock(&session_p->session_mutex); 598 599 rv = soft_find_objects_init(session_p, pTemplate, ulCount); 600 601 if (rv != CKR_OK) { 602 (void) pthread_mutex_lock(&session_p->session_mutex); 603 session_p->find_objects.flags = 0; 604 (void) pthread_mutex_unlock(&session_p->session_mutex); 605 } 606 607 /* decrement the session count, and unlock the mutex */ 608 lock_held = B_FALSE; 609 SES_REFRELE(session_p, lock_held); 610 return (rv); 611 } 612 613 CK_RV 614 C_FindObjects(CK_SESSION_HANDLE sh, 615 CK_OBJECT_HANDLE_PTR phObject, 616 CK_ULONG ulMaxObjectCount, 617 CK_ULONG_PTR pulObjectCount) 618 { 619 soft_session_t *session_p; 620 CK_RV rv = CKR_OK; 621 boolean_t lock_held = B_TRUE; 622 623 if (!softtoken_initialized) 624 return (CKR_CRYPTOKI_NOT_INITIALIZED); 625 626 /* 627 * Obtain the session pointer. Also, increment the session 628 * reference count. 629 */ 630 rv = handle2session(sh, &session_p); 631 if (rv != CKR_OK) 632 return (rv); 633 634 /* check for invalid arguments */ 635 if (((phObject == NULL) && (ulMaxObjectCount != 0)) || 636 (pulObjectCount == NULL)) { 637 /* decrement the session count, we do not hold the lock */ 638 lock_held = B_FALSE; 639 SES_REFRELE(session_p, lock_held); 640 return (CKR_ARGUMENTS_BAD); 641 } 642 643 if (ulMaxObjectCount == 0) { 644 /* don't need to do anything, just return */ 645 *pulObjectCount = 0; 646 /* decrement the session count, we do not hold the lock */ 647 lock_held = B_FALSE; 648 SES_REFRELE(session_p, lock_held); 649 return (CKR_OK); 650 } 651 652 /* Acquire the session lock */ 653 (void) pthread_mutex_lock(&session_p->session_mutex); 654 655 /* Check to see if find operation is active */ 656 if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) { 657 SES_REFRELE(session_p, lock_held); 658 return (CKR_OPERATION_NOT_INITIALIZED); 659 } 660 661 soft_find_objects(session_p, phObject, ulMaxObjectCount, 662 pulObjectCount); 663 664 /* decrement the session count, and release the lock */ 665 SES_REFRELE(session_p, lock_held); 666 return (rv); 667 } 668 669 CK_RV 670 C_FindObjectsFinal(CK_SESSION_HANDLE sh) 671 { 672 soft_session_t *session_p; 673 CK_RV rv; 674 boolean_t lock_held = B_TRUE; 675 676 if (!softtoken_initialized) 677 return (CKR_CRYPTOKI_NOT_INITIALIZED); 678 679 /* 680 * Obtain the session pointer. Also, increment the session 681 * reference count. 682 */ 683 rv = handle2session(sh, &session_p); 684 if (rv != CKR_OK) 685 return (rv); 686 687 /* Acquire the session lock */ 688 (void) pthread_mutex_lock(&session_p->session_mutex); 689 690 /* Check to see if find operation is active */ 691 if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) { 692 SES_REFRELE(session_p, lock_held); 693 return (CKR_OPERATION_NOT_INITIALIZED); 694 } 695 696 soft_find_objects_final(session_p); 697 698 /* decrement the session count, and release the lock */ 699 SES_REFRELE(session_p, lock_held); 700 return (rv); 701 } 702