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