xref: /onnv-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelSession.c (revision 11304:3092d1e303d6)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55616Skrishna  * Common Development and Distribution License (the "License").
65616Skrishna  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11304SJanie.Lu@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <pthread.h>
270Sstevel@tonic-gate #include <errno.h>
280Sstevel@tonic-gate #include <security/cryptoki.h>
290Sstevel@tonic-gate #include <sys/crypto/ioctl.h>
300Sstevel@tonic-gate #include "kernelGlobal.h"
310Sstevel@tonic-gate #include "kernelSession.h"
320Sstevel@tonic-gate #include "kernelSlot.h"
335616Skrishna #include "kernelEmulate.h"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate CK_RV
C_OpenSession(CK_SLOT_ID slotID,CK_FLAGS flags,CK_VOID_PTR pApplication,CK_NOTIFY Notify,CK_SESSION_HANDLE_PTR phSession)360Sstevel@tonic-gate C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication,
370Sstevel@tonic-gate     CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession)
380Sstevel@tonic-gate {
390Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
400Sstevel@tonic-gate 	kernel_slot_t	*pslot;
410Sstevel@tonic-gate 
420Sstevel@tonic-gate 	if (!kernel_initialized)
430Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
440Sstevel@tonic-gate 
450Sstevel@tonic-gate 	/*
460Sstevel@tonic-gate 	 * For legacy reasons, the CKF_SERIAL_SESSION bit must always
470Sstevel@tonic-gate 	 * be set.
480Sstevel@tonic-gate 	 */
490Sstevel@tonic-gate 	if (!(flags & CKF_SERIAL_SESSION))
500Sstevel@tonic-gate 		return (CKR_SESSION_PARALLEL_NOT_SUPPORTED);
510Sstevel@tonic-gate 
520Sstevel@tonic-gate 	if (phSession == NULL)
530Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
540Sstevel@tonic-gate 
550Sstevel@tonic-gate 	if (slotID >= slot_count) {
560Sstevel@tonic-gate 		return (CKR_SLOT_ID_INVALID);
570Sstevel@tonic-gate 	}
580Sstevel@tonic-gate 
590Sstevel@tonic-gate 	/*
600Sstevel@tonic-gate 	 * Acquire the slot lock to protect sl_state and sl_sess_list.
610Sstevel@tonic-gate 	 * These two fields need to be protected atomically, even though
620Sstevel@tonic-gate 	 * "sl_sess_list" is updated in kernel_add_session().
630Sstevel@tonic-gate 	 */
640Sstevel@tonic-gate 	pslot = slot_table[slotID];
650Sstevel@tonic-gate 	(void) pthread_mutex_lock(&pslot->sl_mutex);
660Sstevel@tonic-gate 
670Sstevel@tonic-gate 	/* If SO is logged in the slot, only the RW session is allowed. */
680Sstevel@tonic-gate 	if ((pslot->sl_state == CKU_SO) && !(flags & CKF_RW_SESSION)) {
690Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
700Sstevel@tonic-gate 		return (CKR_SESSION_READ_WRITE_SO_EXISTS);
710Sstevel@tonic-gate 	}
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 	/* Create a new session */
740Sstevel@tonic-gate 	rv = kernel_add_session(slotID, flags, pApplication, Notify,
750Sstevel@tonic-gate 	    phSession);
760Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
770Sstevel@tonic-gate 	return (rv);
780Sstevel@tonic-gate }
790Sstevel@tonic-gate 
800Sstevel@tonic-gate CK_RV
C_CloseSession(CK_SESSION_HANDLE hSession)810Sstevel@tonic-gate C_CloseSession(CK_SESSION_HANDLE hSession)
820Sstevel@tonic-gate {
830Sstevel@tonic-gate 	CK_RV rv;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 	kernel_session_t *session_p;
860Sstevel@tonic-gate 	boolean_t ses_lock_held = B_FALSE;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	if (!kernel_initialized)
890Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	/*
920Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
930Sstevel@tonic-gate 	 * reference count.
940Sstevel@tonic-gate 	 */
950Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
960Sstevel@tonic-gate 	if (rv != CKR_OK)
970Sstevel@tonic-gate 		return (rv);
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
1000Sstevel@tonic-gate 	ses_lock_held = B_TRUE;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	/*
1030Sstevel@tonic-gate 	 * Set SESSION_IS_CLOSING flag so any access to this
1040Sstevel@tonic-gate 	 * session will be rejected.
1050Sstevel@tonic-gate 	 */
106214Smcpowers 	if (session_p->ses_close_sync & SESSION_IS_CLOSING) {
107214Smcpowers 		REFRELE(session_p, ses_lock_held);
108214Smcpowers 		return (CKR_SESSION_CLOSED);
109214Smcpowers 	}
1100Sstevel@tonic-gate 	session_p->ses_close_sync |= SESSION_IS_CLOSING;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	/*
1130Sstevel@tonic-gate 	 * Decrement the session reference count.
1140Sstevel@tonic-gate 	 * We hold the session lock, and REFRELE()
1150Sstevel@tonic-gate 	 * will release the session lock for us.
1160Sstevel@tonic-gate 	 */
1170Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	/*
1200Sstevel@tonic-gate 	 * Delete a session by calling kernel_delete_session() with
1210Sstevel@tonic-gate 	 * a session pointer and two boolean arguments. The 3rd argument
1220Sstevel@tonic-gate 	 * boolean value FALSE indicates that the caller does not
1230Sstevel@tonic-gate 	 * hold the slot lock.  The 4th argument boolean value B_FALSE
1240Sstevel@tonic-gate 	 * indicates that we want to delete all the objects completely.
1250Sstevel@tonic-gate 	 *
1260Sstevel@tonic-gate 	 * kernel_delete_session() will reset SESSION_IS_CLOSING
1270Sstevel@tonic-gate 	 * flag after it is done.
1280Sstevel@tonic-gate 	 */
129214Smcpowers 	kernel_delete_session(session_p->ses_slotid, session_p, B_FALSE,
1300Sstevel@tonic-gate 	    B_FALSE);
1310Sstevel@tonic-gate 	return (rv);
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate CK_RV
C_CloseAllSessions(CK_SLOT_ID slotID)1360Sstevel@tonic-gate C_CloseAllSessions(CK_SLOT_ID slotID)
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate 	if (!kernel_initialized)
1390Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	/* Delete all the sessions and release the allocated resources */
142214Smcpowers 	kernel_delete_all_sessions(slotID, B_FALSE);
1430Sstevel@tonic-gate 
144214Smcpowers 	return (CKR_OK);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate 
1475616Skrishna /*
1485616Skrishna  * Utility routine to get CK_STATE value for a session.
1495616Skrishna  * The caller should not be holding the session lock.
1505616Skrishna  */
1515616Skrishna static CK_STATE
get_ses_state(kernel_session_t * session_p)1525616Skrishna get_ses_state(kernel_session_t *session_p)
1535616Skrishna {
1545616Skrishna 	CK_STATE state;
1555616Skrishna 	kernel_slot_t *pslot;
1565616Skrishna 
1575616Skrishna 	pslot = slot_table[session_p->ses_slotid];
1585616Skrishna 	(void) pthread_mutex_lock(&pslot->sl_mutex);
1595616Skrishna 
1605616Skrishna 	if (pslot->sl_state == CKU_PUBLIC) {
1615616Skrishna 		state = (session_p->ses_RO) ?
1625616Skrishna 		    CKS_RO_PUBLIC_SESSION : CKS_RW_PUBLIC_SESSION;
1635616Skrishna 	} else if (pslot->sl_state == CKU_USER) {
1645616Skrishna 		state = (session_p->ses_RO) ?
1655616Skrishna 		    CKS_RO_USER_FUNCTIONS : CKS_RW_USER_FUNCTIONS;
1665616Skrishna 	} else if (pslot->sl_state == CKU_SO) {
1675616Skrishna 		state = CKS_RW_SO_FUNCTIONS;
1685616Skrishna 	}
1695616Skrishna 
1705616Skrishna 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
1715616Skrishna 
1725616Skrishna 	return (state);
1735616Skrishna }
1745616Skrishna 
1755616Skrishna 
1760Sstevel@tonic-gate CK_RV
C_GetSessionInfo(CK_SESSION_HANDLE hSession,CK_SESSION_INFO_PTR pInfo)1770Sstevel@tonic-gate C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo)
1780Sstevel@tonic-gate {
1790Sstevel@tonic-gate 	kernel_session_t *session_p;
1800Sstevel@tonic-gate 	CK_RV rv;
1810Sstevel@tonic-gate 	boolean_t ses_lock_held = B_FALSE;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	if (!kernel_initialized)
1840Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	if (pInfo == NULL)
1870Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	/*
1900Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
1910Sstevel@tonic-gate 	 * reference count.
1920Sstevel@tonic-gate 	 */
1930Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
1940Sstevel@tonic-gate 	if (rv != CKR_OK)
1950Sstevel@tonic-gate 		return (rv);
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	/* Provide information for the specified session */
1980Sstevel@tonic-gate 	pInfo->slotID = session_p->ses_slotid;
1990Sstevel@tonic-gate 	pInfo->flags = session_p->flags;
2000Sstevel@tonic-gate 	pInfo->ulDeviceError = 0;
2015616Skrishna 	pInfo->state = get_ses_state(session_p);
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	/*
2040Sstevel@tonic-gate 	 * Decrement the session reference count.
2050Sstevel@tonic-gate 	 */
2060Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	return (CKR_OK);
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate 
2115616Skrishna /*
2125616Skrishna  * Save the state in pOperationState. The data format is:
2135616Skrishna  * 1. Total length (including this field)
2145616Skrishna  * 2. session state
2155616Skrishna  * 3. crypto_active_op_t structure
2165616Skrishna  * 4. digest_buf_t's data buffer contents
2175616Skrishna  */
2185616Skrishna static CK_RV
kernel_get_operationstate(kernel_session_t * session_p,CK_STATE ses_state,CK_BYTE_PTR pOperationState,CK_ULONG_PTR pulOperationStateLen)2195616Skrishna kernel_get_operationstate(kernel_session_t *session_p, CK_STATE ses_state,
2205616Skrishna     CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen)
2215616Skrishna {
2225616Skrishna 	int op_data_len = 0;
2235616Skrishna 	CK_BYTE_PTR dst;
2245616Skrishna 	digest_buf_t *bufp;
2250Sstevel@tonic-gate 
2265616Skrishna 	if (!(session_p->digest.flags & CRYPTO_EMULATE)) {
2277076Skrishna 		/*
2287076Skrishna 		 * Return CKR_OPERATION_NOT_INITIALIZED if the slot
2297076Skrishna 		 * is capable of C_GetOperationState(). Return
2307076Skrishna 		 * CKR_FUNCTION_NOT_SUPPORTED otherwise.
2317076Skrishna 		 *
2327076Skrishna 		 * We return these codes because some clients
2337076Skrishna 		 * check the return code to determine if C_GetOperationState()
2347076Skrishna 		 * is supported.
2357076Skrishna 		 */
2367076Skrishna 		if (slot_table[session_p->ses_slotid]->sl_flags &
2377076Skrishna 		    CRYPTO_LIMITED_HASH_SUPPORT)
2387076Skrishna 			return (CKR_OPERATION_NOT_INITIALIZED);
2397076Skrishna 		else
2407076Skrishna 			return (CKR_FUNCTION_NOT_SUPPORTED);
2415616Skrishna 	}
2425616Skrishna 
2435616Skrishna 	/*
2445616Skrishna 	 * XXX Need to support this case in future.
245*11304SJanie.Lu@Sun.COM 	 * This is the case where we exceeded SLOT_HASH_MAX_INDATA_LEN and
246*11304SJanie.Lu@Sun.COM 	 * hence started using libmd. SLOT_HASH_MAX_INDATA_LEN is at least
2475616Skrishna 	 * 64K for current crypto framework providers and web servers
2485616Skrishna 	 * do not need to clone digests that big for SSL operations.
2495616Skrishna 	 */
2505616Skrishna 	if (session_p->digest.flags & CRYPTO_EMULATE_USING_SW) {
2515616Skrishna 		return (CKR_STATE_UNSAVEABLE);
2525616Skrishna 	}
2535616Skrishna 
2545616Skrishna 	/* Check to see if this is an unsupported operation. */
2555616Skrishna 	if (session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE ||
2565616Skrishna 	    session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE ||
2575616Skrishna 	    session_p->sign.flags & CRYPTO_OPERATION_ACTIVE ||
2585616Skrishna 	    session_p->verify.flags & CRYPTO_OPERATION_ACTIVE) {
2595616Skrishna 		return (CKR_STATE_UNSAVEABLE);
2605616Skrishna 	}
2615616Skrishna 
2625616Skrishna 	/* Check to see if digest operation is active. */
2635616Skrishna 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
2645616Skrishna 		return (CKR_OPERATION_NOT_INITIALIZED);
2655616Skrishna 	}
2665616Skrishna 
2675616Skrishna 	bufp = session_p->digest.context;
2685616Skrishna 
2695616Skrishna 	op_data_len =  sizeof (int);
2705616Skrishna 	op_data_len +=  sizeof (CK_STATE);
2715616Skrishna 	op_data_len += sizeof (crypto_active_op_t);
2725616Skrishna 	op_data_len += bufp->indata_len;
2735616Skrishna 
2745616Skrishna 	if (pOperationState == NULL_PTR) {
2755616Skrishna 		*pulOperationStateLen = op_data_len;
2765616Skrishna 		return (CKR_OK);
2775616Skrishna 	} else {
2785616Skrishna 		if (*pulOperationStateLen < op_data_len) {
2795616Skrishna 			*pulOperationStateLen = op_data_len;
2805616Skrishna 			return (CKR_BUFFER_TOO_SMALL);
2815616Skrishna 		}
2825616Skrishna 	}
2835616Skrishna 
2845616Skrishna 	dst = pOperationState;
2855616Skrishna 
2865616Skrishna 	/* Save total length */
2875616Skrishna 	bcopy(&op_data_len, dst, sizeof (int));
2885616Skrishna 	dst += sizeof (int);
2895616Skrishna 
2905616Skrishna 	/* Save session state */
2915616Skrishna 	bcopy(&ses_state, dst, sizeof (CK_STATE));
2925616Skrishna 	dst += sizeof (CK_STATE);
2935616Skrishna 
2945616Skrishna 	/* Save crypto_active_op_t */
2955616Skrishna 	bcopy(&session_p->digest, dst, sizeof (crypto_active_op_t));
2965616Skrishna 	dst += sizeof (crypto_active_op_t);
2975616Skrishna 
2985616Skrishna 	/* Save the data buffer */
2995616Skrishna 	bcopy(bufp->buf, dst, bufp->indata_len);
3005616Skrishna 
3015616Skrishna 	*pulOperationStateLen = op_data_len;
3025616Skrishna 	return (CKR_OK);
3035616Skrishna }
3045616Skrishna 
3050Sstevel@tonic-gate CK_RV
C_GetOperationState(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pOperationState,CK_ULONG_PTR pulOperationStateLen)3060Sstevel@tonic-gate C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
3070Sstevel@tonic-gate     CK_ULONG_PTR pulOperationStateLen)
3080Sstevel@tonic-gate {
3095616Skrishna 	CK_RV rv;
3105616Skrishna 	CK_STATE ses_state;
3115616Skrishna 	kernel_session_t *session_p;
3125616Skrishna 	boolean_t ses_lock_held = B_TRUE;
3135616Skrishna 
3140Sstevel@tonic-gate 	if (!kernel_initialized)
3150Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
3160Sstevel@tonic-gate 
3175616Skrishna 	if (pulOperationStateLen == NULL_PTR)
3185616Skrishna 		return (CKR_ARGUMENTS_BAD);
3195616Skrishna 
3205616Skrishna 	/*
3215616Skrishna 	 * Obtain the session pointer. Also, increment the session
3225616Skrishna 	 * reference count.
3235616Skrishna 	 */
3245616Skrishna 	rv = handle2session(hSession, &session_p);
3255616Skrishna 	if (rv != CKR_OK)
3265616Skrishna 		return (rv);
3275616Skrishna 
3285616Skrishna 	ses_state = get_ses_state(session_p);
3295616Skrishna 
3305616Skrishna 	(void) pthread_mutex_lock(&session_p->session_mutex);
3315616Skrishna 	rv = kernel_get_operationstate(session_p, ses_state,
3325616Skrishna 	    pOperationState, pulOperationStateLen);
3335616Skrishna 
3345616Skrishna 	REFRELE(session_p, ses_lock_held);
3355616Skrishna 	return (rv);
3365616Skrishna }
3375616Skrishna 
3385616Skrishna /*
3395616Skrishna  * Restore the state from pOperationState. The data format is:
3405616Skrishna  * 1. Total length (including this field)
3415616Skrishna  * 2. session state
3425616Skrishna  * 3. crypto_active_op_t structure
3435616Skrishna  * 4. digest_buf_t's data buffer contents
3445616Skrishna  */
3455616Skrishna static CK_RV
kernel_set_operationstate(kernel_session_t * session_p,CK_STATE ses_state,CK_BYTE_PTR pOperationState,CK_ULONG ulOperationStateLen,CK_OBJECT_HANDLE hEncryptionKey,CK_OBJECT_HANDLE hAuthenticationKey)3465616Skrishna kernel_set_operationstate(kernel_session_t *session_p, CK_STATE ses_state,
3475616Skrishna     CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen,
3485616Skrishna     CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey)
3495616Skrishna {
3505616Skrishna 	CK_RV rv;
3515616Skrishna 	CK_BYTE_PTR src;
3525616Skrishna 	CK_STATE src_ses_state;
3535616Skrishna 	int expected_len, indata_len;
3545616Skrishna 	digest_buf_t *bufp;
3555616Skrishna 	crypto_active_op_t tmp_op;
3565616Skrishna 
3575616Skrishna 	if ((hAuthenticationKey != 0) || (hEncryptionKey != 0))
3585616Skrishna 		return (CKR_KEY_NOT_NEEDED);
3595616Skrishna 
3605616Skrishna 	src = pOperationState;
3615616Skrishna 
3625616Skrishna 	/* Get total length field */
3635616Skrishna 	bcopy(src, &expected_len, sizeof (int));
3645616Skrishna 	if (ulOperationStateLen < expected_len)
3655616Skrishna 		return (CKR_SAVED_STATE_INVALID);
3665616Skrishna 
3675616Skrishna 	/* compute the data buffer length */
3685616Skrishna 	indata_len = expected_len - sizeof (int) -
3695616Skrishna 	    sizeof (CK_STATE) - sizeof (crypto_active_op_t);
370*11304SJanie.Lu@Sun.COM 	if (indata_len > SLOT_HASH_MAX_INDATA_LEN(session_p))
3715616Skrishna 		return (CKR_SAVED_STATE_INVALID);
3725616Skrishna 	src += sizeof (int);
3735616Skrishna 
3745616Skrishna 	/* Get session state */
3755616Skrishna 	bcopy(src, &src_ses_state, sizeof (CK_STATE));
3765616Skrishna 	if (ses_state != src_ses_state)
3775616Skrishna 		return (CKR_SAVED_STATE_INVALID);
3785616Skrishna 	src += sizeof (CK_STATE);
3795616Skrishna 
3805616Skrishna 	/*
3815616Skrishna 	 * Restore crypto_active_op_t. We need to use a temporary
3825616Skrishna 	 * buffer to avoid modifying the source session's buffer.
3835616Skrishna 	 */
3845616Skrishna 	bcopy(src, &tmp_op, sizeof (crypto_active_op_t));
3855616Skrishna 	if (tmp_op.flags & CRYPTO_EMULATE_USING_SW)
3865616Skrishna 		return (CKR_SAVED_STATE_INVALID);
3875616Skrishna 	session_p->digest.mech = tmp_op.mech;
3885616Skrishna 	session_p->digest.flags = tmp_op.flags;
3895616Skrishna 	src += sizeof (crypto_active_op_t);
3905616Skrishna 
3915616Skrishna 	/* This routine reuses the session's existing buffer if possible */
3925616Skrishna 	rv = emulate_buf_init(session_p, indata_len, OP_DIGEST);
3935616Skrishna 	if (rv != CKR_OK)
3945616Skrishna 		return (rv);
3955616Skrishna 	bufp = session_p->digest.context;
3965616Skrishna 	bufp->indata_len = indata_len;
3975616Skrishna 
3985616Skrishna 	/* Restore the data buffer */
3995616Skrishna 	bcopy(src, bufp->buf, bufp->indata_len);
4005616Skrishna 
4015616Skrishna 	return (CKR_OK);
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate CK_RV
C_SetOperationState(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pOperationState,CK_ULONG ulOperationStateLen,CK_OBJECT_HANDLE hEncryptionKey,CK_OBJECT_HANDLE hAuthenticationKey)4060Sstevel@tonic-gate C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
4070Sstevel@tonic-gate     CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey,
4080Sstevel@tonic-gate     CK_OBJECT_HANDLE hAuthenticationKey)
4090Sstevel@tonic-gate {
4105616Skrishna 	CK_RV rv;
4115616Skrishna 	CK_STATE ses_state;
4125616Skrishna 	kernel_session_t *session_p;
4135616Skrishna 	boolean_t ses_lock_held = B_TRUE;
4145616Skrishna 
4150Sstevel@tonic-gate 	if (!kernel_initialized)
4160Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
4170Sstevel@tonic-gate 
4185616Skrishna 	if ((pOperationState == NULL_PTR) ||
4195616Skrishna 	    (ulOperationStateLen == 0))
4205616Skrishna 		return (CKR_ARGUMENTS_BAD);
4215616Skrishna 
4225616Skrishna 	rv = handle2session(hSession, &session_p);
4235616Skrishna 	if (rv != CKR_OK)
4245616Skrishna 		return (rv);
4255616Skrishna 
4265616Skrishna 	ses_state = get_ses_state(session_p);
4275616Skrishna 
4285616Skrishna 	(void) pthread_mutex_lock(&session_p->session_mutex);
4295616Skrishna 
4305616Skrishna 	rv = kernel_set_operationstate(session_p, ses_state,
4315616Skrishna 	    pOperationState, ulOperationStateLen,
4325616Skrishna 	    hEncryptionKey, hAuthenticationKey);
4335616Skrishna 
4345616Skrishna 	REFRELE(session_p, ses_lock_held);
4355616Skrishna 	return (rv);
4360Sstevel@tonic-gate }
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate CK_RV
C_Login(CK_SESSION_HANDLE hSession,CK_USER_TYPE userType,CK_UTF8CHAR_PTR pPin,CK_ULONG ulPinLen)4400Sstevel@tonic-gate C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
4410Sstevel@tonic-gate     CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
4420Sstevel@tonic-gate {
4430Sstevel@tonic-gate 	CK_RV	rv = CKR_OK;
4440Sstevel@tonic-gate 	kernel_session_t *session_p;
4450Sstevel@tonic-gate 	kernel_slot_t	*pslot;
4460Sstevel@tonic-gate 	boolean_t ses_lock_held = B_FALSE;
4470Sstevel@tonic-gate 	crypto_login_t  c_login;
4480Sstevel@tonic-gate 	int r;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	if (!kernel_initialized)
4510Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	if ((userType != CKU_SO) && (userType != CKU_USER)) {
4540Sstevel@tonic-gate 		return (CKR_USER_TYPE_INVALID);
4550Sstevel@tonic-gate 	}
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	/*
4580Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
4590Sstevel@tonic-gate 	 * reference count.
4600Sstevel@tonic-gate 	 */
4610Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
4620Sstevel@tonic-gate 	if (rv != CKR_OK)
4630Sstevel@tonic-gate 		return (rv);
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	/* Acquire the slot lock */
4660Sstevel@tonic-gate 	pslot = slot_table[session_p->ses_slotid];
4670Sstevel@tonic-gate 	(void) pthread_mutex_lock(&pslot->sl_mutex);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	/* Check if the slot is logged in already */
4700Sstevel@tonic-gate 	if ((pslot->sl_state == CKU_USER) || (pslot->sl_state == CKU_SO)) {
4710Sstevel@tonic-gate 		rv = CKR_USER_ALREADY_LOGGED_IN;
4720Sstevel@tonic-gate 		goto clean_exit;
4730Sstevel@tonic-gate 	}
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	/* To login as SO, every session in this slot needs to be R/W */
4760Sstevel@tonic-gate 	if (userType == CKU_SO) {
4770Sstevel@tonic-gate 		kernel_session_t  *sp;
4780Sstevel@tonic-gate 		boolean_t	found;
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 		found = B_FALSE;
4810Sstevel@tonic-gate 		sp = pslot->sl_sess_list;
4820Sstevel@tonic-gate 		while (sp) {
4830Sstevel@tonic-gate 			/*
4840Sstevel@tonic-gate 			 * Need not to lock individual sessions before
4850Sstevel@tonic-gate 			 * accessing their "ses_RO" and "next" fields,
4860Sstevel@tonic-gate 			 * because they are always accessed under the
4870Sstevel@tonic-gate 			 * slot's mutex protection.
4880Sstevel@tonic-gate 			 */
4890Sstevel@tonic-gate 			if (sp->ses_RO) {
4900Sstevel@tonic-gate 				found = B_TRUE;
4910Sstevel@tonic-gate 				break;
4920Sstevel@tonic-gate 			}
4930Sstevel@tonic-gate 			sp = sp->next;
4940Sstevel@tonic-gate 		}
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 		if (found) {
4970Sstevel@tonic-gate 			rv = CKR_SESSION_READ_ONLY_EXISTS;
4980Sstevel@tonic-gate 			goto clean_exit;
4990Sstevel@tonic-gate 		}
5000Sstevel@tonic-gate 	}
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	/* Now make the ioctl call; no need to acquire the session lock. */
5030Sstevel@tonic-gate 	c_login.co_session = session_p->k_session;
5040Sstevel@tonic-gate 	c_login.co_user_type = userType;
5050Sstevel@tonic-gate 	c_login.co_pin_len = ulPinLen;
5060Sstevel@tonic-gate 	c_login.co_pin = (char *)pPin;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_LOGIN, &c_login)) < 0) {
5090Sstevel@tonic-gate 		if (errno != EINTR)
5100Sstevel@tonic-gate 			break;
5110Sstevel@tonic-gate 	}
5120Sstevel@tonic-gate 	if (r < 0) {
5130Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
5140Sstevel@tonic-gate 	} else {
5150Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(c_login.co_return_value);
5160Sstevel@tonic-gate 	}
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	if (rv == CKR_OK) {
5190Sstevel@tonic-gate 		/* Set the slot's session state. */
5200Sstevel@tonic-gate 		pslot->sl_state = userType;
5210Sstevel@tonic-gate 	}
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate clean_exit:
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
5260Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
5270Sstevel@tonic-gate 	return (rv);
5280Sstevel@tonic-gate }
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate CK_RV
C_Logout(CK_SESSION_HANDLE hSession)5320Sstevel@tonic-gate C_Logout(CK_SESSION_HANDLE hSession)
5330Sstevel@tonic-gate {
5340Sstevel@tonic-gate 	CK_RV	rv = CKR_OK;
5350Sstevel@tonic-gate 	kernel_session_t *session_p;
5360Sstevel@tonic-gate 	kernel_slot_t	*pslot;
5370Sstevel@tonic-gate 	boolean_t ses_lock_held = B_FALSE;
5380Sstevel@tonic-gate 	crypto_logout_t  c_logout;
5390Sstevel@tonic-gate 	int r;
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	if (!kernel_initialized)
5420Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	/*
5450Sstevel@tonic-gate 	 * Obtain the session pointer. Also, increment the session
5460Sstevel@tonic-gate 	 * reference count.
5470Sstevel@tonic-gate 	 */
5480Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
5490Sstevel@tonic-gate 	if (rv != CKR_OK)
5500Sstevel@tonic-gate 		return (rv);
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	/* Acquire the slot lock. */
5530Sstevel@tonic-gate 	pslot = slot_table[session_p->ses_slotid];
5540Sstevel@tonic-gate 	(void) pthread_mutex_lock(&pslot->sl_mutex);
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	/* Check if the user or SO was logged in  */
5570Sstevel@tonic-gate 	if (pslot->sl_state == CKU_PUBLIC) {
5580Sstevel@tonic-gate 		rv = CKR_USER_NOT_LOGGED_IN;
5590Sstevel@tonic-gate 		goto clean_exit;
5600Sstevel@tonic-gate 	}
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	/* Now make the ioctl call. No need to acquire the session lock. */
5630Sstevel@tonic-gate 	c_logout.cl_session = session_p->k_session;
5640Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_LOGOUT, &c_logout)) < 0) {
5650Sstevel@tonic-gate 		if (errno != EINTR)
5660Sstevel@tonic-gate 			break;
5670Sstevel@tonic-gate 	}
5680Sstevel@tonic-gate 	if (r < 0) {
5690Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
5700Sstevel@tonic-gate 	} else {
5710Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(c_logout.cl_return_value);
5720Sstevel@tonic-gate 	}
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	if (rv != CKR_OK) {
5750Sstevel@tonic-gate 		goto clean_exit;
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	/*
5790Sstevel@tonic-gate 	 * If this slot was logged in as USER previously, we need to clean up
5800Sstevel@tonic-gate 	 * all private object wrappers in library for this slot.
5810Sstevel@tonic-gate 	 */
5820Sstevel@tonic-gate 	kernel_cleanup_pri_objects_in_slot(pslot, session_p);
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	if (rv == CKR_OK) {
5850Sstevel@tonic-gate 		/* Reset the slot's session state. */
5860Sstevel@tonic-gate 		pslot->sl_state = CKU_PUBLIC;
5870Sstevel@tonic-gate 	}
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate clean_exit:
5900Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
5910Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
5920Sstevel@tonic-gate 	return (rv);
5930Sstevel@tonic-gate }
594