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