Mercurial > illumos > illumos-gate
diff usr/src/lib/pkcs11/pkcs11_kms/common/kmsSession.c @ 12720:3db6e0082404
PSARC 2010/195 PKCS11 KMS Provider
6944296 Solaris needs a PKCS#11 provider to allow access to KMS keystore functionality
author | Wyllys Ingersoll <Wyllys.Ingersoll@Sun.COM> |
---|---|
date | Mon, 28 Jun 2010 16:04:11 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/pkcs11/pkcs11_kms/common/kmsSession.c Mon Jun 28 16:04:11 2010 -0700 @@ -0,0 +1,355 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <pthread.h> +#include <errno.h> +#include <security/cryptoki.h> +#include "kmsGlobal.h" +#include "kmsSession.h" +#include "kmsSlot.h" +#include "kmsKeystoreUtil.h" + +CK_RV +C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, + CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) +{ + CK_RV rv = CKR_OK; + kms_slot_t *pslot; + + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + if (!(flags & CKF_SERIAL_SESSION)) + return (CKR_SESSION_PARALLEL_NOT_SUPPORTED); + + if (phSession == NULL) + return (CKR_ARGUMENTS_BAD); + + if (slotID != KMS_TOKEN_SLOTID) { + return (CKR_SLOT_ID_INVALID); + } + + /* + * Acquire the slot lock to protect sl_state and sl_sess_list. + * These two fields need to be protected atomically, even though + * "sl_sess_list" is updated in kms_add_session(). + */ + pslot = get_slotinfo(); + (void) pthread_mutex_lock(&pslot->sl_mutex); + + /* If SO is logged in the slot, only the RW session is allowed. */ + if ((pslot->sl_state == CKU_SO) && !(flags & CKF_RW_SESSION)) { + (void) pthread_mutex_unlock(&pslot->sl_mutex); + return (CKR_SESSION_READ_WRITE_SO_EXISTS); + } + + /* Create a new session */ + rv = kms_add_session(slotID, flags, pApplication, Notify, + phSession); + + (void) pthread_mutex_unlock(&pslot->sl_mutex); + return (rv); +} + +CK_RV +C_CloseSession(CK_SESSION_HANDLE hSession) +{ + CK_RV rv; + + kms_session_t *session_p; + boolean_t ses_lock_held = B_FALSE; + + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + /* + * Obtain the session pointer. Also, increment the session + * reference count. + */ + rv = handle2session(hSession, &session_p); + if (rv != CKR_OK) + return (rv); + + (void) pthread_mutex_lock(&session_p->session_mutex); + ses_lock_held = B_TRUE; + + /* + * Set SESSION_IS_CLOSING flag so any access to this + * session will be rejected. + */ + if (session_p->ses_close_sync & SESSION_IS_CLOSING) { + REFRELE(session_p, ses_lock_held); + return (CKR_SESSION_CLOSED); + } + session_p->ses_close_sync |= SESSION_IS_CLOSING; + + /* + * Decrement the session reference count. + * We hold the session lock, and REFRELE() + * will release the session lock for us. + */ + REFRELE(session_p, ses_lock_held); + + /* + * Delete a session by calling kms_delete_session() with + * a session pointer and two boolean arguments. The 3rd argument + * boolean value FALSE indicates that the caller does not + * hold the slot lock. The 4th argument boolean value B_FALSE + * indicates that we want to delete all the objects completely. + * + * kms_delete_session() will reset SESSION_IS_CLOSING + * flag after it is done. + */ + kms_delete_session(session_p, B_FALSE, B_FALSE); + return (rv); +} + +/*ARGSUSED*/ +CK_RV +C_CloseAllSessions(CK_SLOT_ID slotID) +{ + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + /* Delete all the sessions and release the allocated resources */ + kms_delete_all_sessions(B_FALSE); + + return (CKR_OK); +} + +/* + * Utility routine to get CK_STATE value for a session. + * The caller should not be holding the session lock. + */ +static CK_STATE +get_ses_state(kms_session_t *session_p) +{ + CK_STATE state; + kms_slot_t *pslot; + + pslot = get_slotinfo(); + (void) pthread_mutex_lock(&pslot->sl_mutex); + + if (pslot->sl_state == CKU_PUBLIC) { + state = (session_p->ses_RO) ? + CKS_RO_PUBLIC_SESSION : CKS_RW_PUBLIC_SESSION; + } else if (pslot->sl_state == CKU_USER) { + state = (session_p->ses_RO) ? + CKS_RO_USER_FUNCTIONS : CKS_RW_USER_FUNCTIONS; + } else if (pslot->sl_state == CKU_SO) { + state = CKS_RW_SO_FUNCTIONS; + } + + (void) pthread_mutex_unlock(&pslot->sl_mutex); + + return (state); +} + +CK_RV +C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) +{ + kms_session_t *session_p; + CK_RV rv; + boolean_t ses_lock_held = B_FALSE; + + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + if (pInfo == NULL) + return (CKR_ARGUMENTS_BAD); + + /* + * Obtain the session pointer. Also, increment the session + * reference count. + */ + rv = handle2session(hSession, &session_p); + if (rv != CKR_OK) + return (rv); + + /* Provide information for the specified session */ + pInfo->slotID = session_p->ses_slotid; + pInfo->flags = session_p->flags; + pInfo->ulDeviceError = 0; + pInfo->state = get_ses_state(session_p); + + /* + * Decrement the session reference count. + */ + REFRELE(session_p, ses_lock_held); + + return (rv); +} + +/*ARGSUSED*/ +CK_RV +C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, + CK_ULONG_PTR pulOperationStateLen) +{ + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + return (CKR_FUNCTION_NOT_SUPPORTED); +} + +/*ARGSUSED*/ +CK_RV +C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, + CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, + CK_OBJECT_HANDLE hAuthenticationKey) +{ + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + return (CKR_FUNCTION_NOT_SUPPORTED); +} + +CK_RV +C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, + CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + CK_RV rv = CKR_OK; + kms_session_t *session_p; + kms_slot_t *pslot; + boolean_t ses_lock_held = B_FALSE; + + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + if ((userType != CKU_SO) && (userType != CKU_USER)) { + return (CKR_USER_TYPE_INVALID); + } + + /* + * Obtain the session pointer. Also, increment the session + * reference count. + */ + rv = handle2session(hSession, &session_p); + if (rv != CKR_OK) + return (rv); + + /* Acquire the slot lock */ + pslot = get_slotinfo(); + (void) pthread_mutex_lock(&pslot->sl_mutex); + + /* Check if the slot is logged in already */ + if ((pslot->sl_state == CKU_USER) || (pslot->sl_state == CKU_SO)) { + rv = CKR_USER_ALREADY_LOGGED_IN; + goto clean_exit; + } + + /* To login as SO, every session in this slot needs to be R/W */ + if (userType == CKU_SO) { + kms_session_t *sp; + boolean_t found; + + found = B_FALSE; + sp = pslot->sl_sess_list; + while (sp) { + /* + * Need not to lock individual sessions before + * accessing their "ses_RO" and "next" fields, + * because they are always accessed under the + * slot's mutex protection. + */ + if (sp->ses_RO) { + found = B_TRUE; + break; + } + sp = sp->next; + } + + if (found) { + rv = CKR_SESSION_READ_ONLY_EXISTS; + goto clean_exit; + } + } + + /* + * Login to KMS by attempting to load the profile using + * the given password. + */ + rv = KMS_LoadProfile( + &session_p->kmsProfile, + &session_p->configInfo, + (const char *)pPin, + (size_t)ulPinLen); + + if (rv == CKR_OK) { + /* Set the slot's session state. */ + pslot->sl_state = userType; + } + +clean_exit: + + REFRELE(session_p, ses_lock_held); + (void) pthread_mutex_unlock(&pslot->sl_mutex); + return (rv); +} + +CK_RV +C_Logout(CK_SESSION_HANDLE hSession) +{ + CK_RV rv = CKR_OK; + kms_session_t *session_p; + kms_slot_t *pslot; + boolean_t ses_lock_held = B_FALSE; + + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + /* + * Obtain the session pointer. Also, increment the session + * reference count. + */ + rv = handle2session(hSession, &session_p); + if (rv != CKR_OK) + return (rv); + + /* Acquire the slot lock. */ + pslot = get_slotinfo(); + (void) pthread_mutex_lock(&pslot->sl_mutex); + + /* Check if the user or SO was logged in */ + if (pslot->sl_state == CKU_PUBLIC) { + rv = CKR_USER_NOT_LOGGED_IN; + goto clean_exit; + } + + KMS_UnloadProfile(&session_p->kmsProfile); + + /* + * If this slot was logged in as USER previously, we need to clean up + * all private object wrappers in library for this slot. + */ + kms_cleanup_pri_objects_in_slot(pslot, session_p); + + if (rv == CKR_OK) { + /* Reset the slot's session state. */ + pslot->sl_state = CKU_PUBLIC; + } + +clean_exit: + REFRELE(session_p, ses_lock_held); + (void) pthread_mutex_unlock(&pslot->sl_mutex); + return (rv); +}