17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5b2a96221Skrishna * Common Development and Distribution License (the "License"). 6b2a96221Skrishna * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*4df55fdeSJanie Lu * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <pthread.h> 277c478bd9Sstevel@tonic-gate #include <errno.h> 287c478bd9Sstevel@tonic-gate #include <security/cryptoki.h> 297c478bd9Sstevel@tonic-gate #include <sys/crypto/ioctl.h> 307c478bd9Sstevel@tonic-gate #include "kernelGlobal.h" 317c478bd9Sstevel@tonic-gate #include "kernelSession.h" 327c478bd9Sstevel@tonic-gate #include "kernelSlot.h" 33b2a96221Skrishna #include "kernelEmulate.h" 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate CK_RV 367c478bd9Sstevel@tonic-gate C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, 377c478bd9Sstevel@tonic-gate CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) 387c478bd9Sstevel@tonic-gate { 397c478bd9Sstevel@tonic-gate CK_RV rv = CKR_OK; 407c478bd9Sstevel@tonic-gate kernel_slot_t *pslot; 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate if (!kernel_initialized) 437c478bd9Sstevel@tonic-gate return (CKR_CRYPTOKI_NOT_INITIALIZED); 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate /* 467c478bd9Sstevel@tonic-gate * For legacy reasons, the CKF_SERIAL_SESSION bit must always 477c478bd9Sstevel@tonic-gate * be set. 487c478bd9Sstevel@tonic-gate */ 497c478bd9Sstevel@tonic-gate if (!(flags & CKF_SERIAL_SESSION)) 507c478bd9Sstevel@tonic-gate return (CKR_SESSION_PARALLEL_NOT_SUPPORTED); 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate if (phSession == NULL) 537c478bd9Sstevel@tonic-gate return (CKR_ARGUMENTS_BAD); 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate if (slotID >= slot_count) { 567c478bd9Sstevel@tonic-gate return (CKR_SLOT_ID_INVALID); 577c478bd9Sstevel@tonic-gate } 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * Acquire the slot lock to protect sl_state and sl_sess_list. 617c478bd9Sstevel@tonic-gate * These two fields need to be protected atomically, even though 627c478bd9Sstevel@tonic-gate * "sl_sess_list" is updated in kernel_add_session(). 637c478bd9Sstevel@tonic-gate */ 647c478bd9Sstevel@tonic-gate pslot = slot_table[slotID]; 657c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pslot->sl_mutex); 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate /* If SO is logged in the slot, only the RW session is allowed. */ 687c478bd9Sstevel@tonic-gate if ((pslot->sl_state == CKU_SO) && !(flags & CKF_RW_SESSION)) { 697c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pslot->sl_mutex); 707c478bd9Sstevel@tonic-gate return (CKR_SESSION_READ_WRITE_SO_EXISTS); 717c478bd9Sstevel@tonic-gate } 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* Create a new session */ 747c478bd9Sstevel@tonic-gate rv = kernel_add_session(slotID, flags, pApplication, Notify, 757c478bd9Sstevel@tonic-gate phSession); 767c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pslot->sl_mutex); 777c478bd9Sstevel@tonic-gate return (rv); 787c478bd9Sstevel@tonic-gate } 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate CK_RV 817c478bd9Sstevel@tonic-gate C_CloseSession(CK_SESSION_HANDLE hSession) 827c478bd9Sstevel@tonic-gate { 837c478bd9Sstevel@tonic-gate CK_RV rv; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate kernel_session_t *session_p; 867c478bd9Sstevel@tonic-gate boolean_t ses_lock_held = B_FALSE; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate if (!kernel_initialized) 897c478bd9Sstevel@tonic-gate return (CKR_CRYPTOKI_NOT_INITIALIZED); 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate /* 927c478bd9Sstevel@tonic-gate * Obtain the session pointer. Also, increment the session 937c478bd9Sstevel@tonic-gate * reference count. 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate rv = handle2session(hSession, &session_p); 967c478bd9Sstevel@tonic-gate if (rv != CKR_OK) 977c478bd9Sstevel@tonic-gate return (rv); 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&session_p->session_mutex); 1007c478bd9Sstevel@tonic-gate ses_lock_held = B_TRUE; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* 1037c478bd9Sstevel@tonic-gate * Set SESSION_IS_CLOSING flag so any access to this 1047c478bd9Sstevel@tonic-gate * session will be rejected. 1057c478bd9Sstevel@tonic-gate */ 10601223cbaSmcpowers if (session_p->ses_close_sync & SESSION_IS_CLOSING) { 10701223cbaSmcpowers REFRELE(session_p, ses_lock_held); 10801223cbaSmcpowers return (CKR_SESSION_CLOSED); 10901223cbaSmcpowers } 1107c478bd9Sstevel@tonic-gate session_p->ses_close_sync |= SESSION_IS_CLOSING; 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate /* 1137c478bd9Sstevel@tonic-gate * Decrement the session reference count. 1147c478bd9Sstevel@tonic-gate * We hold the session lock, and REFRELE() 1157c478bd9Sstevel@tonic-gate * will release the session lock for us. 1167c478bd9Sstevel@tonic-gate */ 1177c478bd9Sstevel@tonic-gate REFRELE(session_p, ses_lock_held); 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * Delete a session by calling kernel_delete_session() with 1217c478bd9Sstevel@tonic-gate * a session pointer and two boolean arguments. The 3rd argument 1227c478bd9Sstevel@tonic-gate * boolean value FALSE indicates that the caller does not 1237c478bd9Sstevel@tonic-gate * hold the slot lock. The 4th argument boolean value B_FALSE 1247c478bd9Sstevel@tonic-gate * indicates that we want to delete all the objects completely. 1257c478bd9Sstevel@tonic-gate * 1267c478bd9Sstevel@tonic-gate * kernel_delete_session() will reset SESSION_IS_CLOSING 1277c478bd9Sstevel@tonic-gate * flag after it is done. 1287c478bd9Sstevel@tonic-gate */ 12901223cbaSmcpowers kernel_delete_session(session_p->ses_slotid, session_p, B_FALSE, 1307c478bd9Sstevel@tonic-gate B_FALSE); 1317c478bd9Sstevel@tonic-gate return (rv); 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate CK_RV 1367c478bd9Sstevel@tonic-gate C_CloseAllSessions(CK_SLOT_ID slotID) 1377c478bd9Sstevel@tonic-gate { 1387c478bd9Sstevel@tonic-gate if (!kernel_initialized) 1397c478bd9Sstevel@tonic-gate return (CKR_CRYPTOKI_NOT_INITIALIZED); 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate /* Delete all the sessions and release the allocated resources */ 14201223cbaSmcpowers kernel_delete_all_sessions(slotID, B_FALSE); 1437c478bd9Sstevel@tonic-gate 14401223cbaSmcpowers return (CKR_OK); 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate 147b2a96221Skrishna /* 148b2a96221Skrishna * Utility routine to get CK_STATE value for a session. 149b2a96221Skrishna * The caller should not be holding the session lock. 150b2a96221Skrishna */ 151b2a96221Skrishna static CK_STATE 152b2a96221Skrishna get_ses_state(kernel_session_t *session_p) 153b2a96221Skrishna { 154b2a96221Skrishna CK_STATE state; 155b2a96221Skrishna kernel_slot_t *pslot; 156b2a96221Skrishna 157b2a96221Skrishna pslot = slot_table[session_p->ses_slotid]; 158b2a96221Skrishna (void) pthread_mutex_lock(&pslot->sl_mutex); 159b2a96221Skrishna 160b2a96221Skrishna if (pslot->sl_state == CKU_PUBLIC) { 161b2a96221Skrishna state = (session_p->ses_RO) ? 162b2a96221Skrishna CKS_RO_PUBLIC_SESSION : CKS_RW_PUBLIC_SESSION; 163b2a96221Skrishna } else if (pslot->sl_state == CKU_USER) { 164b2a96221Skrishna state = (session_p->ses_RO) ? 165b2a96221Skrishna CKS_RO_USER_FUNCTIONS : CKS_RW_USER_FUNCTIONS; 166b2a96221Skrishna } else if (pslot->sl_state == CKU_SO) { 167b2a96221Skrishna state = CKS_RW_SO_FUNCTIONS; 168b2a96221Skrishna } 169b2a96221Skrishna 170b2a96221Skrishna (void) pthread_mutex_unlock(&pslot->sl_mutex); 171b2a96221Skrishna 172b2a96221Skrishna return (state); 173b2a96221Skrishna } 174b2a96221Skrishna 175b2a96221Skrishna 1767c478bd9Sstevel@tonic-gate CK_RV 1777c478bd9Sstevel@tonic-gate C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) 1787c478bd9Sstevel@tonic-gate { 1797c478bd9Sstevel@tonic-gate kernel_session_t *session_p; 1807c478bd9Sstevel@tonic-gate CK_RV rv; 1817c478bd9Sstevel@tonic-gate boolean_t ses_lock_held = B_FALSE; 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate if (!kernel_initialized) 1847c478bd9Sstevel@tonic-gate return (CKR_CRYPTOKI_NOT_INITIALIZED); 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate if (pInfo == NULL) 1877c478bd9Sstevel@tonic-gate return (CKR_ARGUMENTS_BAD); 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate /* 1907c478bd9Sstevel@tonic-gate * Obtain the session pointer. Also, increment the session 1917c478bd9Sstevel@tonic-gate * reference count. 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate rv = handle2session(hSession, &session_p); 1947c478bd9Sstevel@tonic-gate if (rv != CKR_OK) 1957c478bd9Sstevel@tonic-gate return (rv); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* Provide information for the specified session */ 1987c478bd9Sstevel@tonic-gate pInfo->slotID = session_p->ses_slotid; 1997c478bd9Sstevel@tonic-gate pInfo->flags = session_p->flags; 2007c478bd9Sstevel@tonic-gate pInfo->ulDeviceError = 0; 201b2a96221Skrishna pInfo->state = get_ses_state(session_p); 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate /* 2047c478bd9Sstevel@tonic-gate * Decrement the session reference count. 2057c478bd9Sstevel@tonic-gate */ 2067c478bd9Sstevel@tonic-gate REFRELE(session_p, ses_lock_held); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate return (CKR_OK); 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate 211b2a96221Skrishna /* 212b2a96221Skrishna * Save the state in pOperationState. The data format is: 213b2a96221Skrishna * 1. Total length (including this field) 214b2a96221Skrishna * 2. session state 215b2a96221Skrishna * 3. crypto_active_op_t structure 216b2a96221Skrishna * 4. digest_buf_t's data buffer contents 217b2a96221Skrishna */ 218b2a96221Skrishna static CK_RV 219b2a96221Skrishna kernel_get_operationstate(kernel_session_t *session_p, CK_STATE ses_state, 220b2a96221Skrishna CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen) 221b2a96221Skrishna { 222b2a96221Skrishna int op_data_len = 0; 223b2a96221Skrishna CK_BYTE_PTR dst; 224b2a96221Skrishna digest_buf_t *bufp; 2257c478bd9Sstevel@tonic-gate 226b2a96221Skrishna if (!(session_p->digest.flags & CRYPTO_EMULATE)) { 22779127a73Skrishna /* 22879127a73Skrishna * Return CKR_OPERATION_NOT_INITIALIZED if the slot 22979127a73Skrishna * is capable of C_GetOperationState(). Return 23079127a73Skrishna * CKR_FUNCTION_NOT_SUPPORTED otherwise. 23179127a73Skrishna * 23279127a73Skrishna * We return these codes because some clients 23379127a73Skrishna * check the return code to determine if C_GetOperationState() 23479127a73Skrishna * is supported. 23579127a73Skrishna */ 23679127a73Skrishna if (slot_table[session_p->ses_slotid]->sl_flags & 23779127a73Skrishna CRYPTO_LIMITED_HASH_SUPPORT) 23879127a73Skrishna return (CKR_OPERATION_NOT_INITIALIZED); 23979127a73Skrishna else 240b2a96221Skrishna return (CKR_FUNCTION_NOT_SUPPORTED); 241b2a96221Skrishna } 242b2a96221Skrishna 243b2a96221Skrishna /* 244b2a96221Skrishna * XXX Need to support this case in future. 245*4df55fdeSJanie Lu * This is the case where we exceeded SLOT_HASH_MAX_INDATA_LEN and 246*4df55fdeSJanie Lu * hence started using libmd. SLOT_HASH_MAX_INDATA_LEN is at least 247b2a96221Skrishna * 64K for current crypto framework providers and web servers 248b2a96221Skrishna * do not need to clone digests that big for SSL operations. 249b2a96221Skrishna */ 250b2a96221Skrishna if (session_p->digest.flags & CRYPTO_EMULATE_USING_SW) { 251b2a96221Skrishna return (CKR_STATE_UNSAVEABLE); 252b2a96221Skrishna } 253b2a96221Skrishna 254b2a96221Skrishna /* Check to see if this is an unsupported operation. */ 255b2a96221Skrishna if (session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE || 256b2a96221Skrishna session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE || 257b2a96221Skrishna session_p->sign.flags & CRYPTO_OPERATION_ACTIVE || 258b2a96221Skrishna session_p->verify.flags & CRYPTO_OPERATION_ACTIVE) { 259b2a96221Skrishna return (CKR_STATE_UNSAVEABLE); 260b2a96221Skrishna } 261b2a96221Skrishna 262b2a96221Skrishna /* Check to see if digest operation is active. */ 263b2a96221Skrishna if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) { 264b2a96221Skrishna return (CKR_OPERATION_NOT_INITIALIZED); 265b2a96221Skrishna } 266b2a96221Skrishna 267b2a96221Skrishna bufp = session_p->digest.context; 268b2a96221Skrishna 269b2a96221Skrishna op_data_len = sizeof (int); 270b2a96221Skrishna op_data_len += sizeof (CK_STATE); 271b2a96221Skrishna op_data_len += sizeof (crypto_active_op_t); 272b2a96221Skrishna op_data_len += bufp->indata_len; 273b2a96221Skrishna 274b2a96221Skrishna if (pOperationState == NULL_PTR) { 275b2a96221Skrishna *pulOperationStateLen = op_data_len; 276b2a96221Skrishna return (CKR_OK); 277b2a96221Skrishna } else { 278b2a96221Skrishna if (*pulOperationStateLen < op_data_len) { 279b2a96221Skrishna *pulOperationStateLen = op_data_len; 280b2a96221Skrishna return (CKR_BUFFER_TOO_SMALL); 281b2a96221Skrishna } 282b2a96221Skrishna } 283b2a96221Skrishna 284b2a96221Skrishna dst = pOperationState; 285b2a96221Skrishna 286b2a96221Skrishna /* Save total length */ 287b2a96221Skrishna bcopy(&op_data_len, dst, sizeof (int)); 288b2a96221Skrishna dst += sizeof (int); 289b2a96221Skrishna 290b2a96221Skrishna /* Save session state */ 291b2a96221Skrishna bcopy(&ses_state, dst, sizeof (CK_STATE)); 292b2a96221Skrishna dst += sizeof (CK_STATE); 293b2a96221Skrishna 294b2a96221Skrishna /* Save crypto_active_op_t */ 295b2a96221Skrishna bcopy(&session_p->digest, dst, sizeof (crypto_active_op_t)); 296b2a96221Skrishna dst += sizeof (crypto_active_op_t); 297b2a96221Skrishna 298b2a96221Skrishna /* Save the data buffer */ 299b2a96221Skrishna bcopy(bufp->buf, dst, bufp->indata_len); 300b2a96221Skrishna 301b2a96221Skrishna *pulOperationStateLen = op_data_len; 302b2a96221Skrishna return (CKR_OK); 303b2a96221Skrishna } 304b2a96221Skrishna 3057c478bd9Sstevel@tonic-gate CK_RV 3067c478bd9Sstevel@tonic-gate C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 3077c478bd9Sstevel@tonic-gate CK_ULONG_PTR pulOperationStateLen) 3087c478bd9Sstevel@tonic-gate { 309b2a96221Skrishna CK_RV rv; 310b2a96221Skrishna CK_STATE ses_state; 311b2a96221Skrishna kernel_session_t *session_p; 312b2a96221Skrishna boolean_t ses_lock_held = B_TRUE; 313b2a96221Skrishna 3147c478bd9Sstevel@tonic-gate if (!kernel_initialized) 3157c478bd9Sstevel@tonic-gate return (CKR_CRYPTOKI_NOT_INITIALIZED); 3167c478bd9Sstevel@tonic-gate 317b2a96221Skrishna if (pulOperationStateLen == NULL_PTR) 318b2a96221Skrishna return (CKR_ARGUMENTS_BAD); 319b2a96221Skrishna 320b2a96221Skrishna /* 321b2a96221Skrishna * Obtain the session pointer. Also, increment the session 322b2a96221Skrishna * reference count. 323b2a96221Skrishna */ 324b2a96221Skrishna rv = handle2session(hSession, &session_p); 325b2a96221Skrishna if (rv != CKR_OK) 326b2a96221Skrishna return (rv); 327b2a96221Skrishna 328b2a96221Skrishna ses_state = get_ses_state(session_p); 329b2a96221Skrishna 330b2a96221Skrishna (void) pthread_mutex_lock(&session_p->session_mutex); 331b2a96221Skrishna rv = kernel_get_operationstate(session_p, ses_state, 332b2a96221Skrishna pOperationState, pulOperationStateLen); 333b2a96221Skrishna 334b2a96221Skrishna REFRELE(session_p, ses_lock_held); 335b2a96221Skrishna return (rv); 336b2a96221Skrishna } 337b2a96221Skrishna 338b2a96221Skrishna /* 339b2a96221Skrishna * Restore the state from pOperationState. The data format is: 340b2a96221Skrishna * 1. Total length (including this field) 341b2a96221Skrishna * 2. session state 342b2a96221Skrishna * 3. crypto_active_op_t structure 343b2a96221Skrishna * 4. digest_buf_t's data buffer contents 344b2a96221Skrishna */ 345b2a96221Skrishna static CK_RV 346b2a96221Skrishna kernel_set_operationstate(kernel_session_t *session_p, CK_STATE ses_state, 347b2a96221Skrishna CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, 348b2a96221Skrishna CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey) 349b2a96221Skrishna { 350b2a96221Skrishna CK_RV rv; 351b2a96221Skrishna CK_BYTE_PTR src; 352b2a96221Skrishna CK_STATE src_ses_state; 353b2a96221Skrishna int expected_len, indata_len; 354b2a96221Skrishna digest_buf_t *bufp; 355b2a96221Skrishna crypto_active_op_t tmp_op; 356b2a96221Skrishna 357b2a96221Skrishna if ((hAuthenticationKey != 0) || (hEncryptionKey != 0)) 358b2a96221Skrishna return (CKR_KEY_NOT_NEEDED); 359b2a96221Skrishna 360b2a96221Skrishna src = pOperationState; 361b2a96221Skrishna 362b2a96221Skrishna /* Get total length field */ 363b2a96221Skrishna bcopy(src, &expected_len, sizeof (int)); 364b2a96221Skrishna if (ulOperationStateLen < expected_len) 365b2a96221Skrishna return (CKR_SAVED_STATE_INVALID); 366b2a96221Skrishna 367b2a96221Skrishna /* compute the data buffer length */ 368b2a96221Skrishna indata_len = expected_len - sizeof (int) - 369b2a96221Skrishna sizeof (CK_STATE) - sizeof (crypto_active_op_t); 370*4df55fdeSJanie Lu if (indata_len > SLOT_HASH_MAX_INDATA_LEN(session_p)) 371b2a96221Skrishna return (CKR_SAVED_STATE_INVALID); 372b2a96221Skrishna src += sizeof (int); 373b2a96221Skrishna 374b2a96221Skrishna /* Get session state */ 375b2a96221Skrishna bcopy(src, &src_ses_state, sizeof (CK_STATE)); 376b2a96221Skrishna if (ses_state != src_ses_state) 377b2a96221Skrishna return (CKR_SAVED_STATE_INVALID); 378b2a96221Skrishna src += sizeof (CK_STATE); 379b2a96221Skrishna 380b2a96221Skrishna /* 381b2a96221Skrishna * Restore crypto_active_op_t. We need to use a temporary 382b2a96221Skrishna * buffer to avoid modifying the source session's buffer. 383b2a96221Skrishna */ 384b2a96221Skrishna bcopy(src, &tmp_op, sizeof (crypto_active_op_t)); 385b2a96221Skrishna if (tmp_op.flags & CRYPTO_EMULATE_USING_SW) 386b2a96221Skrishna return (CKR_SAVED_STATE_INVALID); 387b2a96221Skrishna session_p->digest.mech = tmp_op.mech; 388b2a96221Skrishna session_p->digest.flags = tmp_op.flags; 389b2a96221Skrishna src += sizeof (crypto_active_op_t); 390b2a96221Skrishna 391b2a96221Skrishna /* This routine reuses the session's existing buffer if possible */ 392b2a96221Skrishna rv = emulate_buf_init(session_p, indata_len, OP_DIGEST); 393b2a96221Skrishna if (rv != CKR_OK) 394b2a96221Skrishna return (rv); 395b2a96221Skrishna bufp = session_p->digest.context; 396b2a96221Skrishna bufp->indata_len = indata_len; 397b2a96221Skrishna 398b2a96221Skrishna /* Restore the data buffer */ 399b2a96221Skrishna bcopy(src, bufp->buf, bufp->indata_len); 400b2a96221Skrishna 401b2a96221Skrishna return (CKR_OK); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate CK_RV 4067c478bd9Sstevel@tonic-gate C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, 4077c478bd9Sstevel@tonic-gate CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, 4087c478bd9Sstevel@tonic-gate CK_OBJECT_HANDLE hAuthenticationKey) 4097c478bd9Sstevel@tonic-gate { 410b2a96221Skrishna CK_RV rv; 411b2a96221Skrishna CK_STATE ses_state; 412b2a96221Skrishna kernel_session_t *session_p; 413b2a96221Skrishna boolean_t ses_lock_held = B_TRUE; 414b2a96221Skrishna 4157c478bd9Sstevel@tonic-gate if (!kernel_initialized) 4167c478bd9Sstevel@tonic-gate return (CKR_CRYPTOKI_NOT_INITIALIZED); 4177c478bd9Sstevel@tonic-gate 418b2a96221Skrishna if ((pOperationState == NULL_PTR) || 419b2a96221Skrishna (ulOperationStateLen == 0)) 420b2a96221Skrishna return (CKR_ARGUMENTS_BAD); 421b2a96221Skrishna 422b2a96221Skrishna rv = handle2session(hSession, &session_p); 423b2a96221Skrishna if (rv != CKR_OK) 424b2a96221Skrishna return (rv); 425b2a96221Skrishna 426b2a96221Skrishna ses_state = get_ses_state(session_p); 427b2a96221Skrishna 428b2a96221Skrishna (void) pthread_mutex_lock(&session_p->session_mutex); 429b2a96221Skrishna 430b2a96221Skrishna rv = kernel_set_operationstate(session_p, ses_state, 431b2a96221Skrishna pOperationState, ulOperationStateLen, 432b2a96221Skrishna hEncryptionKey, hAuthenticationKey); 433b2a96221Skrishna 434b2a96221Skrishna REFRELE(session_p, ses_lock_held); 435b2a96221Skrishna return (rv); 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate CK_RV 4407c478bd9Sstevel@tonic-gate C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, 4417c478bd9Sstevel@tonic-gate CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) 4427c478bd9Sstevel@tonic-gate { 4437c478bd9Sstevel@tonic-gate CK_RV rv = CKR_OK; 4447c478bd9Sstevel@tonic-gate kernel_session_t *session_p; 4457c478bd9Sstevel@tonic-gate kernel_slot_t *pslot; 4467c478bd9Sstevel@tonic-gate boolean_t ses_lock_held = B_FALSE; 4477c478bd9Sstevel@tonic-gate crypto_login_t c_login; 4487c478bd9Sstevel@tonic-gate int r; 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate if (!kernel_initialized) 4517c478bd9Sstevel@tonic-gate return (CKR_CRYPTOKI_NOT_INITIALIZED); 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate if ((userType != CKU_SO) && (userType != CKU_USER)) { 4547c478bd9Sstevel@tonic-gate return (CKR_USER_TYPE_INVALID); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate /* 4587c478bd9Sstevel@tonic-gate * Obtain the session pointer. Also, increment the session 4597c478bd9Sstevel@tonic-gate * reference count. 4607c478bd9Sstevel@tonic-gate */ 4617c478bd9Sstevel@tonic-gate rv = handle2session(hSession, &session_p); 4627c478bd9Sstevel@tonic-gate if (rv != CKR_OK) 4637c478bd9Sstevel@tonic-gate return (rv); 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate /* Acquire the slot lock */ 4667c478bd9Sstevel@tonic-gate pslot = slot_table[session_p->ses_slotid]; 4677c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pslot->sl_mutex); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate /* Check if the slot is logged in already */ 4707c478bd9Sstevel@tonic-gate if ((pslot->sl_state == CKU_USER) || (pslot->sl_state == CKU_SO)) { 4717c478bd9Sstevel@tonic-gate rv = CKR_USER_ALREADY_LOGGED_IN; 4727c478bd9Sstevel@tonic-gate goto clean_exit; 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate /* To login as SO, every session in this slot needs to be R/W */ 4767c478bd9Sstevel@tonic-gate if (userType == CKU_SO) { 4777c478bd9Sstevel@tonic-gate kernel_session_t *sp; 4787c478bd9Sstevel@tonic-gate boolean_t found; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate found = B_FALSE; 4817c478bd9Sstevel@tonic-gate sp = pslot->sl_sess_list; 4827c478bd9Sstevel@tonic-gate while (sp) { 4837c478bd9Sstevel@tonic-gate /* 4847c478bd9Sstevel@tonic-gate * Need not to lock individual sessions before 4857c478bd9Sstevel@tonic-gate * accessing their "ses_RO" and "next" fields, 4867c478bd9Sstevel@tonic-gate * because they are always accessed under the 4877c478bd9Sstevel@tonic-gate * slot's mutex protection. 4887c478bd9Sstevel@tonic-gate */ 4897c478bd9Sstevel@tonic-gate if (sp->ses_RO) { 4907c478bd9Sstevel@tonic-gate found = B_TRUE; 4917c478bd9Sstevel@tonic-gate break; 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate sp = sp->next; 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate if (found) { 4977c478bd9Sstevel@tonic-gate rv = CKR_SESSION_READ_ONLY_EXISTS; 4987c478bd9Sstevel@tonic-gate goto clean_exit; 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate /* Now make the ioctl call; no need to acquire the session lock. */ 5037c478bd9Sstevel@tonic-gate c_login.co_session = session_p->k_session; 5047c478bd9Sstevel@tonic-gate c_login.co_user_type = userType; 5057c478bd9Sstevel@tonic-gate c_login.co_pin_len = ulPinLen; 5067c478bd9Sstevel@tonic-gate c_login.co_pin = (char *)pPin; 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate while ((r = ioctl(kernel_fd, CRYPTO_LOGIN, &c_login)) < 0) { 5097c478bd9Sstevel@tonic-gate if (errno != EINTR) 5107c478bd9Sstevel@tonic-gate break; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate if (r < 0) { 5137c478bd9Sstevel@tonic-gate rv = CKR_FUNCTION_FAILED; 5147c478bd9Sstevel@tonic-gate } else { 5157c478bd9Sstevel@tonic-gate rv = crypto2pkcs11_error_number(c_login.co_return_value); 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate if (rv == CKR_OK) { 5197c478bd9Sstevel@tonic-gate /* Set the slot's session state. */ 5207c478bd9Sstevel@tonic-gate pslot->sl_state = userType; 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate clean_exit: 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate REFRELE(session_p, ses_lock_held); 5267c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pslot->sl_mutex); 5277c478bd9Sstevel@tonic-gate return (rv); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate CK_RV 5327c478bd9Sstevel@tonic-gate C_Logout(CK_SESSION_HANDLE hSession) 5337c478bd9Sstevel@tonic-gate { 5347c478bd9Sstevel@tonic-gate CK_RV rv = CKR_OK; 5357c478bd9Sstevel@tonic-gate kernel_session_t *session_p; 5367c478bd9Sstevel@tonic-gate kernel_slot_t *pslot; 5377c478bd9Sstevel@tonic-gate boolean_t ses_lock_held = B_FALSE; 5387c478bd9Sstevel@tonic-gate crypto_logout_t c_logout; 5397c478bd9Sstevel@tonic-gate int r; 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate if (!kernel_initialized) 5427c478bd9Sstevel@tonic-gate return (CKR_CRYPTOKI_NOT_INITIALIZED); 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate /* 5457c478bd9Sstevel@tonic-gate * Obtain the session pointer. Also, increment the session 5467c478bd9Sstevel@tonic-gate * reference count. 5477c478bd9Sstevel@tonic-gate */ 5487c478bd9Sstevel@tonic-gate rv = handle2session(hSession, &session_p); 5497c478bd9Sstevel@tonic-gate if (rv != CKR_OK) 5507c478bd9Sstevel@tonic-gate return (rv); 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate /* Acquire the slot lock. */ 5537c478bd9Sstevel@tonic-gate pslot = slot_table[session_p->ses_slotid]; 5547c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pslot->sl_mutex); 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate /* Check if the user or SO was logged in */ 5577c478bd9Sstevel@tonic-gate if (pslot->sl_state == CKU_PUBLIC) { 5587c478bd9Sstevel@tonic-gate rv = CKR_USER_NOT_LOGGED_IN; 5597c478bd9Sstevel@tonic-gate goto clean_exit; 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate /* Now make the ioctl call. No need to acquire the session lock. */ 5637c478bd9Sstevel@tonic-gate c_logout.cl_session = session_p->k_session; 5647c478bd9Sstevel@tonic-gate while ((r = ioctl(kernel_fd, CRYPTO_LOGOUT, &c_logout)) < 0) { 5657c478bd9Sstevel@tonic-gate if (errno != EINTR) 5667c478bd9Sstevel@tonic-gate break; 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate if (r < 0) { 5697c478bd9Sstevel@tonic-gate rv = CKR_FUNCTION_FAILED; 5707c478bd9Sstevel@tonic-gate } else { 5717c478bd9Sstevel@tonic-gate rv = crypto2pkcs11_error_number(c_logout.cl_return_value); 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate if (rv != CKR_OK) { 5757c478bd9Sstevel@tonic-gate goto clean_exit; 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate /* 5797c478bd9Sstevel@tonic-gate * If this slot was logged in as USER previously, we need to clean up 5807c478bd9Sstevel@tonic-gate * all private object wrappers in library for this slot. 5817c478bd9Sstevel@tonic-gate */ 5827c478bd9Sstevel@tonic-gate kernel_cleanup_pri_objects_in_slot(pslot, session_p); 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate if (rv == CKR_OK) { 5857c478bd9Sstevel@tonic-gate /* Reset the slot's session state. */ 5867c478bd9Sstevel@tonic-gate pslot->sl_state = CKU_PUBLIC; 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate clean_exit: 5907c478bd9Sstevel@tonic-gate REFRELE(session_p, ses_lock_held); 5917c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pslot->sl_mutex); 5927c478bd9Sstevel@tonic-gate return (rv); 5937c478bd9Sstevel@tonic-gate } 594