Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <md5.h>
     27 #include <pthread.h>
     28 #include <syslog.h>
     29 #include <stdlib.h>
     30 #include <string.h>
     31 #include <strings.h>
     32 #include <sys/sha1.h>
     33 #include <security/cryptoki.h>
     34 #include "softGlobal.h"
     35 #include "softSession.h"
     36 #include "softObject.h"
     37 #include "softOps.h"
     38 #include "softKeystore.h"
     39 #include "softKeystoreUtil.h"
     40 
     41 
     42 CK_ULONG soft_session_cnt = 0;		/* the number of opened sessions */
     43 CK_ULONG soft_session_rw_cnt = 0;	/* the number of opened R/W sessions */
     44 
     45 #define	DIGEST_MECH_OK(_m_)	((_m_) == CKM_MD5 || (_m_) == CKM_SHA_1)
     46 
     47 /*
     48  * Delete all the sessions. First, obtain the global session
     49  * list lock. Then start to delete one session at a time.
     50  * Release the global session list lock before returning to
     51  * caller.
     52  */
     53 CK_RV
     54 soft_delete_all_sessions(boolean_t force)
     55 {
     56 
     57 	CK_RV rv = CKR_OK;
     58 	CK_RV rv1;
     59 	soft_session_t *session_p;
     60 	soft_session_t *session_p1;
     61 
     62 	/* Acquire the global session list lock */
     63 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
     64 
     65 	session_p = soft_session_list;
     66 
     67 	/* Delete all the sessions in the session list */
     68 	while (session_p) {
     69 		session_p1 = session_p->next;
     70 
     71 		/*
     72 		 * Delete a session by calling soft_delete_session()
     73 		 * with a session pointer and a boolean arguments.
     74 		 * Boolean value TRUE is used to indicate that the
     75 		 * caller holds the lock on the global session list.
     76 		 *
     77 		 */
     78 		rv1 = soft_delete_session(session_p, force, B_TRUE);
     79 
     80 		/* Record the very first error code */
     81 		if (rv == CKR_OK) {
     82 			rv = rv1;
     83 		}
     84 
     85 		session_p = session_p1;
     86 	}
     87 
     88 	/* No session left */
     89 	soft_session_list = NULL;
     90 
     91 	/* Release the global session list lock */
     92 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
     93 
     94 	return (rv);
     95 
     96 }
     97 
     98 
     99 /*
    100  * Create a new session struct, and add it to the session linked list.
    101  *
    102  * This function will acquire the global session list lock, and release
    103  * it after adding the session to the session linked list.
    104  */
    105 CK_RV
    106 soft_add_session(CK_FLAGS flags, CK_VOID_PTR pApplication,
    107 	CK_NOTIFY notify, CK_ULONG *sessionhandle_p)
    108 {
    109 
    110 	soft_session_t *new_sp = NULL;
    111 
    112 	/* Allocate a new session struct */
    113 	new_sp = calloc(1, sizeof (soft_session_t));
    114 	if (new_sp == NULL) {
    115 		return (CKR_HOST_MEMORY);
    116 	}
    117 
    118 	new_sp->magic_marker = SOFTTOKEN_SESSION_MAGIC;
    119 	new_sp->pApplication = pApplication;
    120 	new_sp->Notify = notify;
    121 	new_sp->flags = flags;
    122 	new_sp->state = CKS_RO_PUBLIC_SESSION;
    123 	new_sp->object_list = NULL;
    124 	new_sp->ses_refcnt = 0;
    125 	new_sp->ses_close_sync = 0;
    126 
    127 	(void) pthread_mutex_lock(&soft_giant_mutex);
    128 	if (soft_slot.authenticated) {
    129 		(void) pthread_mutex_unlock(&soft_giant_mutex);
    130 		if (flags & CKF_RW_SESSION) {
    131 			new_sp->state = CKS_RW_USER_FUNCTIONS;
    132 		} else {
    133 			new_sp->state = CKS_RO_USER_FUNCTIONS;
    134 		}
    135 	} else {
    136 		(void) pthread_mutex_unlock(&soft_giant_mutex);
    137 		if (flags & CKF_RW_SESSION) {
    138 			new_sp->state = CKS_RW_PUBLIC_SESSION;
    139 		} else {
    140 			new_sp->state = CKS_RO_PUBLIC_SESSION;
    141 		}
    142 	}
    143 
    144 	/* Initialize the lock for the newly created session */
    145 	if (pthread_mutex_init(&new_sp->session_mutex, NULL) != 0) {
    146 		free(new_sp);
    147 		return (CKR_CANT_LOCK);
    148 	}
    149 
    150 	(void) pthread_cond_init(&new_sp->ses_free_cond, NULL);
    151 
    152 	/* Acquire the global session list lock */
    153 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
    154 
    155 	/* Insert the new session in front of session list */
    156 	if (soft_session_list == NULL) {
    157 		soft_session_list = new_sp;
    158 		new_sp->next = NULL;
    159 		new_sp->prev = NULL;
    160 	} else {
    161 		soft_session_list->prev = new_sp;
    162 		new_sp->next = soft_session_list;
    163 		new_sp->prev = NULL;
    164 		soft_session_list = new_sp;
    165 	}
    166 
    167 	/* Type casting the address of a session struct to a session handle */
    168 	*sessionhandle_p =  (CK_ULONG)new_sp;
    169 	++soft_session_cnt;
    170 	if (flags & CKF_RW_SESSION)
    171 		++soft_session_rw_cnt;
    172 
    173 	if (soft_session_cnt == 1)
    174 		/*
    175 		 * This is the first session to be opened, so we can set
    176 		 * validate the public token objects in token list now.
    177 		 */
    178 		soft_validate_token_objects(B_TRUE);
    179 
    180 	/* Release the global session list lock */
    181 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
    182 
    183 	return (CKR_OK);
    184 
    185 }
    186 
    187 /*
    188  * This function adds the to-be-freed session to a linked list.
    189  * When the number of sessions queued in the linked list reaches the
    190  * maximum threshold MAX_SES_TO_BE_FREED, it will free the first
    191  * session (FIFO) in the list.
    192  */
    193 void
    194 session_delay_free(soft_session_t *sp)
    195 {
    196 	soft_session_t *tmp;
    197 
    198 	(void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex);
    199 
    200 	/* Add the newly deleted session at the end of the list */
    201 	sp->next = NULL;
    202 	if (ses_delay_freed.first == NULL) {
    203 		ses_delay_freed.last = sp;
    204 		ses_delay_freed.first = sp;
    205 	} else {
    206 		ses_delay_freed.last->next = sp;
    207 		ses_delay_freed.last = sp;
    208 	}
    209 
    210 	if (++ses_delay_freed.count >= MAX_SES_TO_BE_FREED) {
    211 		/*
    212 		 * Free the first session in the list only if
    213 		 * the total count reaches maximum threshold.
    214 		 */
    215 		ses_delay_freed.count--;
    216 		tmp = ses_delay_freed.first->next;
    217 		free(ses_delay_freed.first);
    218 		ses_delay_freed.first = tmp;
    219 	}
    220 	(void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex);
    221 }
    222 
    223 /*
    224  * Delete a session:
    225  * - Remove the session from the session linked list.
    226  *   Holding the lock on the global session list is needed to do this.
    227  * - Release all the objects created by the session.
    228  *
    229  * The boolean argument lock_held is used to indicate that whether
    230  * the caller of this function holds the lock on the global session
    231  * list or not.
    232  * - When called by soft_delete_all_sessions(), which is called by
    233  *   C_Finalize() or C_CloseAllSessions() -- the lock_held = TRUE.
    234  * - When called by C_CloseSession() -- the lock_held = FALSE.
    235  *
    236  * When the caller does not hold the lock on the global session
    237  * list, this function will acquire that lock in order to proceed,
    238  * and also release that lock before returning to caller.
    239  */
    240 CK_RV
    241 soft_delete_session(soft_session_t *session_p,
    242     boolean_t force, boolean_t lock_held)
    243 {
    244 
    245 	/*
    246 	 * Check to see if the caller holds the lock on the global
    247 	 * session list. If not, we need to acquire that lock in
    248 	 * order to proceed.
    249 	 */
    250 	if (!lock_held) {
    251 		/* Acquire the global session list lock */
    252 		(void) pthread_mutex_lock(&soft_sessionlist_mutex);
    253 	}
    254 
    255 	/*
    256 	 * Remove the session from the session linked list first.
    257 	 */
    258 	if (soft_session_list == session_p) {
    259 		/* Session is the first one in the list */
    260 		if (session_p->next) {
    261 			soft_session_list = session_p->next;
    262 			session_p->next->prev = NULL;
    263 		} else {
    264 			/* Session is the only one in the list */
    265 			soft_session_list = NULL;
    266 		}
    267 	} else {
    268 		/* Session is not the first one in the list */
    269 		if (session_p->next) {
    270 			/* Session is in the middle of the list */
    271 			session_p->prev->next = session_p->next;
    272 			session_p->next->prev = session_p->prev;
    273 		} else {
    274 			/* Session is the last one in the list */
    275 			session_p->prev->next = NULL;
    276 		}
    277 	}
    278 
    279 	--soft_session_cnt;
    280 	if (session_p->flags & CKF_RW_SESSION)
    281 		--soft_session_rw_cnt;
    282 
    283 	if (!lock_held) {
    284 		/*
    285 		 * If the global session list lock is obtained by
    286 		 * this function, then release that lock after
    287 		 * removing the session from session linked list.
    288 		 * We want the releasing of the objects of the
    289 		 * session, and freeing of the session itself to
    290 		 * be done without holding the global session list
    291 		 * lock.
    292 		 */
    293 		(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
    294 	}
    295 
    296 
    297 	/* Acquire the individual session lock */
    298 	(void) pthread_mutex_lock(&session_p->session_mutex);
    299 	/*
    300 	 * Make sure another thread hasn't freed the session.
    301 	 */
    302 	if (session_p->magic_marker != SOFTTOKEN_SESSION_MAGIC) {
    303 		(void) pthread_mutex_unlock(&session_p->session_mutex);
    304 		return (CKR_OK);
    305 	}
    306 
    307 	/*
    308 	 * The deletion of a session must be blocked when the session
    309 	 * reference count is not zero. This means if any session related
    310 	 * operation starts prior to the session close operation gets in,
    311 	 * the session closing thread must wait for the non-closing
    312 	 * operation to be completed before it can proceed the close
    313 	 * operation.
    314 	 *
    315 	 * Unless we are being forced to shut everything down, this only
    316 	 * happens if the libraries _fini() is running not of someone
    317 	 * explicitly called C_Finalize().
    318 	 */
    319 	if (force)
    320 		session_p->ses_refcnt = 0;
    321 
    322 	while (session_p->ses_refcnt != 0) {
    323 		/*
    324 		 * We set the SESSION_REFCNT_WAITING flag before we put
    325 		 * this closing thread in a wait state, so other non-closing
    326 		 * operation thread will signal to wake it up only when
    327 		 * the session reference count becomes zero and this flag
    328 		 * is set.
    329 		 */
    330 		session_p->ses_close_sync |= SESSION_REFCNT_WAITING;
    331 		(void) pthread_cond_wait(&session_p->ses_free_cond,
    332 		    &session_p->session_mutex);
    333 	}
    334 
    335 	session_p->ses_close_sync &= ~SESSION_REFCNT_WAITING;
    336 
    337 	/*
    338 	 * Remove all the objects created in this session.
    339 	 */
    340 	soft_delete_all_objects_in_session(session_p, force);
    341 
    342 	/*
    343 	 * Mark session as no longer valid. This can only be done after all
    344 	 * objects created by this session are free'd since the marker is
    345 	 * still needed in the process of removing objects from the session.
    346 	 */
    347 	session_p->magic_marker = 0;
    348 
    349 	(void) pthread_cond_destroy(&session_p->ses_free_cond);
    350 
    351 	/* In case application did not call Final */
    352 	if (session_p->digest.context != NULL)
    353 		free(session_p->digest.context);
    354 
    355 	if (session_p->encrypt.context != NULL)
    356 		/*
    357 		 * 1st B_TRUE: encrypt
    358 		 * 2nd B_TRUE: caller is holding session_mutex.
    359 		 */
    360 		soft_crypt_cleanup(session_p, B_TRUE, B_TRUE);
    361 
    362 	if (session_p->decrypt.context != NULL)
    363 		/*
    364 		 * 1st B_FALSE: decrypt
    365 		 * 2nd B_TRUE: caller is holding session_mutex.
    366 		 */
    367 		soft_crypt_cleanup(session_p, B_FALSE, B_TRUE);
    368 
    369 	if (session_p->sign.context != NULL)
    370 		free(session_p->sign.context);
    371 
    372 	if (session_p->verify.context != NULL)
    373 		free(session_p->verify.context);
    374 
    375 	if (session_p->find_objects.context != NULL) {
    376 		find_context_t *fcontext;
    377 		fcontext = (find_context_t *)session_p->find_objects.context;
    378 		free(fcontext->objs_found);
    379 		free(fcontext);
    380 	}
    381 
    382 	/* Reset SESSION_IS_CLOSIN flag. */
    383 	session_p->ses_close_sync &= ~SESSION_IS_CLOSING;
    384 
    385 	(void) pthread_mutex_unlock(&session_p->session_mutex);
    386 	/* Destroy the individual session lock */
    387 	(void) pthread_mutex_destroy(&session_p->session_mutex);
    388 
    389 	/* Delay freeing the session */
    390 	session_delay_free(session_p);
    391 
    392 	return (CKR_OK);
    393 }
    394 
    395 
    396 /*
    397  * This function is used to type cast a session handle to a pointer to
    398  * the session struct. Also, it does the following things:
    399  * 1) Check to see if the session struct is tagged with a session
    400  *    magic number. This is to detect when an application passes
    401  *    a bogus session pointer.
    402  * 2) Acquire the lock on the designated session.
    403  * 3) Check to see if the session is in the closing state that another
    404  *    thread is performing.
    405  * 4) Increment the session reference count by one. This is to prevent
    406  *    this session from being closed by other thread.
    407  * 5) Release the lock held on the designated session.
    408  */
    409 CK_RV
    410 handle2session(CK_SESSION_HANDLE hSession, soft_session_t **session_p)
    411 {
    412 
    413 	soft_session_t *sp = (soft_session_t *)(hSession);
    414 
    415 	/*
    416 	 * No need to hold soft_sessionlist_mutex as we are
    417 	 * just reading the value and 32-bit reads are atomic.
    418 	 */
    419 	if (all_sessions_closing) {
    420 		return (CKR_SESSION_CLOSED);
    421 	}
    422 
    423 	if ((sp == NULL) ||
    424 	    (sp->magic_marker != SOFTTOKEN_SESSION_MAGIC)) {
    425 		return (CKR_SESSION_HANDLE_INVALID);
    426 	}
    427 	(void) pthread_mutex_lock(&sp->session_mutex);
    428 
    429 	if (sp->ses_close_sync & SESSION_IS_CLOSING) {
    430 		(void) pthread_mutex_unlock(&sp->session_mutex);
    431 		return (CKR_SESSION_CLOSED);
    432 	}
    433 
    434 	/* Increment session ref count. */
    435 	sp->ses_refcnt++;
    436 
    437 	(void) pthread_mutex_unlock(&sp->session_mutex);
    438 
    439 	*session_p = sp;
    440 
    441 	return (CKR_OK);
    442 }
    443 
    444 /*
    445  * The format to be saved in the pOperationState will be:
    446  * 1. internal_op_state_t
    447  * 2. crypto_active_op_t
    448  * 3. actual context of the active operation
    449  */
    450 CK_RV
    451 soft_get_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState,
    452     CK_ULONG_PTR pulOperationStateLen)
    453 {
    454 
    455 	internal_op_state_t *p_op_state;
    456 	CK_ULONG op_data_len = 0;
    457 	CK_RV rv = CKR_OK;
    458 
    459 	if (pulOperationStateLen == NULL)
    460 		return (CKR_ARGUMENTS_BAD);
    461 
    462 	(void) pthread_mutex_lock(&session_p->session_mutex);
    463 
    464 	/* Check to see if encrypt operation is active. */
    465 	if (session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE) {
    466 		rv = CKR_STATE_UNSAVEABLE;
    467 		goto unlock_session;
    468 	}
    469 
    470 	/* Check to see if decrypt operation is active. */
    471 	if (session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE) {
    472 		rv = CKR_STATE_UNSAVEABLE;
    473 		goto unlock_session;
    474 	}
    475 
    476 	/* Check to see if sign operation is active. */
    477 	if (session_p->sign.flags & CRYPTO_OPERATION_ACTIVE) {
    478 		rv = CKR_STATE_UNSAVEABLE;
    479 		goto unlock_session;
    480 	}
    481 
    482 	/* Check to see if verify operation is active. */
    483 	if (session_p->verify.flags & CRYPTO_OPERATION_ACTIVE) {
    484 		rv = CKR_STATE_UNSAVEABLE;
    485 		goto unlock_session;
    486 	}
    487 
    488 	/* Check to see if digest operation is active. */
    489 	if (session_p->digest.flags & CRYPTO_OPERATION_ACTIVE) {
    490 		op_data_len = sizeof (internal_op_state_t) +
    491 		    sizeof (crypto_active_op_t);
    492 
    493 		switch (session_p->digest.mech.mechanism) {
    494 		case CKM_MD5:
    495 			op_data_len += sizeof (MD5_CTX);
    496 			break;
    497 		case CKM_SHA_1:
    498 			op_data_len += sizeof (SHA1_CTX);
    499 			break;
    500 		default:
    501 			rv = CKR_STATE_UNSAVEABLE;
    502 			goto unlock_session;
    503 		}
    504 
    505 		if (pOperationState == NULL_PTR) {
    506 			*pulOperationStateLen = op_data_len;
    507 			goto unlock_session;
    508 		} else {
    509 			if (*pulOperationStateLen < op_data_len) {
    510 				*pulOperationStateLen = op_data_len;
    511 				rv = CKR_BUFFER_TOO_SMALL;
    512 				goto unlock_session;
    513 			}
    514 		}
    515 
    516 		/* Save internal_op_state_t */
    517 		/* LINTED E_BAD_PTR_CAST_ALIGN */
    518 		p_op_state = (internal_op_state_t *)pOperationState;
    519 		p_op_state->op_len = op_data_len;
    520 		p_op_state->op_active = DIGEST_OP;
    521 		p_op_state->op_session_state = session_p->state;
    522 
    523 		/* Save crypto_active_op_t */
    524 		(void) memcpy((CK_BYTE *)pOperationState +
    525 		    sizeof (internal_op_state_t),
    526 		    &session_p->digest,
    527 		    sizeof (crypto_active_op_t));
    528 
    529 		switch (session_p->digest.mech.mechanism) {
    530 		case CKM_MD5:
    531 			/* Save MD5_CTX for the active digest operation */
    532 			(void) memcpy((CK_BYTE *)pOperationState +
    533 			    sizeof (internal_op_state_t) +
    534 			    sizeof (crypto_active_op_t),
    535 			    session_p->digest.context,
    536 			    sizeof (MD5_CTX));
    537 			break;
    538 
    539 		case CKM_SHA_1:
    540 			/* Save SHA1_CTX for the active digest operation */
    541 			(void) memcpy((CK_BYTE *)pOperationState +
    542 			    sizeof (internal_op_state_t) +
    543 			    sizeof (crypto_active_op_t),
    544 			    session_p->digest.context,
    545 			    sizeof (SHA1_CTX));
    546 			break;
    547 
    548 		default:
    549 			rv = CKR_STATE_UNSAVEABLE;
    550 		}
    551 	} else {
    552 		rv = CKR_OPERATION_NOT_INITIALIZED;
    553 		goto unlock_session;
    554 	}
    555 
    556 	*pulOperationStateLen = op_data_len;
    557 
    558 unlock_session:
    559 	(void) pthread_mutex_unlock(&session_p->session_mutex);
    560 
    561 	return (rv);
    562 
    563 }
    564 
    565 static CK_BYTE_PTR alloc_digest(CK_ULONG mech)
    566 {
    567 	CK_BYTE_PTR	ret_val;
    568 
    569 	switch (mech) {
    570 		case CKM_MD5:
    571 			ret_val = (CK_BYTE_PTR) malloc(sizeof (MD5_CTX));
    572 			break;
    573 		case CKM_SHA_1:
    574 			ret_val = (CK_BYTE_PTR) malloc(sizeof (SHA1_CTX));
    575 			break;
    576 		default: ret_val = NULL;
    577 	}
    578 
    579 	return (ret_val);
    580 }
    581 
    582 /*
    583  * The format to be restored from the pOperationState will be:
    584  * 1. internal_op_state_t
    585  * 2. crypto_active_op_t
    586  * 3. actual context of the saved operation
    587  */
    588 CK_RV
    589 soft_set_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState,
    590     CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey,
    591     CK_OBJECT_HANDLE hAuthenticationKey)
    592 {
    593 
    594 	CK_RV		rv = CKR_OK;
    595 	internal_op_state_t *p_op_state;
    596 	crypto_active_op_t *p_active_op;
    597 	CK_ULONG offset = 0;
    598 	CK_ULONG mech;
    599 	void *free_it = NULL;
    600 
    601 	/* LINTED E_BAD_PTR_CAST_ALIGN */
    602 	p_op_state = (internal_op_state_t *)pOperationState;
    603 
    604 	if (p_op_state->op_len != ulOperationStateLen) {
    605 		/*
    606 		 * The supplied data length does not match with
    607 		 * the saved data length.
    608 		 */
    609 		return (CKR_SAVED_STATE_INVALID);
    610 	}
    611 
    612 	if (p_op_state->op_active != DIGEST_OP)
    613 		return (CKR_SAVED_STATE_INVALID);
    614 
    615 	if ((hAuthenticationKey != 0) || (hEncryptionKey != 0)) {
    616 		return (CKR_KEY_NOT_NEEDED);
    617 	}
    618 
    619 	offset = sizeof (internal_op_state_t);
    620 	/* LINTED E_BAD_PTR_CAST_ALIGN */
    621 	p_active_op = (crypto_active_op_t *)(pOperationState + offset);
    622 	offset += sizeof (crypto_active_op_t);
    623 	mech = p_active_op->mech.mechanism;
    624 
    625 	if (!DIGEST_MECH_OK(mech)) {
    626 		return (CKR_SAVED_STATE_INVALID);
    627 	}
    628 
    629 	/*
    630 	 * We may reuse digest.context in case the digest mechanisms (the one,
    631 	 * which belongs to session and the operation, which we are restoring)
    632 	 * are the same. If digest mechanisms are different, we have to release
    633 	 * the digest context, which belongs to session and allocate a new one.
    634 	 */
    635 	(void) pthread_mutex_lock(&session_p->session_mutex);
    636 
    637 	if (session_p->state != p_op_state->op_session_state) {
    638 		/*
    639 		 * The supplied session state does not match with
    640 		 * the saved session state.
    641 		 */
    642 		rv = CKR_SAVED_STATE_INVALID;
    643 		goto unlock_session;
    644 	}
    645 
    646 	if (session_p->digest.context &&
    647 	    (session_p->digest.mech.mechanism != mech)) {
    648 		free_it = session_p->digest.context;
    649 		session_p->digest.context = NULL;
    650 	}
    651 
    652 	if (session_p->digest.context == NULL) {
    653 		session_p->digest.context = alloc_digest(mech);
    654 
    655 		if (session_p->digest.context == NULL) {
    656 			/*
    657 			 * put back original context into session in case
    658 			 * allocation of new context has failed.
    659 			 */
    660 			session_p->digest.context = free_it;
    661 			free_it = NULL;
    662 			rv = CKR_HOST_MEMORY;
    663 			goto unlock_session;
    664 		}
    665 	}
    666 
    667 	/* Restore crypto_active_op_t */
    668 	session_p->digest.mech.mechanism = mech;
    669 	session_p->digest.flags = p_active_op->flags;
    670 
    671 	switch (mech) {
    672 		case CKM_MD5:
    673 			/* Restore MD5_CTX from the saved digest operation */
    674 			(void) memcpy((CK_BYTE *)session_p->digest.context,
    675 			    (CK_BYTE *)pOperationState + offset,
    676 			    sizeof (MD5_CTX));
    677 			break;
    678 		case CKM_SHA_1:
    679 			/* Restore SHA1_CTX from the saved digest operation */
    680 			(void) memcpy((CK_BYTE *)session_p->digest.context,
    681 			    (CK_BYTE *)pOperationState + offset,
    682 			    sizeof (SHA1_CTX));
    683 			break;
    684 		default:
    685 			/* never reached */
    686 			rv = CKR_SAVED_STATE_INVALID;
    687 	}
    688 
    689 unlock_session:
    690 	(void) pthread_mutex_unlock(&session_p->session_mutex);
    691 
    692 	if (free_it != NULL)
    693 		free(free_it);
    694 
    695 	return (rv);
    696 }
    697 
    698 
    699 CK_RV
    700 soft_login(CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
    701 {
    702 
    703 	/*
    704 	 * Authenticate the input PIN.
    705 	 */
    706 	return (soft_verify_pin(pPin, ulPinLen));
    707 
    708 }
    709 
    710 void
    711 soft_logout(void)
    712 {
    713 
    714 	/*
    715 	 * Delete all the private token objects from the "token_object_list".
    716 	 */
    717 	soft_delete_all_in_core_token_objects(PRIVATE_TOKEN);
    718 	return;
    719 
    720 }
    721 
    722 void
    723 soft_acquire_all_session_mutexes(soft_session_t *session_p)
    724 {
    725 	/* Iterate through sessions acquiring all mutexes */
    726 	while (session_p) {
    727 		soft_object_t *object_p;
    728 
    729 		(void) pthread_mutex_lock(&session_p->session_mutex);
    730 		object_p = session_p->object_list;
    731 
    732 		/* Lock also all objects related to session */
    733 		while (object_p) {
    734 			(void) pthread_mutex_lock(&object_p->object_mutex);
    735 			object_p = object_p->next;
    736 		}
    737 		session_p = session_p->next;
    738 	}
    739 }
    740 
    741 void
    742 soft_release_all_session_mutexes(soft_session_t *session_p)
    743 {
    744 	/* Iterate through sessions releasing all mutexes */
    745 	while (session_p) {
    746 		/*
    747 		 * N.B. Ideally, should go in opposite order to guarantee
    748 		 * lock-order requirements but there is no tail pointer.
    749 		 */
    750 		soft_object_t *object_p = session_p->object_list;
    751 
    752 		/* Unlock also all objects related to session */
    753 		while (object_p) {
    754 			(void) pthread_mutex_unlock(&object_p->object_mutex);
    755 			object_p = object_p->next;
    756 		}
    757 		(void) pthread_mutex_unlock(&session_p->session_mutex);
    758 		session_p = session_p->next;
    759 	}
    760 }
    761