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 2007 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 /* 229 * We return CKR_FUNCTION_NOT_SUPPORTED because some clients 230 * check for this code and work around the lack of this routine. 231 */ 232 if (!(session_p->digest.flags & CRYPTO_EMULATE)) { 233 return (CKR_FUNCTION_NOT_SUPPORTED); 234 } 235 236 /* 237 * XXX Need to support this case in future. 238 * This is the case where we exceeded SLOT_MAX_INDATA_LEN and 239 * hence started using libmd. SLOT_MAX_INDATA_LEN is at least 240 * 64K for current crypto framework providers and web servers 241 * do not need to clone digests that big for SSL operations. 242 */ 243 if (session_p->digest.flags & CRYPTO_EMULATE_USING_SW) { 244 return (CKR_STATE_UNSAVEABLE); 245 } 246 247 /* Check to see if this is an unsupported operation. */ 248 if (session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE || 249 session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE || 250 session_p->sign.flags & CRYPTO_OPERATION_ACTIVE || 251 session_p->verify.flags & CRYPTO_OPERATION_ACTIVE) { 252 return (CKR_STATE_UNSAVEABLE); 253 } 254 255 /* Check to see if digest operation is active. */ 256 if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 257 return (CKR_OPERATION_NOT_INITIALIZED); 258 } 259 260 bufp = session_p->digest.context; 261 262 op_data_len = sizeof (int); 263 op_data_len += sizeof (CK_STATE); 264 op_data_len += sizeof (crypto_active_op_t); 265 op_data_len += bufp->indata_len; 266 267 if (pOperationState == NULL_PTR) { 268 *pulOperationStateLen = op_data_len; 269 return (CKR_OK); 270 } else { 271 if (*pulOperationStateLen < op_data_len) { 272 *pulOperationStateLen = op_data_len; 273 return (CKR_BUFFER_TOO_SMALL); 274 } 275 } 276 277 dst = pOperationState; 278 279 /* Save total length */ 280 bcopy(&op_data_len, dst, sizeof (int)); 281 dst += sizeof (int); 282 283 /* Save session state */ 284 bcopy(&ses_state, dst, sizeof (CK_STATE)); 285 dst += sizeof (CK_STATE); 286 287 /* Save crypto_active_op_t */ 288 bcopy(&session_p->digest, dst, sizeof (crypto_active_op_t)); 289 dst += sizeof (crypto_active_op_t); 290 291 /* Save the data buffer */ 292 bcopy(bufp->buf, dst, bufp->indata_len); 293 294 *pulOperationStateLen = op_data_len; 295 return (CKR_OK); 296 } 297 298 CK_RV 299 C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 300 CK_ULONG_PTR pulOperationStateLen) 301 { 302 CK_RV rv; 303 CK_STATE ses_state; 304 kernel_session_t *session_p; 305 boolean_t ses_lock_held = B_TRUE; 306 307 if (!kernel_initialized) 308 return (CKR_CRYPTOKI_NOT_INITIALIZED); 309 310 if (pulOperationStateLen == NULL_PTR) 311 return (CKR_ARGUMENTS_BAD); 312 313 /* 314 * Obtain the session pointer. Also, increment the session 315 * reference count. 316 */ 317 rv = handle2session(hSession, &session_p); 318 if (rv != CKR_OK) 319 return (rv); 320 321 ses_state = get_ses_state(session_p); 322 323 (void) pthread_mutex_lock(&session_p->session_mutex); 324 rv = kernel_get_operationstate(session_p, ses_state, 325 pOperationState, pulOperationStateLen); 326 327 REFRELE(session_p, ses_lock_held); 328 return (rv); 329 } 330 331 /* 332 * Restore the state from pOperationState. The data format is: 333 * 1. Total length (including this field) 334 * 2. session state 335 * 3. crypto_active_op_t structure 336 * 4. digest_buf_t's data buffer contents 337 */ 338 static CK_RV 339 kernel_set_operationstate(kernel_session_t *session_p, CK_STATE ses_state, 340 CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, 341 CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey) 342 { 343 CK_RV rv; 344 CK_BYTE_PTR src; 345 CK_STATE src_ses_state; 346 int expected_len, indata_len; 347 digest_buf_t *bufp; 348 crypto_active_op_t tmp_op; 349 350 if ((hAuthenticationKey != 0) || (hEncryptionKey != 0)) 351 return (CKR_KEY_NOT_NEEDED); 352 353 src = pOperationState; 354 355 /* Get total length field */ 356 bcopy(src, &expected_len, sizeof (int)); 357 if (ulOperationStateLen < expected_len) 358 return (CKR_SAVED_STATE_INVALID); 359 360 /* compute the data buffer length */ 361 indata_len = expected_len - sizeof (int) - 362 sizeof (CK_STATE) - sizeof (crypto_active_op_t); 363 if (indata_len > SLOT_MAX_INDATA_LEN(session_p)) 364 return (CKR_SAVED_STATE_INVALID); 365 src += sizeof (int); 366 367 /* Get session state */ 368 bcopy(src, &src_ses_state, sizeof (CK_STATE)); 369 if (ses_state != src_ses_state) 370 return (CKR_SAVED_STATE_INVALID); 371 src += sizeof (CK_STATE); 372 373 /* 374 * Restore crypto_active_op_t. We need to use a temporary 375 * buffer to avoid modifying the source session's buffer. 376 */ 377 bcopy(src, &tmp_op, sizeof (crypto_active_op_t)); 378 if (tmp_op.flags & CRYPTO_EMULATE_USING_SW) 379 return (CKR_SAVED_STATE_INVALID); 380 session_p->digest.mech = tmp_op.mech; 381 session_p->digest.flags = tmp_op.flags; 382 src += sizeof (crypto_active_op_t); 383 384 /* This routine reuses the session's existing buffer if possible */ 385 rv = emulate_buf_init(session_p, indata_len, OP_DIGEST); 386 if (rv != CKR_OK) 387 return (rv); 388 bufp = session_p->digest.context; 389 bufp->indata_len = indata_len; 390 391 /* Restore the data buffer */ 392 bcopy(src, bufp->buf, bufp->indata_len); 393 394 return (CKR_OK); 395 } 396 397 398 CK_RV 399 C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 400 CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, 401 CK_OBJECT_HANDLE hAuthenticationKey) 402 { 403 CK_RV rv; 404 CK_STATE ses_state; 405 kernel_session_t *session_p; 406 boolean_t ses_lock_held = B_TRUE; 407 408 if (!kernel_initialized) 409 return (CKR_CRYPTOKI_NOT_INITIALIZED); 410 411 if ((pOperationState == NULL_PTR) || 412 (ulOperationStateLen == 0)) 413 return (CKR_ARGUMENTS_BAD); 414 415 rv = handle2session(hSession, &session_p); 416 if (rv != CKR_OK) 417 return (rv); 418 419 ses_state = get_ses_state(session_p); 420 421 (void) pthread_mutex_lock(&session_p->session_mutex); 422 423 rv = kernel_set_operationstate(session_p, ses_state, 424 pOperationState, ulOperationStateLen, 425 hEncryptionKey, hAuthenticationKey); 426 427 REFRELE(session_p, ses_lock_held); 428 return (rv); 429 } 430 431 432 CK_RV 433 C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, 434 CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) 435 { 436 CK_RV rv = CKR_OK; 437 kernel_session_t *session_p; 438 kernel_slot_t *pslot; 439 boolean_t ses_lock_held = B_FALSE; 440 crypto_login_t c_login; 441 int r; 442 443 if (!kernel_initialized) 444 return (CKR_CRYPTOKI_NOT_INITIALIZED); 445 446 if ((userType != CKU_SO) && (userType != CKU_USER)) { 447 return (CKR_USER_TYPE_INVALID); 448 } 449 450 /* 451 * Obtain the session pointer. Also, increment the session 452 * reference count. 453 */ 454 rv = handle2session(hSession, &session_p); 455 if (rv != CKR_OK) 456 return (rv); 457 458 /* Acquire the slot lock */ 459 pslot = slot_table[session_p->ses_slotid]; 460 (void) pthread_mutex_lock(&pslot->sl_mutex); 461 462 /* Check if the slot is logged in already */ 463 if ((pslot->sl_state == CKU_USER) || (pslot->sl_state == CKU_SO)) { 464 rv = CKR_USER_ALREADY_LOGGED_IN; 465 goto clean_exit; 466 } 467 468 /* To login as SO, every session in this slot needs to be R/W */ 469 if (userType == CKU_SO) { 470 kernel_session_t *sp; 471 boolean_t found; 472 473 found = B_FALSE; 474 sp = pslot->sl_sess_list; 475 while (sp) { 476 /* 477 * Need not to lock individual sessions before 478 * accessing their "ses_RO" and "next" fields, 479 * because they are always accessed under the 480 * slot's mutex protection. 481 */ 482 if (sp->ses_RO) { 483 found = B_TRUE; 484 break; 485 } 486 sp = sp->next; 487 } 488 489 if (found) { 490 rv = CKR_SESSION_READ_ONLY_EXISTS; 491 goto clean_exit; 492 } 493 } 494 495 /* Now make the ioctl call; no need to acquire the session lock. */ 496 c_login.co_session = session_p->k_session; 497 c_login.co_user_type = userType; 498 c_login.co_pin_len = ulPinLen; 499 c_login.co_pin = (char *)pPin; 500 501 while ((r = ioctl(kernel_fd, CRYPTO_LOGIN, &c_login)) < 0) { 502 if (errno != EINTR) 503 break; 504 } 505 if (r < 0) { 506 rv = CKR_FUNCTION_FAILED; 507 } else { 508 rv = crypto2pkcs11_error_number(c_login.co_return_value); 509 } 510 511 if (rv == CKR_OK) { 512 /* Set the slot's session state. */ 513 pslot->sl_state = userType; 514 } 515 516 clean_exit: 517 518 REFRELE(session_p, ses_lock_held); 519 (void) pthread_mutex_unlock(&pslot->sl_mutex); 520 return (rv); 521 } 522 523 524 CK_RV 525 C_Logout(CK_SESSION_HANDLE hSession) 526 { 527 CK_RV rv = CKR_OK; 528 kernel_session_t *session_p; 529 kernel_slot_t *pslot; 530 boolean_t ses_lock_held = B_FALSE; 531 crypto_logout_t c_logout; 532 int r; 533 534 if (!kernel_initialized) 535 return (CKR_CRYPTOKI_NOT_INITIALIZED); 536 537 /* 538 * Obtain the session pointer. Also, increment the session 539 * reference count. 540 */ 541 rv = handle2session(hSession, &session_p); 542 if (rv != CKR_OK) 543 return (rv); 544 545 /* Acquire the slot lock. */ 546 pslot = slot_table[session_p->ses_slotid]; 547 (void) pthread_mutex_lock(&pslot->sl_mutex); 548 549 /* Check if the user or SO was logged in */ 550 if (pslot->sl_state == CKU_PUBLIC) { 551 rv = CKR_USER_NOT_LOGGED_IN; 552 goto clean_exit; 553 } 554 555 /* Now make the ioctl call. No need to acquire the session lock. */ 556 c_logout.cl_session = session_p->k_session; 557 while ((r = ioctl(kernel_fd, CRYPTO_LOGOUT, &c_logout)) < 0) { 558 if (errno != EINTR) 559 break; 560 } 561 if (r < 0) { 562 rv = CKR_FUNCTION_FAILED; 563 } else { 564 rv = crypto2pkcs11_error_number(c_logout.cl_return_value); 565 } 566 567 if (rv != CKR_OK) { 568 goto clean_exit; 569 } 570 571 /* 572 * If this slot was logged in as USER previously, we need to clean up 573 * all private object wrappers in library for this slot. 574 */ 575 kernel_cleanup_pri_objects_in_slot(pslot, session_p); 576 577 if (rv == CKR_OK) { 578 /* Reset the slot's session state. */ 579 pslot->sl_state = CKU_PUBLIC; 580 } 581 582 clean_exit: 583 REFRELE(session_p, ses_lock_held); 584 (void) pthread_mutex_unlock(&pslot->sl_mutex); 585 return (rv); 586 } 587