#include <cryptoutil.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <strings.h>
#include "metaGlobal.h"
extern cipher_mechs_threshold_t meta_mechs_threshold[];
static boolean_t threshold_chk_enabled = B_FALSE;
CK_RV
meta_operation_init_defer(CK_FLAGS optype, meta_session_t *session,
CK_MECHANISM *pMechanism, meta_object_t *key)
{
if (session->init.pMech == NULL) {
session->init.pMech = malloc(sizeof (CK_MECHANISM));
if (session->init.pMech == NULL)
return (CKR_HOST_MEMORY);
(void) memcpy(session->init.pMech, pMechanism,
sizeof (CK_MECHANISM));
if ((pMechanism->ulParameterLen > 0) &&
(pMechanism->pParameter != NULL)) {
session->init.pMech->pParameter =
malloc(pMechanism->ulParameterLen);
if (session->init.pMech->pParameter == NULL) {
free(session->init.pMech);
session->init.pMech = NULL;
return (CKR_HOST_MEMORY);
}
(void) memcpy(session->init.pMech->pParameter,
pMechanism->pParameter, pMechanism->ulParameterLen);
} else {
session->init.pMech->pParameter = NULL;
}
} else {
if ((pMechanism->ulParameterLen > 0) &&
(pMechanism->pParameter != NULL)) {
if (pMechanism->ulParameterLen !=
session->init.pMech->ulParameterLen) {
if (session->init.pMech->pParameter != NULL)
free(session->init.pMech->pParameter);
session->init.pMech->pParameter =
malloc(pMechanism->ulParameterLen);
if (session->init.pMech->pParameter == NULL) {
free(session->init.pMech);
session->init.pMech = NULL;
return (CKR_HOST_MEMORY);
}
}
(void) memcpy(session->init.pMech->pParameter,
pMechanism->pParameter, pMechanism->ulParameterLen);
} else {
if (session->init.pMech->pParameter != NULL) {
free(session->init.pMech->pParameter);
session->init.pMech->pParameter = NULL;
}
}
session->init.pMech->mechanism =
pMechanism->mechanism;
session->init.pMech->ulParameterLen =
pMechanism->ulParameterLen;
}
session->init.session = session;
session->init.optype = optype;
session->init.key = key;
session->init.done = B_FALSE;
session->init.app = B_TRUE;
return (CKR_OK);
}
CK_RV
meta_operation_init(CK_FLAGS optype, meta_session_t *session,
CK_MECHANISM *pMechanism, meta_object_t *key)
{
CK_RV rv, save_rv;
mechinfo_t **supporting_slots;
CK_ULONG slotnum;
unsigned long i, slotCount = 0;
slot_session_t *init_session = NULL;
CK_MECHANISM_INFO mech_info;
if (session->op1.type != 0) {
CK_MECHANISM mech;
if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) ||
(optype == CKF_DIGEST)) {
mech = *pMechanism;
if ((pMechanism->ulParameterLen > 0) &&
(pMechanism->pParameter != NULL)) {
mech.pParameter =
malloc(pMechanism->ulParameterLen);
if (mech.pParameter == NULL) {
return (CKR_HOST_MEMORY);
}
(void) memcpy(mech.pParameter,
pMechanism->pParameter,
pMechanism->ulParameterLen);
} else {
mech.pParameter = NULL;
mech.ulParameterLen = 0;
}
meta_operation_cleanup(session, session->op1.type,
B_FALSE);
rv = meta_operation_init_defer(optype, session,
&mech, key);
if (mech.pParameter != NULL) {
free(mech.pParameter);
}
if (rv != CKR_OK)
return (rv);
} else {
meta_operation_cleanup(session, session->op1.type,
B_FALSE);
}
}
mech_info.flags = optype;
if (((session->mech_support_info).mech != pMechanism->mechanism) ||
((session->mech_support_info).num_supporting_slots == 0)) {
(session->mech_support_info).mech = pMechanism->mechanism;
rv = meta_mechManager_get_slots(&(session->mech_support_info),
B_FALSE, &mech_info);
if (rv != CKR_OK) {
goto finish;
}
}
rv = CKR_FUNCTION_FAILED;
slotCount = (session->mech_support_info).num_supporting_slots;
supporting_slots = (session->mech_support_info).supporting_slots;
for (i = 0; i < slotCount; i++) {
slot_object_t *init_key;
CK_SLOT_ID fw_st_id;
init_session = NULL;
slotnum = supporting_slots[i]->slotnum;
if (session->op1.session != NULL) {
if ((session->op1.session)->slotnum == slotnum) {
init_session = session->op1.session;
session->op1.session = NULL;
} else {
init_session = NULL;
}
}
if (!init_session) {
rv = meta_get_slot_session(slotnum, &init_session,
session->session_flags);
if (rv != CKR_OK) {
goto loop_cleanup;
}
}
if (optype != CKF_DIGEST) {
rv = meta_object_get_clone(key, slotnum, init_session,
&init_key);
if (rv != CKR_OK) {
goto loop_cleanup;
}
}
fw_st_id = init_session->fw_st_id;
switch (optype) {
case CKF_ENCRYPT:
rv = FUNCLIST(fw_st_id)->C_EncryptInit(
init_session->hSession, pMechanism,
init_key->hObject);
break;
case CKF_DECRYPT:
rv = FUNCLIST(fw_st_id)->C_DecryptInit(
init_session->hSession, pMechanism,
init_key->hObject);
break;
case CKF_DIGEST:
rv = FUNCLIST(fw_st_id)->C_DigestInit(
init_session->hSession, pMechanism);
break;
case CKF_SIGN:
rv = FUNCLIST(fw_st_id)->C_SignInit(
init_session->hSession, pMechanism,
init_key->hObject);
break;
case CKF_VERIFY:
rv = FUNCLIST(fw_st_id)->C_VerifyInit(
init_session->hSession, pMechanism,
init_key->hObject);
break;
case CKF_SIGN_RECOVER:
rv = FUNCLIST(fw_st_id)->C_SignRecoverInit(
init_session->hSession, pMechanism,
init_key->hObject);
break;
case CKF_VERIFY_RECOVER:
rv = FUNCLIST(fw_st_id)->C_VerifyRecoverInit(
init_session->hSession, pMechanism,
init_key->hObject);
break;
default:
rv = CKR_FUNCTION_FAILED;
break;
}
if (rv == CKR_OK)
break;
loop_cleanup:
if (i == 0) {
save_rv = rv;
}
if (init_session) {
meta_release_slot_session(init_session);
init_session = NULL;
}
}
if (rv == CKR_OK) {
if ((session->op1.session) &&
(session->op1.session != init_session)) {
meta_release_slot_session(session->op1.session);
}
session->op1.session = init_session;
session->op1.type = optype;
session->init.slotnum = slotnum;
session->init.done = B_TRUE;
} else {
rv = save_rv;
}
finish:
return (rv);
}
CK_RV
meta_operation_init_softtoken(CK_FLAGS optype, meta_session_t *session,
CK_MECHANISM *pMechanism, meta_object_t *key)
{
CK_RV rv = CKR_FUNCTION_FAILED;
slot_session_t *init_session = NULL;
slot_object_t *init_key;
CK_SLOT_ID fw_st_id;
CK_ULONG softtoken_slot_num;
softtoken_slot_num = get_softtoken_slotnum();
if (session->op1.type != 0) {
CK_MECHANISM mech;
mech = *pMechanism;
if ((pMechanism->ulParameterLen > 0) &&
(pMechanism->pParameter != NULL)) {
mech.pParameter =
malloc(pMechanism->ulParameterLen);
if (mech.pParameter == NULL) {
return (CKR_HOST_MEMORY);
}
(void) memcpy(mech.pParameter,
pMechanism->pParameter, pMechanism->ulParameterLen);
} else {
mech.pParameter = NULL;
mech.ulParameterLen = 0;
}
meta_operation_cleanup(session, session->op1.type, B_FALSE);
rv = meta_operation_init_defer(optype, session, &mech,
key);
if (mech.pParameter != NULL) {
free(mech.pParameter);
}
if (rv != CKR_OK)
return (rv);
}
if (session->op1.session != NULL) {
if ((session->op1.session)->slotnum ==
softtoken_slot_num) {
init_session = session->op1.session;
session->op1.session = NULL;
} else {
init_session = NULL;
}
}
if (init_session == NULL) {
rv = meta_get_slot_session(softtoken_slot_num,
&init_session, session->session_flags);
if (rv != CKR_OK) {
goto finish;
}
}
if (optype != CKF_DIGEST) {
rv = meta_object_get_clone(key, softtoken_slot_num,
init_session, &init_key);
if (rv != CKR_OK) {
if (init_session != NULL) {
meta_release_slot_session(init_session);
init_session = NULL;
}
goto finish;
}
}
fw_st_id = init_session->fw_st_id;
switch (optype) {
case CKF_ENCRYPT:
rv = FUNCLIST(fw_st_id)->C_EncryptInit(
init_session->hSession, pMechanism,
init_key->hObject);
break;
case CKF_DECRYPT:
rv = FUNCLIST(fw_st_id)->C_DecryptInit(
init_session->hSession, pMechanism,
init_key->hObject);
break;
case CKF_DIGEST:
rv = FUNCLIST(fw_st_id)->C_DigestInit(
init_session->hSession, pMechanism);
break;
default:
rv = CKR_FUNCTION_FAILED;
break;
}
if (rv == CKR_OK) {
if ((session->op1.session) &&
(session->op1.session != init_session)) {
meta_release_slot_session(session->op1.session);
}
session->op1.session = init_session;
session->op1.type = optype;
session->init.done = B_TRUE;
session->init.slotnum = softtoken_slot_num;
}
finish:
return (rv);
}
int
meta_GetThreshold(CK_MECHANISM_TYPE mechanism)
{
int i;
for (i = 0; i < MAX_NUM_THRESHOLD; i++) {
if (mechanism == meta_mechs_threshold[i].mech_type)
return (meta_mechs_threshold[i].mech_threshold);
}
return (0);
}
CK_RV
meta_do_operation(CK_FLAGS optype, int mode,
meta_session_t *session, meta_object_t *object,
CK_BYTE *in, CK_ULONG inLen, CK_BYTE *out, CK_ULONG *outLen)
{
CK_RV rv;
CK_SESSION_HANDLE hSession;
CK_SLOT_ID fw_st_id;
slot_session_t *slot_session = NULL;
slot_object_t *slot_object = NULL;
int threshold = 0;
boolean_t shutdown, finished_normally;
if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) ||
(optype == CKF_DIGEST)) {
if (Tmp_GetThreshold != NULL) {
if (!session->init.app) {
return (CKR_OPERATION_NOT_INITIALIZED);
}
threshold = meta_GetThreshold(
session->init.pMech->mechanism);
}
if ((threshold_chk_enabled == B_FALSE) || (inLen > threshold)) {
if ((session->init.app) && (!session->init.done)) {
rv = meta_operation_init(optype,
session->init.session,
session->init.pMech,
session->init.key);
if (rv != CKR_OK)
goto exit;
} else if (!session->init.app) {
return (CKR_OPERATION_NOT_INITIALIZED);
}
} else {
if ((session->init.app) && (!session->init.done)) {
rv = meta_operation_init_softtoken(optype,
session->init.session,
session->init.pMech,
session->init.key);
if (rv != CKR_OK) {
rv = meta_operation_init(optype,
session->init.session,
session->init.pMech,
session->init.key);
if (rv != CKR_OK)
goto exit;
}
} else if (!session->init.app) {
return (CKR_OPERATION_NOT_INITIALIZED);
}
}
} else if (optype != session->op1.type) {
return (CKR_OPERATION_NOT_INITIALIZED);
}
slot_session = session->op1.session;
if (slot_session) {
hSession = slot_session->hSession;
fw_st_id = slot_session->fw_st_id;
} else {
rv = CKR_FUNCTION_FAILED;
goto exit;
}
if (optype == CKF_ENCRYPT && mode == MODE_SINGLE) {
rv = FUNCLIST(fw_st_id)->C_Encrypt(hSession, in,
inLen, out, outLen);
} else if (optype == CKF_ENCRYPT && mode == MODE_UPDATE) {
rv = FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession, in,
inLen, out, outLen);
} else if (optype == CKF_ENCRYPT && mode == MODE_FINAL) {
rv = FUNCLIST(fw_st_id)->C_EncryptFinal(hSession, out,
outLen);
} else if (optype == CKF_DECRYPT && mode == MODE_SINGLE) {
rv = FUNCLIST(fw_st_id)->C_Decrypt(hSession, in,
inLen, out, outLen);
} else if (optype == CKF_DECRYPT && mode == MODE_UPDATE) {
rv = FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession, in,
inLen, out, outLen);
} else if (optype == CKF_DECRYPT && mode == MODE_FINAL) {
rv = FUNCLIST(fw_st_id)->C_DecryptFinal(hSession, out,
outLen);
} else if (optype == CKF_DIGEST && mode == MODE_SINGLE) {
rv = FUNCLIST(fw_st_id)->C_Digest(hSession, in, inLen,
out, outLen);
} else if (optype == CKF_DIGEST && mode == MODE_UPDATE) {
rv = FUNCLIST(fw_st_id)->C_DigestUpdate(hSession, in,
inLen);
} else if (optype == CKF_DIGEST && mode == MODE_UPDATE_WITHKEY) {
rv = meta_object_get_clone(object,
slot_session->slotnum, slot_session, &slot_object);
if (rv == CKR_OK)
rv = FUNCLIST(fw_st_id)->C_DigestKey(hSession,
slot_object->hObject);
} else if (optype == CKF_DIGEST && mode == MODE_FINAL) {
rv = FUNCLIST(fw_st_id)->C_DigestFinal(hSession, out,
outLen);
} else if (optype == CKF_SIGN && mode == MODE_SINGLE) {
rv = FUNCLIST(fw_st_id)->C_Sign(hSession, in, inLen,
out, outLen);
} else if (optype == CKF_SIGN && mode == MODE_UPDATE) {
rv = FUNCLIST(fw_st_id)->C_SignUpdate(hSession, in,
inLen);
} else if (optype == CKF_SIGN && mode == MODE_FINAL) {
rv = FUNCLIST(fw_st_id)->C_SignFinal(hSession, out,
outLen);
} else if (optype == CKF_VERIFY && mode == MODE_SINGLE) {
rv = FUNCLIST(fw_st_id)->C_Verify(hSession, in,
inLen, out, *outLen);
} else if (optype == CKF_VERIFY && mode == MODE_UPDATE) {
rv = FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession, in,
inLen);
} else if (optype == CKF_VERIFY && mode == MODE_FINAL) {
rv = FUNCLIST(fw_st_id)->C_VerifyFinal(hSession, in,
inLen);
} else if (optype == CKF_SIGN_RECOVER && mode == MODE_SINGLE) {
rv = FUNCLIST(fw_st_id)->C_SignRecover(hSession, in,
inLen, out, outLen);
} else if (optype == CKF_VERIFY_RECOVER && mode == MODE_SINGLE) {
rv = FUNCLIST(fw_st_id)->C_VerifyRecover(hSession, in,
inLen, out, outLen);
} else {
rv = CKR_FUNCTION_FAILED;
}
exit:
if (rv == CKR_BUFFER_TOO_SMALL ||
(rv == CKR_OK && out == NULL && optype != CKF_VERIFY)) {
shutdown = B_FALSE;
} else if (rv != CKR_OK) {
shutdown = B_TRUE;
finished_normally = B_FALSE;
} else {
if (mode == MODE_SINGLE || mode == MODE_FINAL) {
shutdown = B_TRUE;
finished_normally = B_TRUE;
} else {
shutdown = B_FALSE;
}
}
if (shutdown) {
if (mode == MODE_SINGLE || mode == MODE_FINAL) {
session->init.app = B_FALSE;
}
meta_operation_cleanup(session, optype, finished_normally);
}
return (rv);
}
void
free_session_mechanism(meta_session_t *session)
{
if (session->init.pMech != NULL) {
if (session->init.pMech->pParameter != NULL) {
free(session->init.pMech->pParameter);
session->init.pMech->pParameter = NULL;
session->init.pMech->ulParameterLen = 0;
}
free(session->init.pMech);
session->init.pMech = NULL;
}
}
void
meta_operation_cleanup(meta_session_t *session, CK_FLAGS optype,
boolean_t finished_normally)
{
operation_info_t *op;
CK_SESSION_HANDLE hSession;
CK_SLOT_ID fw_st_id;
if (!finished_normally) {
CK_BYTE dummy_buf[8];
if (session->op1.type == optype) {
op = &session->op1;
} else {
if ((optype == CKF_ENCRYPT) ||
(optype == CKF_DECRYPT) ||
(optype == CKF_DIGEST)) {
session->op1.type = 0;
session->init.app = B_FALSE;
session->init.done = B_FALSE;
free_session_mechanism(session);
}
return;
}
hSession = op->session->hSession;
fw_st_id = op->session->fw_st_id;
switch (optype) {
case CKF_ENCRYPT:
(void) FUNCLIST(fw_st_id)->C_EncryptUpdate(hSession,
NULL, 8, dummy_buf, NULL);
break;
case CKF_DECRYPT:
(void) FUNCLIST(fw_st_id)->C_DecryptUpdate(hSession,
NULL, 8, dummy_buf, NULL);
break;
case CKF_DIGEST:
(void) FUNCLIST(fw_st_id)->C_DigestUpdate(hSession,
NULL, 8);
break;
case CKF_SIGN:
(void) FUNCLIST(fw_st_id)->C_SignUpdate(hSession,
NULL, 8);
break;
case CKF_SIGN_RECOVER:
(void) FUNCLIST(fw_st_id)->C_SignRecover(hSession,
NULL, 8, dummy_buf, NULL);
break;
case CKF_VERIFY:
(void) FUNCLIST(fw_st_id)->C_VerifyUpdate(hSession,
NULL, 8);
break;
case CKF_VERIFY_RECOVER:
(void) FUNCLIST(fw_st_id)->C_VerifyRecover(hSession,
NULL, 8, dummy_buf, NULL);
break;
default:
break;
}
meta_release_slot_session(session->op1.session);
session->op1.session = NULL;
}
if ((optype == CKF_ENCRYPT) || (optype == CKF_DECRYPT) ||
(optype == CKF_DIGEST)) {
session->init.done = B_FALSE;
free_session_mechanism(session);
}
session->op1.type = 0;
}
static CK_RV
get_slotlist_for_mech(CK_MECHANISM_TYPE mech_type,
mech_support_info_t *mech_support_info,
mechinfo_t ***slots, unsigned long *slot_count, boolean_t token_only,
CK_MECHANISM_INFO *mech_info)
{
boolean_t mech_supported = B_FALSE;
CK_RV rv = CKR_OK;
if (token_only) {
rv = meta_mechManager_slot_supports_mech(mech_type,
get_keystore_slotnum(), &mech_supported,
&((mech_support_info->supporting_slots)[0]), B_FALSE,
mech_info);
if (rv != CKR_OK) {
return (rv);
}
if (mech_supported) {
mech_support_info->mech = mech_type;
mech_support_info->num_supporting_slots = 0;
*slots = mech_support_info->supporting_slots;
*slot_count = 1;
} else {
rv = CKR_FUNCTION_FAILED;
}
} else {
if ((mech_support_info->mech != mech_type) ||
(mech_support_info->num_supporting_slots == 0)) {
mech_support_info->mech = mech_type;
rv = meta_mechManager_get_slots(mech_support_info,
B_FALSE, mech_info);
if (rv != CKR_OK) {
return (CKR_FUNCTION_FAILED);
}
}
*slots = mech_support_info->supporting_slots;
*slot_count = mech_support_info->num_supporting_slots;
}
return (rv);
}
CK_RV
meta_generate_keys(meta_session_t *session, CK_MECHANISM *pMechanism,
CK_ATTRIBUTE *k1Template, CK_ULONG k1AttrCount, meta_object_t *key1,
CK_ATTRIBUTE *k2Template, CK_ULONG k2AttrCount, meta_object_t *key2)
{
CK_RV rv, save_rv;
slot_session_t *gen_session = NULL;
slot_object_t *slot_key1 = NULL, *slot_key2 = NULL;
mechinfo_t **slots = NULL;
unsigned long i, slotCount = 0;
boolean_t doKeyPair = B_FALSE, token_only = B_FALSE;
CK_ULONG slotnum;
CK_MECHANISM_INFO mech_info;
CK_BBOOL current_token1_value = FALSE, current_token2_value = FALSE;
(void) get_template_boolean(CKA_TOKEN, k1Template, k1AttrCount,
&(key1->isToken));
(void) get_template_boolean(CKA_SENSITIVE, k1Template, k1AttrCount,
&(key1->isSensitive));
(void) get_template_boolean(CKA_PRIVATE, k1Template, k1AttrCount,
&(key1->isPrivate));
if (!get_template_boolean(CKA_EXTRACTABLE, k1Template, k1AttrCount,
&(key1->isExtractable)))
key1->isExtractable = B_TRUE;
if (key1->isToken)
current_token1_value = TRUE;
mech_info.flags = CKF_GENERATE;
if (key2) {
(void) get_template_boolean(CKA_TOKEN, k2Template, k2AttrCount,
&(key2->isToken));
(void) get_template_boolean(CKA_SENSITIVE, k2Template,
k2AttrCount, &(key2->isSensitive));
(void) get_template_boolean(CKA_PRIVATE, k2Template,
k2AttrCount, &(key2->isPrivate));
if (!get_template_boolean(CKA_EXTRACTABLE, k2Template,
k2AttrCount, &(key2->isExtractable)))
key2->isExtractable = B_TRUE;
if (key2->isToken)
current_token2_value = TRUE;
doKeyPair = B_TRUE;
mech_info.flags = CKF_GENERATE_KEY_PAIR;
}
if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
((key1->isToken) || ((key2) && (key2->isToken)))) {
return (CKR_SESSION_READ_ONLY);
}
if (meta_freeobject_check(session, key1, pMechanism, k1Template,
k1AttrCount, 0)) {
if ((key1->isPrivate || (doKeyPair && key2->isPrivate)) &&
!metaslot_logged_in())
return (CKR_USER_NOT_LOGGED_IN);
if (!meta_freeobject_set(key1, k1Template, k1AttrCount,
B_FALSE))
return (CKR_FUNCTION_FAILED);
if (doKeyPair) {
key2->isFreeObject = FREE_ALLOWED_KEY;
if (!meta_freeobject_set(key2, k2Template, k2AttrCount,
B_FALSE))
return (CKR_FUNCTION_FAILED);
}
} else if (doKeyPair) {
key2->isFreeObject = FREE_DISABLED;
key2->isFreeToken = FREE_DISABLED;
}
if ((key1->isToken) || ((doKeyPair) && (key2->isToken))) {
token_only = B_TRUE;
}
rv = get_slotlist_for_mech(pMechanism->mechanism,
&(session->mech_support_info), &slots, &slotCount, token_only,
&mech_info);
if (rv != CKR_OK) {
goto finish;
}
rv = meta_slot_object_alloc(&slot_key1);
if (doKeyPair && rv == CKR_OK)
rv = meta_slot_object_alloc(&slot_key2);
if (rv != CKR_OK)
goto finish;
for (i = 0; i < slotCount; i++) {
CK_SESSION_HANDLE hSession;
CK_SLOT_ID fw_st_id;
gen_session = NULL;
slotnum = slots[i]->slotnum;
if (session->op1.session != NULL) {
if ((session->op1.session)->slotnum == slotnum) {
gen_session = session->op1.session;
session->op1.session = NULL;
} else {
gen_session = NULL;
}
}
if (gen_session == NULL) {
rv = meta_get_slot_session(slotnum, &gen_session,
session->session_flags);
if (rv != CKR_OK) {
goto loop_cleanup;
}
}
if (key1->isFreeToken == FREE_ENABLED) {
rv = meta_freetoken_set(slotnum,
¤t_token1_value, k1Template, k1AttrCount);
if (rv != CKR_OK)
goto loop_cleanup;
}
if (doKeyPair && key2->isFreeToken == FREE_ENABLED) {
rv = meta_freetoken_set(slotnum,
¤t_token2_value, k2Template, k2AttrCount);
if (rv != CKR_OK)
goto loop_cleanup;
}
fw_st_id = gen_session->fw_st_id;
hSession = gen_session->hSession;
if (doKeyPair) {
rv = FUNCLIST(fw_st_id)->C_GenerateKeyPair(hSession,
pMechanism, k1Template, k1AttrCount,
k2Template, k2AttrCount,
&slot_key1->hObject, &slot_key2->hObject);
} else {
rv = FUNCLIST(fw_st_id)->C_GenerateKey(hSession,
pMechanism, k1Template, k1AttrCount,
&slot_key1->hObject);
}
if (rv == CKR_OK)
break;
loop_cleanup:
if (i == 0) {
save_rv = rv;
}
if (gen_session) {
meta_release_slot_session(gen_session);
gen_session = NULL;
}
}
if (rv != CKR_OK) {
rv = save_rv;
goto finish;
}
rv = meta_object_get_attr(gen_session, slot_key1->hObject, key1);
if (rv != CKR_OK) {
goto finish;
}
if (key2) {
rv = meta_object_get_attr(gen_session, slot_key2->hObject,
key2);
if (rv != CKR_OK) {
goto finish;
}
}
if (key1->isFreeToken == FREE_ENABLED)
key1->isToken = B_TRUE;
meta_slot_object_activate(slot_key1, gen_session, key1->isToken);
key1->clones[slotnum] = slot_key1;
key1->master_clone_slotnum = slotnum;
slot_key1 = NULL;
if (key1->isFreeObject == FREE_ENABLED) {
rv = meta_freeobject_clone(session, key1);
if (rv != CKR_OK)
goto finish;
}
if (doKeyPair) {
if (key2->isFreeToken == FREE_ENABLED)
key2->isToken = B_TRUE;
meta_slot_object_activate(slot_key2, gen_session,
key2->isToken);
key2->clones[slotnum] = slot_key2;
key2->master_clone_slotnum = slotnum;
slot_key2 = NULL;
if (key2->isFreeObject == FREE_ENABLED) {
rv = meta_freeobject_clone(session, key2);
if (rv != CKR_OK)
goto finish;
}
}
finish:
if (slot_key1) {
meta_slot_object_dealloc(slot_key1);
}
if (slot_key2) {
meta_slot_object_dealloc(slot_key2);
}
if (rv == CKR_OK) {
if ((session->op1.session) &&
(session->op1.session != gen_session)) {
meta_release_slot_session(session->op1.session);
}
session->op1.session = gen_session;
}
return (rv);
}
CK_RV
meta_wrap_key(meta_session_t *session, CK_MECHANISM *pMechanism,
meta_object_t *wrappingkey, meta_object_t *inputkey, CK_BYTE *wrapped_key,
CK_ULONG *wrapped_key_len)
{
CK_RV rv, save_rv;
slot_session_t *wrap_session = NULL;
slot_object_t *slot_wrappingkey, *slot_inputkey;
mechinfo_t **slots = NULL;
unsigned long i, slotCount = 0;
CK_ULONG slotnum;
CK_MECHANISM_INFO mech_info;
mech_info.flags = CKF_WRAP;
rv = get_slotlist_for_mech(pMechanism->mechanism,
&(session->mech_support_info), &slots, &slotCount,
inputkey->isToken, &mech_info);
if (rv != CKR_OK) {
return (rv);
}
for (i = 0; i < slotCount; i++) {
slotnum = slots[i]->slotnum;
wrap_session = NULL;
if (session->op1.session != NULL) {
if ((session->op1.session)->slotnum == slotnum) {
wrap_session = session->op1.session;
session->op1.session = NULL;
} else {
wrap_session = NULL;
}
}
if (wrap_session == NULL) {
rv = meta_get_slot_session(slotnum, &wrap_session,
session->session_flags);
if (rv != CKR_OK) {
goto loop_cleanup;
}
}
rv = meta_object_get_clone(wrappingkey, slotnum,
wrap_session, &slot_wrappingkey);
if (rv != CKR_OK)
goto loop_cleanup;
rv = meta_object_get_clone(inputkey, slotnum,
wrap_session, &slot_inputkey);
if (rv != CKR_OK)
goto loop_cleanup;
rv = FUNCLIST(wrap_session->fw_st_id)->C_WrapKey(
wrap_session->hSession, pMechanism,
slot_wrappingkey->hObject, slot_inputkey->hObject,
wrapped_key, wrapped_key_len);
if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
break;
loop_cleanup:
if (i == 0) {
save_rv = rv;
}
if (wrap_session) {
meta_release_slot_session(wrap_session);
wrap_session = NULL;
}
}
if (rv != CKR_OK) {
if (rv != CKR_BUFFER_TOO_SMALL) {
if (i == slotCount) {
rv = save_rv;
}
}
}
if (rv == CKR_OK) {
if ((session->op1.session) &&
(session->op1.session != wrap_session)) {
meta_release_slot_session(session->op1.session);
}
session->op1.session = wrap_session;
}
return (rv);
}
CK_RV
meta_unwrap_key(meta_session_t *session,
CK_MECHANISM *pMechanism, meta_object_t *unwrapping_key,
CK_BYTE *wrapped_key, CK_ULONG wrapped_key_len,
CK_ATTRIBUTE *template, CK_ULONG template_size,
meta_object_t *unwrapped_key)
{
CK_RV rv, save_rv;
CK_OBJECT_HANDLE hUnwrappedKey;
slot_session_t *unwrap_session = NULL;
slot_object_t *slot_unwrappingkey, *slot_unwrapped_key;
mechinfo_t **slots = NULL;
unsigned long i, slotCount = 0;
CK_ULONG slotnum;
CK_MECHANISM_INFO mech_info;
if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
unwrapped_key->isToken) {
return (CKR_SESSION_READ_ONLY);
}
mech_info.flags = CKF_UNWRAP;
rv = get_slotlist_for_mech(pMechanism->mechanism,
&(session->mech_support_info), &slots, &slotCount,
unwrapped_key->isToken, &mech_info);
if (rv != CKR_OK) {
return (rv);
}
rv = meta_slot_object_alloc(&slot_unwrapped_key);
if (rv != CKR_OK) {
goto finish;
}
for (i = 0; i < slotCount; i++) {
slotnum = slots[i]->slotnum;
unwrap_session = NULL;
if (session->op1.session != NULL) {
if ((session->op1.session)->slotnum == slotnum) {
unwrap_session = session->op1.session;
session->op1.session = NULL;
} else {
unwrap_session = NULL;
}
}
if (unwrap_session == NULL) {
rv = meta_get_slot_session(slotnum, &unwrap_session,
session->session_flags);
if (rv != CKR_OK) {
goto loop_cleanup;
}
}
rv = meta_object_get_clone(unwrapping_key, slotnum,
unwrap_session, &slot_unwrappingkey);
if (rv != CKR_OK)
goto loop_cleanup;
rv = FUNCLIST(unwrap_session->fw_st_id)->C_UnwrapKey(
unwrap_session->hSession, pMechanism,
slot_unwrappingkey->hObject, wrapped_key, wrapped_key_len,
template, template_size, &hUnwrappedKey);
if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
break;
loop_cleanup:
if (i == 0) {
save_rv = rv;
}
if (unwrap_session) {
meta_release_slot_session(unwrap_session);
unwrap_session = NULL;
}
}
if (rv != CKR_OK) {
if (rv != CKR_BUFFER_TOO_SMALL) {
rv = save_rv;
}
goto finish;
}
slot_unwrapped_key->hObject = hUnwrappedKey;
unwrapped_key->clones[slotnum] = slot_unwrapped_key;
unwrapped_key->master_clone_slotnum = slotnum;
rv = meta_object_get_attr(unwrap_session,
slot_unwrapped_key->hObject, unwrapped_key);
if (rv != CKR_OK) {
goto finish;
}
meta_slot_object_activate(slot_unwrapped_key, unwrap_session,
unwrapped_key->isToken);
slot_unwrapped_key = NULL;
finish:
if (slot_unwrapped_key) {
meta_slot_object_dealloc(slot_unwrapped_key);
}
if (rv == CKR_OK) {
if ((session->op1.session) &&
(session->op1.session != unwrap_session)) {
meta_release_slot_session(session->op1.session);
}
session->op1.session = unwrap_session;
}
return (rv);
}
CK_RV
meta_derive_key(meta_session_t *session, CK_MECHANISM *pMechanism,
meta_object_t *basekey1, meta_object_t *basekey2,
CK_OBJECT_HANDLE *phBaseKey2,
CK_ATTRIBUTE *pTemplate, CK_ULONG ulAttributeCount,
meta_object_t *newKey1, meta_object_t *newKey2,
meta_object_t *newKey3, meta_object_t *newKey4)
{
CK_RV rv, save_rv;
CK_OBJECT_HANDLE hDerivedKey;
CK_ULONG slotnum;
boolean_t isSSL = B_FALSE;
boolean_t isTLSPRF = B_FALSE;
mechinfo_t **slots = NULL;
unsigned long i, slot_count = 0;
slot_session_t *derive_session = NULL;
slot_object_t *slot_basekey1 = NULL, *slot_basekey2 = NULL;
slot_object_t *slotkey1 = NULL, *slotkey2 = NULL, *slotkey3 = NULL,
*slotkey4 = NULL;
CK_MECHANISM_INFO mech_info;
CK_BBOOL current_token_value = FALSE;
(void) get_template_boolean(CKA_TOKEN, pTemplate, ulAttributeCount,
&(newKey1->isToken));
(void) get_template_boolean(CKA_PRIVATE, pTemplate, ulAttributeCount,
&(newKey1->isPrivate));
(void) get_template_boolean(CKA_SENSITIVE, pTemplate, ulAttributeCount,
&(newKey1->isSensitive));
if (newKey1->isToken)
current_token_value = TRUE;
if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
newKey1->isToken) {
rv = CKR_SESSION_READ_ONLY;
goto finish;
}
if (meta_freeobject_check(session, newKey1, pMechanism, pTemplate,
ulAttributeCount, 0)) {
if (newKey1->isPrivate && !metaslot_logged_in())
return (CKR_USER_NOT_LOGGED_IN);
if (!meta_freeobject_set(newKey1, pTemplate, ulAttributeCount,
B_FALSE))
return (CKR_FUNCTION_FAILED);
}
mech_info.flags = CKF_DERIVE;
rv = get_slotlist_for_mech(pMechanism->mechanism,
&(session->mech_support_info), &slots, &slot_count,
newKey1->isToken, &mech_info);
if (rv != CKR_OK) {
return (rv);
}
if (pMechanism->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE ||
pMechanism->mechanism == CKM_TLS_KEY_AND_MAC_DERIVE)
isSSL = B_TRUE;
else if (pMechanism->mechanism == CKM_TLS_PRF)
isTLSPRF = B_TRUE;
rv = meta_slot_object_alloc(&slotkey1);
if (isSSL) {
if (rv == CKR_OK)
rv = meta_slot_object_alloc(&slotkey2);
if (rv == CKR_OK)
rv = meta_slot_object_alloc(&slotkey3);
if (rv == CKR_OK)
rv = meta_slot_object_alloc(&slotkey4);
}
if (rv != CKR_OK) {
goto finish;
}
for (i = 0; i < slot_count; i++) {
slotnum = slots[i]->slotnum;
derive_session = NULL;
if (session->op1.session != NULL) {
if ((session->op1.session)->slotnum == slotnum) {
derive_session = session->op1.session;
session->op1.session = NULL;
} else {
derive_session = NULL;
}
}
if (derive_session == NULL) {
rv = meta_get_slot_session(slotnum, &derive_session,
session->session_flags);
if (rv != CKR_OK) {
goto loop_cleanup;
}
}
rv = meta_object_get_clone(basekey1, slotnum,
derive_session, &slot_basekey1);
if (rv != CKR_OK)
goto loop_cleanup;
if (basekey2) {
rv = meta_object_get_clone(basekey2, slotnum,
derive_session, &slot_basekey2);
if (rv != CKR_OK)
goto loop_cleanup;
*phBaseKey2 = slot_basekey2->hObject;
}
if (newKey1->isFreeToken == FREE_ENABLED) {
rv = meta_freetoken_set(slotnum, ¤t_token_value,
pTemplate, ulAttributeCount);
if (rv != CKR_OK)
goto loop_cleanup;
}
rv = FUNCLIST(derive_session->fw_st_id)->C_DeriveKey(
derive_session->hSession, pMechanism,
slot_basekey1->hObject, pTemplate, ulAttributeCount,
(isSSL || isTLSPRF) ? NULL : &hDerivedKey);
if (rv == CKR_OK)
break;
loop_cleanup:
if (i == 0) {
save_rv = rv;
}
if (derive_session) {
meta_release_slot_session(derive_session);
derive_session = NULL;
}
}
if (rv != CKR_OK) {
rv = save_rv;
goto finish;
}
if (isTLSPRF)
goto finish;
if (isSSL) {
CK_SSL3_KEY_MAT_PARAMS *keyparams;
CK_SSL3_KEY_MAT_OUT *keys;
keyparams = (CK_SSL3_KEY_MAT_PARAMS*)pMechanism->pParameter;
keys = keyparams->pReturnedKeyMaterial;
slotkey1->hObject = keys->hClientMacSecret;
slotkey2->hObject = keys->hServerMacSecret;
slotkey3->hObject = keys->hClientKey;
slotkey4->hObject = keys->hServerKey;
rv = meta_object_get_attr(derive_session,
slotkey1->hObject, newKey1);
if (rv != CKR_OK) {
goto finish;
}
rv = meta_object_get_attr(derive_session,
slotkey2->hObject, newKey2);
if (rv != CKR_OK) {
goto finish;
}
rv = meta_object_get_attr(derive_session,
slotkey3->hObject, newKey3);
if (rv != CKR_OK) {
goto finish;
}
rv = meta_object_get_attr(derive_session,
slotkey4->hObject, newKey4);
if (rv != CKR_OK) {
goto finish;
}
newKey1->clones[slotnum] = slotkey1;
newKey2->clones[slotnum] = slotkey2;
newKey3->clones[slotnum] = slotkey3;
newKey4->clones[slotnum] = slotkey4;
newKey1->master_clone_slotnum = slotnum;
newKey2->master_clone_slotnum = slotnum;
newKey3->master_clone_slotnum = slotnum;
newKey4->master_clone_slotnum = slotnum;
meta_slot_object_activate(slotkey1, derive_session,
newKey1->isToken);
slotkey1 = NULL;
meta_slot_object_activate(slotkey2, derive_session,
newKey2->isToken);
slotkey2 = NULL;
meta_slot_object_activate(slotkey3, derive_session,
newKey3->isToken);
slotkey3 = NULL;
meta_slot_object_activate(slotkey4, derive_session,
newKey4->isToken);
slotkey4 = NULL;
} else {
slotkey1->hObject = hDerivedKey;
newKey1->clones[slotnum] = slotkey1;
newKey1->master_clone_slotnum = slotnum;
rv = meta_object_get_attr(derive_session,
slotkey1->hObject, newKey1);
if (rv != CKR_OK) {
goto finish;
}
if (newKey1->isFreeToken == FREE_ENABLED)
newKey1->isToken = B_TRUE;
meta_slot_object_activate(slotkey1, derive_session,
newKey1->isToken);
slotkey1 = NULL;
}
if (newKey1->isFreeObject == FREE_ENABLED)
(void) meta_freeobject_clone(session, newKey1);
finish:
if (slotkey1) {
meta_slot_object_dealloc(slotkey1);
}
if (slotkey2) {
meta_slot_object_dealloc(slotkey2);
}
if (slotkey3) {
meta_slot_object_dealloc(slotkey3);
}
if (slotkey4) {
meta_slot_object_dealloc(slotkey4);
}
if (rv == CKR_OK) {
if ((session->op1.session) &&
(session->op1.session != derive_session)) {
meta_release_slot_session(session->op1.session);
}
session->op1.session = derive_session;
}
return (rv);
}
void
get_user_metaslot_config()
{
char *env_val = NULL;
bzero(&metaslot_config, sizeof (metaslot_config));
env_val = getenv("METASLOT_ENABLED");
if (env_val) {
metaslot_config.enabled_specified = B_TRUE;
if (strcasecmp(env_val, TRUE_STRING) == 0) {
metaslot_config.enabled = B_TRUE;
} else if (strcasecmp(env_val, FALSE_STRING) == 0) {
metaslot_config.enabled = B_FALSE;
} else {
metaslot_config.enabled_specified = B_FALSE;
}
}
env_val = getenv("METASLOT_AUTO_KEY_MIGRATE");
if (env_val) {
metaslot_config.auto_key_migrate_specified = B_TRUE;
if (strcasecmp(env_val, TRUE_STRING) == 0) {
metaslot_config.auto_key_migrate = B_TRUE;
} else if (strcasecmp(env_val, FALSE_STRING) == 0) {
metaslot_config.auto_key_migrate = B_FALSE;
} else {
metaslot_config.auto_key_migrate_specified = B_FALSE;
}
}
env_val = getenv("METASLOT_OBJECTSTORE_SLOT");
if (env_val) {
metaslot_config.keystore_slot_specified = B_TRUE;
(void) strlcpy((char *)metaslot_config.keystore_slot, env_val,
SLOT_DESCRIPTION_SIZE);
}
env_val = getenv("METASLOT_OBJECTSTORE_TOKEN");
if (env_val) {
metaslot_config.keystore_token_specified = B_TRUE;
(void) strlcpy((char *)metaslot_config.keystore_token, env_val,
TOKEN_LABEL_SIZE);
}
env_val = getenv("_METASLOT_ENABLE_THRESHOLD");
if (env_val) {
threshold_chk_enabled = B_TRUE;
}
}