#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "metaGlobal.h"
#define WRAP_KEY_TEMPLATE_SIZE 7
typedef struct _wrap_info {
CK_OBJECT_CLASS class;
CK_KEY_TYPE key_type;
CK_ULONG key_length;
CK_MECHANISM_TYPE mech_type;
CK_ULONG iv_length;
boolean_t src_supports;
boolean_t dst_supports;
} wrap_info_t;
extern pthread_rwlock_t meta_sessionlist_lock;
extern meta_session_t *meta_sessionlist_head;
static wrap_info_t common_wrap_info[] = {
{CKO_SECRET_KEY, CKK_AES, 16, CKM_AES_CBC_PAD, 16, B_FALSE, B_FALSE},
{CKO_SECRET_KEY, CKK_DES3, 24, CKM_DES3_CBC_PAD, 8, B_FALSE, B_FALSE},
{CKO_SECRET_KEY, CKK_DES, 8, CKM_DES_CBC_PAD, 8, B_FALSE, B_FALSE},
};
static unsigned int num_common_wrap_info =
sizeof (common_wrap_info) / sizeof (wrap_info_t);
static wrap_info_t special_wrap_info[] = {
{CKO_SECRET_KEY, CKK_SKIPJACK, 12, CKM_SKIPJACK_WRAP, 0,
B_FALSE, B_FALSE},
{CKO_SECRET_KEY, CKK_BATON, 40, CKM_BATON_WRAP, 0,
B_FALSE, B_FALSE},
{CKO_SECRET_KEY, CKK_JUNIPER, 40, CKM_JUNIPER_WRAP, 0,
B_FALSE, B_FALSE},
};
static unsigned int num_special_wrap_info =
sizeof (special_wrap_info) / sizeof (wrap_info_t);
static wrap_info_t rsa_wrap_info[] = {
{CKO_PUBLIC_KEY, CKK_RSA, 0, CKM_RSA_PKCS, 0,
B_FALSE, B_FALSE},
{CKO_PUBLIC_KEY, CKK_RSA, 0, CKM_RSA_X_509, 0,
B_FALSE, B_FALSE},
};
static unsigned int num_rsa_wrap_info =
sizeof (rsa_wrap_info) / sizeof (wrap_info_t);
static pthread_rwlock_t meta_objectclose_lock;
static pthread_rwlock_t tokenobject_list_lock;
static meta_object_t *tokenobject_list_head;
CK_BBOOL falsevalue = FALSE;
CK_BBOOL truevalue = TRUE;
static CK_BYTE PubExpo[3] = {0x01, 0x00, 0x01};
CK_BYTE PriExpo[128] = {
0x8e, 0xc9, 0x70, 0x57, 0x6b, 0xcd, 0xfb, 0xa9,
0x19, 0xad, 0xcd, 0x91, 0x69, 0xd5, 0x52, 0xec,
0x72, 0x1e, 0x45, 0x15, 0x06, 0xdc, 0x65, 0x2d,
0x98, 0xc4, 0xce, 0x33, 0x54, 0x15, 0x70, 0x8d,
0xfa, 0x65, 0xea, 0x53, 0x44, 0xf3, 0x3e, 0x3f,
0xb4, 0x4c, 0x60, 0xd5, 0x01, 0x2d, 0xa4, 0x12,
0x99, 0xbf, 0x3f, 0x0b, 0xcd, 0xbb, 0x24, 0x10,
0x60, 0x30, 0x5e, 0x58, 0xf8, 0x59, 0xaa, 0xd1,
0x63, 0x3b, 0xbc, 0xcb, 0x94, 0x58, 0x38, 0x24,
0xfc, 0x65, 0x25, 0xc5, 0xa6, 0x51, 0xa2, 0x2e,
0xf1, 0x5e, 0xf5, 0xc1, 0xf5, 0x46, 0xf7, 0xbd,
0xc7, 0x62, 0xa8, 0xe2, 0x27, 0xd6, 0x94, 0x5b,
0xd3, 0xa2, 0xb5, 0x76, 0x42, 0x67, 0x6b, 0x86,
0x91, 0x97, 0x4d, 0x07, 0x92, 0x00, 0x4a, 0xdf,
0x0b, 0x65, 0x64, 0x05, 0x03, 0x48, 0x27, 0xeb,
0xce, 0x9a, 0x49, 0x7f, 0x3e, 0x10, 0xe0, 0x01};
static CK_BYTE Modulus[128] = {
0x94, 0x32, 0xb9, 0x12, 0x1d, 0x68, 0x2c, 0xda,
0x2b, 0xe0, 0xe4, 0x97, 0x1b, 0x4d, 0xdc, 0x43,
0xdf, 0x38, 0x6e, 0x7b, 0x9f, 0x07, 0x58, 0xae,
0x9d, 0x82, 0x1e, 0xc7, 0xbc, 0x92, 0xbf, 0xd3,
0xce, 0x00, 0xbb, 0x91, 0xc9, 0x79, 0x06, 0x03,
0x1f, 0xbc, 0x9f, 0x94, 0x75, 0x29, 0x5f, 0xd7,
0xc5, 0xf3, 0x73, 0x8a, 0xa4, 0x35, 0x43, 0x7a,
0x00, 0x32, 0x97, 0x3e, 0x86, 0xef, 0x70, 0x6f,
0x18, 0x56, 0x15, 0xaa, 0x6a, 0x87, 0xe7, 0x8d,
0x7d, 0xdd, 0x1f, 0xa4, 0xe4, 0x31, 0xd4, 0x7a,
0x8c, 0x0e, 0x20, 0xd2, 0x23, 0xf5, 0x57, 0x3c,
0x1b, 0xa8, 0x44, 0xa4, 0x57, 0x8f, 0x33, 0x52,
0xad, 0x83, 0xae, 0x4a, 0x97, 0xa6, 0x1e, 0xa6,
0x2b, 0xfa, 0xea, 0xeb, 0x6e, 0x71, 0xb8, 0xb6,
0x0a, 0x36, 0xed, 0x83, 0xce, 0xb0, 0xdf, 0xc1,
0xd4, 0x3a, 0xe9, 0x99, 0x6f, 0xf3, 0x96, 0xb7};
static CK_RV
meta_clone_template_setup(meta_object_t *object,
const generic_attr_t *attributes, size_t num_attributes);
CK_RV
meta_objectManager_initialize()
{
if (pthread_rwlock_init(&meta_objectclose_lock, NULL) != 0) {
return (CKR_FUNCTION_FAILED);
}
if (pthread_rwlock_init(&tokenobject_list_lock, NULL) != 0) {
(void) pthread_rwlock_destroy(&meta_objectclose_lock);
return (CKR_FUNCTION_FAILED);
}
tokenobject_list_head = NULL;
return (CKR_OK);
}
void
meta_objectManager_finalize()
{
(void) meta_token_object_deactivate(ALL_TOKEN);
(void) pthread_rwlock_destroy(&meta_objectclose_lock);
(void) pthread_rwlock_destroy(&tokenobject_list_lock);
}
CK_RV
meta_handle2object(CK_OBJECT_HANDLE hObject, meta_object_t **object)
{
meta_object_t *tmp_object = (meta_object_t *)(hObject);
if (tmp_object == NULL) {
*object = NULL;
return (CKR_OBJECT_HANDLE_INVALID);
}
(void) pthread_rwlock_rdlock(&meta_objectclose_lock);
if (tmp_object->magic_marker != METASLOT_OBJECT_MAGIC) {
(void) pthread_rwlock_unlock(&meta_objectclose_lock);
*object = NULL;
return (CKR_OBJECT_HANDLE_INVALID);
}
(void) pthread_rwlock_rdlock(&tmp_object->object_lock);
(void) pthread_rwlock_unlock(&meta_objectclose_lock);
*object = tmp_object;
return (CKR_OK);
}
CK_RV
meta_object_alloc(meta_session_t *session, meta_object_t **object)
{
meta_object_t *new_object;
CK_ULONG num_slots;
new_object = calloc(1, sizeof (meta_object_t));
if (new_object == NULL)
return (CKR_HOST_MEMORY);
num_slots = meta_slotManager_get_slotcount();
new_object->clones = calloc(num_slots, sizeof (slot_object_t *));
if (new_object->clones == NULL) {
free(new_object);
return (CKR_HOST_MEMORY);
}
new_object->tried_create_clone = calloc(num_slots, sizeof (boolean_t));
if (new_object->tried_create_clone == NULL) {
free(new_object->clones);
free(new_object);
return (CKR_HOST_MEMORY);
}
new_object->magic_marker = METASLOT_OBJECT_MAGIC;
(void) pthread_rwlock_init(&new_object->object_lock, NULL);
(void) pthread_rwlock_init(&new_object->attribute_lock, NULL);
(void) pthread_mutex_init(&new_object->clone_create_lock, NULL);
(void) pthread_mutex_init(&new_object->isClosingObject_lock, NULL);
new_object->creator_session = session;
*object = new_object;
return (CKR_OK);
}
CK_RV
meta_object_get_attr(slot_session_t *slot_session, CK_OBJECT_HANDLE hObject,
meta_object_t *object)
{
CK_BBOOL is_sensitive = object->isSensitive;
CK_BBOOL is_extractable = object->isExtractable;
CK_BBOOL is_token = B_FALSE, is_private = B_FALSE;
CK_KEY_TYPE keytype;
CK_OBJECT_CLASS class;
CK_ATTRIBUTE attrs[3];
CK_RV rv;
CK_SESSION_HANDLE hSession = slot_session->hSession;
CK_SLOT_ID fw_st_id = slot_session->fw_st_id;
int count = 1;
attrs[0].type = CKA_CLASS;
attrs[0].pValue = &class;
attrs[0].ulValueLen = sizeof (class);
if (object->isFreeObject != FREE_ENABLED) {
attrs[1].type = CKA_TOKEN;
attrs[1].pValue = &is_token;
attrs[1].ulValueLen = sizeof (is_token);
count++;
}
if (object->isFreeObject <= FREE_DISABLED) {
attrs[count].type = CKA_PRIVATE;
attrs[count].pValue = &is_private;
attrs[count].ulValueLen = sizeof (is_private);
count++;
} else
is_private = object->isPrivate;
rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession, hObject,
attrs, count);
if (rv != CKR_OK) {
return (rv);
}
count = 0;
switch (class) {
case CKO_PRIVATE_KEY:
case CKO_SECRET_KEY:
attrs[0].type = CKA_EXTRACTABLE;
attrs[0].pValue = &is_extractable;
attrs[0].ulValueLen = sizeof (is_extractable);
count = 1;
if (object->isFreeObject <= FREE_DISABLED) {
attrs[1].type = CKA_SENSITIVE;
attrs[1].pValue = &is_sensitive;
attrs[1].ulValueLen = sizeof (is_sensitive);
count = 2;
if (object->isFreeObject == FREE_UNCHECKED) {
attrs[2].type = CKA_KEY_TYPE;
attrs[2].pValue = &keytype;
attrs[2].ulValueLen = sizeof (keytype);
count = 3;
}
}
break;
case CKO_PUBLIC_KEY:
if (object->isFreeObject == FREE_UNCHECKED) {
attrs[count].type = CKA_KEY_TYPE;
attrs[count].pValue = &keytype;
attrs[count].ulValueLen = sizeof (keytype);
count++;
}
is_sensitive = CK_FALSE;
is_extractable = CK_TRUE;
break;
default:
object->isFreeObject = FREE_DISABLED;
is_sensitive = CK_FALSE;
is_extractable = CK_TRUE;
};
if (count > 0) {
rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession, hObject,
attrs, count);
if (rv != CKR_OK) {
return (rv);
}
if (object->isFreeObject == FREE_UNCHECKED) {
if (keytype == CKK_EC || keytype == CKK_RSA ||
keytype == CKK_DH) {
if (metaslot_config.auto_key_migrate) {
object->isFreeObject = FREE_DISABLED;
object->isFreeToken = FREE_DISABLED;
}
object->isFreeObject = FREE_ENABLED;
if (is_token)
object->isFreeToken = FREE_ENABLED;
} else
object->isFreeObject = FREE_DISABLED;
}
}
object->isToken = is_token;
object->isPrivate = is_private;
object->isSensitive = is_sensitive;
object->isExtractable = is_extractable;
return (CKR_OK);
}
void
meta_object_activate(meta_object_t *new_object)
{
pthread_rwlock_t *list_lock;
meta_object_t **list_head;
if (new_object->isToken) {
list_lock = &tokenobject_list_lock;
list_head = &tokenobject_list_head;
} else {
list_lock = &new_object->creator_session->object_list_lock;
list_head = &new_object->creator_session->object_list_head;
}
(void) pthread_rwlock_wrlock(list_lock);
INSERT_INTO_LIST(*list_head, new_object);
(void) pthread_rwlock_unlock(list_lock);
}
CK_RV
meta_object_deactivate(meta_object_t *object, boolean_t have_list_lock,
boolean_t have_object_lock)
{
pthread_rwlock_t *list_lock;
meta_object_t **list_head;
if (!have_object_lock) {
(void) pthread_rwlock_rdlock(&object->object_lock);
}
(void) pthread_mutex_lock(&object->isClosingObject_lock);
if (object->isClosingObject) {
(void) pthread_mutex_unlock(&object->isClosingObject_lock);
OBJRELEASE(object);
return (CKR_OBJECT_HANDLE_INVALID);
}
object->isClosingObject = B_TRUE;
(void) pthread_mutex_unlock(&object->isClosingObject_lock);
if (object->isToken || (object->isFreeToken == FREE_ENABLED)) {
list_lock = &tokenobject_list_lock;
list_head = &tokenobject_list_head;
} else {
list_lock = &object->creator_session->object_list_lock;
list_head = &object->creator_session->object_list_head;
}
(void) pthread_rwlock_wrlock(&meta_objectclose_lock);
if (!have_list_lock) {
(void) pthread_rwlock_wrlock(list_lock);
}
object->magic_marker = METASLOT_OBJECT_BADMAGIC;
if (*list_head == object) {
if (object->next) {
*list_head = object->next;
object->next->prev = NULL;
} else {
*list_head = NULL;
}
} else if (object->next != NULL || object->prev != NULL) {
if (object->next) {
object->prev->next = object->next;
object->next->prev = object->prev;
} else {
object->prev->next = NULL;
}
}
if (!have_list_lock) {
(void) pthread_rwlock_unlock(list_lock);
}
(void) pthread_rwlock_unlock(&meta_objectclose_lock);
(void) pthread_rwlock_unlock(&object->object_lock);
(void) pthread_rwlock_wrlock(&object->object_lock);
(void) pthread_rwlock_unlock(&object->object_lock);
return (CKR_OK);
}
CK_RV
meta_object_dealloc(meta_session_t *session, meta_object_t *object,
boolean_t nukeSourceObj)
{
CK_RV rv, save_rv = CKR_OK;
CK_ULONG slotnum, num_slots;
CK_ULONG i;
num_slots = meta_slotManager_get_slotcount();
for (slotnum = 0; slotnum < num_slots; slotnum++) {
slot_session_t *obj_session;
slot_object_t *clone;
clone = object->clones[slotnum];
if (clone == NULL)
continue;
if (nukeSourceObj || (!object->isToken &&
!(object->isFreeToken == FREE_ENABLED &&
get_keystore_slotnum() == slotnum))) {
rv = meta_get_slot_session(slotnum, &obj_session,
(session == NULL) ?
object->creator_session->session_flags :
session->session_flags);
if (rv == CKR_OK) {
rv = FUNCLIST(obj_session->fw_st_id)->\
C_DestroyObject(obj_session->hSession,
clone->hObject);
meta_release_slot_session(obj_session);
if ((rv != CKR_OK) && (save_rv == CKR_OK)) {
save_rv = rv;
}
}
}
meta_slot_object_deactivate(clone);
meta_slot_object_dealloc(clone);
object->clones[slotnum] = NULL;
}
dealloc_attributes(object->attributes, object->num_attributes);
free(object->clones);
free(object->tried_create_clone);
if (object->clone_template) {
for (i = 0; i < object->clone_template_size; i++) {
freezero((object->clone_template)[i].pValue,
(object->clone_template)[i].ulValueLen);
}
free(object->clone_template);
}
(void) pthread_rwlock_destroy(&object->object_lock);
(void) pthread_rwlock_destroy(&object->attribute_lock);
(void) pthread_mutex_destroy(&object->isClosingObject_lock);
(void) pthread_mutex_destroy(&object->clone_create_lock);
meta_object_delay_free(object);
return (save_rv);
}
CK_RV
meta_slot_object_alloc(slot_object_t **object)
{
slot_object_t *new_object;
new_object = calloc(1, sizeof (slot_object_t));
if (new_object == NULL)
return (CKR_HOST_MEMORY);
*object = new_object;
return (CKR_OK);
}
void
meta_slot_object_activate(slot_object_t *object,
slot_session_t *creator_session, boolean_t isToken)
{
object->creator_session = creator_session;
if (isToken) {
extern slot_data_t *slots;
slot_data_t *slot;
slot = &(slots[object->creator_session->slotnum]);
(void) pthread_rwlock_wrlock(&slot->tokenobject_list_lock);
INSERT_INTO_LIST(slot->tokenobject_list_head, object);
(void) pthread_rwlock_unlock(&slot->tokenobject_list_lock);
} else {
slot_session_t *session = object->creator_session;
(void) pthread_rwlock_wrlock(&session->object_list_lock);
INSERT_INTO_LIST(session->object_list_head, object);
(void) pthread_rwlock_unlock(&session->object_list_lock);
}
object->isToken = isToken;
}
void
meta_slot_object_deactivate(slot_object_t *object)
{
slot_object_t **list_head;
pthread_rwlock_t *list_lock;
if (object->isToken) {
extern slot_data_t *slots;
slot_data_t *slot;
slot = &(slots[object->creator_session->slotnum]);
list_head = &slot->tokenobject_list_head;
list_lock = &slot->tokenobject_list_lock;
} else {
list_head = &object->creator_session->object_list_head;
list_lock = &object->creator_session->object_list_lock;
}
(void) pthread_rwlock_wrlock(list_lock);
REMOVE_FROM_LIST(*list_head, object);
(void) pthread_rwlock_unlock(list_lock);
}
void
meta_slot_object_dealloc(slot_object_t *object)
{
free(object);
}
CK_RV
meta_object_copyin(meta_object_t *object)
{
CK_RV rv = CKR_OK;
slot_session_t *session = NULL;
CK_ATTRIBUTE *attrs = NULL, *attrs_with_val = NULL;
slot_object_t *slot_object = NULL;
CK_ULONG num_attrs = 0, i, num_attrs_with_val;
CK_SESSION_HANDLE hSession;
CK_SLOT_ID fw_st_id;
(void) pthread_rwlock_wrlock(&object->attribute_lock);
if (object->attributes != NULL) {
goto finish;
}
slot_object = object->clones[object->master_clone_slotnum];
rv = meta_get_slot_session(object->master_clone_slotnum, &session,
object->creator_session->session_flags);
if (rv != CKR_OK) {
goto finish;
}
rv = get_master_attributes_by_object(session, slot_object,
&(object->attributes), &(object->num_attributes));
if (rv != CKR_OK) {
goto finish;
}
attrs = calloc(object->num_attributes, sizeof (CK_ATTRIBUTE));
if (attrs == NULL) {
rv = CKR_HOST_MEMORY;
goto finish;
}
for (i = 0; i < object->num_attributes; i++) {
attrs[i].type =
((object->attributes[i]).attribute).type;
}
num_attrs = object->num_attributes;
hSession = session->hSession;
fw_st_id = session->fw_st_id;
rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession,
slot_object->hObject, attrs, num_attrs);
if ((rv != CKR_OK) && (rv != CKR_ATTRIBUTE_TYPE_INVALID)) {
rv = CKR_FUNCTION_FAILED;
goto finish;
}
attrs_with_val = calloc(num_attrs, sizeof (CK_ATTRIBUTE));
if (attrs_with_val == NULL) {
rv = CKR_HOST_MEMORY;
goto finish;
}
num_attrs_with_val = 0;
for (i = 0; i < num_attrs; i++) {
if (!(((CK_LONG)(attrs[i].ulValueLen)) > 0)) {
if (!object->attributes[i].canBeEmptyValue) {
rv = CKR_FUNCTION_FAILED;
goto finish;
}
} else {
attrs_with_val[num_attrs_with_val].type = attrs[i].type;
attrs_with_val[num_attrs_with_val].ulValueLen =
attrs[i].ulValueLen;
attrs_with_val[num_attrs_with_val].pValue =
malloc(attrs[i].ulValueLen);
if (attrs_with_val[num_attrs_with_val].pValue == NULL) {
rv = CKR_HOST_MEMORY;
goto finish;
}
num_attrs_with_val++;
}
}
rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession,
slot_object->hObject, attrs_with_val, num_attrs_with_val);
if (rv != CKR_OK) {
goto finish;
}
for (i = 0; i < num_attrs_with_val; i++) {
rv = attribute_set_value(&(attrs_with_val[i]),
object->attributes, object->num_attributes);
if (rv != CKR_OK) {
goto finish;
}
}
finish:
(void) pthread_rwlock_unlock(&object->attribute_lock);
if (session)
meta_release_slot_session(session);
if (attrs) {
for (i = 0; i < num_attrs; i++) {
if (attrs[i].pValue != NULL) {
free(attrs[i].pValue);
}
}
free(attrs);
}
if (attrs_with_val) {
for (i = 0; i < num_attrs; i++) {
if (attrs_with_val[i].pValue != NULL) {
freezero(attrs_with_val[i].pValue,
attrs_with_val[i].ulValueLen);
}
}
free(attrs_with_val);
}
return (rv);
}
static CK_RV
create_wrap_unwrap_key(slot_session_t *slot_session, CK_OBJECT_HANDLE *hObject,
wrap_info_t *wrap_info, char *key_data, CK_ULONG key_len)
{
CK_OBJECT_CLASS objclass;
CK_KEY_TYPE keytype;
CK_RV rv = CKR_OK;
int i;
CK_ATTRIBUTE template[WRAP_KEY_TEMPLATE_SIZE];
i = 0;
objclass = wrap_info->class;
template[i].type = CKA_CLASS;
template[i].pValue = &objclass;
template[i].ulValueLen = sizeof (objclass);
i++;
keytype = wrap_info->key_type;
template[i].type = CKA_KEY_TYPE;
template[i].pValue = &keytype;
template[i].ulValueLen = sizeof (keytype);
i++;
template[i].type = CKA_TOKEN;
template[i].pValue = &falsevalue;
template[i].ulValueLen = sizeof (falsevalue);
if (objclass == CKO_SECRET_KEY) {
i++;
template[i].type = CKA_VALUE;
template[i].pValue = key_data;
template[i].ulValueLen = key_len;
i++;
template[i].type = CKA_WRAP;
template[i].pValue = &truevalue;
template[i].ulValueLen = sizeof (truevalue);
i++;
template[i].type = CKA_UNWRAP;
template[i].pValue = &truevalue;
template[i].ulValueLen = sizeof (truevalue);
} else {
i++;
template[i].type = CKA_MODULUS;
template[i].pValue = Modulus;
template[i].ulValueLen = sizeof (Modulus);
if (objclass == CKO_PUBLIC_KEY) {
i++;
template[i].type = CKA_PUBLIC_EXPONENT;
template[i].pValue = PubExpo;
template[i].ulValueLen = sizeof (PubExpo);
i++;
template[i].type = CKA_WRAP;
template[i].pValue = &truevalue;
template[i].ulValueLen = sizeof (truevalue);
} else {
i++;
template[i].type = CKA_PRIVATE_EXPONENT;
template[i].pValue = PriExpo;
template[i].ulValueLen = sizeof (PriExpo);
i++;
template[i].type = CKA_UNWRAP;
template[i].pValue = &truevalue;
template[i].ulValueLen = sizeof (truevalue);
}
}
rv = FUNCLIST(slot_session->fw_st_id)->C_CreateObject(
slot_session->hSession, template, i + 1, hObject);
return (rv);
}
static CK_RV
clone_by_create(meta_object_t *object, slot_object_t *new_clone,
slot_session_t *dst_slot_session)
{
CK_RV rv;
int free_token_index = -1;
if (object->attributes == NULL) {
rv = meta_object_copyin(object);
if (rv != CKR_OK) {
return (rv);
}
}
if (object->clone_template == NULL) {
rv = meta_clone_template_setup(object, object->attributes,
object->num_attributes);
if (rv != CKR_OK) {
return (rv);
}
}
if (object->isFreeToken == FREE_ENABLED) {
if (dst_slot_session->slotnum == get_keystore_slotnum())
free_token_index = set_template_boolean(CKA_TOKEN,
object->clone_template,
object->clone_template_size, B_FALSE, &truevalue);
else
free_token_index = set_template_boolean(CKA_TOKEN,
object->clone_template,
object->clone_template_size, B_FALSE, &falsevalue);
}
rv = FUNCLIST(dst_slot_session->fw_st_id)->C_CreateObject(
dst_slot_session->hSession, object->clone_template,
object->clone_template_size, &(new_clone->hObject));
if (free_token_index != -1) {
free_token_index = set_template_boolean(CKA_TOKEN,
object->clone_template, object->clone_template_size,
B_FALSE, &falsevalue);
}
if (rv != CKR_OK) {
return (rv);
}
return (CKR_OK);
}
static CK_RV
find_best_match_wrap_mech(wrap_info_t *wrap_info, int num_info,
CK_ULONG src_slotnum, CK_ULONG dst_slotnum, int *first_both_mech,
int *first_src_mech)
{
int i;
boolean_t src_supports, dst_supports;
CK_RV rv;
CK_MECHANISM_INFO mech_info;
mech_info.flags = CKF_WRAP;
for (i = 0; i < num_info; i++) {
src_supports = B_FALSE;
dst_supports = B_FALSE;
rv = meta_mechManager_slot_supports_mech(
(wrap_info[i]).mech_type, src_slotnum,
&src_supports, NULL, B_FALSE, &mech_info);
if (rv != CKR_OK) {
return (rv);
}
rv = meta_mechManager_slot_supports_mech(
(wrap_info[i]).mech_type, dst_slotnum,
&dst_supports, NULL, B_FALSE, &mech_info);
if (rv != CKR_OK) {
return (rv);
}
if ((src_supports) && (dst_supports)) {
*first_both_mech = i;
return (CKR_OK);
}
if ((src_supports) && (*first_src_mech == -1)) {
*first_src_mech = i;
}
}
return (CKR_OK);
}
static CK_RV
get_wrap_mechanism(CK_OBJECT_CLASS obj_class, CK_KEY_TYPE key_type,
CK_ULONG src_slotnum, CK_ULONG dst_slotnum, wrap_info_t *wrap_info)
{
wrap_info_t *wrap_info_to_search = NULL;
unsigned int num_wrap_info;
CK_RV rv;
int i;
boolean_t src_supports = B_FALSE, dst_supports = B_FALSE;
int first_src_mech, rsa_first_src_mech, first_both_mech;
CK_MECHANISM_INFO mech_info;
mech_info.flags = CKF_WRAP;
if ((obj_class == CKO_PRIVATE_KEY) && (key_type == CKK_KEA)) {
for (i = 0; i < num_special_wrap_info; i++) {
if ((special_wrap_info[i]).mech_type
!= CKM_SKIPJACK_WRAP) {
continue;
}
src_supports = B_FALSE;
dst_supports = B_FALSE;
rv = meta_mechManager_slot_supports_mech(
(special_wrap_info[i]).mech_type, src_slotnum,
&src_supports, NULL, B_FALSE, &mech_info);
if (rv != CKR_OK) {
goto finish;
}
rv = meta_mechManager_slot_supports_mech(
(special_wrap_info[i]).mech_type, dst_slotnum,
&dst_supports, NULL, B_FALSE, &mech_info);
if (rv != CKR_OK) {
goto finish;
}
if (src_supports) {
(void) memcpy(wrap_info,
&(special_wrap_info[i]),
sizeof (wrap_info_t));
wrap_info->src_supports = src_supports;
wrap_info->dst_supports = dst_supports;
rv = CKR_OK;
goto finish;
}
}
rv = CKR_FUNCTION_FAILED;
goto finish;
}
if ((key_type == CKK_SKIPJACK) || (key_type == CKK_BATON) ||
(key_type == CKK_JUNIPER)) {
wrap_info_to_search = special_wrap_info;
num_wrap_info = num_special_wrap_info;
} else {
wrap_info_to_search = common_wrap_info;
num_wrap_info = num_common_wrap_info;
}
first_both_mech = -1;
first_src_mech = -1;
rv = find_best_match_wrap_mech(wrap_info_to_search, num_wrap_info,
src_slotnum, dst_slotnum, &first_both_mech, &first_src_mech);
if (rv != CKR_OK) {
goto finish;
}
if (first_both_mech != -1) {
(void) memcpy(wrap_info,
&(wrap_info_to_search[first_both_mech]),
sizeof (wrap_info_t));
wrap_info->src_supports = B_TRUE;
wrap_info->dst_supports = B_TRUE;
rv = CKR_OK;
goto finish;
}
if (obj_class == CKO_SECRET_KEY) {
first_both_mech = -1;
rsa_first_src_mech = -1;
rv = find_best_match_wrap_mech(rsa_wrap_info,
num_rsa_wrap_info, src_slotnum, dst_slotnum,
&first_both_mech, &rsa_first_src_mech);
if (rv != CKR_OK) {
goto finish;
}
if (first_both_mech > -1) {
(void) memcpy(wrap_info,
&(rsa_wrap_info[first_both_mech]),
sizeof (wrap_info_t));
wrap_info->src_supports = B_TRUE;
wrap_info->dst_supports = B_TRUE;
rv = CKR_OK;
goto finish;
}
}
if (first_src_mech > -1) {
(void) memcpy(wrap_info,
&(wrap_info_to_search[first_src_mech]),
sizeof (wrap_info_t));
wrap_info->src_supports = B_TRUE;
wrap_info->dst_supports = B_FALSE;
rv = CKR_OK;
} else if (rsa_first_src_mech > -1) {
(void) memcpy(wrap_info, &(rsa_wrap_info[rsa_first_src_mech]),
sizeof (wrap_info_t));
wrap_info->src_supports = B_TRUE;
wrap_info->dst_supports = B_FALSE;
rv = CKR_OK;
} else {
rv = CKR_FUNCTION_FAILED;
}
finish:
return (rv);
}
static CK_RV
clone_by_wrap(meta_object_t *object, slot_object_t *new_clone,
slot_session_t *dst_slot_session)
{
slot_session_t *src_slot_session = NULL;
CK_OBJECT_HANDLE wrappingKey = 0, unwrappingKey = 0;
CK_MECHANISM wrappingMech;
CK_BYTE *wrappedKey = NULL;
CK_ULONG wrappedKeyLen = 0;
slot_object_t *slot_object = NULL;
CK_RV rv = CKR_OK;
CK_OBJECT_HANDLE unwrapped_obj;
meta_object_t *tmp_meta_obj = NULL;
slot_object_t *tmp_slot_obj = NULL;
CK_OBJECT_CLASS obj_class;
CK_KEY_TYPE key_type;
meta_session_t *tmp_meta_session = NULL;
CK_ATTRIBUTE unwrap_template[4];
char key_data[1024];
char ivbuf[1024];
wrap_info_t wrap_info;
CK_ULONG key_len, unwrap_template_size;
slot_object = object->clones[object->master_clone_slotnum];
rv = meta_get_slot_session(object->master_clone_slotnum,
&src_slot_session, object->creator_session->session_flags);
if (rv != CKR_OK) {
return (rv);
}
unwrap_template[0].type = CKA_CLASS;
unwrap_template[0].pValue = &obj_class;
unwrap_template[0].ulValueLen = sizeof (obj_class);
unwrap_template[1].type = CKA_KEY_TYPE;
unwrap_template[1].pValue = &key_type;
unwrap_template[1].ulValueLen = sizeof (key_type);
rv = FUNCLIST(src_slot_session->fw_st_id)->C_GetAttributeValue(
src_slot_session->hSession, slot_object->hObject,
unwrap_template, 2);
if (rv != CKR_OK) {
goto finish;
}
rv = get_wrap_mechanism(obj_class, key_type, src_slot_session->slotnum,
dst_slot_session->slotnum, &wrap_info);
if (rv != CKR_OK) {
goto finish;
}
if (wrap_info.class == CKO_SECRET_KEY) {
key_len = wrap_info.key_length;
if (pkcs11_get_urandom(key_data, key_len) < 0) {
rv = CKR_FUNCTION_FAILED;
goto finish;
}
if (wrap_info.iv_length > 0) {
if (pkcs11_get_urandom(
ivbuf, wrap_info.iv_length) < 0) {
rv = CKR_FUNCTION_FAILED;
goto finish;
}
}
}
rv = create_wrap_unwrap_key(src_slot_session, &wrappingKey,
&wrap_info, key_data, key_len);
if (rv != CKR_OK) {
goto finish;
}
wrappingMech.mechanism = wrap_info.mech_type;
wrappingMech.pParameter = ((wrap_info.iv_length > 0) ? ivbuf : NULL);
wrappingMech.ulParameterLen = wrap_info.iv_length;
rv = FUNCLIST(src_slot_session->fw_st_id)->C_WrapKey(
src_slot_session->hSession, &wrappingMech,
wrappingKey, slot_object->hObject, NULL, &wrappedKeyLen);
if (rv != CKR_OK) {
goto finish;
}
wrappedKey = malloc(wrappedKeyLen * sizeof (CK_BYTE));
if (wrappedKey == NULL) {
rv = CKR_HOST_MEMORY;
goto finish;
}
rv = FUNCLIST(src_slot_session->fw_st_id)->C_WrapKey(
src_slot_session->hSession, &wrappingMech,
wrappingKey, slot_object->hObject, wrappedKey, &wrappedKeyLen);
if (rv != CKR_OK) {
goto finish;
}
unwrap_template[2].type = CKA_SENSITIVE;
unwrap_template[2].pValue = &falsevalue;
unwrap_template[2].ulValueLen = sizeof (falsevalue);
unwrap_template[3].type = CKA_TOKEN;
unwrap_template[3].pValue = &falsevalue;
unwrap_template[3].ulValueLen = sizeof (falsevalue);
unwrap_template_size =
sizeof (unwrap_template) / sizeof (CK_ATTRIBUTE);
if (!wrap_info.dst_supports) {
goto unwrap_in_source;
}
if (wrap_info.key_type == CKK_RSA) {
wrap_info.class = CKO_PRIVATE_KEY;
}
rv = create_wrap_unwrap_key(dst_slot_session,
&unwrappingKey, &wrap_info, key_data, key_len);
if (rv != CKR_OK) {
goto finish;
}
rv = FUNCLIST(dst_slot_session->fw_st_id)->C_UnwrapKey(
dst_slot_session->hSession, &wrappingMech,
unwrappingKey, wrappedKey, wrappedKeyLen, unwrap_template,
unwrap_template_size, &(new_clone->hObject));
if (rv != CKR_OK) {
unwrap_in_source:
if (wrap_info.class == CKO_SECRET_KEY) {
rv = FUNCLIST(src_slot_session->fw_st_id)->C_UnwrapKey(
src_slot_session->hSession,
&wrappingMech, wrappingKey, wrappedKey,
wrappedKeyLen, unwrap_template,
unwrap_template_size, &(unwrapped_obj));
} else {
wrap_info.class = CKO_PRIVATE_KEY;
rv = create_wrap_unwrap_key(src_slot_session,
&unwrappingKey, &wrap_info, key_data, key_len);
if (rv != CKR_OK) {
goto finish;
}
rv = FUNCLIST(src_slot_session->fw_st_id)->C_UnwrapKey(
src_slot_session->hSession,
&wrappingMech, unwrappingKey, wrappedKey,
wrappedKeyLen, unwrap_template,
unwrap_template_size, &(unwrapped_obj));
}
if (rv != CKR_OK) {
goto finish;
}
rv = meta_session_alloc(&tmp_meta_session);
if (rv != CKR_OK) {
goto finish;
}
tmp_meta_session->session_flags = CKF_SERIAL_SESSION;
rv = meta_object_alloc(tmp_meta_session, &tmp_meta_obj);
if (rv != CKR_OK) {
goto finish;
}
rv = meta_slot_object_alloc(&tmp_slot_obj);
if (rv != CKR_OK) {
goto finish;
}
tmp_meta_obj->master_clone_slotnum = src_slot_session->slotnum;
tmp_slot_obj->hObject = unwrapped_obj;
tmp_meta_obj->clones[tmp_meta_obj->master_clone_slotnum]
= tmp_slot_obj;
meta_slot_object_activate(tmp_slot_obj, src_slot_session,
B_FALSE);
tmp_slot_obj = NULL;
rv = clone_by_create(tmp_meta_obj, new_clone,
dst_slot_session);
if (rv != CKR_OK) {
goto finish;
}
}
finish:
if (unwrappingKey) {
(void) FUNCLIST(dst_slot_session->fw_st_id)->C_DestroyObject(
dst_slot_session->hSession, unwrappingKey);
}
if (wrappingKey) {
(void) FUNCLIST(src_slot_session->fw_st_id)->C_DestroyObject(
src_slot_session->hSession, wrappingKey);
}
if (tmp_slot_obj) {
(void) meta_slot_object_dealloc(tmp_slot_obj);
}
if (tmp_meta_obj) {
(void) meta_object_dealloc(tmp_meta_session, tmp_meta_obj,
B_TRUE);
}
if (tmp_meta_session) {
(void) meta_session_dealloc(tmp_meta_session);
}
if (wrappedKey) {
freezero(wrappedKey, wrappedKeyLen);
}
if (src_slot_session) {
meta_release_slot_session(src_slot_session);
}
return (rv);
}
CK_RV
meta_object_get_clone(meta_object_t *object,
CK_ULONG slot_num, slot_session_t *slot_session, slot_object_t **clone)
{
CK_RV rv = CKR_OK;
slot_object_t *newclone = NULL;
if (object->clones[slot_num] != NULL) {
*clone = object->clones[slot_num];
return (CKR_OK);
}
if ((object->isSensitive) && (object->isToken) &&
(!metaslot_auto_key_migrate)) {
return (CKR_FUNCTION_FAILED);
}
if ((!object->isExtractable) && (object->attributes == NULL)) {
return (CKR_FUNCTION_FAILED);
}
(void) pthread_mutex_lock(&object->clone_create_lock);
if (object->clones[slot_num] != NULL) {
*clone = object->clones[slot_num];
goto finish;
}
if (object->tried_create_clone[slot_num]) {
(void) pthread_mutex_unlock(&object->clone_create_lock);
return (CKR_FUNCTION_FAILED);
}
rv = meta_slot_object_alloc(&newclone);
if (rv != CKR_OK)
goto finish;
object->tried_create_clone[slot_num] = B_TRUE;
if (object->isSensitive && object->attributes == NULL) {
rv = clone_by_wrap(object, newclone, slot_session);
} else {
rv = clone_by_create(object, newclone, slot_session);
}
if (rv != CKR_OK) {
goto finish;
}
object->clones[slot_num] = newclone;
meta_slot_object_activate(newclone, slot_session, object->isToken);
*clone = newclone;
newclone = NULL;
finish:
(void) pthread_mutex_unlock(&object->clone_create_lock);
if (newclone)
meta_slot_object_dealloc(newclone);
return (rv);
}
static CK_RV
meta_clone_template_setup(meta_object_t *object,
const generic_attr_t *attributes, size_t num_attributes)
{
CK_RV rv = CKR_OK;
CK_ATTRIBUTE *clone_template;
size_t i, c = 0;
clone_template = malloc(num_attributes * sizeof (CK_ATTRIBUTE));
if (clone_template == NULL) {
rv = CKR_HOST_MEMORY;
goto finish;
}
(void) pthread_rwlock_rdlock(&object->attribute_lock);
for (i = 0; i < num_attributes; i++) {
if (!attributes[i].isCloneAttr ||
(attributes[i].attribute.type == CKA_TOKEN &&
object->isFreeToken == FREE_DISABLED)) {
continue;
}
if ((!(attributes[i].hasValueForClone)) &&
(attributes[i].canBeEmptyValue)) {
continue;
}
clone_template[c].type = attributes[i].attribute.type;
clone_template[c].ulValueLen =
attributes[i].attribute.ulValueLen;
clone_template[c].pValue = malloc(clone_template[c].ulValueLen);
if (clone_template[c].pValue == NULL) {
free(clone_template);
rv = CKR_HOST_MEMORY;
(void) pthread_rwlock_unlock(&object->attribute_lock);
goto finish;
}
(void) memcpy(clone_template[c].pValue,
object->attributes[i].attribute.pValue,
clone_template[c].ulValueLen);
c++;
}
(void) pthread_rwlock_unlock(&object->attribute_lock);
object->clone_template = clone_template;
object->clone_template_size = c;
finish:
return (rv);
}
meta_object_t *
meta_object_find_by_handle(CK_OBJECT_HANDLE hObject, CK_ULONG slotnum,
boolean_t token_only)
{
meta_object_t *object = NULL, *tmp_obj;
meta_session_t *session;
if (!token_only) {
(void) pthread_rwlock_rdlock(&meta_sessionlist_lock);
session = meta_sessionlist_head;
while (session != NULL) {
(void) pthread_rwlock_rdlock(
&(session->object_list_lock));
tmp_obj = session->object_list_head;
while (tmp_obj != NULL) {
slot_object_t *slot_object;
(void) pthread_rwlock_rdlock(
&(tmp_obj->object_lock));
slot_object = tmp_obj->clones[slotnum];
if (slot_object != NULL) {
if (slot_object->hObject == hObject) {
object = tmp_obj;
}
}
(void) pthread_rwlock_unlock(
&(tmp_obj->object_lock));
if (object != NULL) {
break;
}
tmp_obj = tmp_obj->next;
}
(void) pthread_rwlock_unlock(
&(session->object_list_lock));
if (object != NULL) {
break;
}
session = session->next;
}
(void) pthread_rwlock_unlock(&meta_sessionlist_lock);
}
if (object != NULL) {
return (object);
}
(void) pthread_rwlock_rdlock(&tokenobject_list_lock);
tmp_obj = tokenobject_list_head;
while (tmp_obj != NULL) {
slot_object_t *slot_object;
(void) pthread_rwlock_rdlock(&(tmp_obj->object_lock));
slot_object = tmp_obj->clones[slotnum];
if (slot_object != NULL) {
if (slot_object->hObject == hObject)
object = tmp_obj;
}
(void) pthread_rwlock_unlock(&(tmp_obj->object_lock));
if (object != NULL) {
break;
}
tmp_obj = tmp_obj->next;
}
(void) pthread_rwlock_unlock(&tokenobject_list_lock);
return (object);
}
CK_RV
meta_token_object_deactivate(token_obj_type_t token_type)
{
meta_object_t *object, *tmp_object;
CK_RV save_rv = CKR_OK, rv;
(void) pthread_rwlock_wrlock(&tokenobject_list_lock);
object = tokenobject_list_head;
while (object != NULL) {
tmp_object = object->next;
if ((token_type == ALL_TOKEN) ||
((object->isPrivate) && (token_type == PRIVATE_TOKEN)) ||
((!object->isPrivate) && (token_type == PUBLIC_TOKEN))) {
rv = meta_object_deactivate(object, B_TRUE, B_FALSE);
if ((rv != CKR_OK) && (save_rv == CKR_OK)) {
save_rv = rv;
goto finish;
}
rv = meta_object_dealloc(NULL, object, B_FALSE);
if ((rv != CKR_OK) && (save_rv == CKR_OK)) {
save_rv = rv;
goto finish;
}
}
object = tmp_object;
}
finish:
(void) pthread_rwlock_unlock(&tokenobject_list_lock);
return (save_rv);
}
void
meta_object_delay_free(meta_object_t *objp)
{
meta_object_t *tmp;
(void) pthread_mutex_lock(&obj_delay_freed.obj_to_be_free_mutex);
objp->next = NULL;
if (obj_delay_freed.first == NULL) {
obj_delay_freed.last = objp;
obj_delay_freed.first = objp;
} else {
obj_delay_freed.last->next = objp;
obj_delay_freed.last = objp;
}
if (++obj_delay_freed.count >= MAX_OBJ_TO_BE_FREED) {
obj_delay_freed.count--;
tmp = obj_delay_freed.first->next;
free(obj_delay_freed.first);
obj_delay_freed.first = tmp;
}
(void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex);
}
boolean_t
meta_freeobject_check(meta_session_t *session, meta_object_t *object,
CK_MECHANISM *pMech, CK_ATTRIBUTE *tmpl, CK_ULONG tmpl_len,
CK_KEY_TYPE keytype)
{
mech_support_info_t *info = &(session->mech_support_info);
if (!metaslot_auto_key_migrate ||
(!object->isToken && !object->isSensitive &&
meta_slotManager_get_slotcount() < 2))
goto failure;
if (pMech != NULL) {
if (pMech->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN ||
pMech->mechanism == CKM_EC_KEY_PAIR_GEN ||
pMech->mechanism == CKM_DH_PKCS_KEY_PAIR_GEN ||
pMech->mechanism == CKM_DH_PKCS_DERIVE)
info->mech = pMech->mechanism;
else
goto failure;
} else if (tmpl_len > 0) {
if (!get_template_ulong(CKA_KEY_TYPE, tmpl, tmpl_len, &keytype))
goto failure;
switch (keytype) {
case CKK_RSA:
info->mech = CKM_RSA_PKCS_KEY_PAIR_GEN;
break;
case CKK_EC:
info->mech = CKM_EC_KEY_PAIR_GEN;
break;
case CKK_DH:
info->mech = CKM_DH_PKCS_KEY_PAIR_GEN;
break;
default:
goto failure;
}
} else
goto failure;
if (meta_mechManager_get_slots(info, B_FALSE, NULL) != CKR_OK)
goto failure;
if (info->num_supporting_slots < 2 &&
info->supporting_slots[0]->slotnum == get_keystore_slotnum())
goto failure;
if (object->isToken)
object->isFreeToken = FREE_ALLOWED_KEY;
else
object->isFreeToken = FREE_DISABLED;
object->isFreeObject = FREE_ALLOWED_KEY;
return (B_TRUE);
failure:
object->isFreeToken = FREE_DISABLED;
object->isFreeObject = FREE_DISABLED;
return (B_FALSE);
}
boolean_t
meta_freeobject_set(meta_object_t *object, CK_ATTRIBUTE *tmpl,
CK_ULONG tmpl_len, boolean_t create)
{
if (object->isFreeObject < FREE_ALLOWED_KEY)
return (B_FALSE);
if (!create) {
if (object->isSensitive) {
if (set_template_boolean(CKA_SENSITIVE, tmpl, tmpl_len,
B_TRUE, &falsevalue) == -1)
goto failure;
object->isFreeObject = FREE_ENABLED;
}
if (object->isPrivate) {
if (set_template_boolean(CKA_PRIVATE, tmpl, tmpl_len,
B_TRUE, &falsevalue) == -1)
goto failure;
object->isFreeObject = FREE_ENABLED;
}
}
if (object->isToken) {
object->isToken = B_FALSE;
object->isFreeToken = FREE_ENABLED;
object->isFreeObject = FREE_ENABLED;
} else
object->isFreeToken = FREE_DISABLED;
if (object->isFreeObject == FREE_ALLOWED_KEY)
object->isFreeObject = FREE_DISABLED;
return (B_TRUE);
failure:
object->isFreeToken = FREE_DISABLED;
object->isFreeObject = FREE_DISABLED;
return (B_FALSE);
}
CK_RV
meta_freetoken_set(CK_ULONG slot_num, CK_BBOOL *current_value,
CK_ATTRIBUTE *tmpl, CK_ULONG tmpl_len)
{
if (slot_num == get_keystore_slotnum()) {
if (*current_value == TRUE)
return (CKR_OK);
if (set_template_boolean(CKA_TOKEN, tmpl, tmpl_len, B_TRUE,
&truevalue) == -1)
return (CKR_FUNCTION_FAILED);
} else {
if (*current_value == FALSE)
return (CKR_OK);
if (set_template_boolean(CKA_TOKEN, tmpl, tmpl_len, B_TRUE,
&falsevalue) == -1)
return (CKR_FUNCTION_FAILED);
*current_value = FALSE;
}
return (CKR_OK);
}
static CK_RV
meta_freeobject_clone_maker(meta_session_t *session, meta_object_t *object,
CK_ULONG slotnum)
{
slot_object_t *slot_object = NULL;
slot_session_t *slot_session = NULL;
CK_RV rv;
rv = meta_slot_object_alloc(&slot_object);
if (rv != CKR_OK)
goto cleanup;
rv = meta_get_slot_session(slotnum, &slot_session,
session->session_flags);
if (rv != CKR_OK)
goto cleanup;
rv = clone_by_create(object, slot_object, slot_session);
if (rv == CKR_OK) {
object->clones[slotnum] = slot_object;
meta_slot_object_activate(slot_object, slot_session, B_TRUE);
}
cleanup:
meta_release_slot_session(slot_session);
return (rv);
}
boolean_t
meta_freeobject_clone(meta_session_t *session, meta_object_t *object)
{
CK_RV rv;
CK_ULONG keystore_slotnum;
CK_ATTRIBUTE attr[2];
boolean_t failover = B_FALSE;
if (object->attributes == NULL) {
rv = meta_object_copyin(object);
if (rv != CKR_OK)
return (rv);
}
if (object->isPrivate) {
CK_OBJECT_HANDLE new_clone;
CK_ULONG slotnum = object->master_clone_slotnum;
slot_session_t *slot_session;
attr[0].type = CKA_PRIVATE;
attr[0].pValue = &truevalue;
attr[0].ulValueLen = sizeof (truevalue);
rv = attribute_set_value(attr, object->attributes,
object->num_attributes);
if (rv > 0)
return (CKR_FUNCTION_FAILED);
rv = meta_get_slot_session(slotnum, &slot_session,
session->session_flags);
if (rv > 0)
return (rv);
rv = FUNCLIST(slot_session->fw_st_id)->\
C_CopyObject(slot_session->hSession,
object->clones[slotnum]->hObject, attr, 1, &new_clone);
if (rv == CKR_USER_NOT_LOGGED_IN) {
failover = B_TRUE;
keystore_slotnum = get_keystore_slotnum();
if (object->clones[keystore_slotnum] == NULL) {
rv = meta_freeobject_clone_maker(session,
object, keystore_slotnum);
if (rv != CKR_OK) {
goto failure;
}
}
object->master_clone_slotnum = keystore_slotnum;
} else if (rv != CKR_OK) {
meta_release_slot_session(slot_session);
goto failure;
}
rv = FUNCLIST(slot_session->fw_st_id)-> \
C_DestroyObject(slot_session->hSession,
object->clones[slotnum]->hObject);
if (rv != CKR_OK) {
meta_release_slot_session(slot_session);
goto failure;
}
if (!failover)
object->clones[slotnum]->hObject = new_clone;
else
object->clones[slotnum] = NULL;
meta_release_slot_session(slot_session);
}
if (object->isSensitive) {
slot_session_t *slot_session;
CK_ULONG slotnum = object->master_clone_slotnum;
attr[0].type = CKA_SENSITIVE;
attr[0].pValue = &truevalue;
attr[0].ulValueLen = sizeof (truevalue);
rv = attribute_set_value(attr, object->attributes,
object->num_attributes);
if (rv != CKR_OK)
goto failure;
rv = meta_get_slot_session(slotnum, &slot_session,
session->session_flags);
if (rv == CKR_OK) {
rv = FUNCLIST(slot_session->fw_st_id)-> \
C_SetAttributeValue(slot_session->hSession,
object->clones[slotnum]->hObject, attr, 1);
meta_release_slot_session(slot_session);
}
}
if (object->isFreeToken == FREE_ENABLED || failover) {
keystore_slotnum = get_keystore_slotnum();
if (object->clones[keystore_slotnum] == NULL) {
rv = meta_freeobject_clone_maker(session, object,
keystore_slotnum);
if (rv != CKR_OK)
goto failure;
object->master_clone_slotnum = keystore_slotnum;
}
object->isFreeToken = FREE_ENABLED;
}
object->isFreeObject = FREE_ENABLED;
return (CKR_OK);
failure:
object->isFreeToken = FREE_DISABLED;
object->isFreeObject = FREE_DISABLED;
return (rv);
}