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