Mercurial > illumos > illumos-gate
diff usr/src/lib/pkcs11/pkcs11_kms/common/kmsObject.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/kmsObject.c Mon Jun 28 16:04:11 2010 -0700 @@ -0,0 +1,664 @@ +/* + * 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 <stdlib.h> +#include <errno.h> +#include <errno.h> +#include <string.h> +#include <security/cryptoki.h> +#include "kmsGlobal.h" +#include "kmsObject.h" +#include "kmsSession.h" + +CK_RV +C_CreateObject(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phObject) +{ + + CK_RV rv; + kms_session_t *session_p; + boolean_t ses_lock_held = B_FALSE; + + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + if ((pTemplate == NULL) || (ulCount == 0) || + (phObject == 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); + + /* Create a new object. */ + rv = kms_add_object(pTemplate, ulCount, phObject, session_p); + + /* + * Decrement the session reference count. + * We do not hold the session lock. + */ + REFRELE(session_p, ses_lock_held); + + return (rv); +} + +CK_RV +C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phNewObject) +{ + + CK_RV rv; + kms_session_t *session_p; + boolean_t ses_lock_held = B_FALSE; + kms_object_t *old_object; + kms_object_t *new_object = NULL; + int i; + + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + /* Check arguments */ + if (((ulCount > 0) && (pTemplate == NULL)) || + (phNewObject == 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); + + /* Obtain the object pointer. */ + HANDLE2OBJECT(hObject, old_object, rv); + if (rv != CKR_OK) { + /* + * Decrement the session reference count. + * We do not hold the session lock. + */ + REFRELE(session_p, ses_lock_held); + return (rv); + } + + (void) pthread_mutex_lock(&old_object->object_mutex); + + if (old_object->is_lib_obj) { + /* + * Copy the old object to a new object. + * The 3rd argument with TRUE value indicates that + * everything in the object will be duplicated. + */ + rv = kms_copy_object(old_object, &new_object, B_TRUE, + session_p); + (void) pthread_mutex_unlock(&old_object->object_mutex); + if ((rv != CKR_OK) || (new_object == NULL)) { + /* + * Most likely we ran out of space. + * Decrement the session reference count. + * We do not hold the session lock. + */ + OBJ_REFRELE(old_object); + REFRELE(session_p, ses_lock_held); + return (rv); + } + + new_object->is_lib_obj = B_TRUE; + + /* Modify the object attribute if requested */ + for (i = 0; i < ulCount; i++) { + /* Set the requested attribute into the new object. */ + rv = kms_set_attribute(new_object, &pTemplate[i], + B_TRUE); + + if (rv != CKR_OK) { + kms_cleanup_object(new_object); + OBJ_REFRELE(old_object); + REFRELE(session_p, ses_lock_held); + return (rv); + } + } + + /* Insert the new object into this session's object list. */ + kms_add_object_to_session(new_object, session_p); + + /* + * Decrement the session reference count. + * We do not hold the session lock. + */ + OBJ_REFRELE(old_object); + REFRELE(session_p, ses_lock_held); + + /* set handle of the new object */ + *phNewObject = (CK_ULONG)new_object; + + } + + return (rv); + +failed_cleanup: + if (new_object != NULL) { + (void) kms_free_object(new_object); + } + + OBJ_REFRELE(old_object); + REFRELE(session_p, ses_lock_held); + return (rv); +} + +CK_RV +C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) +{ + CK_RV rv; + kms_object_t *object_p; + kms_session_t *session_p = (kms_session_t *)(hSession); + kms_slot_t *pslot; + boolean_t ses_lock_held = B_FALSE; + CK_SESSION_HANDLE creating_session; + + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + /* + * The reason that we don't call handle2session is because + * the argument hSession may not be the creating_session of + * the object to be destroyed, and we want to avoid the lock + * contention. The handle2session will be called later for + * the creating_session. + */ + if ((session_p == NULL) || + (session_p->magic_marker != KMSTOKEN_SESSION_MAGIC)) { + return (CKR_SESSION_HANDLE_INVALID); + } + /* Obtain the object pointer without incrementing reference count. */ + HANDLE2OBJECT_DESTROY(hObject, object_p, rv); + if (rv != CKR_OK) { + return (rv); + } + + /* Only session objects can be destroyed at a read-only session. */ + if ((session_p->ses_RO) && + (object_p->bool_attr_mask & TOKEN_BOOL_ON)) { + return (CKR_SESSION_READ_ONLY); + } + + + /* + * If the object is a session object, obtain the session handle + * which object belongs to. For a token object, we will use the + * session handle from the caller, because the session used to + * create the token object may no longer exist. + */ + if (!(object_p->bool_attr_mask & TOKEN_BOOL_ON)) + creating_session = object_p->session_handle; + else + creating_session = hSession; + + rv = handle2session(creating_session, &session_p); + if (rv != CKR_OK) { + return (rv); + } + + /* + * Set OBJECT_IS_DELETING flag so any access to this + * object will be rejected. + */ + (void) pthread_mutex_lock(&object_p->object_mutex); + if (object_p->obj_delete_sync & OBJECT_IS_DELETING) { + (void) pthread_mutex_unlock(&object_p->object_mutex); + REFRELE(session_p, ses_lock_held); + return (CKR_OBJECT_HANDLE_INVALID); + } + object_p->obj_delete_sync |= OBJECT_IS_DELETING; + (void) pthread_mutex_unlock(&object_p->object_mutex); + + if (object_p->bool_attr_mask & TOKEN_BOOL_ON) { + /* + * The first FALSE boolean argument indicates that the caller + * does not hold the slot lock. The second FALSE boolean + * argument indicates that the caller wants to clean up the + * object in the HW provider also. + */ + pslot = get_slotinfo(); + rv = kms_delete_token_object(pslot, session_p, object_p, + B_FALSE, B_FALSE); + } else { + /* + * The first FALSE boolean argument indicates that the caller + * does not hold the session lock. The second FALSE boolean + * argument indicates that the caller wants to clean the object + * in the HW provider also. + */ + rv = kms_delete_object(session_p, object_p, B_FALSE, + B_FALSE); + } + /* + * Decrement the session reference count. + * We do not hold the session lock. + */ + REFRELE(session_p, ses_lock_held); + return (rv); +} + +CK_RV +C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) +{ + + CK_RV rv = CKR_OK, rv1 = CKR_OK; + kms_object_t *object_p; + kms_session_t *session_p; + boolean_t ses_lock_held = B_FALSE; + int i; + + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + if ((pTemplate == NULL) || (ulCount == 0)) + 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); + + /* Obtain the object pointer. */ + HANDLE2OBJECT(hObject, object_p, rv); + if (rv != CKR_OK) { + /* + * Decrement the session reference count. + * We do not hold the session lock. + */ + REFRELE(session_p, ses_lock_held); + return (rv); + } + + /* Acquire the lock on the object. */ + (void) pthread_mutex_lock(&object_p->object_mutex); + + /* + * The object was created in the library. The library + * contains the value information of each attribute. + */ + for (i = 0; i < ulCount; i++) { + /* + * Get the value of each attribute in the template. + * (We must process EVERY attribute in the template.) + */ + rv = kms_get_attribute(object_p, &pTemplate[i]); + if (rv != CKR_OK) + rv1 = rv; + } + (void) pthread_mutex_unlock(&object_p->object_mutex); + +clean_exit: + /* + * Decrement the session reference count. + * We do not hold the session lock. + */ + OBJ_REFRELE(object_p); + REFRELE(session_p, ses_lock_held); + rv = rv1; + return (rv); +} + +CK_RV +C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) +{ + CK_RV rv = CKR_OK; + kms_object_t *object_p; + kms_object_t *new_object = NULL; + kms_session_t *session_p; + boolean_t ses_lock_held = B_FALSE; + int i; + + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + if ((pTemplate == NULL) || (ulCount == 0)) + 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); + + /* Obtain the object pointer. */ + HANDLE2OBJECT(hObject, object_p, rv); + if (rv != CKR_OK) { + /* + * Decrement the session reference count. + * We do not hold the session lock. + */ + REFRELE(session_p, ses_lock_held); + return (rv); + } + + /* lock the object */ + (void) pthread_mutex_lock(&object_p->object_mutex); + + /* + * If the object was created in the HW provider, changing its + * attributes' values need to be done in the provider too. + */ + if (!object_p->is_lib_obj) { + + /* Cannot modify a token object with a READ-ONLY session */ + if (session_p->ses_RO && + (object_p->bool_attr_mask & TOKEN_BOOL_ON)) { + (void) pthread_mutex_unlock(&object_p->object_mutex); + rv = CKR_SESSION_READ_ONLY; + goto clean_exit; + } + } + + /* + * if we come here, the object must have been created in the + * library. The work will be done completely in the library. + * + * Copy the old object to a new object. We work on the copied + * version because in case of error we still keep the old one + * intact. + */ + rv = kms_copy_object(object_p, &new_object, B_FALSE, NULL); + (void) pthread_mutex_unlock(&object_p->object_mutex); + if ((rv != CKR_OK) || (new_object == NULL)) { + /* + * Most likely we ran out of space. + * Decrement the session reference count. + * We do not hold the session lock. + */ + goto clean_exit; + } + + for (i = 0; i < ulCount; i++) { + /* Set the requested attribute into the new object. */ + rv = kms_set_attribute(new_object, &pTemplate[i], B_FALSE); + + if (rv != CKR_OK) { + kms_cleanup_object(new_object); + goto clean_exit; + } + } + + /* + * We've successfully set all the requested attributes. + * Merge the new object with the old object, then destory + * the new one. The reason to do the merging is because we + * have to keep the original object handle (address of object). + */ + (void) pthread_mutex_lock(&object_p->object_mutex); + kms_merge_object(object_p, new_object); + (void) pthread_mutex_unlock(&object_p->object_mutex); + +clean_exit: + if (new_object != NULL) + (void) kms_free_object(new_object); + + /* + * Decrement the session reference count. + * We do not hold the session lock. + */ + OBJ_REFRELE(object_p); + REFRELE(session_p, ses_lock_held); + + return (rv); +} + +CK_RV +C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, + CK_ULONG_PTR pulSize) +{ + + CK_RV rv = CKR_OK; + kms_object_t *object_p; + kms_session_t *session_p; + boolean_t ses_lock_held = B_FALSE; + + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + /* Check if pulSize is valid */ + if (pulSize == 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); + + /* Obtain the object pointer. */ + HANDLE2OBJECT(hObject, object_p, rv); + if (rv != CKR_OK) { + /* + * Decrement the session reference count. + * We do not hold the session lock. + */ + REFRELE(session_p, ses_lock_held); + return (rv); + } + + /* Acquire the lock on the object. */ + (void) pthread_mutex_lock(&object_p->object_mutex); + + rv = kms_get_object_size(object_p, pulSize); + + (void) pthread_mutex_unlock(&object_p->object_mutex); + + /* + * Decrement the session reference count. + * We do not hold the session lock. + */ + OBJ_REFRELE(object_p); + REFRELE(session_p, ses_lock_held); + return (rv); +} + +CK_RV +C_FindObjectsInit(CK_SESSION_HANDLE sh, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount) +{ + CK_RV rv; + kms_session_t *session_p; + boolean_t ses_lock_held = B_FALSE; + + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + /* Check the arguments */ + if ((ulCount > 0) && (pTemplate == NULL)) { + return (CKR_ARGUMENTS_BAD); + } + + /* + * Obtain the session pointer. Also, increment the session + * reference count. + */ + rv = handle2session(sh, &session_p); + if (rv != CKR_OK) + return (rv); + + /* Acquire the session lock */ + (void) pthread_mutex_lock(&session_p->session_mutex); + ses_lock_held = B_TRUE; + + /* Check to see if find operation is already active */ + if (session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE) { + /* decrement the session count, and unlock the mutex */ + REFRELE(session_p, ses_lock_held); + return (CKR_OPERATION_ACTIVE); + } else { + /* + * This active flag will remain ON until application calls + * C_FindObjectsFinal. + */ + session_p->find_objects.flags = CRYPTO_OPERATION_ACTIVE; + } + (void) pthread_mutex_unlock(&session_p->session_mutex); + + /* + * If the KMS provider supports object creation, we call the + * CRYPTO_OBJECT_FIND_INIT to initialize object finding. + * Otherwise, all the objects are created in the library and we + * do the find objects solely in the library. + */ + rv = kms_find_objects_init(session_p, pTemplate, ulCount); + if (rv != CKR_OK) { + (void) pthread_mutex_lock(&session_p->session_mutex); + session_p->find_objects.flags = 0; + (void) pthread_mutex_unlock(&session_p->session_mutex); + } + /* decrement the session count, and unlock the mutex */ + REFRELE(session_p, ses_lock_held); + return (rv); +} + +CK_RV +C_FindObjects(CK_SESSION_HANDLE sh, CK_OBJECT_HANDLE_PTR phObject, + CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) +{ + CK_RV rv = CKR_OK; + kms_slot_t *pslot = NULL; + kms_session_t *session_p; + boolean_t ses_lock_held = B_FALSE; + + if (!kms_initialized) + return (CKR_CRYPTOKI_NOT_INITIALIZED); + + /* check for invalid arguments */ + if (((phObject == NULL) && (ulMaxObjectCount != 0)) || + (pulObjectCount == NULL)) { + return (CKR_ARGUMENTS_BAD); + } + + if (ulMaxObjectCount == 0) { + /* don't need to do anything, just return */ + *pulObjectCount = 0; + return (CKR_OK); + } + + /* + * Obtain the session pointer. Also, increment the session + * reference count. + */ + rv = handle2session(sh, &session_p); + if (rv != CKR_OK) + return (rv); + + /* Acquire the slot lock */ + pslot = get_slotinfo(); + (void) pthread_mutex_lock(&pslot->sl_mutex); + + /* Acquire the session lock */ + (void) pthread_mutex_lock(&session_p->session_mutex); + ses_lock_held = B_TRUE; + + /* Check to see if find operation is active */ + if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) { + rv = CKR_OPERATION_NOT_INITIALIZED; + goto clean_exit; + } + + /* + * Similar to C_FindObjectInit(), if the KMS provider supports object + * creation, we need to find objects. + * Otherwise, all the objects are created in the library and we do + * the find objects solely in the library. + */ + + rv = kms_find_objects(session_p, phObject, + ulMaxObjectCount, pulObjectCount); + +clean_exit: + /* decrement the session count, and release the session lock */ + REFRELE(session_p, ses_lock_held); + + /* release the slot lock */ + if (pslot) + (void) pthread_mutex_unlock(&pslot->sl_mutex); + + return (rv); +} + +CK_RV +C_FindObjectsFinal(CK_SESSION_HANDLE sh) +{ + kms_session_t *session_p; + CK_RV rv; + 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(sh, &session_p); + if (rv != CKR_OK) + return (rv); + + /* Acquire the session lock */ + (void) pthread_mutex_lock(&session_p->session_mutex); + ses_lock_held = B_TRUE; + + /* Check to see if find operation is active */ + if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) { + REFRELE(session_p, ses_lock_held); + return (CKR_OPERATION_NOT_INITIALIZED); + } + + /* + * Similar to C_FindObjectInit(), if the KMS provider supports object + * creation, we need to finalize the search on the KMS side. + */ + kms_find_objects_final(session_p); + + /* decrement the session count, and release the lock */ + REFRELE(session_p, ses_lock_held); + return (rv); +}