#include <stdlib.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include <assert.h>
#include <cryptoutil.h>
#include <pkcs11Global.h>
static CK_OBJECT_CLASS objclass = CKO_SECRET_KEY;
static CK_BBOOL falsevalue = FALSE;
static CK_BBOOL truevalue = TRUE;
#define NUM_SECRETKEY_ATTRS 12
typedef struct _ATTRTYPE_MECHINFO_MAPPING {
CK_ATTRIBUTE_TYPE attr;
CK_FLAGS flag;
} ATTRTYPE_MECHINFO_MAPPING;
ATTRTYPE_MECHINFO_MAPPING mapping[] = {
{CKA_ENCRYPT, CKF_ENCRYPT},
{CKA_DECRYPT, CKF_DECRYPT},
{CKA_SIGN, CKF_SIGN},
{CKA_VERIFY, CKF_VERIFY},
{CKA_WRAP, CKF_WRAP},
{CKA_UNWRAP, CKF_UNWRAP}
};
CK_MECHANISM_TYPE asymmetric_mechs[] = {
CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_PKCS, CKM_RSA_9796, CKM_RSA_X_509,
CKM_RSA_PKCS_OAEP, CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31,
CKM_RSA_PKCS_PSS, CKM_DSA_KEY_PAIR_GEN, CKM_DSA, CKM_DSA_SHA1,
CKM_DSA_PARAMETER_GEN, CKM_ECDSA_KEY_PAIR_GEN, CKM_EC_KEY_PAIR_GEN,
CKM_ECDSA, CKM_ECDSA_SHA1, CKM_ECDH1_DERIVE,
CKM_ECDH1_COFACTOR_DERIVE, CKM_ECMQV_DERIVE
};
typedef struct _KEY_TYPE_SIZE_MAPPING {
CK_KEY_TYPE type;
CK_ULONG len;
} KEY_TYPE_SIZE_MAPPING;
KEY_TYPE_SIZE_MAPPING fixed_size_secrets[] = {
{CKK_DES, 8}, {CKK_DES2, 16}, {CKK_DES3, 24}, {CKK_IDEA, 16},
{CKK_CDMF, 8}, {CKK_SKIPJACK, 12}, {CKK_BATON, 40}, {CKK_JUNIPER, 40}
};
boolean_t
match_mech(CK_SLOT_ID slot_id, void *args, CK_RV *rv)
{
CK_MECHANISM_INFO mech_info;
CK_MECHANISM_TYPE mech = (CK_MECHANISM_TYPE)args;
*rv = CKR_MECHANISM_INVALID;
return (C_GetMechanismInfo(slot_id, mech, &mech_info) == CKR_OK);
}
CK_RV
pkcs11_GetCriteriaSession(
boolean_t (*criteria)(CK_SLOT_ID slot_id, void *args, CK_RV *rv),
void *args, CK_SESSION_HANDLE_PTR hSession)
{
CK_RV rv;
CK_ULONG slotcount;
CK_SLOT_ID_PTR slot_list;
CK_SLOT_ID slot_id;
CK_ULONG i;
if (hSession == NULL || criteria == NULL) {
return (CKR_ARGUMENTS_BAD);
}
if (!pkcs11_initialized) {
rv = C_Initialize(NULL);
if ((rv != CKR_OK) &&
(rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
return (rv);
}
}
rv = C_GetSlotList(0, NULL, &slotcount);
if (rv != CKR_OK) {
return (rv);
}
if (slotcount == 0) {
return (CKR_FUNCTION_FAILED);
}
slot_list = malloc(slotcount * sizeof (CK_SLOT_ID));
if (slot_list == NULL) {
return (CKR_HOST_MEMORY);
}
if ((rv = C_GetSlotList(0, slot_list, &slotcount)) != CKR_OK) {
free(slot_list);
return (rv);
}
for (i = 0; i < slotcount; i++) {
slot_id = slot_list[i];
if ((*criteria)(slot_id, args, &rv)) {
break;
}
}
if (i == slotcount) {
free(slot_list);
return (rv);
}
rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL,
NULL, hSession);
free(slot_list);
return (rv);
}
CK_RV
SUNW_C_GetMechSession(CK_MECHANISM_TYPE mech, CK_SESSION_HANDLE_PTR hSession)
{
CK_RV rv;
CK_ULONG slotcount;
CK_SLOT_ID_PTR slot_list;
CK_SLOT_ID slot_id;
CK_MECHANISM_INFO mech_info;
CK_ULONG i;
if (hSession == NULL) {
return (CKR_ARGUMENTS_BAD);
}
if (!pkcs11_initialized) {
rv = C_Initialize(NULL);
if ((rv != CKR_OK) &&
(rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
return (rv);
}
}
rv = C_GetSlotList(0, NULL, &slotcount);
if (rv != CKR_OK) {
return (rv);
}
if (slotcount == 0) {
return (CKR_FUNCTION_FAILED);
}
slot_list = malloc(slotcount * sizeof (CK_SLOT_ID));
if (slot_list == NULL) {
return (CKR_HOST_MEMORY);
}
if ((rv = C_GetSlotList(0, slot_list, &slotcount)) != CKR_OK) {
free(slot_list);
return (rv);
}
for (i = 0; i < slotcount; i++) {
slot_id = slot_list[i];
if (C_GetMechanismInfo(slot_id, mech, &mech_info) == CKR_OK) {
break;
}
}
if (i == slotcount) {
free(slot_list);
return (CKR_MECHANISM_INVALID);
}
rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL,
NULL, hSession);
free(slot_list);
return (rv);
}
CK_RV
SUNW_C_KeyToObject(CK_SESSION_HANDLE hSession, CK_MECHANISM_TYPE mech,
const void *rawkey, size_t rawkey_len, CK_OBJECT_HANDLE_PTR obj)
{
CK_RV rv;
CK_SESSION_INFO session_info;
CK_SLOT_ID slot_id;
CK_MECHANISM_INFO mech_info;
CK_ULONG i, j;
CK_KEY_TYPE keytype;
CK_ULONG num_asym_mechs, num_mapping;
CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS];
if ((hSession == CK_INVALID_HANDLE) || (obj == NULL) ||
(rawkey == NULL) || (rawkey_len == 0)) {
return (CKR_ARGUMENTS_BAD);
}
num_asym_mechs = sizeof (asymmetric_mechs) / sizeof (CK_MECHANISM_TYPE);
for (i = 0; i < num_asym_mechs; i++) {
if (mech == asymmetric_mechs[i]) {
return (CKR_MECHANISM_INVALID);
}
}
rv = C_GetSessionInfo(hSession, &session_info);
if (rv != CKR_OK) {
return (rv);
}
slot_id = session_info.slotID;
i = 0;
template[i].type = CKA_CLASS;
template[i].pValue = &objclass;
template[i].ulValueLen = sizeof (objclass);
i++;
if ((rv = pkcs11_mech2keytype(mech, &keytype)) != CKR_OK) {
return (rv);
}
assert(i < NUM_SECRETKEY_ATTRS);
template[i].type = CKA_KEY_TYPE;
template[i].pValue = &keytype;
template[i].ulValueLen = sizeof (keytype);
i++;
rv = C_GetMechanismInfo(slot_id, mech, &mech_info);
if (rv != CKR_OK) {
return (rv);
}
num_mapping = sizeof (mapping) / sizeof (ATTRTYPE_MECHINFO_MAPPING);
for (j = 0; j < num_mapping; j++) {
assert(i < NUM_SECRETKEY_ATTRS);
template[i].type = mapping[j].attr;
template[i].ulValueLen = sizeof (falsevalue);
if (mech_info.flags & ((mapping[j]).flag)) {
template[i].pValue = &truevalue;
} else {
template[i].pValue = &falsevalue;
}
i++;
}
assert(i < NUM_SECRETKEY_ATTRS);
template[i].type = CKA_TOKEN;
template[i].pValue = &falsevalue;
template[i].ulValueLen = sizeof (falsevalue);
i++;
assert(i < NUM_SECRETKEY_ATTRS);
template[i].type = CKA_VALUE;
template[i].pValue = (CK_VOID_PTR)rawkey;
template[i].ulValueLen = (CK_ULONG)rawkey_len;
i++;
rv = C_CreateObject(hSession, template, i, obj);
return (rv);
}
CK_RV
pkcs11_PasswdToPBKD2Object(CK_SESSION_HANDLE hSession, char *passphrase,
size_t passphrase_len, void *salt, size_t salt_len, CK_ULONG iterations,
CK_KEY_TYPE key_type, CK_ULONG key_len, CK_FLAGS key_flags,
CK_OBJECT_HANDLE_PTR obj)
{
CK_RV rv;
CK_PKCS5_PBKD2_PARAMS params;
CK_MECHANISM mechanism;
CK_KEY_TYPE asym_key_type;
CK_ULONG i, j, num_asym_mechs, num_fixed_secs, num_mapping;
CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS];
if (hSession == CK_INVALID_HANDLE || obj == NULL ||
passphrase == NULL || passphrase_len == 0 ||
iterations == 0UL) {
return (CKR_ARGUMENTS_BAD);
}
num_asym_mechs = sizeof (asymmetric_mechs) / sizeof (CK_MECHANISM_TYPE);
for (i = 0; i < num_asym_mechs; i++) {
rv = pkcs11_mech2keytype(asymmetric_mechs[i], &asym_key_type);
assert(rv == CKR_OK);
if (key_type == asym_key_type) {
return (CKR_KEY_TYPE_INCONSISTENT);
}
}
num_fixed_secs =
sizeof (fixed_size_secrets) / sizeof (KEY_TYPE_SIZE_MAPPING);
for (i = 0; i < num_fixed_secs; i++) {
if (key_type == fixed_size_secrets[i].type) {
if (key_len == fixed_size_secrets[i].len) {
key_len = 0;
}
if (key_len == 0) {
break;
}
return (CKR_KEY_SIZE_RANGE);
}
}
if (salt == NULL || salt_len == 0) {
params.saltSource = 0;
params.pSaltSourceData = NULL;
params.ulSaltSourceDataLen = 0;
} else {
params.saltSource = CKZ_SALT_SPECIFIED;
params.pSaltSourceData = salt;
params.ulSaltSourceDataLen = salt_len;
}
params.iterations = iterations;
params.prf = CKP_PKCS5_PBKD2_HMAC_SHA1;
params.pPrfData = NULL;
params.ulPrfDataLen = 0;
params.pPassword = (CK_UTF8CHAR_PTR)passphrase;
params.ulPasswordLen = (CK_ULONG_PTR)&passphrase_len;
mechanism.mechanism = CKM_PKCS5_PBKD2;
mechanism.pParameter = ¶ms;
mechanism.ulParameterLen = sizeof (params);
i = 0;
template[i].type = CKA_CLASS;
template[i].pValue = &objclass;
template[i].ulValueLen = sizeof (objclass);
i++;
assert(i < NUM_SECRETKEY_ATTRS);
template[i].type = CKA_KEY_TYPE;
template[i].pValue = &key_type;
template[i].ulValueLen = sizeof (key_type);
i++;
assert(i < NUM_SECRETKEY_ATTRS);
template[i].type = CKA_TOKEN;
template[i].pValue = &falsevalue;
template[i].ulValueLen = sizeof (falsevalue);
i++;
if (key_len != 0) {
assert(i < NUM_SECRETKEY_ATTRS);
template[i].type = CKA_VALUE_LEN;
template[i].pValue = &key_len;
template[i].ulValueLen = sizeof (key_len);
i++;
}
num_mapping = sizeof (mapping) / sizeof (ATTRTYPE_MECHINFO_MAPPING);
for (j = 0; j < num_mapping; j++) {
assert(i < NUM_SECRETKEY_ATTRS);
template[i].type = mapping[j].attr;
template[i].pValue = (key_flags & ((mapping[j]).flag)) ?
&truevalue : &falsevalue;
template[i].ulValueLen = sizeof (falsevalue);
i++;
}
rv = C_GenerateKey(hSession, &mechanism, template, i, obj);
return (rv);
}
CK_RV
pkcs11_ObjectToKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE obj,
void **rawkey, size_t *rawkey_len, boolean_t destroy_obj)
{
CK_RV rv;
CK_ATTRIBUTE template;
if (hSession == CK_INVALID_HANDLE)
return (CKR_SESSION_HANDLE_INVALID);
if (obj == 0)
return (CKR_OBJECT_HANDLE_INVALID);
if (rawkey == NULL || rawkey_len == NULL)
return (CKR_ARGUMENTS_BAD);
template.type = CKA_VALUE;
template.pValue = NULL;
template.ulValueLen = 0;
rv = C_GetAttributeValue(hSession, obj, &template, 1);
if (rv != CKR_OK) {
return (rv);
}
template.pValue = malloc(template.ulValueLen);
if (template.pValue == NULL) {
return (CKR_HOST_MEMORY);
}
rv = C_GetAttributeValue(hSession, obj, &template, 1);
if (rv != CKR_OK) {
free(template.pValue);
return (rv);
}
if (destroy_obj) {
(void) C_DestroyObject(hSession, obj);
}
*rawkey = template.pValue;
*rawkey_len = template.ulValueLen;
return (CKR_OK);
}
CK_RV
pkcs11_PasswdToKey(CK_SESSION_HANDLE hSession, char *passphrase,
size_t passphrase_len, void *salt, size_t salt_len, CK_KEY_TYPE key_type,
CK_ULONG key_len, void **rawkey, size_t *rawkey_len)
{
CK_RV rv;
CK_OBJECT_HANDLE obj;
rv = pkcs11_PasswdToPBKD2Object(hSession, passphrase, passphrase_len,
salt, salt_len, CK_PKCS5_PBKD2_ITERATIONS, key_type, key_len, 0,
&obj);
if (rv != CKR_OK)
return (rv);
rv = pkcs11_ObjectToKey(hSession, obj, rawkey, rawkey_len, B_TRUE);
return (rv);
}