2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <md5.h>
2N/A#include <pthread.h>
2N/A#include <syslog.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <sys/sha1.h>
2N/A#include <sys/sha2.h>
2N/A#include <security/cryptoki.h>
2N/A#include "softGlobal.h"
2N/A#include "softSession.h"
2N/A#include "softObject.h"
2N/A#include "softOps.h"
2N/A#include "softKeystore.h"
2N/A#include "softKeystoreUtil.h"
2N/A
2N/A
2N/ACK_ULONG soft_session_cnt = 0; /* the number of opened sessions */
2N/ACK_ULONG soft_session_rw_cnt = 0; /* the number of opened R/W sessions */
2N/A
2N/A#define DIGEST_MECH_OK(_m_) ((_m_) == CKM_MD5 || (_m_) == CKM_SHA_1 || \
2N/A (_m_) == CKM_SHA224 || (_m_) == CKM_SHA256 || \
2N/A (_m_) == CKM_SHA384 || (_m_) == CKM_SHA512)
2N/A
2N/Aextern soft_session_t token_session;
2N/A
2N/A/*
2N/A * Delete all the sessions. First, obtain the global session
2N/A * list lock. Then start to delete one session at a time.
2N/A * Release the global session list lock before returning to
2N/A * caller.
2N/A */
2N/ACK_RV
2N/Asoft_delete_all_sessions(boolean_t force)
2N/A{
2N/A
2N/A CK_RV rv = CKR_OK;
2N/A CK_RV rv1;
2N/A soft_session_t *session_p;
2N/A soft_session_t *session_p1;
2N/A
2N/A /* Acquire the global session list lock */
2N/A (void) pthread_mutex_lock(&soft_sessionlist_mutex);
2N/A
2N/A session_p = soft_session_list;
2N/A
2N/A /* Delete all the sessions in the session list */
2N/A while (session_p) {
2N/A session_p1 = session_p->next;
2N/A
2N/A /*
2N/A * Delete a session by calling soft_delete_session()
2N/A * with a session pointer and a boolean arguments.
2N/A * Boolean value TRUE is used to indicate that the
2N/A * caller holds the lock on the global session list.
2N/A *
2N/A */
2N/A rv1 = soft_delete_session(session_p, force, B_TRUE);
2N/A
2N/A /* Record the very first error code */
2N/A if (rv == CKR_OK) {
2N/A rv = rv1;
2N/A }
2N/A
2N/A session_p = session_p1;
2N/A }
2N/A
2N/A /* No session left */
2N/A soft_session_list = NULL;
2N/A
2N/A /* Release the global session list lock */
2N/A (void) pthread_mutex_unlock(&soft_sessionlist_mutex);
2N/A
2N/A return (rv);
2N/A
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Create a new session struct, and add it to the session linked list.
2N/A *
2N/A * This function will acquire the global session list lock, and release
2N/A * it after adding the session to the session linked list.
2N/A */
2N/ACK_RV
2N/Asoft_add_session(CK_FLAGS flags, CK_VOID_PTR pApplication,
2N/A CK_NOTIFY notify, CK_ULONG *sessionhandle_p)
2N/A{
2N/A
2N/A soft_session_t *new_sp = NULL;
2N/A
2N/A /* Allocate a new session struct */
2N/A new_sp = calloc(1, sizeof (soft_session_t));
2N/A if (new_sp == NULL) {
2N/A return (CKR_HOST_MEMORY);
2N/A }
2N/A
2N/A new_sp->magic_marker = SOFTTOKEN_SESSION_MAGIC;
2N/A new_sp->pApplication = pApplication;
2N/A new_sp->Notify = notify;
2N/A new_sp->flags = flags;
2N/A new_sp->state = CKS_RO_PUBLIC_SESSION;
2N/A new_sp->object_list = NULL;
2N/A new_sp->ses_refcnt = 0;
2N/A new_sp->ses_close_sync = 0;
2N/A
2N/A (void) pthread_mutex_lock(&soft_giant_mutex);
2N/A if (soft_slot.authenticated) {
2N/A (void) pthread_mutex_unlock(&soft_giant_mutex);
2N/A if (flags & CKF_RW_SESSION) {
2N/A new_sp->state = CKS_RW_USER_FUNCTIONS;
2N/A } else {
2N/A new_sp->state = CKS_RO_USER_FUNCTIONS;
2N/A }
2N/A } else {
2N/A (void) pthread_mutex_unlock(&soft_giant_mutex);
2N/A if (flags & CKF_RW_SESSION) {
2N/A new_sp->state = CKS_RW_PUBLIC_SESSION;
2N/A } else {
2N/A new_sp->state = CKS_RO_PUBLIC_SESSION;
2N/A }
2N/A }
2N/A
2N/A /* Initialize the lock for the newly created session */
2N/A if (pthread_mutex_init(&new_sp->session_mutex, NULL) != 0) {
2N/A free(new_sp);
2N/A return (CKR_CANT_LOCK);
2N/A }
2N/A
2N/A (void) pthread_cond_init(&new_sp->ses_free_cond, NULL);
2N/A
2N/A /* Acquire the global session list lock */
2N/A (void) pthread_mutex_lock(&soft_sessionlist_mutex);
2N/A
2N/A /* Insert the new session in front of session list */
2N/A if (soft_session_list == NULL) {
2N/A soft_session_list = new_sp;
2N/A new_sp->next = NULL;
2N/A new_sp->prev = NULL;
2N/A } else {
2N/A soft_session_list->prev = new_sp;
2N/A new_sp->next = soft_session_list;
2N/A new_sp->prev = NULL;
2N/A soft_session_list = new_sp;
2N/A }
2N/A
2N/A /* Type casting the address of a session struct to a session handle */
2N/A *sessionhandle_p = (CK_ULONG)new_sp;
2N/A ++soft_session_cnt;
2N/A if (flags & CKF_RW_SESSION)
2N/A ++soft_session_rw_cnt;
2N/A
2N/A if (soft_session_cnt == 1)
2N/A /*
2N/A * This is the first session to be opened, so we can set
2N/A * validate the public token objects in token list now.
2N/A */
2N/A soft_validate_token_objects(B_TRUE);
2N/A
2N/A /* Release the global session list lock */
2N/A (void) pthread_mutex_unlock(&soft_sessionlist_mutex);
2N/A
2N/A return (CKR_OK);
2N/A
2N/A}
2N/A
2N/A/*
2N/A * This function adds the to-be-freed session to a linked list.
2N/A * When the number of sessions queued in the linked list reaches the
2N/A * maximum threshold MAX_SES_TO_BE_FREED, it will free the first
2N/A * session (FIFO) in the list.
2N/A */
2N/Avoid
2N/Asession_delay_free(soft_session_t *sp)
2N/A{
2N/A soft_session_t *tmp;
2N/A
2N/A (void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex);
2N/A
2N/A /* Add the newly deleted session at the end of the list */
2N/A sp->next = NULL;
2N/A if (ses_delay_freed.first == NULL) {
2N/A ses_delay_freed.last = sp;
2N/A ses_delay_freed.first = sp;
2N/A } else {
2N/A ses_delay_freed.last->next = sp;
2N/A ses_delay_freed.last = sp;
2N/A }
2N/A
2N/A if (++ses_delay_freed.count >= MAX_SES_TO_BE_FREED) {
2N/A /*
2N/A * Free the first session in the list only if
2N/A * the total count reaches maximum threshold.
2N/A */
2N/A ses_delay_freed.count--;
2N/A tmp = ses_delay_freed.first->next;
2N/A free(ses_delay_freed.first);
2N/A ses_delay_freed.first = tmp;
2N/A }
2N/A (void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex);
2N/A}
2N/A
2N/A/*
2N/A * Delete a session:
2N/A * - Remove the session from the session linked list.
2N/A * Holding the lock on the global session list is needed to do this.
2N/A * - Release all the objects created by the session.
2N/A *
2N/A * The boolean argument lock_held is used to indicate that whether
2N/A * the caller of this function holds the lock on the global session
2N/A * list or not.
2N/A * - When called by soft_delete_all_sessions(), which is called by
2N/A * C_Finalize() or C_CloseAllSessions() -- the lock_held = TRUE.
2N/A * - When called by C_CloseSession() -- the lock_held = FALSE.
2N/A *
2N/A * When the caller does not hold the lock on the global session
2N/A * list, this function will acquire that lock in order to proceed,
2N/A * and also release that lock before returning to caller.
2N/A */
2N/ACK_RV
2N/Asoft_delete_session(soft_session_t *session_p,
2N/A boolean_t force, boolean_t lock_held)
2N/A{
2N/A
2N/A /*
2N/A * Check to see if the caller holds the lock on the global
2N/A * session list. If not, we need to acquire that lock in
2N/A * order to proceed.
2N/A */
2N/A if (!lock_held) {
2N/A /* Acquire the global session list lock */
2N/A (void) pthread_mutex_lock(&soft_sessionlist_mutex);
2N/A }
2N/A
2N/A /*
2N/A * Remove the session from the session linked list first.
2N/A */
2N/A if (soft_session_list == session_p) {
2N/A /* Session is the first one in the list */
2N/A if (session_p->next) {
2N/A soft_session_list = session_p->next;
2N/A session_p->next->prev = NULL;
2N/A } else {
2N/A /* Session is the only one in the list */
2N/A soft_session_list = NULL;
2N/A }
2N/A } else {
2N/A /* Session is not the first one in the list */
2N/A if (session_p->next) {
2N/A /* Session is in the middle of the list */
2N/A session_p->prev->next = session_p->next;
2N/A session_p->next->prev = session_p->prev;
2N/A } else {
2N/A /* Session is the last one in the list */
2N/A session_p->prev->next = NULL;
2N/A }
2N/A }
2N/A
2N/A --soft_session_cnt;
2N/A if (session_p->flags & CKF_RW_SESSION)
2N/A --soft_session_rw_cnt;
2N/A
2N/A if (!lock_held) {
2N/A /*
2N/A * If the global session list lock is obtained by
2N/A * this function, then release that lock after
2N/A * removing the session from session linked list.
2N/A * We want the releasing of the objects of the
2N/A * session, and freeing of the session itself to
2N/A * be done without holding the global session list
2N/A * lock.
2N/A */
2N/A (void) pthread_mutex_unlock(&soft_sessionlist_mutex);
2N/A }
2N/A
2N/A
2N/A /* Acquire the individual session lock */
2N/A (void) pthread_mutex_lock(&session_p->session_mutex);
2N/A /*
2N/A * Make sure another thread hasn't freed the session.
2N/A */
2N/A if (session_p->magic_marker != SOFTTOKEN_SESSION_MAGIC) {
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A return (CKR_OK);
2N/A }
2N/A
2N/A /*
2N/A * The deletion of a session must be blocked when the session
2N/A * reference count is not zero. This means if any session related
2N/A * operation starts prior to the session close operation gets in,
2N/A * the session closing thread must wait for the non-closing
2N/A * operation to be completed before it can proceed the close
2N/A * operation.
2N/A *
2N/A * Unless we are being forced to shut everything down, this only
2N/A * happens if the libraries _fini() is running not of someone
2N/A * explicitly called C_Finalize().
2N/A */
2N/A if (force)
2N/A session_p->ses_refcnt = 0;
2N/A
2N/A while (session_p->ses_refcnt != 0) {
2N/A /*
2N/A * We set the SESSION_REFCNT_WAITING flag before we put
2N/A * this closing thread in a wait state, so other non-closing
2N/A * operation thread will signal to wake it up only when
2N/A * the session reference count becomes zero and this flag
2N/A * is set.
2N/A */
2N/A session_p->ses_close_sync |= SESSION_REFCNT_WAITING;
2N/A (void) pthread_cond_wait(&session_p->ses_free_cond,
2N/A &session_p->session_mutex);
2N/A }
2N/A
2N/A session_p->ses_close_sync &= ~SESSION_REFCNT_WAITING;
2N/A
2N/A /*
2N/A * Remove all the objects created in this session.
2N/A */
2N/A soft_delete_all_objects_in_session(session_p, force);
2N/A
2N/A /*
2N/A * Mark session as no longer valid. This can only be done after all
2N/A * objects created by this session are free'd since the marker is
2N/A * still needed in the process of removing objects from the session.
2N/A */
2N/A session_p->magic_marker = 0;
2N/A
2N/A (void) pthread_cond_destroy(&session_p->ses_free_cond);
2N/A
2N/A /* In case application did not call Final */
2N/A if (session_p->digest.context != NULL)
2N/A free(session_p->digest.context);
2N/A
2N/A if (session_p->encrypt.context != NULL)
2N/A /*
2N/A * 1st B_TRUE: encrypt
2N/A * 2nd B_TRUE: caller is holding session_mutex.
2N/A */
2N/A soft_crypt_cleanup(session_p, B_TRUE, B_TRUE);
2N/A
2N/A if (session_p->decrypt.context != NULL)
2N/A /*
2N/A * 1st B_FALSE: decrypt
2N/A * 2nd B_TRUE: caller is holding session_mutex.
2N/A */
2N/A soft_crypt_cleanup(session_p, B_FALSE, B_TRUE);
2N/A
2N/A if (session_p->sign.context != NULL)
2N/A free(session_p->sign.context);
2N/A
2N/A if (session_p->verify.context != NULL)
2N/A free(session_p->verify.context);
2N/A
2N/A if (session_p->find_objects.context != NULL) {
2N/A find_context_t *fcontext;
2N/A fcontext = (find_context_t *)session_p->find_objects.context;
2N/A free(fcontext->objs_found);
2N/A free(fcontext);
2N/A }
2N/A
2N/A /* Reset SESSION_IS_CLOSIN flag. */
2N/A session_p->ses_close_sync &= ~SESSION_IS_CLOSING;
2N/A
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A /* Destroy the individual session lock */
2N/A (void) pthread_mutex_destroy(&session_p->session_mutex);
2N/A
2N/A /* Delay freeing the session */
2N/A session_delay_free(session_p);
2N/A
2N/A return (CKR_OK);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * This function is used to type cast a session handle to a pointer to
2N/A * the session struct. Also, it does the following things:
2N/A * 1) Check to see if the session struct is tagged with a session
2N/A * magic number. This is to detect when an application passes
2N/A * a bogus session pointer.
2N/A * 2) Acquire the lock on the designated session.
2N/A * 3) Check to see if the session is in the closing state that another
2N/A * thread is performing.
2N/A * 4) Increment the session reference count by one. This is to prevent
2N/A * this session from being closed by other thread.
2N/A * 5) Release the lock held on the designated session.
2N/A */
2N/ACK_RV
2N/Ahandle2session(CK_SESSION_HANDLE hSession, soft_session_t **session_p)
2N/A{
2N/A int rv;
2N/A
2N/A HANDLE2SESSION(hSession, session_p, rv);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * The format to be saved in the pOperationState will be:
2N/A * 1. internal_op_state_t
2N/A * 2. crypto_active_op_t
2N/A * 3. actual context of the active operation
2N/A */
2N/ACK_RV
2N/Asoft_get_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState,
2N/A CK_ULONG_PTR pulOperationStateLen)
2N/A{
2N/A CK_ULONG op_data_len = 0;
2N/A CK_RV rv = CKR_OK;
2N/A internal_op_state_t op_state;
2N/A
2N/A if (pulOperationStateLen == NULL)
2N/A return (CKR_ARGUMENTS_BAD);
2N/A
2N/A (void) pthread_mutex_lock(&session_p->session_mutex);
2N/A
2N/A /* Check to see if encrypt operation is active. */
2N/A if (session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE) {
2N/A rv = CKR_STATE_UNSAVEABLE;
2N/A goto unlock_session;
2N/A }
2N/A
2N/A /* Check to see if decrypt operation is active. */
2N/A if (session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE) {
2N/A rv = CKR_STATE_UNSAVEABLE;
2N/A goto unlock_session;
2N/A }
2N/A
2N/A /* Check to see if sign operation is active. */
2N/A if (session_p->sign.flags & CRYPTO_OPERATION_ACTIVE) {
2N/A rv = CKR_STATE_UNSAVEABLE;
2N/A goto unlock_session;
2N/A }
2N/A
2N/A /* Check to see if verify operation is active. */
2N/A if (session_p->verify.flags & CRYPTO_OPERATION_ACTIVE) {
2N/A rv = CKR_STATE_UNSAVEABLE;
2N/A goto unlock_session;
2N/A }
2N/A
2N/A /* Check to see if digest operation is active. */
2N/A if (session_p->digest.flags & CRYPTO_OPERATION_ACTIVE) {
2N/A op_data_len = sizeof (internal_op_state_t) +
2N/A sizeof (crypto_active_op_t);
2N/A
2N/A switch (session_p->digest.mech.mechanism) {
2N/A case CKM_MD5:
2N/A op_data_len += sizeof (MD5_CTX);
2N/A break;
2N/A case CKM_SHA_1:
2N/A op_data_len += sizeof (SHA1_CTX);
2N/A break;
2N/A case CKM_SHA224:
2N/A case CKM_SHA256:
2N/A case CKM_SHA384:
2N/A case CKM_SHA512:
2N/A op_data_len += sizeof (SHA2_CTX);
2N/A break;
2N/A default:
2N/A rv = CKR_STATE_UNSAVEABLE;
2N/A goto unlock_session;
2N/A }
2N/A
2N/A if (pOperationState == NULL_PTR) {
2N/A *pulOperationStateLen = op_data_len;
2N/A goto unlock_session;
2N/A } else {
2N/A if (*pulOperationStateLen < op_data_len) {
2N/A *pulOperationStateLen = op_data_len;
2N/A rv = CKR_BUFFER_TOO_SMALL;
2N/A goto unlock_session;
2N/A }
2N/A }
2N/A
2N/A /* Save internal_op_state_t */
2N/A op_state.op_len = op_data_len;
2N/A op_state.op_active = DIGEST_OP;
2N/A op_state.op_session_state = session_p->state;
2N/A (void) memcpy(pOperationState, &op_state,
2N/A sizeof (internal_op_state_t));
2N/A
2N/A /* Save crypto_active_op_t */
2N/A (void) memcpy((CK_BYTE *)pOperationState +
2N/A sizeof (internal_op_state_t),
2N/A &session_p->digest,
2N/A sizeof (crypto_active_op_t));
2N/A
2N/A switch (session_p->digest.mech.mechanism) {
2N/A case CKM_MD5:
2N/A /* Save MD5_CTX for the active digest operation */
2N/A (void) memcpy((CK_BYTE *)pOperationState +
2N/A sizeof (internal_op_state_t) +
2N/A sizeof (crypto_active_op_t),
2N/A session_p->digest.context,
2N/A sizeof (MD5_CTX));
2N/A break;
2N/A
2N/A case CKM_SHA_1:
2N/A /* Save SHA1_CTX for the active digest operation */
2N/A (void) memcpy((CK_BYTE *)pOperationState +
2N/A sizeof (internal_op_state_t) +
2N/A sizeof (crypto_active_op_t),
2N/A session_p->digest.context,
2N/A sizeof (SHA1_CTX));
2N/A break;
2N/A
2N/A case CKM_SHA224:
2N/A case CKM_SHA256:
2N/A case CKM_SHA384:
2N/A case CKM_SHA512:
2N/A /* Save SHA2_CTX for the active digest operation */
2N/A (void) memcpy((CK_BYTE *)pOperationState +
2N/A sizeof (internal_op_state_t) +
2N/A sizeof (crypto_active_op_t),
2N/A session_p->digest.context,
2N/A sizeof (SHA2_CTX));
2N/A break;
2N/A
2N/A default:
2N/A rv = CKR_STATE_UNSAVEABLE;
2N/A }
2N/A } else {
2N/A rv = CKR_OPERATION_NOT_INITIALIZED;
2N/A goto unlock_session;
2N/A }
2N/A
2N/A *pulOperationStateLen = op_data_len;
2N/A
2N/Aunlock_session:
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A
2N/A return (rv);
2N/A
2N/A}
2N/A
2N/Astatic CK_BYTE_PTR alloc_digest(CK_ULONG mech)
2N/A{
2N/A CK_BYTE_PTR ret_val;
2N/A
2N/A switch (mech) {
2N/A case CKM_MD5:
2N/A ret_val = (CK_BYTE_PTR) malloc(sizeof (MD5_CTX));
2N/A break;
2N/A case CKM_SHA_1:
2N/A ret_val = (CK_BYTE_PTR) malloc(sizeof (SHA1_CTX));
2N/A break;
2N/A case CKM_SHA224:
2N/A case CKM_SHA256:
2N/A case CKM_SHA384:
2N/A case CKM_SHA512:
2N/A ret_val = (CK_BYTE_PTR) malloc(sizeof (SHA2_CTX));
2N/A break;
2N/A default:
2N/A ret_val = NULL;
2N/A }
2N/A
2N/A return (ret_val);
2N/A}
2N/A
2N/A/*
2N/A * The format to be restored from the pOperationState will be:
2N/A * 1. internal_op_state_t
2N/A * 2. crypto_active_op_t
2N/A * 3. actual context of the saved operation
2N/A */
2N/ACK_RV
2N/Asoft_set_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState,
2N/A CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey,
2N/A CK_OBJECT_HANDLE hAuthenticationKey)
2N/A{
2N/A
2N/A CK_RV rv = CKR_OK;
2N/A internal_op_state_t op_state;
2N/A crypto_active_op_t active_op;
2N/A crypto_active_op_t *p_active_op = &active_op;
2N/A CK_ULONG offset = 0;
2N/A CK_ULONG mech;
2N/A void *free_it = NULL;
2N/A
2N/A (void) memcpy(&op_state, pOperationState, sizeof (internal_op_state_t));
2N/A
2N/A if (op_state.op_len != ulOperationStateLen) {
2N/A /*
2N/A * The supplied data length does not match with
2N/A * the saved data length.
2N/A */
2N/A return (CKR_SAVED_STATE_INVALID);
2N/A }
2N/A
2N/A if (op_state.op_active != DIGEST_OP)
2N/A return (CKR_SAVED_STATE_INVALID);
2N/A
2N/A if ((hAuthenticationKey != 0) || (hEncryptionKey != 0)) {
2N/A return (CKR_KEY_NOT_NEEDED);
2N/A }
2N/A
2N/A offset = sizeof (internal_op_state_t);
2N/A (void) memcpy(p_active_op, pOperationState + offset,
2N/A sizeof (crypto_active_op_t));
2N/A offset += sizeof (crypto_active_op_t);
2N/A mech = p_active_op->mech.mechanism;
2N/A
2N/A if (!DIGEST_MECH_OK(mech)) {
2N/A return (CKR_SAVED_STATE_INVALID);
2N/A }
2N/A
2N/A /*
2N/A * We may reuse digest.context in case the digest mechanisms (the one,
2N/A * which belongs to session and the operation, which we are restoring)
2N/A * are the same. If digest mechanisms are different, we have to release
2N/A * the digest context, which belongs to session and allocate a new one.
2N/A */
2N/A (void) pthread_mutex_lock(&session_p->session_mutex);
2N/A
2N/A if (session_p->state != op_state.op_session_state) {
2N/A /*
2N/A * The supplied session state does not match with
2N/A * the saved session state.
2N/A */
2N/A rv = CKR_SAVED_STATE_INVALID;
2N/A goto unlock_session;
2N/A }
2N/A
2N/A if (session_p->digest.context &&
2N/A (session_p->digest.mech.mechanism != mech)) {
2N/A free_it = session_p->digest.context;
2N/A session_p->digest.context = NULL;
2N/A }
2N/A
2N/A if (session_p->digest.context == NULL) {
2N/A session_p->digest.context = alloc_digest(mech);
2N/A
2N/A if (session_p->digest.context == NULL) {
2N/A /*
2N/A * put back original context into session in case
2N/A * allocation of new context has failed.
2N/A */
2N/A session_p->digest.context = free_it;
2N/A free_it = NULL;
2N/A rv = CKR_HOST_MEMORY;
2N/A goto unlock_session;
2N/A }
2N/A }
2N/A
2N/A /* Restore crypto_active_op_t */
2N/A session_p->digest.mech.mechanism = mech;
2N/A session_p->digest.flags = p_active_op->flags;
2N/A
2N/A switch (mech) {
2N/A case CKM_MD5:
2N/A /* Restore MD5_CTX from the saved digest operation */
2N/A (void) memcpy((CK_BYTE *)session_p->digest.context,
2N/A (CK_BYTE *)pOperationState + offset,
2N/A sizeof (MD5_CTX));
2N/A break;
2N/A case CKM_SHA_1:
2N/A /* Restore SHA1_CTX from the saved digest operation */
2N/A (void) memcpy((CK_BYTE *)session_p->digest.context,
2N/A (CK_BYTE *)pOperationState + offset,
2N/A sizeof (SHA1_CTX));
2N/A break;
2N/A case CKM_SHA224:
2N/A case CKM_SHA256:
2N/A case CKM_SHA384:
2N/A case CKM_SHA512:
2N/A /* Restore SHA2_CTX from the saved digest operation */
2N/A (void) memcpy((CK_BYTE *)session_p->digest.context,
2N/A (CK_BYTE *)pOperationState + offset,
2N/A sizeof (SHA2_CTX));
2N/A break;
2N/A default:
2N/A rv = CKR_SAVED_STATE_INVALID;
2N/A }
2N/A
2N/Aunlock_session:
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A
2N/A if (free_it != NULL)
2N/A free(free_it);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A
2N/ACK_RV
2N/Asoft_login(CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
2N/A{
2N/A
2N/A /*
2N/A * Authenticate the input PIN.
2N/A */
2N/A return (soft_verify_pin(pPin, ulPinLen));
2N/A
2N/A}
2N/A
2N/Avoid
2N/Asoft_logout(void)
2N/A{
2N/A
2N/A /*
2N/A * Delete all the private token objects from the "token_object_list".
2N/A */
2N/A soft_delete_all_objects_in_session(&token_session, B_TRUE);
2N/A soft_delete_all_in_core_token_objects(PRIVATE_TOKEN);
2N/A return;
2N/A
2N/A}
2N/A
2N/A/*
2N/A * Acquire all session mutexes and their objects.
2N/A * Order:
2N/A * for each session:
2N/A * 1. session_p->session_mutex
2N/A * when sessions are locked we can lock their objects and
2N/A * for each session go through the session_p->object_list
2N/A * 2. objp->object_mutex
2N/A *
2N/A * Note 1: We have to lock all sessions first and after that we can lock their
2N/A * objects, because sometimes a function is called with a session and an object
2N/A * which does not belong to the session. Because session lock is acquired always
2N/A * before the object lock, it avoids deadlock.
2N/A *
2N/A * Note 2: The unlocking of the sessions and objects list should optimally be
2N/A * in the opposite order, but currently no thread locks two sessions or objects
2N/A * at the same time.
2N/A */
2N/Avoid
2N/Asoft_acquire_all_session_mutexes(soft_session_t *session_p)
2N/A{
2N/A soft_session_t *session_orig = session_p;
2N/A
2N/A /* Iterate through sessions acquiring all mutexes */
2N/A while (session_p) {
2N/A (void) pthread_mutex_lock(&session_p->session_mutex);
2N/A session_p = session_p->next;
2N/A }
2N/A
2N/A /* Iterate through sessions acquiring all object's mutexes */
2N/A session_p = session_orig;
2N/A while (session_p) {
2N/A soft_object_t *object_p = session_p->object_list;
2N/A
2N/A /* Lock also all objects related to session */
2N/A while (object_p) {
2N/A (void) pthread_mutex_lock(&object_p->object_mutex);
2N/A (void) pthread_rwlock_wrlock(&object_p->object_rwlock);
2N/A object_p = object_p->next;
2N/A }
2N/A session_p = session_p->next;
2N/A }
2N/A}
2N/A
2N/Avoid
2N/Asoft_release_all_session_mutexes(soft_session_t *session_p)
2N/A{
2N/A soft_session_t *session_orig = session_p;
2N/A
2N/A /* Iterate through sessions releasing all object's mutexes */
2N/A while (session_p) {
2N/A soft_object_t *object_p = session_p->object_list;
2N/A
2N/A /* Unlock also all objects related to session */
2N/A while (object_p) {
2N/A (void) pthread_rwlock_unlock(&object_p->object_rwlock);
2N/A (void) pthread_mutex_unlock(&object_p->object_mutex);
2N/A object_p = object_p->next;
2N/A }
2N/A session_p = session_p->next;
2N/A }
2N/A
2N/A /* Iterate through sessions releasing all mutexes */
2N/A session_p = session_orig;
2N/A while (session_p) {
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A session_p = session_p->next;
2N/A }
2N/A}
2N/A
2N/Avoid
2N/Asoft_set_session_context(soft_session_t *session_p, soft_session_op_t op,
2N/A void *pContext, CK_MECHANISM_PTR pMechanism)
2N/A{
2N/A (void) pthread_mutex_lock(&session_p->session_mutex);
2N/A
2N/A switch (op) {
2N/A case SOFT_ENCRYPT_OP:
2N/A session_p->encrypt.context = pContext;
2N/A session_p->encrypt.mech.mechanism = pMechanism->mechanism;
2N/A break;
2N/A case SOFT_DECRYPT_OP:
2N/A session_p->decrypt.context = pContext;
2N/A session_p->decrypt.mech.mechanism = pMechanism->mechanism;
2N/A break;
2N/A case SOFT_SIGN_OP:
2N/A session_p->sign.context = pContext;
2N/A session_p->sign.mech.mechanism = pMechanism->mechanism;
2N/A break;
2N/A case SOFT_VERIFY_OP:
2N/A session_p->verify.context = pContext;
2N/A session_p->verify.mech.mechanism = pMechanism->mechanism;
2N/A break;
2N/A case SOFT_DIGEST_OP:
2N/A session_p->digest.context = pContext;
2N/A session_p->digest.mech.mechanism = pMechanism->mechanism;
2N/A if (pMechanism->mechanism == CKM_SHA_1) {
2N/A session_p->digest.mech.pParameter =
2N/A pMechanism->pParameter;
2N/A session_p->digest.mech.ulParameterLen =
2N/A pMechanism->ulParameterLen;
2N/A }
2N/A break;
2N/A default:
2N/A break;
2N/A }
2N/A
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A}
2N/A
2N/Avoid
2N/Asoft_clear_session_context(soft_session_t *session_p, soft_session_op_t op,
2N/A size_t context_sz)
2N/A{
2N/A crypto_active_op_t *active_op;
2N/A
2N/A (void) pthread_mutex_lock(&session_p->session_mutex);
2N/A
2N/A switch (op) {
2N/A case SOFT_ENCRYPT_OP:
2N/A active_op = &(session_p->encrypt);
2N/A break;
2N/A case SOFT_DECRYPT_OP:
2N/A active_op = &(session_p->decrypt);
2N/A break;
2N/A case SOFT_SIGN_OP:
2N/A active_op = &(session_p->sign);
2N/A break;
2N/A case SOFT_VERIFY_OP:
2N/A active_op = &(session_p->verify);
2N/A break;
2N/A case SOFT_DIGEST_OP:
2N/A active_op = &(session_p->digest);
2N/A break;
2N/A default:
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A return;
2N/A }
2N/A
2N/A if (active_op->context != NULL) {
2N/A bzero(active_op->context, context_sz);
2N/A free(active_op->context);
2N/A active_op->context = NULL;
2N/A }
2N/A
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A}
2N/A
2N/Aint
2N/Asoft_session_operation_active(soft_session_t *session_p,
2N/A soft_session_op_t op, boolean_t keep_lock)
2N/A{
2N/A crypto_active_op_t *active_op;
2N/A
2N/A (void) pthread_mutex_lock(&session_p->session_mutex);
2N/A
2N/A switch (op) {
2N/A case SOFT_ENCRYPT_OP:
2N/A active_op = &(session_p->encrypt);
2N/A break;
2N/A case SOFT_DECRYPT_OP:
2N/A active_op = &(session_p->decrypt);
2N/A break;
2N/A case SOFT_SIGN_OP:
2N/A active_op = &(session_p->sign);
2N/A break;
2N/A case SOFT_VERIFY_OP:
2N/A active_op = &(session_p->verify);
2N/A break;
2N/A default:
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A return (0);
2N/A }
2N/A
2N/A /* Check to see if the operation is already active. */
2N/A if (active_op->flags & CRYPTO_OPERATION_ACTIVE) {
2N/A if (!keep_lock)
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A return (-1);
2N/A }
2N/A
2N/A /* This active flag will remain ON during the entire operation. */
2N/A active_op->flags = CRYPTO_OPERATION_ACTIVE;
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A return (0);
2N/A}
2N/A
2N/Avoid
2N/Asoft_session_operation_inactive(soft_session_t *session_p,
2N/A soft_session_op_t op)
2N/A{
2N/A crypto_active_op_t *active_op;
2N/A
2N/A (void) pthread_mutex_lock(&session_p->session_mutex);
2N/A
2N/A switch (op) {
2N/A case SOFT_ENCRYPT_OP:
2N/A active_op = &(session_p->encrypt);
2N/A break;
2N/A case SOFT_DECRYPT_OP:
2N/A active_op = &(session_p->decrypt);
2N/A break;
2N/A case SOFT_SIGN_OP:
2N/A active_op = &(session_p->sign);
2N/A break;
2N/A case SOFT_VERIFY_OP:
2N/A active_op = &(session_p->verify);
2N/A break;
2N/A default:
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A return;
2N/A }
2N/A
2N/A active_op->flags &= ~CRYPTO_OPERATION_ACTIVE;
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A}