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
5f243d98aSkrishna  * Common Development and Distribution License (the "License").
6f243d98aSkrishna  * 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 /*
22d288ba74SAnthony Scarpino  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*cfcec266SJason King  *
25*cfcec266SJason King  * Copyright 2020 Joyent, Inc.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <md5.h>
297c478bd9Sstevel@tonic-gate #include <pthread.h>
307c478bd9Sstevel@tonic-gate #include <syslog.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <strings.h>
347c478bd9Sstevel@tonic-gate #include <sys/sha1.h>
357c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
367c478bd9Sstevel@tonic-gate #include "softGlobal.h"
377c478bd9Sstevel@tonic-gate #include "softSession.h"
387c478bd9Sstevel@tonic-gate #include "softObject.h"
397c478bd9Sstevel@tonic-gate #include "softOps.h"
407c478bd9Sstevel@tonic-gate #include "softKeystore.h"
417c478bd9Sstevel@tonic-gate #include "softKeystoreUtil.h"
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate CK_ULONG soft_session_cnt = 0;		/* the number of opened sessions */
457c478bd9Sstevel@tonic-gate CK_ULONG soft_session_rw_cnt = 0;	/* the number of opened R/W sessions */
467c478bd9Sstevel@tonic-gate 
47588a1af0SAlexandr Nedvedicky #define	DIGEST_MECH_OK(_m_)	((_m_) == CKM_MD5 || (_m_) == CKM_SHA_1)
48588a1af0SAlexandr Nedvedicky 
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate  * Delete all the sessions. First, obtain the global session
517c478bd9Sstevel@tonic-gate  * list lock. Then start to delete one session at a time.
527c478bd9Sstevel@tonic-gate  * Release the global session list lock before returning to
537c478bd9Sstevel@tonic-gate  * caller.
547c478bd9Sstevel@tonic-gate  */
557c478bd9Sstevel@tonic-gate CK_RV
soft_delete_all_sessions(boolean_t force)56a62b4373Sdarrenm soft_delete_all_sessions(boolean_t force)
577c478bd9Sstevel@tonic-gate {
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
607c478bd9Sstevel@tonic-gate 	CK_RV rv1;
617c478bd9Sstevel@tonic-gate 	soft_session_t *session_p;
627c478bd9Sstevel@tonic-gate 	soft_session_t *session_p1;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	/* Acquire the global session list lock */
657c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	session_p = soft_session_list;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	/* Delete all the sessions in the session list */
707c478bd9Sstevel@tonic-gate 	while (session_p) {
717c478bd9Sstevel@tonic-gate 		session_p1 = session_p->next;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 		/*
747c478bd9Sstevel@tonic-gate 		 * Delete a session by calling soft_delete_session()
757c478bd9Sstevel@tonic-gate 		 * with a session pointer and a boolean arguments.
767c478bd9Sstevel@tonic-gate 		 * Boolean value TRUE is used to indicate that the
777c478bd9Sstevel@tonic-gate 		 * caller holds the lock on the global session list.
78a62b4373Sdarrenm 		 *
797c478bd9Sstevel@tonic-gate 		 */
80a62b4373Sdarrenm 		rv1 = soft_delete_session(session_p, force, B_TRUE);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 		/* Record the very first error code */
837c478bd9Sstevel@tonic-gate 		if (rv == CKR_OK) {
847c478bd9Sstevel@tonic-gate 			rv = rv1;
857c478bd9Sstevel@tonic-gate 		}
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 		session_p = session_p1;
887c478bd9Sstevel@tonic-gate 	}
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	/* No session left */
917c478bd9Sstevel@tonic-gate 	soft_session_list = NULL;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	/* Release the global session list lock */
947c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	return (rv);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate }
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate /*
1017c478bd9Sstevel@tonic-gate  * Create a new session struct, and add it to the session linked list.
1027c478bd9Sstevel@tonic-gate  *
1037c478bd9Sstevel@tonic-gate  * This function will acquire the global session list lock, and release
1047c478bd9Sstevel@tonic-gate  * it after adding the session to the session linked list.
1057c478bd9Sstevel@tonic-gate  */
1067c478bd9Sstevel@tonic-gate CK_RV
soft_add_session(CK_FLAGS flags,CK_VOID_PTR pApplication,CK_NOTIFY notify,CK_ULONG * sessionhandle_p)1077c478bd9Sstevel@tonic-gate soft_add_session(CK_FLAGS flags, CK_VOID_PTR pApplication,
108*cfcec266SJason King     CK_NOTIFY notify, CK_ULONG *sessionhandle_p)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate 	soft_session_t *new_sp = NULL;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	/* Allocate a new session struct */
1137c478bd9Sstevel@tonic-gate 	new_sp = calloc(1, sizeof (soft_session_t));
1147c478bd9Sstevel@tonic-gate 	if (new_sp == NULL) {
1157c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
1167c478bd9Sstevel@tonic-gate 	}
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	new_sp->magic_marker = SOFTTOKEN_SESSION_MAGIC;
1197c478bd9Sstevel@tonic-gate 	new_sp->pApplication = pApplication;
1207c478bd9Sstevel@tonic-gate 	new_sp->Notify = notify;
1217c478bd9Sstevel@tonic-gate 	new_sp->flags = flags;
1227c478bd9Sstevel@tonic-gate 	new_sp->state = CKS_RO_PUBLIC_SESSION;
1237c478bd9Sstevel@tonic-gate 	new_sp->object_list = NULL;
1247c478bd9Sstevel@tonic-gate 	new_sp->ses_refcnt = 0;
1257c478bd9Sstevel@tonic-gate 	new_sp->ses_close_sync = 0;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&soft_giant_mutex);
1287c478bd9Sstevel@tonic-gate 	if (soft_slot.authenticated) {
1297c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&soft_giant_mutex);
1307c478bd9Sstevel@tonic-gate 		if (flags & CKF_RW_SESSION) {
1317c478bd9Sstevel@tonic-gate 			new_sp->state = CKS_RW_USER_FUNCTIONS;
1327c478bd9Sstevel@tonic-gate 		} else {
1337c478bd9Sstevel@tonic-gate 			new_sp->state = CKS_RO_USER_FUNCTIONS;
1347c478bd9Sstevel@tonic-gate 		}
1357c478bd9Sstevel@tonic-gate 	} else {
1367c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&soft_giant_mutex);
1377c478bd9Sstevel@tonic-gate 		if (flags & CKF_RW_SESSION) {
1387c478bd9Sstevel@tonic-gate 			new_sp->state = CKS_RW_PUBLIC_SESSION;
1397c478bd9Sstevel@tonic-gate 		} else {
1407c478bd9Sstevel@tonic-gate 			new_sp->state = CKS_RO_PUBLIC_SESSION;
1417c478bd9Sstevel@tonic-gate 		}
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	/* Initialize the lock for the newly created session */
1457c478bd9Sstevel@tonic-gate 	if (pthread_mutex_init(&new_sp->session_mutex, NULL) != 0) {
1467c478bd9Sstevel@tonic-gate 		free(new_sp);
1477c478bd9Sstevel@tonic-gate 		return (CKR_CANT_LOCK);
1487c478bd9Sstevel@tonic-gate 	}
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	(void) pthread_cond_init(&new_sp->ses_free_cond, NULL);
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	/* Acquire the global session list lock */
1537c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
1547c478bd9Sstevel@tonic-gate 
155*cfcec266SJason King 	/* Generate a unique session handle. */
156*cfcec266SJason King 	do {
157*cfcec266SJason King 		arc4random_buf(&new_sp->handle, sizeof (new_sp->handle));
158*cfcec266SJason King 		if (new_sp->handle == CK_INVALID_HANDLE)
159*cfcec266SJason King 			continue;
160*cfcec266SJason King 	} while (avl_find(&soft_session_tree, new_sp, NULL) != NULL);
161*cfcec266SJason King 
162*cfcec266SJason King 	avl_add(&soft_session_tree, new_sp);
163*cfcec266SJason King 	*sessionhandle_p = new_sp->handle;
164*cfcec266SJason King 
1657c478bd9Sstevel@tonic-gate 	/* Insert the new session in front of session list */
1667c478bd9Sstevel@tonic-gate 	if (soft_session_list == NULL) {
1677c478bd9Sstevel@tonic-gate 		soft_session_list = new_sp;
1687c478bd9Sstevel@tonic-gate 		new_sp->next = NULL;
1697c478bd9Sstevel@tonic-gate 		new_sp->prev = NULL;
1707c478bd9Sstevel@tonic-gate 	} else {
1717c478bd9Sstevel@tonic-gate 		soft_session_list->prev = new_sp;
1727c478bd9Sstevel@tonic-gate 		new_sp->next = soft_session_list;
1737c478bd9Sstevel@tonic-gate 		new_sp->prev = NULL;
1747c478bd9Sstevel@tonic-gate 		soft_session_list = new_sp;
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	++soft_session_cnt;
1787c478bd9Sstevel@tonic-gate 	if (flags & CKF_RW_SESSION)
1797c478bd9Sstevel@tonic-gate 		++soft_session_rw_cnt;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	if (soft_session_cnt == 1)
1827c478bd9Sstevel@tonic-gate 		/*
1837c478bd9Sstevel@tonic-gate 		 * This is the first session to be opened, so we can set
1847c478bd9Sstevel@tonic-gate 		 * validate the public token objects in token list now.
1857c478bd9Sstevel@tonic-gate 		 */
1867c478bd9Sstevel@tonic-gate 		soft_validate_token_objects(B_TRUE);
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	/* Release the global session list lock */
1897c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	return (CKR_OK);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate /*
1967c478bd9Sstevel@tonic-gate  * This function adds the to-be-freed session to a linked list.
1977c478bd9Sstevel@tonic-gate  * When the number of sessions queued in the linked list reaches the
1987c478bd9Sstevel@tonic-gate  * maximum threshold MAX_SES_TO_BE_FREED, it will free the first
1997c478bd9Sstevel@tonic-gate  * session (FIFO) in the list.
2007c478bd9Sstevel@tonic-gate  */
2017c478bd9Sstevel@tonic-gate void
session_delay_free(soft_session_t * sp)2027c478bd9Sstevel@tonic-gate session_delay_free(soft_session_t *sp)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	soft_session_t *tmp;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex);
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	/* Add the newly deleted session at the end of the list */
2097c478bd9Sstevel@tonic-gate 	sp->next = NULL;
2107c478bd9Sstevel@tonic-gate 	if (ses_delay_freed.first == NULL) {
2117c478bd9Sstevel@tonic-gate 		ses_delay_freed.last = sp;
2127c478bd9Sstevel@tonic-gate 		ses_delay_freed.first = sp;
2137c478bd9Sstevel@tonic-gate 	} else {
2147c478bd9Sstevel@tonic-gate 		ses_delay_freed.last->next = sp;
2157c478bd9Sstevel@tonic-gate 		ses_delay_freed.last = sp;
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	if (++ses_delay_freed.count >= MAX_SES_TO_BE_FREED) {
2197c478bd9Sstevel@tonic-gate 		/*
2207c478bd9Sstevel@tonic-gate 		 * Free the first session in the list only if
2217c478bd9Sstevel@tonic-gate 		 * the total count reaches maximum threshold.
2227c478bd9Sstevel@tonic-gate 		 */
2237c478bd9Sstevel@tonic-gate 		ses_delay_freed.count--;
2247c478bd9Sstevel@tonic-gate 		tmp = ses_delay_freed.first->next;
2257c478bd9Sstevel@tonic-gate 		free(ses_delay_freed.first);
2267c478bd9Sstevel@tonic-gate 		ses_delay_freed.first = tmp;
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate /*
2327c478bd9Sstevel@tonic-gate  * Delete a session:
2337c478bd9Sstevel@tonic-gate  * - Remove the session from the session linked list.
2347c478bd9Sstevel@tonic-gate  *   Holding the lock on the global session list is needed to do this.
2357c478bd9Sstevel@tonic-gate  * - Release all the objects created by the session.
2367c478bd9Sstevel@tonic-gate  *
2377c478bd9Sstevel@tonic-gate  * The boolean argument lock_held is used to indicate that whether
2387c478bd9Sstevel@tonic-gate  * the caller of this function holds the lock on the global session
2397c478bd9Sstevel@tonic-gate  * list or not.
2407c478bd9Sstevel@tonic-gate  * - When called by soft_delete_all_sessions(), which is called by
2417c478bd9Sstevel@tonic-gate  *   C_Finalize() or C_CloseAllSessions() -- the lock_held = TRUE.
2427c478bd9Sstevel@tonic-gate  * - When called by C_CloseSession() -- the lock_held = FALSE.
2437c478bd9Sstevel@tonic-gate  *
2447c478bd9Sstevel@tonic-gate  * When the caller does not hold the lock on the global session
2457c478bd9Sstevel@tonic-gate  * list, this function will acquire that lock in order to proceed,
2467c478bd9Sstevel@tonic-gate  * and also release that lock before returning to caller.
2477c478bd9Sstevel@tonic-gate  */
2487c478bd9Sstevel@tonic-gate CK_RV
soft_delete_session(soft_session_t * session_p,boolean_t force,boolean_t lock_held)249a62b4373Sdarrenm soft_delete_session(soft_session_t *session_p,
250a62b4373Sdarrenm     boolean_t force, boolean_t lock_held)
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	/*
2547c478bd9Sstevel@tonic-gate 	 * Check to see if the caller holds the lock on the global
2557c478bd9Sstevel@tonic-gate 	 * session list. If not, we need to acquire that lock in
2567c478bd9Sstevel@tonic-gate 	 * order to proceed.
2577c478bd9Sstevel@tonic-gate 	 */
2587c478bd9Sstevel@tonic-gate 	if (!lock_held) {
2597c478bd9Sstevel@tonic-gate 		/* Acquire the global session list lock */
2607c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&soft_sessionlist_mutex);
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	/*
2647c478bd9Sstevel@tonic-gate 	 * Remove the session from the session linked list first.
2657c478bd9Sstevel@tonic-gate 	 */
2667c478bd9Sstevel@tonic-gate 	if (soft_session_list == session_p) {
2677c478bd9Sstevel@tonic-gate 		/* Session is the first one in the list */
2687c478bd9Sstevel@tonic-gate 		if (session_p->next) {
2697c478bd9Sstevel@tonic-gate 			soft_session_list = session_p->next;
2707c478bd9Sstevel@tonic-gate 			session_p->next->prev = NULL;
2717c478bd9Sstevel@tonic-gate 		} else {
2727c478bd9Sstevel@tonic-gate 			/* Session is the only one in the list */
2737c478bd9Sstevel@tonic-gate 			soft_session_list = NULL;
2747c478bd9Sstevel@tonic-gate 		}
2757c478bd9Sstevel@tonic-gate 	} else {
2767c478bd9Sstevel@tonic-gate 		/* Session is not the first one in the list */
2777c478bd9Sstevel@tonic-gate 		if (session_p->next) {
2787c478bd9Sstevel@tonic-gate 			/* Session is in the middle of the list */
2797c478bd9Sstevel@tonic-gate 			session_p->prev->next = session_p->next;
2807c478bd9Sstevel@tonic-gate 			session_p->next->prev = session_p->prev;
2817c478bd9Sstevel@tonic-gate 		} else {
2827c478bd9Sstevel@tonic-gate 			/* Session is the last one in the list */
2837c478bd9Sstevel@tonic-gate 			session_p->prev->next = NULL;
2847c478bd9Sstevel@tonic-gate 		}
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 
287*cfcec266SJason King 	avl_remove(&soft_session_tree, session_p);
288*cfcec266SJason King 
2897c478bd9Sstevel@tonic-gate 	--soft_session_cnt;
2907c478bd9Sstevel@tonic-gate 	if (session_p->flags & CKF_RW_SESSION)
2917c478bd9Sstevel@tonic-gate 		--soft_session_rw_cnt;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	if (!lock_held) {
2947c478bd9Sstevel@tonic-gate 		/*
2957c478bd9Sstevel@tonic-gate 		 * If the global session list lock is obtained by
2967c478bd9Sstevel@tonic-gate 		 * this function, then release that lock after
2977c478bd9Sstevel@tonic-gate 		 * removing the session from session linked list.
2987c478bd9Sstevel@tonic-gate 		 * We want the releasing of the objects of the
2997c478bd9Sstevel@tonic-gate 		 * session, and freeing of the session itself to
3007c478bd9Sstevel@tonic-gate 		 * be done without holding the global session list
3017c478bd9Sstevel@tonic-gate 		 * lock.
3027c478bd9Sstevel@tonic-gate 		 */
3037c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	/* Acquire the individual session lock */
3087c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
3097c478bd9Sstevel@tonic-gate 	/*
3107c478bd9Sstevel@tonic-gate 	 * Make sure another thread hasn't freed the session.
3117c478bd9Sstevel@tonic-gate 	 */
3127c478bd9Sstevel@tonic-gate 	if (session_p->magic_marker != SOFTTOKEN_SESSION_MAGIC) {
3137c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&session_p->session_mutex);
3147c478bd9Sstevel@tonic-gate 		return (CKR_OK);
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	/*
3187c478bd9Sstevel@tonic-gate 	 * The deletion of a session must be blocked when the session
3197c478bd9Sstevel@tonic-gate 	 * reference count is not zero. This means if any session related
3207c478bd9Sstevel@tonic-gate 	 * operation starts prior to the session close operation gets in,
3217c478bd9Sstevel@tonic-gate 	 * the session closing thread must wait for the non-closing
3227c478bd9Sstevel@tonic-gate 	 * operation to be completed before it can proceed the close
3237c478bd9Sstevel@tonic-gate 	 * operation.
324a62b4373Sdarrenm 	 *
325a62b4373Sdarrenm 	 * Unless we are being forced to shut everything down, this only
326a62b4373Sdarrenm 	 * happens if the libraries _fini() is running not of someone
327a62b4373Sdarrenm 	 * explicitly called C_Finalize().
3287c478bd9Sstevel@tonic-gate 	 */
329a62b4373Sdarrenm 	if (force)
330a62b4373Sdarrenm 		session_p->ses_refcnt = 0;
331a62b4373Sdarrenm 
3327c478bd9Sstevel@tonic-gate 	while (session_p->ses_refcnt != 0) {
3337c478bd9Sstevel@tonic-gate 		/*
3347c478bd9Sstevel@tonic-gate 		 * We set the SESSION_REFCNT_WAITING flag before we put
3357c478bd9Sstevel@tonic-gate 		 * this closing thread in a wait state, so other non-closing
3367c478bd9Sstevel@tonic-gate 		 * operation thread will signal to wake it up only when
3377c478bd9Sstevel@tonic-gate 		 * the session reference count becomes zero and this flag
3387c478bd9Sstevel@tonic-gate 		 * is set.
3397c478bd9Sstevel@tonic-gate 		 */
3407c478bd9Sstevel@tonic-gate 		session_p->ses_close_sync |= SESSION_REFCNT_WAITING;
3417c478bd9Sstevel@tonic-gate 		(void) pthread_cond_wait(&session_p->ses_free_cond,
342f243d98aSkrishna 		    &session_p->session_mutex);
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	session_p->ses_close_sync &= ~SESSION_REFCNT_WAITING;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	/*
3487c478bd9Sstevel@tonic-gate 	 * Remove all the objects created in this session.
3497c478bd9Sstevel@tonic-gate 	 */
3501f49a79aSZdenek Kotala 	soft_delete_all_objects_in_session(session_p, force);
3517c478bd9Sstevel@tonic-gate 
352429cc41dSVladimir Kotal 	/*
353429cc41dSVladimir Kotal 	 * Mark session as no longer valid. This can only be done after all
354429cc41dSVladimir Kotal 	 * objects created by this session are free'd since the marker is
355429cc41dSVladimir Kotal 	 * still needed in the process of removing objects from the session.
356429cc41dSVladimir Kotal 	 */
357429cc41dSVladimir Kotal 	session_p->magic_marker = 0;
358429cc41dSVladimir Kotal 
359429cc41dSVladimir Kotal 	(void) pthread_cond_destroy(&session_p->ses_free_cond);
360429cc41dSVladimir Kotal 
3617c478bd9Sstevel@tonic-gate 	/* In case application did not call Final */
3627c478bd9Sstevel@tonic-gate 	if (session_p->digest.context != NULL)
3637c478bd9Sstevel@tonic-gate 		free(session_p->digest.context);
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	if (session_p->encrypt.context != NULL)
3667c478bd9Sstevel@tonic-gate 		/*
3677c478bd9Sstevel@tonic-gate 		 * 1st B_TRUE: encrypt
3687c478bd9Sstevel@tonic-gate 		 * 2nd B_TRUE: caller is holding session_mutex.
3697c478bd9Sstevel@tonic-gate 		 */
3707c478bd9Sstevel@tonic-gate 		soft_crypt_cleanup(session_p, B_TRUE, B_TRUE);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	if (session_p->decrypt.context != NULL)
3737c478bd9Sstevel@tonic-gate 		/*
3747c478bd9Sstevel@tonic-gate 		 * 1st B_FALSE: decrypt
3757c478bd9Sstevel@tonic-gate 		 * 2nd B_TRUE: caller is holding session_mutex.
3767c478bd9Sstevel@tonic-gate 		 */
3777c478bd9Sstevel@tonic-gate 		soft_crypt_cleanup(session_p, B_FALSE, B_TRUE);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	if (session_p->sign.context != NULL)
3807c478bd9Sstevel@tonic-gate 		free(session_p->sign.context);
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	if (session_p->verify.context != NULL)
3837c478bd9Sstevel@tonic-gate 		free(session_p->verify.context);
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	if (session_p->find_objects.context != NULL) {
3867c478bd9Sstevel@tonic-gate 		find_context_t *fcontext;
3877c478bd9Sstevel@tonic-gate 		fcontext = (find_context_t *)session_p->find_objects.context;
3887c478bd9Sstevel@tonic-gate 		free(fcontext->objs_found);
3897c478bd9Sstevel@tonic-gate 		free(fcontext);
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 
392*cfcec266SJason King 	/* Reset SESSION_IS_CLOSING flag. */
3937c478bd9Sstevel@tonic-gate 	session_p->ses_close_sync &= ~SESSION_IS_CLOSING;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
3967c478bd9Sstevel@tonic-gate 	/* Destroy the individual session lock */
3977c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_destroy(&session_p->session_mutex);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	/* Delay freeing the session */
4007c478bd9Sstevel@tonic-gate 	session_delay_free(session_p);
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	return (CKR_OK);
4037c478bd9Sstevel@tonic-gate }
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate /*
4077c478bd9Sstevel@tonic-gate  * This function is used to type cast a session handle to a pointer to
4087c478bd9Sstevel@tonic-gate  * the session struct. Also, it does the following things:
4097c478bd9Sstevel@tonic-gate  * 1) Check to see if the session struct is tagged with a session
4107c478bd9Sstevel@tonic-gate  *    magic number. This is to detect when an application passes
4117c478bd9Sstevel@tonic-gate  *    a bogus session pointer.
412f243d98aSkrishna  * 2) Acquire the lock on the designated session.
4137c478bd9Sstevel@tonic-gate  * 3) Check to see if the session is in the closing state that another
4147c478bd9Sstevel@tonic-gate  *    thread is performing.
4157c478bd9Sstevel@tonic-gate  * 4) Increment the session reference count by one. This is to prevent
4167c478bd9Sstevel@tonic-gate  *    this session from being closed by other thread.
417f243d98aSkrishna  * 5) Release the lock held on the designated session.
4187c478bd9Sstevel@tonic-gate  */
4197c478bd9Sstevel@tonic-gate CK_RV
handle2session(CK_SESSION_HANDLE hSession,soft_session_t ** session_p)4207c478bd9Sstevel@tonic-gate handle2session(CK_SESSION_HANDLE hSession, soft_session_t **session_p)
4217c478bd9Sstevel@tonic-gate {
4227c478bd9Sstevel@tonic-gate 
423*cfcec266SJason King 	soft_session_t *sp;
424*cfcec266SJason King 	soft_session_t node;
4257c478bd9Sstevel@tonic-gate 
426f243d98aSkrishna 	/*
427f243d98aSkrishna 	 * No need to hold soft_sessionlist_mutex as we are
428f243d98aSkrishna 	 * just reading the value and 32-bit reads are atomic.
429f243d98aSkrishna 	 */
4307c478bd9Sstevel@tonic-gate 	if (all_sessions_closing) {
4317c478bd9Sstevel@tonic-gate 		return (CKR_SESSION_CLOSED);
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate 
434*cfcec266SJason King 	(void) memset(&node, 0, sizeof (node));
435*cfcec266SJason King 	node.handle = hSession;
436*cfcec266SJason King 
437*cfcec266SJason King 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
438*cfcec266SJason King 
439*cfcec266SJason King 	sp = avl_find(&soft_session_tree, &node, NULL);
4407c478bd9Sstevel@tonic-gate 	if ((sp == NULL) ||
4417c478bd9Sstevel@tonic-gate 	    (sp->magic_marker != SOFTTOKEN_SESSION_MAGIC)) {
442*cfcec266SJason King 		(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
4437c478bd9Sstevel@tonic-gate 		return (CKR_SESSION_HANDLE_INVALID);
4447c478bd9Sstevel@tonic-gate 	}
4457c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&sp->session_mutex);
446*cfcec266SJason King 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	if (sp->ses_close_sync & SESSION_IS_CLOSING) {
4497c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&sp->session_mutex);
4507c478bd9Sstevel@tonic-gate 		return (CKR_SESSION_CLOSED);
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	/* Increment session ref count. */
4547c478bd9Sstevel@tonic-gate 	sp->ses_refcnt++;
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&sp->session_mutex);
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	*session_p = sp;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	return (CKR_OK);
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate /*
4647c478bd9Sstevel@tonic-gate  * The format to be saved in the pOperationState will be:
4657c478bd9Sstevel@tonic-gate  * 1. internal_op_state_t
4667c478bd9Sstevel@tonic-gate  * 2. crypto_active_op_t
4677c478bd9Sstevel@tonic-gate  * 3. actual context of the active operation
4687c478bd9Sstevel@tonic-gate  */
4697c478bd9Sstevel@tonic-gate CK_RV
soft_get_operationstate(soft_session_t * session_p,CK_BYTE_PTR pOperationState,CK_ULONG_PTR pulOperationStateLen)4707c478bd9Sstevel@tonic-gate soft_get_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState,
4717c478bd9Sstevel@tonic-gate     CK_ULONG_PTR pulOperationStateLen)
4727c478bd9Sstevel@tonic-gate {
4737c478bd9Sstevel@tonic-gate 
474588a1af0SAlexandr Nedvedicky 	internal_op_state_t *p_op_state;
4757c478bd9Sstevel@tonic-gate 	CK_ULONG op_data_len = 0;
476588a1af0SAlexandr Nedvedicky 	CK_RV rv = CKR_OK;
477588a1af0SAlexandr Nedvedicky 
478588a1af0SAlexandr Nedvedicky 	if (pulOperationStateLen == NULL)
479588a1af0SAlexandr Nedvedicky 		return (CKR_ARGUMENTS_BAD);
480588a1af0SAlexandr Nedvedicky 
481588a1af0SAlexandr Nedvedicky 	(void) pthread_mutex_lock(&session_p->session_mutex);
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	/* Check to see if encrypt operation is active. */
4847c478bd9Sstevel@tonic-gate 	if (session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE) {
485588a1af0SAlexandr Nedvedicky 		rv = CKR_STATE_UNSAVEABLE;
486588a1af0SAlexandr Nedvedicky 		goto unlock_session;
4877c478bd9Sstevel@tonic-gate 	}
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	/* Check to see if decrypt operation is active. */
4907c478bd9Sstevel@tonic-gate 	if (session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE) {
491588a1af0SAlexandr Nedvedicky 		rv = CKR_STATE_UNSAVEABLE;
492588a1af0SAlexandr Nedvedicky 		goto unlock_session;
4937c478bd9Sstevel@tonic-gate 	}
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	/* Check to see if sign operation is active. */
4967c478bd9Sstevel@tonic-gate 	if (session_p->sign.flags & CRYPTO_OPERATION_ACTIVE) {
497588a1af0SAlexandr Nedvedicky 		rv = CKR_STATE_UNSAVEABLE;
498588a1af0SAlexandr Nedvedicky 		goto unlock_session;
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	/* Check to see if verify operation is active. */
5027c478bd9Sstevel@tonic-gate 	if (session_p->verify.flags & CRYPTO_OPERATION_ACTIVE) {
503588a1af0SAlexandr Nedvedicky 		rv = CKR_STATE_UNSAVEABLE;
504588a1af0SAlexandr Nedvedicky 		goto unlock_session;
5057c478bd9Sstevel@tonic-gate 	}
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	/* Check to see if digest operation is active. */
5087c478bd9Sstevel@tonic-gate 	if (session_p->digest.flags & CRYPTO_OPERATION_ACTIVE) {
5097c478bd9Sstevel@tonic-gate 		op_data_len = sizeof (internal_op_state_t) +
5107c478bd9Sstevel@tonic-gate 		    sizeof (crypto_active_op_t);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 		switch (session_p->digest.mech.mechanism) {
5137c478bd9Sstevel@tonic-gate 		case CKM_MD5:
5147c478bd9Sstevel@tonic-gate 			op_data_len += sizeof (MD5_CTX);
5157c478bd9Sstevel@tonic-gate 			break;
5167c478bd9Sstevel@tonic-gate 		case CKM_SHA_1:
5177c478bd9Sstevel@tonic-gate 			op_data_len += sizeof (SHA1_CTX);
5187c478bd9Sstevel@tonic-gate 			break;
5197c478bd9Sstevel@tonic-gate 		default:
520588a1af0SAlexandr Nedvedicky 			rv = CKR_STATE_UNSAVEABLE;
521588a1af0SAlexandr Nedvedicky 			goto unlock_session;
5227c478bd9Sstevel@tonic-gate 		}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 		if (pOperationState == NULL_PTR) {
5257c478bd9Sstevel@tonic-gate 			*pulOperationStateLen = op_data_len;
526588a1af0SAlexandr Nedvedicky 			goto unlock_session;
5277c478bd9Sstevel@tonic-gate 		} else {
5287c478bd9Sstevel@tonic-gate 			if (*pulOperationStateLen < op_data_len) {
5297c478bd9Sstevel@tonic-gate 				*pulOperationStateLen = op_data_len;
530588a1af0SAlexandr Nedvedicky 				rv = CKR_BUFFER_TOO_SMALL;
531588a1af0SAlexandr Nedvedicky 				goto unlock_session;
5327c478bd9Sstevel@tonic-gate 			}
5337c478bd9Sstevel@tonic-gate 		}
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 		/* Save internal_op_state_t */
536588a1af0SAlexandr Nedvedicky 		/* LINTED E_BAD_PTR_CAST_ALIGN */
537588a1af0SAlexandr Nedvedicky 		p_op_state = (internal_op_state_t *)pOperationState;
538588a1af0SAlexandr Nedvedicky 		p_op_state->op_len = op_data_len;
539588a1af0SAlexandr Nedvedicky 		p_op_state->op_active = DIGEST_OP;
540588a1af0SAlexandr Nedvedicky 		p_op_state->op_session_state = session_p->state;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 		/* Save crypto_active_op_t */
5437c478bd9Sstevel@tonic-gate 		(void) memcpy((CK_BYTE *)pOperationState +
5447c478bd9Sstevel@tonic-gate 		    sizeof (internal_op_state_t),
5457c478bd9Sstevel@tonic-gate 		    &session_p->digest,
5467c478bd9Sstevel@tonic-gate 		    sizeof (crypto_active_op_t));
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 		switch (session_p->digest.mech.mechanism) {
5497c478bd9Sstevel@tonic-gate 		case CKM_MD5:
5507c478bd9Sstevel@tonic-gate 			/* Save MD5_CTX for the active digest operation */
5517c478bd9Sstevel@tonic-gate 			(void) memcpy((CK_BYTE *)pOperationState +
5527c478bd9Sstevel@tonic-gate 			    sizeof (internal_op_state_t) +
5537c478bd9Sstevel@tonic-gate 			    sizeof (crypto_active_op_t),
5547c478bd9Sstevel@tonic-gate 			    session_p->digest.context,
5557c478bd9Sstevel@tonic-gate 			    sizeof (MD5_CTX));
5567c478bd9Sstevel@tonic-gate 			break;
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 		case CKM_SHA_1:
5597c478bd9Sstevel@tonic-gate 			/* Save SHA1_CTX for the active digest operation */
5607c478bd9Sstevel@tonic-gate 			(void) memcpy((CK_BYTE *)pOperationState +
5617c478bd9Sstevel@tonic-gate 			    sizeof (internal_op_state_t) +
5627c478bd9Sstevel@tonic-gate 			    sizeof (crypto_active_op_t),
5637c478bd9Sstevel@tonic-gate 			    session_p->digest.context,
5647c478bd9Sstevel@tonic-gate 			    sizeof (SHA1_CTX));
5657c478bd9Sstevel@tonic-gate 			break;
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 		default:
568588a1af0SAlexandr Nedvedicky 			rv = CKR_STATE_UNSAVEABLE;
5697c478bd9Sstevel@tonic-gate 		}
570d288ba74SAnthony Scarpino 	} else {
571d288ba74SAnthony Scarpino 		rv = CKR_OPERATION_NOT_INITIALIZED;
572d288ba74SAnthony Scarpino 		goto unlock_session;
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	*pulOperationStateLen = op_data_len;
576588a1af0SAlexandr Nedvedicky 
577588a1af0SAlexandr Nedvedicky unlock_session:
578588a1af0SAlexandr Nedvedicky 	(void) pthread_mutex_unlock(&session_p->session_mutex);
579588a1af0SAlexandr Nedvedicky 
580588a1af0SAlexandr Nedvedicky 	return (rv);
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate 
alloc_digest(CK_ULONG mech)584588a1af0SAlexandr Nedvedicky static CK_BYTE_PTR alloc_digest(CK_ULONG mech)
585588a1af0SAlexandr Nedvedicky {
586588a1af0SAlexandr Nedvedicky 	CK_BYTE_PTR	ret_val;
587588a1af0SAlexandr Nedvedicky 
588588a1af0SAlexandr Nedvedicky 	switch (mech) {
589588a1af0SAlexandr Nedvedicky 		case CKM_MD5:
590588a1af0SAlexandr Nedvedicky 			ret_val = (CK_BYTE_PTR) malloc(sizeof (MD5_CTX));
591588a1af0SAlexandr Nedvedicky 			break;
592588a1af0SAlexandr Nedvedicky 		case CKM_SHA_1:
593588a1af0SAlexandr Nedvedicky 			ret_val = (CK_BYTE_PTR) malloc(sizeof (SHA1_CTX));
594588a1af0SAlexandr Nedvedicky 			break;
595588a1af0SAlexandr Nedvedicky 		default: ret_val = NULL;
596588a1af0SAlexandr Nedvedicky 	}
597588a1af0SAlexandr Nedvedicky 
598588a1af0SAlexandr Nedvedicky 	return (ret_val);
599588a1af0SAlexandr Nedvedicky }
600588a1af0SAlexandr Nedvedicky 
6017c478bd9Sstevel@tonic-gate /*
6027c478bd9Sstevel@tonic-gate  * The format to be restored from the pOperationState will be:
6037c478bd9Sstevel@tonic-gate  * 1. internal_op_state_t
6047c478bd9Sstevel@tonic-gate  * 2. crypto_active_op_t
6057c478bd9Sstevel@tonic-gate  * 3. actual context of the saved operation
6067c478bd9Sstevel@tonic-gate  */
6077c478bd9Sstevel@tonic-gate CK_RV
soft_set_operationstate(soft_session_t * session_p,CK_BYTE_PTR pOperationState,CK_ULONG ulOperationStateLen,CK_OBJECT_HANDLE hEncryptionKey,CK_OBJECT_HANDLE hAuthenticationKey)6087c478bd9Sstevel@tonic-gate soft_set_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState,
6097c478bd9Sstevel@tonic-gate     CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey,
6107c478bd9Sstevel@tonic-gate     CK_OBJECT_HANDLE hAuthenticationKey)
6117c478bd9Sstevel@tonic-gate {
6127c478bd9Sstevel@tonic-gate 
613588a1af0SAlexandr Nedvedicky 	CK_RV		rv = CKR_OK;
614588a1af0SAlexandr Nedvedicky 	internal_op_state_t *p_op_state;
615588a1af0SAlexandr Nedvedicky 	crypto_active_op_t *p_active_op;
6167c478bd9Sstevel@tonic-gate 	CK_ULONG offset = 0;
617588a1af0SAlexandr Nedvedicky 	CK_ULONG mech;
618588a1af0SAlexandr Nedvedicky 	void *free_it = NULL;
6197c478bd9Sstevel@tonic-gate 
620588a1af0SAlexandr Nedvedicky 	/* LINTED E_BAD_PTR_CAST_ALIGN */
621588a1af0SAlexandr Nedvedicky 	p_op_state = (internal_op_state_t *)pOperationState;
6227c478bd9Sstevel@tonic-gate 
623588a1af0SAlexandr Nedvedicky 	if (p_op_state->op_len != ulOperationStateLen) {
6247c478bd9Sstevel@tonic-gate 		/*
625588a1af0SAlexandr Nedvedicky 		 * The supplied data length does not match with
626588a1af0SAlexandr Nedvedicky 		 * the saved data length.
6277c478bd9Sstevel@tonic-gate 		 */
6287c478bd9Sstevel@tonic-gate 		return (CKR_SAVED_STATE_INVALID);
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate 
631588a1af0SAlexandr Nedvedicky 	if (p_op_state->op_active != DIGEST_OP)
6327c478bd9Sstevel@tonic-gate 		return (CKR_SAVED_STATE_INVALID);
633588a1af0SAlexandr Nedvedicky 
634588a1af0SAlexandr Nedvedicky 	if ((hAuthenticationKey != 0) || (hEncryptionKey != 0)) {
635588a1af0SAlexandr Nedvedicky 		return (CKR_KEY_NOT_NEEDED);
6367c478bd9Sstevel@tonic-gate 	}
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	offset = sizeof (internal_op_state_t);
639588a1af0SAlexandr Nedvedicky 	/* LINTED E_BAD_PTR_CAST_ALIGN */
640588a1af0SAlexandr Nedvedicky 	p_active_op = (crypto_active_op_t *)(pOperationState + offset);
641588a1af0SAlexandr Nedvedicky 	offset += sizeof (crypto_active_op_t);
642588a1af0SAlexandr Nedvedicky 	mech = p_active_op->mech.mechanism;
6437c478bd9Sstevel@tonic-gate 
644588a1af0SAlexandr Nedvedicky 	if (!DIGEST_MECH_OK(mech)) {
645588a1af0SAlexandr Nedvedicky 		return (CKR_SAVED_STATE_INVALID);
646588a1af0SAlexandr Nedvedicky 	}
6477c478bd9Sstevel@tonic-gate 
648588a1af0SAlexandr Nedvedicky 	/*
649588a1af0SAlexandr Nedvedicky 	 * We may reuse digest.context in case the digest mechanisms (the one,
650588a1af0SAlexandr Nedvedicky 	 * which belongs to session and the operation, which we are restoring)
651588a1af0SAlexandr Nedvedicky 	 * are the same. If digest mechanisms are different, we have to release
652588a1af0SAlexandr Nedvedicky 	 * the digest context, which belongs to session and allocate a new one.
653588a1af0SAlexandr Nedvedicky 	 */
654588a1af0SAlexandr Nedvedicky 	(void) pthread_mutex_lock(&session_p->session_mutex);
6557c478bd9Sstevel@tonic-gate 
656588a1af0SAlexandr Nedvedicky 	if (session_p->state != p_op_state->op_session_state) {
6577c478bd9Sstevel@tonic-gate 		/*
658588a1af0SAlexandr Nedvedicky 		 * The supplied session state does not match with
659588a1af0SAlexandr Nedvedicky 		 * the saved session state.
6607c478bd9Sstevel@tonic-gate 		 */
661588a1af0SAlexandr Nedvedicky 		rv = CKR_SAVED_STATE_INVALID;
662588a1af0SAlexandr Nedvedicky 		goto unlock_session;
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 
665588a1af0SAlexandr Nedvedicky 	if (session_p->digest.context &&
666588a1af0SAlexandr Nedvedicky 	    (session_p->digest.mech.mechanism != mech)) {
667588a1af0SAlexandr Nedvedicky 		free_it = session_p->digest.context;
668588a1af0SAlexandr Nedvedicky 		session_p->digest.context = NULL;
669588a1af0SAlexandr Nedvedicky 	}
6707c478bd9Sstevel@tonic-gate 
671588a1af0SAlexandr Nedvedicky 	if (session_p->digest.context == NULL) {
672588a1af0SAlexandr Nedvedicky 		session_p->digest.context = alloc_digest(mech);
673588a1af0SAlexandr Nedvedicky 
674588a1af0SAlexandr Nedvedicky 		if (session_p->digest.context == NULL) {
675588a1af0SAlexandr Nedvedicky 			/*
676588a1af0SAlexandr Nedvedicky 			 * put back original context into session in case
677588a1af0SAlexandr Nedvedicky 			 * allocation of new context has failed.
678588a1af0SAlexandr Nedvedicky 			 */
679588a1af0SAlexandr Nedvedicky 			session_p->digest.context = free_it;
680588a1af0SAlexandr Nedvedicky 			free_it = NULL;
681588a1af0SAlexandr Nedvedicky 			rv = CKR_HOST_MEMORY;
682588a1af0SAlexandr Nedvedicky 			goto unlock_session;
683588a1af0SAlexandr Nedvedicky 		}
684588a1af0SAlexandr Nedvedicky 	}
6857c478bd9Sstevel@tonic-gate 
686588a1af0SAlexandr Nedvedicky 	/* Restore crypto_active_op_t */
687588a1af0SAlexandr Nedvedicky 	session_p->digest.mech.mechanism = mech;
688588a1af0SAlexandr Nedvedicky 	session_p->digest.flags = p_active_op->flags;
6897c478bd9Sstevel@tonic-gate 
690588a1af0SAlexandr Nedvedicky 	switch (mech) {
6917c478bd9Sstevel@tonic-gate 		case CKM_MD5:
6927c478bd9Sstevel@tonic-gate 			/* Restore MD5_CTX from the saved digest operation */
6937c478bd9Sstevel@tonic-gate 			(void) memcpy((CK_BYTE *)session_p->digest.context,
6947c478bd9Sstevel@tonic-gate 			    (CK_BYTE *)pOperationState + offset,
6957c478bd9Sstevel@tonic-gate 			    sizeof (MD5_CTX));
6967c478bd9Sstevel@tonic-gate 			break;
6977c478bd9Sstevel@tonic-gate 		case CKM_SHA_1:
6987c478bd9Sstevel@tonic-gate 			/* Restore SHA1_CTX from the saved digest operation */
6997c478bd9Sstevel@tonic-gate 			(void) memcpy((CK_BYTE *)session_p->digest.context,
7007c478bd9Sstevel@tonic-gate 			    (CK_BYTE *)pOperationState + offset,
7017c478bd9Sstevel@tonic-gate 			    sizeof (SHA1_CTX));
7027c478bd9Sstevel@tonic-gate 			break;
7037c478bd9Sstevel@tonic-gate 		default:
704588a1af0SAlexandr Nedvedicky 			/* never reached */
7057c478bd9Sstevel@tonic-gate 			rv = CKR_SAVED_STATE_INVALID;
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 
708588a1af0SAlexandr Nedvedicky unlock_session:
709588a1af0SAlexandr Nedvedicky 	(void) pthread_mutex_unlock(&session_p->session_mutex);
7107c478bd9Sstevel@tonic-gate 
711588a1af0SAlexandr Nedvedicky 	if (free_it != NULL)
712588a1af0SAlexandr Nedvedicky 		free(free_it);
713588a1af0SAlexandr Nedvedicky 
714588a1af0SAlexandr Nedvedicky 	return (rv);
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate CK_RV
soft_login(CK_UTF8CHAR_PTR pPin,CK_ULONG ulPinLen)7197c478bd9Sstevel@tonic-gate soft_login(CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
7207c478bd9Sstevel@tonic-gate {
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	/*
7237c478bd9Sstevel@tonic-gate 	 * Authenticate the input PIN.
7247c478bd9Sstevel@tonic-gate 	 */
7257c478bd9Sstevel@tonic-gate 	return (soft_verify_pin(pPin, ulPinLen));
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate void
soft_logout(void)7307c478bd9Sstevel@tonic-gate soft_logout(void)
7317c478bd9Sstevel@tonic-gate {
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	/*
7347c478bd9Sstevel@tonic-gate 	 * Delete all the private token objects from the "token_object_list".
7357c478bd9Sstevel@tonic-gate 	 */
7367c478bd9Sstevel@tonic-gate 	soft_delete_all_in_core_token_objects(PRIVATE_TOKEN);
7377c478bd9Sstevel@tonic-gate 	return;
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate }
7404daf2311Srupertk 
7414daf2311Srupertk void
soft_acquire_all_session_mutexes(soft_session_t * session_p)74283140133SZdenek Kotala soft_acquire_all_session_mutexes(soft_session_t *session_p)
7434daf2311Srupertk {
7444daf2311Srupertk 	/* Iterate through sessions acquiring all mutexes */
7454daf2311Srupertk 	while (session_p) {
7461f49a79aSZdenek Kotala 		soft_object_t *object_p;
7471f49a79aSZdenek Kotala 
7484daf2311Srupertk 		(void) pthread_mutex_lock(&session_p->session_mutex);
7491f49a79aSZdenek Kotala 		object_p = session_p->object_list;
7501f49a79aSZdenek Kotala 
7511f49a79aSZdenek Kotala 		/* Lock also all objects related to session */
7521f49a79aSZdenek Kotala 		while (object_p) {
7531f49a79aSZdenek Kotala 			(void) pthread_mutex_lock(&object_p->object_mutex);
7541f49a79aSZdenek Kotala 			object_p = object_p->next;
7551f49a79aSZdenek Kotala 		}
7564daf2311Srupertk 		session_p = session_p->next;
7574daf2311Srupertk 	}
7584daf2311Srupertk }
7594daf2311Srupertk 
7604daf2311Srupertk void
soft_release_all_session_mutexes(soft_session_t * session_p)76183140133SZdenek Kotala soft_release_all_session_mutexes(soft_session_t *session_p)
7624daf2311Srupertk {
7634daf2311Srupertk 	/* Iterate through sessions releasing all mutexes */
7644daf2311Srupertk 	while (session_p) {
7654daf2311Srupertk 		/*
7664daf2311Srupertk 		 * N.B. Ideally, should go in opposite order to guarantee
7674daf2311Srupertk 		 * lock-order requirements but there is no tail pointer.
7684daf2311Srupertk 		 */
7691f49a79aSZdenek Kotala 		soft_object_t *object_p = session_p->object_list;
7701f49a79aSZdenek Kotala 
7711f49a79aSZdenek Kotala 		/* Unlock also all objects related to session */
7721f49a79aSZdenek Kotala 		while (object_p) {
7731f49a79aSZdenek Kotala 			(void) pthread_mutex_unlock(&object_p->object_mutex);
7741f49a79aSZdenek Kotala 			object_p = object_p->next;
7751f49a79aSZdenek Kotala 		}
7764daf2311Srupertk 		(void) pthread_mutex_unlock(&session_p->session_mutex);
7774daf2311Srupertk 		session_p = session_p->next;
7784daf2311Srupertk 	}
7794daf2311Srupertk }
780