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