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
C_OpenSession(CK_SLOT_ID slotID,CK_FLAGS flags,CK_VOID_PTR pApplication,CK_NOTIFY Notify,CK_SESSION_HANDLE_PTR phSession)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
C_CloseSession(CK_SESSION_HANDLE hSession)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
C_CloseAllSessions(CK_SLOT_ID slotID)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
get_ses_state(kernel_session_t * session_p)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
C_GetSessionInfo(CK_SESSION_HANDLE hSession,CK_SESSION_INFO_PTR pInfo)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
kernel_get_operationstate(kernel_session_t * session_p,CK_STATE ses_state,CK_BYTE_PTR pOperationState,CK_ULONG_PTR pulOperationStateLen)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;
225b2a96221Skrishna 
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
24079127a73Skrishna 			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 }
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate CK_RV
C_GetOperationState(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pOperationState,CK_ULONG_PTR pulOperationStateLen)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
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)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
C_SetOperationState(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pOperationState,CK_ULONG ulOperationStateLen,CK_OBJECT_HANDLE hEncryptionKey,CK_OBJECT_HANDLE hAuthenticationKey)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
C_Login(CK_SESSION_HANDLE hSession,CK_USER_TYPE userType,CK_UTF8CHAR_PTR pPin,CK_ULONG ulPinLen)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
C_Logout(CK_SESSION_HANDLE hSession)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