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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <pthread.h> 29 #include <errno.h> 30 #include <security/cryptoki.h> 31 #include <sys/crypto/ioctl.h> 32 #include "kernelGlobal.h" 33 #include "kernelSession.h" 34 #include "kernelSlot.h" 35 #include "kernelEmulate.h" 36 37 CK_RV 38 C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, 39 CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) 40 { 41 CK_RV rv = CKR_OK; 42 kernel_slot_t *pslot; 43 44 if (!kernel_initialized) 45 return (CKR_CRYPTOKI_NOT_INITIALIZED); 46 47 /* 48 * For legacy reasons, the CKF_SERIAL_SESSION bit must always 49 * be set. 50 */ 51 if (!(flags & CKF_SERIAL_SESSION)) 52 return (CKR_SESSION_PARALLEL_NOT_SUPPORTED); 53 54 if (phSession == NULL) 55 return (CKR_ARGUMENTS_BAD); 56 57 if (slotID >= slot_count) { 58 return (CKR_SLOT_ID_INVALID); 59 } 60 61 /* 62 * Acquire the slot lock to protect sl_state and sl_sess_list. 63 * These two fields need to be protected atomically, even though 64 * "sl_sess_list" is updated in kernel_add_session(). 65 */ 66 pslot = slot_table[slotID]; 67 (void) pthread_mutex_lock(&pslot->sl_mutex); 68 69 /* If SO is logged in the slot, only the RW session is allowed. */ 70 if ((pslot->sl_state == CKU_SO) && !(flags & CKF_RW_SESSION)) { 71 (void) pthread_mutex_unlock(&pslot->sl_mutex); 72 return (CKR_SESSION_READ_WRITE_SO_EXISTS); 73 } 74 75 /* Create a new session */ 76 rv = kernel_add_session(slotID, flags, pApplication, Notify, 77 phSession); 78 (void) pthread_mutex_unlock(&pslot->sl_mutex); 79 return (rv); 80 } 81 82 CK_RV 83 C_CloseSession(CK_SESSION_HANDLE hSession) 84 { 85 CK_RV rv; 86 87 kernel_session_t *session_p; 88 boolean_t ses_lock_held = B_FALSE; 89 90 if (!kernel_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 (void) pthread_mutex_lock(&session_p->session_mutex); 102 ses_lock_held = B_TRUE; 103 104 /* 105 * Set SESSION_IS_CLOSING flag so any access to this 106 * session will be rejected. 107 */ 108 if (session_p->ses_close_sync & SESSION_IS_CLOSING) { 109 REFRELE(session_p, ses_lock_held); 110 return (CKR_SESSION_CLOSED); 111 } 112 session_p->ses_close_sync |= SESSION_IS_CLOSING; 113 114 /* 115 * Decrement the session reference count. 116 * We hold the session lock, and REFRELE() 117 * will release the session lock for us. 118 */ 119 REFRELE(session_p, ses_lock_held); 120 121 /* 122 * Delete a session by calling kernel_delete_session() with 123 * a session pointer and two boolean arguments. The 3rd argument 124 * boolean value FALSE indicates that the caller does not 125 * hold the slot lock. The 4th argument boolean value B_FALSE 126 * indicates that we want to delete all the objects completely. 127 * 128 * kernel_delete_session() will reset SESSION_IS_CLOSING 129 * flag after it is done. 130 */ 131 kernel_delete_session(session_p->ses_slotid, session_p, B_FALSE, 132 B_FALSE); 133 return (rv); 134 } 135 136 137 CK_RV 138 C_CloseAllSessions(CK_SLOT_ID slotID) 139 { 140 if (!kernel_initialized) 141 return (CKR_CRYPTOKI_NOT_INITIALIZED); 142 143 /* Delete all the sessions and release the allocated resources */ 144 kernel_delete_all_sessions(slotID, B_FALSE); 145 146 return (CKR_OK); 147 } 148 149 /* 150 * Utility routine to get CK_STATE value for a session. 151 * The caller should not be holding the session lock. 152 */ 153 static CK_STATE 154 get_ses_state(kernel_session_t *session_p) 155 { 156 CK_STATE state; 157 kernel_slot_t *pslot; 158 159 pslot = slot_table[session_p->ses_slotid]; 160 (void) pthread_mutex_lock(&pslot->sl_mutex); 161 162 if (pslot->sl_state == CKU_PUBLIC) { 163 state = (session_p->ses_RO) ? 164 CKS_RO_PUBLIC_SESSION : CKS_RW_PUBLIC_SESSION; 165 } else if (pslot->sl_state == CKU_USER) { 166 state = (session_p->ses_RO) ? 167 CKS_RO_USER_FUNCTIONS : CKS_RW_USER_FUNCTIONS; 168 } else if (pslot->sl_state == CKU_SO) { 169 state = CKS_RW_SO_FUNCTIONS; 170 } 171 172 (void) pthread_mutex_unlock(&pslot->sl_mutex); 173 174 return (state); 175 } 176 177 178 CK_RV 179 C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) 180 { 181 kernel_session_t *session_p; 182 CK_RV rv; 183 boolean_t ses_lock_held = B_FALSE; 184 185 if (!kernel_initialized) 186 return (CKR_CRYPTOKI_NOT_INITIALIZED); 187 188 if (pInfo == NULL) 189 return (CKR_ARGUMENTS_BAD); 190 191 /* 192 * Obtain the session pointer. Also, increment the session 193 * reference count. 194 */ 195 rv = handle2session(hSession, &session_p); 196 if (rv != CKR_OK) 197 return (rv); 198 199 /* Provide information for the specified session */ 200 pInfo->slotID = session_p->ses_slotid; 201 pInfo->flags = session_p->flags; 202 pInfo->ulDeviceError = 0; 203 pInfo->state = get_ses_state(session_p); 204 205 /* 206 * Decrement the session reference count. 207 */ 208 REFRELE(session_p, ses_lock_held); 209 210 return (CKR_OK); 211 } 212 213 /* 214 * Save the state in pOperationState. The data format is: 215 * 1. Total length (including this field) 216 * 2. session state 217 * 3. crypto_active_op_t structure 218 * 4. digest_buf_t's data buffer contents 219 */ 220 static CK_RV 221 kernel_get_operationstate(kernel_session_t *session_p, CK_STATE ses_state, 222 CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen) 223 { 224 int op_data_len = 0; 225 CK_BYTE_PTR dst; 226 digest_buf_t *bufp; 227 228 if (!(session_p->digest.flags & CRYPTO_EMULATE)) { 229 /* 230 * Return CKR_OPERATION_NOT_INITIALIZED if the slot 231 * is capable of C_GetOperationState(). Return 232 * CKR_FUNCTION_NOT_SUPPORTED otherwise. 233 * 234 * We return these codes because some clients 235 * check the return code to determine if C_GetOperationState() 236 * is supported. 237 */ 238 if (slot_table[session_p->ses_slotid]->sl_flags & 239 CRYPTO_LIMITED_HASH_SUPPORT) 240 return (CKR_OPERATION_NOT_INITIALIZED); 241 else 242 return (CKR_FUNCTION_NOT_SUPPORTED); 243 } 244 245 /* 246 * XXX Need to support this case in future. 247 * This is the case where we exceeded SLOT_MAX_INDATA_LEN and 248 * hence started using libmd. SLOT_MAX_INDATA_LEN is at least 249 * 64K for current crypto framework providers and web servers 250 * do not need to clone digests that big for SSL operations. 251 */ 252 if (session_p->digest.flags & CRYPTO_EMULATE_USING_SW) { 253 return (CKR_STATE_UNSAVEABLE); 254 } 255 256 /* Check to see if this is an unsupported operation. */ 257 if (session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE || 258 session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE || 259 session_p->sign.flags & CRYPTO_OPERATION_ACTIVE || 260 session_p->verify.flags & CRYPTO_OPERATION_ACTIVE) { 261 return (CKR_STATE_UNSAVEABLE); 262 } 263 264 /* Check to see if digest operation is active. */ 265 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 266 return (CKR_OPERATION_NOT_INITIALIZED); 267 } 268 269 bufp = session_p->digest.context; 270 271 op_data_len = sizeof (int); 272 op_data_len += sizeof (CK_STATE); 273 op_data_len += sizeof (crypto_active_op_t); 274 op_data_len += bufp->indata_len; 275 276 if (pOperationState == NULL_PTR) { 277 *pulOperationStateLen = op_data_len; 278 return (CKR_OK); 279 } else { 280 if (*pulOperationStateLen < op_data_len) { 281 *pulOperationStateLen = op_data_len; 282 return (CKR_BUFFER_TOO_SMALL); 283 } 284 } 285 286 dst = pOperationState; 287 288 /* Save total length */ 289 bcopy(&op_data_len, dst, sizeof (int)); 290 dst += sizeof (int); 291 292 /* Save session state */ 293 bcopy(&ses_state, dst, sizeof (CK_STATE)); 294 dst += sizeof (CK_STATE); 295 296 /* Save crypto_active_op_t */ 297 bcopy(&session_p->digest, dst, sizeof (crypto_active_op_t)); 298 dst += sizeof (crypto_active_op_t); 299 300 /* Save the data buffer */ 301 bcopy(bufp->buf, dst, bufp->indata_len); 302 303 *pulOperationStateLen = op_data_len; 304 return (CKR_OK); 305 } 306 307 CK_RV 308 C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 309 CK_ULONG_PTR pulOperationStateLen) 310 { 311 CK_RV rv; 312 CK_STATE ses_state; 313 kernel_session_t *session_p; 314 boolean_t ses_lock_held = B_TRUE; 315 316 if (!kernel_initialized) 317 return (CKR_CRYPTOKI_NOT_INITIALIZED); 318 319 if (pulOperationStateLen == NULL_PTR) 320 return (CKR_ARGUMENTS_BAD); 321 322 /* 323 * Obtain the session pointer. Also, increment the session 324 * reference count. 325 */ 326 rv = handle2session(hSession, &session_p); 327 if (rv != CKR_OK) 328 return (rv); 329 330 ses_state = get_ses_state(session_p); 331 332 (void) pthread_mutex_lock(&session_p->session_mutex); 333 rv = kernel_get_operationstate(session_p, ses_state, 334 pOperationState, pulOperationStateLen); 335 336 REFRELE(session_p, ses_lock_held); 337 return (rv); 338 } 339 340 /* 341 * Restore the state from pOperationState. The data format is: 342 * 1. Total length (including this field) 343 * 2. session state 344 * 3. crypto_active_op_t structure 345 * 4. digest_buf_t's data buffer contents 346 */ 347 static CK_RV 348 kernel_set_operationstate(kernel_session_t *session_p, CK_STATE ses_state, 349 CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, 350 CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey) 351 { 352 CK_RV rv; 353 CK_BYTE_PTR src; 354 CK_STATE src_ses_state; 355 int expected_len, indata_len; 356 digest_buf_t *bufp; 357 crypto_active_op_t tmp_op; 358 359 if ((hAuthenticationKey != 0) || (hEncryptionKey != 0)) 360 return (CKR_KEY_NOT_NEEDED); 361 362 src = pOperationState; 363 364 /* Get total length field */ 365 bcopy(src, &expected_len, sizeof (int)); 366 if (ulOperationStateLen < expected_len) 367 return (CKR_SAVED_STATE_INVALID); 368 369 /* compute the data buffer length */ 370 indata_len = expected_len - sizeof (int) - 371 sizeof (CK_STATE) - sizeof (crypto_active_op_t); 372 if (indata_len > SLOT_MAX_INDATA_LEN(session_p)) 373 return (CKR_SAVED_STATE_INVALID); 374 src += sizeof (int); 375 376 /* Get session state */ 377 bcopy(src, &src_ses_state, sizeof (CK_STATE)); 378 if (ses_state != src_ses_state) 379 return (CKR_SAVED_STATE_INVALID); 380 src += sizeof (CK_STATE); 381 382 /* 383 * Restore crypto_active_op_t. We need to use a temporary 384 * buffer to avoid modifying the source session's buffer. 385 */ 386 bcopy(src, &tmp_op, sizeof (crypto_active_op_t)); 387 if (tmp_op.flags & CRYPTO_EMULATE_USING_SW) 388 return (CKR_SAVED_STATE_INVALID); 389 session_p->digest.mech = tmp_op.mech; 390 session_p->digest.flags = tmp_op.flags; 391 src += sizeof (crypto_active_op_t); 392 393 /* This routine reuses the session's existing buffer if possible */ 394 rv = emulate_buf_init(session_p, indata_len, OP_DIGEST); 395 if (rv != CKR_OK) 396 return (rv); 397 bufp = session_p->digest.context; 398 bufp->indata_len = indata_len; 399 400 /* Restore the data buffer */ 401 bcopy(src, bufp->buf, bufp->indata_len); 402 403 return (CKR_OK); 404 } 405 406 407 CK_RV 408 C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 409 CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, 410 CK_OBJECT_HANDLE hAuthenticationKey) 411 { 412 CK_RV rv; 413 CK_STATE ses_state; 414 kernel_session_t *session_p; 415 boolean_t ses_lock_held = B_TRUE; 416 417 if (!kernel_initialized) 418 return (CKR_CRYPTOKI_NOT_INITIALIZED); 419 420 if ((pOperationState == NULL_PTR) || 421 (ulOperationStateLen == 0)) 422 return (CKR_ARGUMENTS_BAD); 423 424 rv = handle2session(hSession, &session_p); 425 if (rv != CKR_OK) 426 return (rv); 427 428 ses_state = get_ses_state(session_p); 429 430 (void) pthread_mutex_lock(&session_p->session_mutex); 431 432 rv = kernel_set_operationstate(session_p, ses_state, 433 pOperationState, ulOperationStateLen, 434 hEncryptionKey, hAuthenticationKey); 435 436 REFRELE(session_p, ses_lock_held); 437 return (rv); 438 } 439 440 441 CK_RV 442 C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, 443 CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) 444 { 445 CK_RV rv = CKR_OK; 446 kernel_session_t *session_p; 447 kernel_slot_t *pslot; 448 boolean_t ses_lock_held = B_FALSE; 449 crypto_login_t c_login; 450 int r; 451 452 if (!kernel_initialized) 453 return (CKR_CRYPTOKI_NOT_INITIALIZED); 454 455 if ((userType != CKU_SO) && (userType != CKU_USER)) { 456 return (CKR_USER_TYPE_INVALID); 457 } 458 459 /* 460 * Obtain the session pointer. Also, increment the session 461 * reference count. 462 */ 463 rv = handle2session(hSession, &session_p); 464 if (rv != CKR_OK) 465 return (rv); 466 467 /* Acquire the slot lock */ 468 pslot = slot_table[session_p->ses_slotid]; 469 (void) pthread_mutex_lock(&pslot->sl_mutex); 470 471 /* Check if the slot is logged in already */ 472 if ((pslot->sl_state == CKU_USER) || (pslot->sl_state == CKU_SO)) { 473 rv = CKR_USER_ALREADY_LOGGED_IN; 474 goto clean_exit; 475 } 476 477 /* To login as SO, every session in this slot needs to be R/W */ 478 if (userType == CKU_SO) { 479 kernel_session_t *sp; 480 boolean_t found; 481 482 found = B_FALSE; 483 sp = pslot->sl_sess_list; 484 while (sp) { 485 /* 486 * Need not to lock individual sessions before 487 * accessing their "ses_RO" and "next" fields, 488 * because they are always accessed under the 489 * slot's mutex protection. 490 */ 491 if (sp->ses_RO) { 492 found = B_TRUE; 493 break; 494 } 495 sp = sp->next; 496 } 497 498 if (found) { 499 rv = CKR_SESSION_READ_ONLY_EXISTS; 500 goto clean_exit; 501 } 502 } 503 504 /* Now make the ioctl call; no need to acquire the session lock. */ 505 c_login.co_session = session_p->k_session; 506 c_login.co_user_type = userType; 507 c_login.co_pin_len = ulPinLen; 508 c_login.co_pin = (char *)pPin; 509 510 while ((r = ioctl(kernel_fd, CRYPTO_LOGIN, &c_login)) < 0) { 511 if (errno != EINTR) 512 break; 513 } 514 if (r < 0) { 515 rv = CKR_FUNCTION_FAILED; 516 } else { 517 rv = crypto2pkcs11_error_number(c_login.co_return_value); 518 } 519 520 if (rv == CKR_OK) { 521 /* Set the slot's session state. */ 522 pslot->sl_state = userType; 523 } 524 525 clean_exit: 526 527 REFRELE(session_p, ses_lock_held); 528 (void) pthread_mutex_unlock(&pslot->sl_mutex); 529 return (rv); 530 } 531 532 533 CK_RV 534 C_Logout(CK_SESSION_HANDLE hSession) 535 { 536 CK_RV rv = CKR_OK; 537 kernel_session_t *session_p; 538 kernel_slot_t *pslot; 539 boolean_t ses_lock_held = B_FALSE; 540 crypto_logout_t c_logout; 541 int r; 542 543 if (!kernel_initialized) 544 return (CKR_CRYPTOKI_NOT_INITIALIZED); 545 546 /* 547 * Obtain the session pointer. Also, increment the session 548 * reference count. 549 */ 550 rv = handle2session(hSession, &session_p); 551 if (rv != CKR_OK) 552 return (rv); 553 554 /* Acquire the slot lock. */ 555 pslot = slot_table[session_p->ses_slotid]; 556 (void) pthread_mutex_lock(&pslot->sl_mutex); 557 558 /* Check if the user or SO was logged in */ 559 if (pslot->sl_state == CKU_PUBLIC) { 560 rv = CKR_USER_NOT_LOGGED_IN; 561 goto clean_exit; 562 } 563 564 /* Now make the ioctl call. No need to acquire the session lock. */ 565 c_logout.cl_session = session_p->k_session; 566 while ((r = ioctl(kernel_fd, CRYPTO_LOGOUT, &c_logout)) < 0) { 567 if (errno != EINTR) 568 break; 569 } 570 if (r < 0) { 571 rv = CKR_FUNCTION_FAILED; 572 } else { 573 rv = crypto2pkcs11_error_number(c_logout.cl_return_value); 574 } 575 576 if (rv != CKR_OK) { 577 goto clean_exit; 578 } 579 580 /* 581 * If this slot was logged in as USER previously, we need to clean up 582 * all private object wrappers in library for this slot. 583 */ 584 kernel_cleanup_pri_objects_in_slot(pslot, session_p); 585 586 if (rv == CKR_OK) { 587 /* Reset the slot's session state. */ 588 pslot->sl_state = CKU_PUBLIC; 589 } 590 591 clean_exit: 592 REFRELE(session_p, ses_lock_held); 593 (void) pthread_mutex_unlock(&pslot->sl_mutex); 594 return (rv); 595 } 596