#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <security/cryptoki.h>
#include "kernelGlobal.h"
#include "kernelObject.h"
#include "kernelSession.h"
#include <errno.h>
#include <string.h>
#include <cryptoutil.h>
CK_RV
C_CreateObject(CK_SESSION_HANDLE hSession,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulCount,
CK_OBJECT_HANDLE_PTR phObject)
{
CK_RV rv;
kernel_session_t *session_p;
boolean_t ses_lock_held = B_FALSE;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
if ((pTemplate == NULL) || (ulCount == 0) ||
(phObject == NULL)) {
return (CKR_ARGUMENTS_BAD);
}
rv = handle2session(hSession, &session_p);
if (rv != CKR_OK)
return (rv);
rv = kernel_add_object(pTemplate, ulCount, phObject, session_p);
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;
kernel_session_t *session_p;
boolean_t ses_lock_held = B_FALSE;
kernel_object_t *old_object;
kernel_object_t *new_object = NULL;
crypto_object_copy_t object_copy;
CK_BBOOL is_pri_obj = FALSE;
CK_BBOOL is_token_obj = FALSE;
kernel_slot_t *pslot;
int i, r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
if (((ulCount > 0) && (pTemplate == NULL)) ||
(phNewObject == NULL)) {
return (CKR_ARGUMENTS_BAD);
}
rv = handle2session(hSession, &session_p);
if (rv != CKR_OK)
return (rv);
HANDLE2OBJECT(hObject, old_object, rv);
if (rv != CKR_OK) {
REFRELE(session_p, ses_lock_held);
return (rv);
}
(void) pthread_mutex_lock(&old_object->object_mutex);
if (old_object->is_lib_obj) {
rv = kernel_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)) {
OBJ_REFRELE(old_object);
REFRELE(session_p, ses_lock_held);
return (rv);
}
new_object->is_lib_obj = B_TRUE;
for (i = 0; i < ulCount; i++) {
rv = kernel_set_attribute(new_object, &pTemplate[i],
B_TRUE, session_p);
if (rv != CKR_OK) {
kernel_cleanup_object(new_object);
OBJ_REFRELE(old_object);
REFRELE(session_p, ses_lock_held);
return (rv);
}
}
kernel_add_object_to_session(new_object, session_p);
OBJ_REFRELE(old_object);
REFRELE(session_p, ses_lock_held);
*phNewObject = (CK_ULONG)new_object;
} else {
new_object = calloc(1, sizeof (kernel_object_t));
if (new_object == NULL) {
(void) pthread_mutex_unlock(&old_object->object_mutex);
OBJ_REFRELE(old_object);
REFRELE(session_p, ses_lock_held);
return (CKR_HOST_MEMORY);
}
object_copy.oc_session = session_p->k_session;
object_copy.oc_handle = old_object->k_handle;
(void) pthread_mutex_unlock(&old_object->object_mutex);
object_copy.oc_count = ulCount;
object_copy.oc_new_attributes = NULL;
if (ulCount > 0) {
rv = process_object_attributes(pTemplate, ulCount,
&object_copy.oc_new_attributes, &is_token_obj);
if (rv != CKR_OK) {
goto failed_cleanup;
}
}
while ((r = ioctl(kernel_fd, CRYPTO_OBJECT_COPY,
&object_copy)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(
object_copy.oc_return_value);
}
free_object_attributes(object_copy.oc_new_attributes, ulCount);
if (rv != CKR_OK) {
goto failed_cleanup;
}
new_object->k_handle = object_copy.oc_new_handle;
rv = get_cka_private_value(session_p, new_object->k_handle,
&is_pri_obj);
if (rv != CKR_OK) {
goto failed_cleanup;
}
new_object->is_lib_obj = B_FALSE;
new_object->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
new_object->session_handle = (CK_SESSION_HANDLE)session_p;
(void) pthread_mutex_init(&new_object->object_mutex, NULL);
if (is_pri_obj)
new_object->bool_attr_mask |= PRIVATE_BOOL_ON;
else
new_object->bool_attr_mask &= ~PRIVATE_BOOL_ON;
if (is_token_obj)
new_object->bool_attr_mask |= TOKEN_BOOL_ON;
else
new_object->bool_attr_mask &= ~TOKEN_BOOL_ON;
if (is_token_obj) {
pslot = slot_table[session_p->ses_slotid];
OBJ_REFRELE(old_object);
REFRELE(session_p, ses_lock_held);
kernel_add_token_object_to_slot(new_object, pslot);
} else {
kernel_add_object_to_session(new_object, session_p);
OBJ_REFRELE(old_object);
REFRELE(session_p, ses_lock_held);
}
*phNewObject = (CK_ULONG)new_object;
}
return (rv);
failed_cleanup:
if (new_object != NULL) {
(void) free(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;
kernel_object_t *object_p;
kernel_session_t *session_p = (kernel_session_t *)(hSession);
kernel_slot_t *pslot;
boolean_t ses_lock_held = B_FALSE;
CK_SESSION_HANDLE creating_session;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
if ((session_p == NULL) ||
(session_p->magic_marker != KERNELTOKEN_SESSION_MAGIC)) {
return (CKR_SESSION_HANDLE_INVALID);
}
HANDLE2OBJECT_DESTROY(hObject, object_p, rv);
if (rv != CKR_OK) {
return (rv);
}
if ((session_p->ses_RO) &&
(object_p->bool_attr_mask & TOKEN_BOOL_ON)) {
return (CKR_SESSION_READ_ONLY);
}
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);
}
(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) {
pslot = slot_table[session_p->ses_slotid];
rv = kernel_delete_token_object(pslot, session_p, object_p,
B_FALSE, B_FALSE);
} else {
rv = kernel_delete_session_object(session_p, object_p, B_FALSE,
B_FALSE);
}
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;
kernel_object_t *object_p;
kernel_session_t *session_p;
boolean_t ses_lock_held = B_FALSE;
crypto_object_get_attribute_value_t obj_get_attr;
int i, r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
if ((pTemplate == NULL) || (ulCount == 0))
return (CKR_ARGUMENTS_BAD);
rv = handle2session(hSession, &session_p);
if (rv != CKR_OK)
return (rv);
HANDLE2OBJECT(hObject, object_p, rv);
if (rv != CKR_OK) {
REFRELE(session_p, ses_lock_held);
return (rv);
}
(void) pthread_mutex_lock(&object_p->object_mutex);
if (object_p->is_lib_obj) {
for (i = 0; i < ulCount; i++) {
rv = kernel_get_attribute(object_p, &pTemplate[i]);
if (rv != CKR_OK)
rv1 = rv;
}
rv = rv1;
(void) pthread_mutex_unlock(&object_p->object_mutex);
} else {
obj_get_attr.og_session = session_p->k_session;
obj_get_attr.og_handle = object_p->k_handle;
(void) pthread_mutex_unlock(&object_p->object_mutex);
obj_get_attr.og_count = ulCount;
rv = process_object_attributes(pTemplate, ulCount,
&obj_get_attr.og_attributes, NULL);
if (rv != CKR_OK) {
goto clean_exit;
}
while ((r = ioctl(kernel_fd, CRYPTO_OBJECT_GET_ATTRIBUTE_VALUE,
&obj_get_attr)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(
obj_get_attr.og_return_value);
}
if ((rv == CKR_OK) ||
(rv == CKR_ATTRIBUTE_SENSITIVE) ||
(rv == CKR_ATTRIBUTE_TYPE_INVALID) ||
(rv == CKR_BUFFER_TOO_SMALL)) {
rv1 = get_object_attributes(pTemplate, ulCount,
obj_get_attr.og_attributes);
if (rv1 != CKR_OK) {
rv = rv1;
}
}
free_object_attributes(obj_get_attr.og_attributes, ulCount);
}
clean_exit:
OBJ_REFRELE(object_p);
REFRELE(session_p, ses_lock_held);
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;
kernel_object_t *object_p;
kernel_object_t *new_object = NULL;
kernel_session_t *session_p;
boolean_t ses_lock_held = B_FALSE;
crypto_object_set_attribute_value_t obj_set_attr;
int i, r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
if ((pTemplate == NULL) || (ulCount == 0))
return (CKR_ARGUMENTS_BAD);
rv = handle2session(hSession, &session_p);
if (rv != CKR_OK)
return (rv);
HANDLE2OBJECT(hObject, object_p, rv);
if (rv != CKR_OK) {
REFRELE(session_p, ses_lock_held);
return (rv);
}
(void) pthread_mutex_lock(&object_p->object_mutex);
if (!object_p->is_lib_obj) {
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;
}
obj_set_attr.sa_session = session_p->k_session;
obj_set_attr.sa_handle = object_p->k_handle;
(void) pthread_mutex_unlock(&object_p->object_mutex);
obj_set_attr.sa_count = ulCount;
rv = process_object_attributes(pTemplate, ulCount,
&obj_set_attr.sa_attributes, NULL);
if (rv != CKR_OK) {
goto clean_exit;
}
while ((r = ioctl(kernel_fd, CRYPTO_OBJECT_SET_ATTRIBUTE_VALUE,
&obj_set_attr)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(
obj_set_attr.sa_return_value);
}
free_object_attributes(obj_set_attr.sa_attributes, ulCount);
goto clean_exit;
}
rv = kernel_copy_object(object_p, &new_object, B_FALSE, NULL);
(void) pthread_mutex_unlock(&object_p->object_mutex);
if ((rv != CKR_OK) || (new_object == NULL)) {
goto clean_exit;
}
for (i = 0; i < ulCount; i++) {
rv = kernel_set_attribute(new_object, &pTemplate[i], B_FALSE,
session_p);
if (rv != CKR_OK) {
kernel_cleanup_object(new_object);
goto clean_exit;
}
}
(void) pthread_mutex_lock(&object_p->object_mutex);
kernel_merge_object(object_p, new_object);
(void) pthread_mutex_unlock(&object_p->object_mutex);
clean_exit:
if (new_object != NULL)
(void) free(new_object);
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;
kernel_object_t *object_p;
kernel_session_t *session_p;
boolean_t ses_lock_held = B_FALSE;
crypto_object_get_size_t obj_gs;
int r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
if (pulSize == NULL) {
return (CKR_ARGUMENTS_BAD);
}
rv = handle2session(hSession, &session_p);
if (rv != CKR_OK)
return (rv);
HANDLE2OBJECT(hObject, object_p, rv);
if (rv != CKR_OK) {
REFRELE(session_p, ses_lock_held);
return (rv);
}
(void) pthread_mutex_lock(&object_p->object_mutex);
if (!object_p->is_lib_obj) {
obj_gs.gs_session = session_p->k_session;
obj_gs.gs_handle = object_p->k_handle;
(void) pthread_mutex_unlock(&object_p->object_mutex);
while ((r = ioctl(kernel_fd, CRYPTO_OBJECT_GET_SIZE,
&obj_gs)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(
obj_gs.gs_return_value);
}
if (rv == CKR_OK) {
*pulSize = obj_gs.gs_size;
}
} else {
rv = kernel_get_object_size(object_p, pulSize);
(void) pthread_mutex_unlock(&object_p->object_mutex);
}
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;
kernel_session_t *session_p;
boolean_t ses_lock_held = B_FALSE;
kernel_slot_t *pslot;
crypto_object_find_init_t obj_fi;
int r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
if ((ulCount > 0) && (pTemplate == NULL)) {
return (CKR_ARGUMENTS_BAD);
}
rv = handle2session(sh, &session_p);
if (rv != CKR_OK)
return (rv);
(void) pthread_mutex_lock(&session_p->session_mutex);
ses_lock_held = B_TRUE;
if (session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE) {
REFRELE(session_p, ses_lock_held);
return (CKR_OPERATION_ACTIVE);
} else {
session_p->find_objects.flags = CRYPTO_OPERATION_ACTIVE;
}
pslot = slot_table[session_p->ses_slotid];
if (pslot->sl_func_list.fl_object_create) {
obj_fi.fi_session = session_p->k_session;
(void) pthread_mutex_unlock(&session_p->session_mutex);
ses_lock_held = B_FALSE;
obj_fi.fi_count = ulCount;
rv = process_object_attributes(pTemplate, ulCount,
&obj_fi.fi_attributes, NULL);
if (rv == CKR_OK) {
while ((r = ioctl(kernel_fd, CRYPTO_OBJECT_FIND_INIT,
&obj_fi)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(
obj_fi.fi_return_value);
}
}
free_object_attributes(obj_fi.fi_attributes, ulCount);
} else {
(void) pthread_mutex_unlock(&session_p->session_mutex);
ses_lock_held = B_FALSE;
rv = kernel_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);
}
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;
kernel_slot_t *pslot;
kernel_session_t *session_p;
boolean_t ses_lock_held = B_FALSE;
crypto_object_find_update_t obj_fu;
int r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
if (((phObject == NULL) && (ulMaxObjectCount != 0)) ||
(pulObjectCount == NULL)) {
return (CKR_ARGUMENTS_BAD);
}
if (ulMaxObjectCount == 0) {
*pulObjectCount = 0;
return (CKR_OK);
}
rv = handle2session(sh, &session_p);
if (rv != CKR_OK)
return (rv);
pslot = slot_table[session_p->ses_slotid];
(void) pthread_mutex_lock(&pslot->sl_mutex);
(void) pthread_mutex_lock(&session_p->session_mutex);
ses_lock_held = B_TRUE;
if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) {
rv = CKR_OPERATION_NOT_INITIALIZED;
goto clean_exit;
}
if (pslot->sl_func_list.fl_object_create) {
obj_fu.fu_session = session_p->k_session;
obj_fu.fu_max_count = ulMaxObjectCount;
obj_fu.fu_handles = (char *)calloc(1,
ulMaxObjectCount * sizeof (crypto_object_id_t));
if (obj_fu.fu_handles == NULL) {
rv = CKR_HOST_MEMORY;
goto clean_exit;
}
while ((r = ioctl(kernel_fd, CRYPTO_OBJECT_FIND_UPDATE,
&obj_fu)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(
obj_fu.fu_return_value);
}
if (rv == CKR_OK) {
rv = process_found_objects(session_p, phObject,
pulObjectCount, obj_fu);
}
free(obj_fu.fu_handles);
} else {
kernel_find_objects(session_p, phObject, ulMaxObjectCount,
pulObjectCount);
rv = CKR_OK;
}
clean_exit:
REFRELE(session_p, ses_lock_held);
(void) pthread_mutex_unlock(&pslot->sl_mutex);
return (rv);
}
CK_RV
C_FindObjectsFinal(CK_SESSION_HANDLE sh)
{
kernel_session_t *session_p;
CK_RV rv;
boolean_t ses_lock_held = B_FALSE;
kernel_slot_t *pslot;
crypto_object_find_final_t obj_ff;
int r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
rv = handle2session(sh, &session_p);
if (rv != CKR_OK)
return (rv);
(void) pthread_mutex_lock(&session_p->session_mutex);
ses_lock_held = B_TRUE;
if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) {
REFRELE(session_p, ses_lock_held);
return (CKR_OPERATION_NOT_INITIALIZED);
}
pslot = slot_table[session_p->ses_slotid];
if (pslot->sl_func_list.fl_object_create) {
obj_ff.ff_session = session_p->k_session;
while ((r = ioctl(kernel_fd, CRYPTO_OBJECT_FIND_FINAL,
&obj_ff)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(
obj_ff.ff_return_value);
}
if (rv == CKR_OK) {
session_p->find_objects.flags = 0;
}
} else {
kernel_find_objects_final(session_p);
rv = CKR_OK;
}
REFRELE(session_p, ses_lock_held);
return (rv);
}