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 <md5.h> 30 #include <pthread.h> 31 #include <syslog.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <strings.h> 35 #include <sys/sha1.h> 36 #include <security/cryptoki.h> 37 #include "softGlobal.h" 38 #include "softSession.h" 39 #include "softObject.h" 40 #include "softOps.h" 41 #include "softKeystore.h" 42 #include "softKeystoreUtil.h" 43 44 45 CK_ULONG soft_session_cnt = 0; /* the number of opened sessions */ 46 CK_ULONG soft_session_rw_cnt = 0; /* the number of opened R/W sessions */ 47 48 /* 49 * Delete all the sessions. First, obtain the global session 50 * list lock. Then start to delete one session at a time. 51 * Release the global session list lock before returning to 52 * caller. 53 */ 54 CK_RV 55 soft_delete_all_sessions(boolean_t force) 56 { 57 58 CK_RV rv = CKR_OK; 59 CK_RV rv1; 60 soft_session_t *session_p; 61 soft_session_t *session_p1; 62 63 /* Acquire the global session list lock */ 64 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 65 66 session_p = soft_session_list; 67 68 /* Delete all the sessions in the session list */ 69 while (session_p) { 70 session_p1 = session_p->next; 71 72 /* 73 * Delete a session by calling soft_delete_session() 74 * with a session pointer and a boolean arguments. 75 * Boolean value TRUE is used to indicate that the 76 * caller holds the lock on the global session list. 77 * 78 */ 79 rv1 = soft_delete_session(session_p, force, B_TRUE); 80 81 /* Record the very first error code */ 82 if (rv == CKR_OK) { 83 rv = rv1; 84 } 85 86 session_p = session_p1; 87 } 88 89 /* No session left */ 90 soft_session_list = NULL; 91 92 /* Release the global session list lock */ 93 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 94 95 return (rv); 96 97 } 98 99 100 /* 101 * Create a new session struct, and add it to the session linked list. 102 * 103 * This function will acquire the global session list lock, and release 104 * it after adding the session to the session linked list. 105 */ 106 CK_RV 107 soft_add_session(CK_FLAGS flags, CK_VOID_PTR pApplication, 108 CK_NOTIFY notify, CK_ULONG *sessionhandle_p) 109 { 110 111 soft_session_t *new_sp = NULL; 112 113 /* Allocate a new session struct */ 114 new_sp = calloc(1, sizeof (soft_session_t)); 115 if (new_sp == NULL) { 116 return (CKR_HOST_MEMORY); 117 } 118 119 new_sp->magic_marker = SOFTTOKEN_SESSION_MAGIC; 120 new_sp->pApplication = pApplication; 121 new_sp->Notify = notify; 122 new_sp->flags = flags; 123 new_sp->state = CKS_RO_PUBLIC_SESSION; 124 new_sp->object_list = NULL; 125 new_sp->ses_refcnt = 0; 126 new_sp->ses_close_sync = 0; 127 128 (void) pthread_mutex_lock(&soft_giant_mutex); 129 if (soft_slot.authenticated) { 130 (void) pthread_mutex_unlock(&soft_giant_mutex); 131 if (flags & CKF_RW_SESSION) { 132 new_sp->state = CKS_RW_USER_FUNCTIONS; 133 } else { 134 new_sp->state = CKS_RO_USER_FUNCTIONS; 135 } 136 } else { 137 (void) pthread_mutex_unlock(&soft_giant_mutex); 138 if (flags & CKF_RW_SESSION) { 139 new_sp->state = CKS_RW_PUBLIC_SESSION; 140 } else { 141 new_sp->state = CKS_RO_PUBLIC_SESSION; 142 } 143 } 144 145 /* Initialize the lock for the newly created session */ 146 if (pthread_mutex_init(&new_sp->session_mutex, NULL) != 0) { 147 free(new_sp); 148 return (CKR_CANT_LOCK); 149 } 150 151 (void) pthread_cond_init(&new_sp->ses_free_cond, NULL); 152 153 /* Acquire the global session list lock */ 154 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 155 156 /* Insert the new session in front of session list */ 157 if (soft_session_list == NULL) { 158 soft_session_list = new_sp; 159 new_sp->next = NULL; 160 new_sp->prev = NULL; 161 } else { 162 soft_session_list->prev = new_sp; 163 new_sp->next = soft_session_list; 164 new_sp->prev = NULL; 165 soft_session_list = new_sp; 166 } 167 168 /* Type casting the address of a session struct to a session handle */ 169 *sessionhandle_p = (CK_ULONG)new_sp; 170 ++soft_session_cnt; 171 if (flags & CKF_RW_SESSION) 172 ++soft_session_rw_cnt; 173 174 if (soft_session_cnt == 1) 175 /* 176 * This is the first session to be opened, so we can set 177 * validate the public token objects in token list now. 178 */ 179 soft_validate_token_objects(B_TRUE); 180 181 /* Release the global session list lock */ 182 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 183 184 return (CKR_OK); 185 186 } 187 188 /* 189 * This function adds the to-be-freed session to a linked list. 190 * When the number of sessions queued in the linked list reaches the 191 * maximum threshold MAX_SES_TO_BE_FREED, it will free the first 192 * session (FIFO) in the list. 193 */ 194 void 195 session_delay_free(soft_session_t *sp) 196 { 197 soft_session_t *tmp; 198 199 (void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex); 200 201 /* Add the newly deleted session at the end of the list */ 202 sp->next = NULL; 203 if (ses_delay_freed.first == NULL) { 204 ses_delay_freed.last = sp; 205 ses_delay_freed.first = sp; 206 } else { 207 ses_delay_freed.last->next = sp; 208 ses_delay_freed.last = sp; 209 } 210 211 if (++ses_delay_freed.count >= MAX_SES_TO_BE_FREED) { 212 /* 213 * Free the first session in the list only if 214 * the total count reaches maximum threshold. 215 */ 216 ses_delay_freed.count--; 217 tmp = ses_delay_freed.first->next; 218 free(ses_delay_freed.first); 219 ses_delay_freed.first = tmp; 220 } 221 (void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex); 222 } 223 224 /* 225 * Delete a session: 226 * - Remove the session from the session linked list. 227 * Holding the lock on the global session list is needed to do this. 228 * - Release all the objects created by the session. 229 * 230 * The boolean argument lock_held is used to indicate that whether 231 * the caller of this function holds the lock on the global session 232 * list or not. 233 * - When called by soft_delete_all_sessions(), which is called by 234 * C_Finalize() or C_CloseAllSessions() -- the lock_held = TRUE. 235 * - When called by C_CloseSession() -- the lock_held = FALSE. 236 * 237 * When the caller does not hold the lock on the global session 238 * list, this function will acquire that lock in order to proceed, 239 * and also release that lock before returning to caller. 240 */ 241 CK_RV 242 soft_delete_session(soft_session_t *session_p, 243 boolean_t force, boolean_t lock_held) 244 { 245 246 /* 247 * Check to see if the caller holds the lock on the global 248 * session list. If not, we need to acquire that lock in 249 * order to proceed. 250 */ 251 if (!lock_held) { 252 /* Acquire the global session list lock */ 253 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 254 } 255 256 /* 257 * Remove the session from the session linked list first. 258 */ 259 if (soft_session_list == session_p) { 260 /* Session is the first one in the list */ 261 if (session_p->next) { 262 soft_session_list = session_p->next; 263 session_p->next->prev = NULL; 264 } else { 265 /* Session is the only one in the list */ 266 soft_session_list = NULL; 267 } 268 } else { 269 /* Session is not the first one in the list */ 270 if (session_p->next) { 271 /* Session is in the middle of the list */ 272 session_p->prev->next = session_p->next; 273 session_p->next->prev = session_p->prev; 274 } else { 275 /* Session is the last one in the list */ 276 session_p->prev->next = NULL; 277 } 278 } 279 280 --soft_session_cnt; 281 if (session_p->flags & CKF_RW_SESSION) 282 --soft_session_rw_cnt; 283 284 if (!lock_held) { 285 /* 286 * If the global session list lock is obtained by 287 * this function, then release that lock after 288 * removing the session from session linked list. 289 * We want the releasing of the objects of the 290 * session, and freeing of the session itself to 291 * be done without holding the global session list 292 * lock. 293 */ 294 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 295 } 296 297 298 /* Acquire the individual session lock */ 299 (void) pthread_mutex_lock(&session_p->session_mutex); 300 /* 301 * Make sure another thread hasn't freed the session. 302 */ 303 if (session_p->magic_marker != SOFTTOKEN_SESSION_MAGIC) { 304 (void) pthread_mutex_unlock(&session_p->session_mutex); 305 return (CKR_OK); 306 } 307 308 /* 309 * The deletion of a session must be blocked when the session 310 * reference count is not zero. This means if any session related 311 * operation starts prior to the session close operation gets in, 312 * the session closing thread must wait for the non-closing 313 * operation to be completed before it can proceed the close 314 * operation. 315 * 316 * Unless we are being forced to shut everything down, this only 317 * happens if the libraries _fini() is running not of someone 318 * explicitly called C_Finalize(). 319 */ 320 if (force) 321 session_p->ses_refcnt = 0; 322 323 while (session_p->ses_refcnt != 0) { 324 /* 325 * We set the SESSION_REFCNT_WAITING flag before we put 326 * this closing thread in a wait state, so other non-closing 327 * operation thread will signal to wake it up only when 328 * the session reference count becomes zero and this flag 329 * is set. 330 */ 331 session_p->ses_close_sync |= SESSION_REFCNT_WAITING; 332 (void) pthread_cond_wait(&session_p->ses_free_cond, 333 &session_p->session_mutex); 334 } 335 336 session_p->ses_close_sync &= ~SESSION_REFCNT_WAITING; 337 338 /* Mark session as no longer valid. */ 339 session_p->magic_marker = 0; 340 341 (void) pthread_cond_destroy(&session_p->ses_free_cond); 342 343 /* 344 * Remove all the objects created in this session. 345 */ 346 soft_delete_all_objects_in_session(session_p); 347 348 /* In case application did not call Final */ 349 if (session_p->digest.context != NULL) 350 free(session_p->digest.context); 351 352 if (session_p->encrypt.context != NULL) 353 /* 354 * 1st B_TRUE: encrypt 355 * 2nd B_TRUE: caller is holding session_mutex. 356 */ 357 soft_crypt_cleanup(session_p, B_TRUE, B_TRUE); 358 359 if (session_p->decrypt.context != NULL) 360 /* 361 * 1st B_FALSE: decrypt 362 * 2nd B_TRUE: caller is holding session_mutex. 363 */ 364 soft_crypt_cleanup(session_p, B_FALSE, B_TRUE); 365 366 if (session_p->sign.context != NULL) 367 free(session_p->sign.context); 368 369 if (session_p->verify.context != NULL) 370 free(session_p->verify.context); 371 372 if (session_p->find_objects.context != NULL) { 373 find_context_t *fcontext; 374 fcontext = (find_context_t *)session_p->find_objects.context; 375 free(fcontext->objs_found); 376 free(fcontext); 377 } 378 379 /* Reset SESSION_IS_CLOSIN flag. */ 380 session_p->ses_close_sync &= ~SESSION_IS_CLOSING; 381 382 (void) pthread_mutex_unlock(&session_p->session_mutex); 383 /* Destroy the individual session lock */ 384 (void) pthread_mutex_destroy(&session_p->session_mutex); 385 386 /* Delay freeing the session */ 387 session_delay_free(session_p); 388 389 return (CKR_OK); 390 } 391 392 393 /* 394 * This function is used to type cast a session handle to a pointer to 395 * the session struct. Also, it does the following things: 396 * 1) Check to see if the session struct is tagged with a session 397 * magic number. This is to detect when an application passes 398 * a bogus session pointer. 399 * 2) Acquire the locks on the global session list and on the designated 400 * session. 401 * 3) Check to see if the session is in the closing state that another 402 * thread is performing. 403 * 4) Increment the session reference count by one. This is to prevent 404 * this session from being closed by other thread. 405 * 5) Release the locks held on the designated session and on the global 406 * session list. 407 */ 408 CK_RV 409 handle2session(CK_SESSION_HANDLE hSession, soft_session_t **session_p) 410 { 411 412 soft_session_t *sp = (soft_session_t *)(hSession); 413 414 (void) pthread_mutex_lock(&soft_sessionlist_mutex); 415 if (all_sessions_closing) { 416 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 417 return (CKR_SESSION_CLOSED); 418 } 419 /* 420 * We need to free the global session list lock to prevent deadlock 421 * between C_CloseSession and C_DestroyObject. S1WS/NSS does 422 * explicit deletion (C_DestroyObject) after implicit deletion by 423 * C_CloseSession. 424 */ 425 (void) pthread_mutex_unlock(&soft_sessionlist_mutex); 426 427 if ((sp == NULL) || 428 (sp->magic_marker != SOFTTOKEN_SESSION_MAGIC)) { 429 return (CKR_SESSION_HANDLE_INVALID); 430 } 431 (void) pthread_mutex_lock(&sp->session_mutex); 432 433 if (sp->ses_close_sync & SESSION_IS_CLOSING) { 434 (void) pthread_mutex_unlock(&sp->session_mutex); 435 return (CKR_SESSION_CLOSED); 436 } 437 438 /* Increment session ref count. */ 439 sp->ses_refcnt++; 440 441 (void) pthread_mutex_unlock(&sp->session_mutex); 442 443 *session_p = sp; 444 445 return (CKR_OK); 446 } 447 448 /* 449 * The format to be saved in the pOperationState will be: 450 * 1. internal_op_state_t 451 * 2. crypto_active_op_t 452 * 3. actual context of the active operation 453 */ 454 CK_RV 455 soft_get_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState, 456 CK_ULONG_PTR pulOperationStateLen) 457 { 458 459 internal_op_state_t op_state; 460 CK_ULONG op_data_len = 0; 461 462 /* Check to see if encrypt operation is active. */ 463 if (session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE) { 464 return (CKR_STATE_UNSAVEABLE); 465 } 466 467 /* Check to see if decrypt operation is active. */ 468 if (session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE) { 469 return (CKR_STATE_UNSAVEABLE); 470 } 471 472 /* Check to see if sign operation is active. */ 473 if (session_p->sign.flags & CRYPTO_OPERATION_ACTIVE) { 474 return (CKR_STATE_UNSAVEABLE); 475 } 476 477 /* Check to see if verify operation is active. */ 478 if (session_p->verify.flags & CRYPTO_OPERATION_ACTIVE) { 479 return (CKR_STATE_UNSAVEABLE); 480 } 481 482 /* Check to see if digest operation is active. */ 483 if (session_p->digest.flags & CRYPTO_OPERATION_ACTIVE) { 484 op_data_len = sizeof (internal_op_state_t) + 485 sizeof (crypto_active_op_t); 486 487 switch (session_p->digest.mech.mechanism) { 488 case CKM_MD5: 489 op_data_len += sizeof (MD5_CTX); 490 break; 491 case CKM_SHA_1: 492 op_data_len += sizeof (SHA1_CTX); 493 break; 494 default: 495 return (CKR_STATE_UNSAVEABLE); 496 } 497 498 if (pOperationState == NULL_PTR) { 499 *pulOperationStateLen = op_data_len; 500 return (CKR_OK); 501 } else { 502 if (*pulOperationStateLen < op_data_len) { 503 *pulOperationStateLen = op_data_len; 504 return (CKR_BUFFER_TOO_SMALL); 505 } 506 } 507 508 op_state.op_len = op_data_len; 509 op_state.op_active = DIGEST_OP; 510 op_state.op_session_state = session_p->state; 511 512 /* Save internal_op_state_t */ 513 (void) memcpy(pOperationState, (CK_BYTE_PTR)&op_state, 514 sizeof (internal_op_state_t)); 515 516 /* Save crypto_active_op_t */ 517 (void) memcpy((CK_BYTE *)pOperationState + 518 sizeof (internal_op_state_t), 519 &session_p->digest, 520 sizeof (crypto_active_op_t)); 521 522 switch (session_p->digest.mech.mechanism) { 523 case CKM_MD5: 524 /* Save MD5_CTX for the active digest operation */ 525 (void) memcpy((CK_BYTE *)pOperationState + 526 sizeof (internal_op_state_t) + 527 sizeof (crypto_active_op_t), 528 session_p->digest.context, 529 sizeof (MD5_CTX)); 530 break; 531 532 case CKM_SHA_1: 533 /* Save SHA1_CTX for the active digest operation */ 534 (void) memcpy((CK_BYTE *)pOperationState + 535 sizeof (internal_op_state_t) + 536 sizeof (crypto_active_op_t), 537 session_p->digest.context, 538 sizeof (SHA1_CTX)); 539 break; 540 541 default: 542 return (CKR_STATE_UNSAVEABLE); 543 } 544 } 545 546 *pulOperationStateLen = op_data_len; 547 return (CKR_OK); 548 549 } 550 551 /* 552 * The format to be restored from the pOperationState will be: 553 * 1. internal_op_state_t 554 * 2. crypto_active_op_t 555 * 3. actual context of the saved operation 556 */ 557 CK_RV 558 soft_set_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState, 559 CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, 560 CK_OBJECT_HANDLE hAuthenticationKey) 561 { 562 563 CK_RV rv; 564 internal_op_state_t op_state; 565 crypto_active_op_t crypto_tmp; 566 CK_ULONG offset = 0; 567 568 /* Restore internal_op_state_t */ 569 (void) memcpy((CK_BYTE_PTR)&op_state, pOperationState, 570 sizeof (internal_op_state_t)); 571 572 if (session_p->state != op_state.op_session_state) { 573 /* 574 * The supplied session state does not match with 575 * the saved session state. 576 */ 577 return (CKR_SAVED_STATE_INVALID); 578 } 579 580 if (op_state.op_len != ulOperationStateLen) { 581 /* 582 * The supplied data length does not match with 583 * the saved data length. 584 */ 585 return (CKR_SAVED_STATE_INVALID); 586 } 587 588 offset = sizeof (internal_op_state_t); 589 590 (void) memcpy((CK_BYTE *)&crypto_tmp, 591 (CK_BYTE *)pOperationState + offset, 592 sizeof (crypto_active_op_t)); 593 594 switch (op_state.op_active) { 595 case DIGEST_OP: 596 if ((hAuthenticationKey != 0) || (hEncryptionKey != 0)) { 597 return (CKR_KEY_NOT_NEEDED); 598 } 599 600 /* 601 * If the destination session has the same mechanism 602 * as the source, we can reuse the memory allocated for 603 * the crypto context. Otherwise, we free the crypto 604 * context of the destination session now. 605 */ 606 if (session_p->digest.context) { 607 if (session_p->digest.mech.mechanism != 608 crypto_tmp.mech.mechanism) { 609 (void) pthread_mutex_lock(&session_p-> 610 session_mutex); 611 free(session_p->digest.context); 612 session_p->digest.context = NULL; 613 (void) pthread_mutex_unlock(&session_p-> 614 session_mutex); 615 } 616 } 617 break; 618 619 default: 620 return (CKR_SAVED_STATE_INVALID); 621 } 622 623 /* Restore crypto_active_op_t */ 624 (void) pthread_mutex_lock(&session_p->session_mutex); 625 session_p->digest.mech.mechanism = crypto_tmp.mech.mechanism; 626 session_p->digest.flags = crypto_tmp.flags; 627 (void) pthread_mutex_unlock(&session_p->session_mutex); 628 629 offset += sizeof (crypto_active_op_t); 630 631 /* 632 * Make sure the supplied crypto operation state is valid 633 */ 634 switch (op_state.op_active) { 635 case DIGEST_OP: 636 637 switch (session_p->digest.mech.mechanism) { 638 case CKM_MD5: 639 (void) pthread_mutex_lock(&session_p->session_mutex); 640 if (session_p->digest.context == NULL) { 641 session_p->digest.context = 642 malloc(sizeof (MD5_CTX)); 643 644 if (session_p->digest.context == NULL) { 645 (void) pthread_mutex_unlock( 646 &session_p->session_mutex); 647 return (CKR_HOST_MEMORY); 648 } 649 } 650 651 /* Restore MD5_CTX from the saved digest operation */ 652 (void) memcpy((CK_BYTE *)session_p->digest.context, 653 (CK_BYTE *)pOperationState + offset, 654 sizeof (MD5_CTX)); 655 656 (void) pthread_mutex_unlock(&session_p->session_mutex); 657 658 rv = CKR_OK; 659 break; 660 661 case CKM_SHA_1: 662 (void) pthread_mutex_lock(&session_p->session_mutex); 663 if (session_p->digest.context == NULL) { 664 session_p->digest.context = 665 malloc(sizeof (SHA1_CTX)); 666 667 if (session_p->digest.context == NULL) { 668 (void) pthread_mutex_unlock( 669 &session_p->session_mutex); 670 return (CKR_HOST_MEMORY); 671 } 672 } 673 674 /* Restore SHA1_CTX from the saved digest operation */ 675 (void) memcpy((CK_BYTE *)session_p->digest.context, 676 (CK_BYTE *)pOperationState + offset, 677 sizeof (SHA1_CTX)); 678 679 (void) pthread_mutex_unlock(&session_p->session_mutex); 680 681 rv = CKR_OK; 682 break; 683 684 default: 685 rv = CKR_SAVED_STATE_INVALID; 686 break; 687 } 688 break; 689 690 default: 691 rv = CKR_SAVED_STATE_INVALID; 692 break; 693 } 694 695 return (rv); 696 697 } 698 699 700 CK_RV 701 soft_login(CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) 702 { 703 704 /* 705 * Authenticate the input PIN. 706 */ 707 return (soft_verify_pin(pPin, ulPinLen)); 708 709 } 710 711 void 712 soft_logout(void) 713 { 714 715 /* 716 * Delete all the private token objects from the "token_object_list". 717 */ 718 soft_delete_all_in_core_token_objects(PRIVATE_TOKEN); 719 return; 720 721 } 722