kernelKeys.c revision 77e5e96b8d34d976d069a4766c20607ba36a6a93
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <strings.h>
#include <errno.h>
#include <ecc_impl.h>
#include <security/cryptoki.h>
#include <sys/crypto/ioctl.h>
#include "kernelGlobal.h"
#include "kernelSession.h"
#include "kernelObject.h"
static boolean_t
attribute_in_template(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
{
int i;
for (i = 0; i < cnt; i++) {
if (t[i].type == type)
return (B_TRUE);
}
return (B_FALSE);
}
/*
* This routine returns modulus bytes rounded up to the nearest 8 byte
* chunk. This is so we don't have to pass in max sized buffers for
* returned attributes. Every unnecessary byte that we pass in results
* in a kernel allocation.
*/
static ulong_t
get_modulus_bytes(CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
{
CK_ULONG modulus_len;
int i;
for (i = 0; i < cnt; i++) {
if (t[i].type == CKA_MODULUS_BITS) {
get_ulong_attr_from_template(&modulus_len, &t[i]);
/* convert from bit length to byte length */
modulus_len = (modulus_len - 1) / 64 + 1;
return (modulus_len * 8);
}
}
return (0);
}
/*
* Remove specified attribute from array. Storage for the attribute's
* value is freed if 'free_attr' is TRUE. Attributes are shifted so they are
* contiguous within the array, i.e. the next attribute is shifted into
* the position of the removed attribute. Returns TRUE if specified
* attribute is removed.
*/
static boolean_t
remove_one_attribute(CK_ATTRIBUTE_PTR t, CK_ULONG type, uint_t count,
boolean_t free_attr)
{
int i, j;
for (i = 0, j = 0; i < count; i++) {
if (t[i].type == type) {
if (free_attr) {
free(t[i].pValue);
}
continue;
}
if (i != j) {
t[j].type = t[i].type;
t[j].pValue = t[i].pValue;
t[j].ulValueLen = t[i].ulValueLen;
}
j++;
}
if (j == count)
return (B_FALSE);
/* safety */
t[j].pValue = NULL;
t[j].ulValueLen = 0;
return (B_TRUE);
}
static boolean_t
is_secret_key_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
{
int i;
for (i = 0; i < ulAttributeCount; i++) {
if (pTemplate[i].type == CKA_CLASS &&
*(CK_OBJECT_CLASS *)(pTemplate[i].pValue) ==
CKO_SECRET_KEY)
return (B_TRUE);
}
return (B_FALSE);
}
/*
* Allocate a template with space for new_count entries and copy the
* specified template into the new template.
*/
static CK_ATTRIBUTE_PTR
grow_template(CK_ATTRIBUTE_PTR old_template, CK_ULONG old_count,
CK_ULONG new_count)
{
CK_ATTRIBUTE_PTR new_template;
new_template = malloc(new_count * sizeof (CK_ATTRIBUTE));
if (new_template != NULL)
bcopy(old_template, new_template,
old_count * sizeof (CK_ATTRIBUTE));
return (new_template);
}
/*
* For fixed length keys such as DES, return the length based on
* the key type. For variable length keys such as AES, take the
* length from the CKA_VALUE_LEN attribute.
*/
static int
get_key_len_from_template(CK_MECHANISM_PTR pMechanism,
CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
kernel_object_t *basekey_p, ulong_t *key_len)
{
boolean_t fixed_len_key = B_FALSE;
ulong_t key_type;
int i;
for (i = 0; i < ulAttributeCount; i++) {
if (pTemplate[i].type == CKA_KEY_TYPE) {
get_ulong_attr_from_template(&key_type, &pTemplate[i]);
break;
}
}
/* CKA_KEY_TYPE must be present */
if (i == ulAttributeCount)
return (CKR_TEMPLATE_INCOMPLETE);
switch (key_type) {
case CKK_DES:
*key_len = 8;
fixed_len_key = B_TRUE;
break;
case CKK_DES3:
*key_len = 24;
fixed_len_key = B_TRUE;
break;
case CKK_AES:
case CKK_BLOWFISH:
for (i = 0; i < ulAttributeCount; i++) {
if (pTemplate[i].type == CKA_VALUE_LEN) {
get_ulong_attr_from_template(key_len,
&pTemplate[i]);
break;
}
}
/* CKA_VALUE_LEN must be present */
if (i == ulAttributeCount)
return (CKR_TEMPLATE_INCOMPLETE);
break;
case CKK_GENERIC_SECRET:
/*
* The key will not be truncated, so we need to
* get the max length for the mechanism.
*/
if (pMechanism->mechanism == CKM_DH_PKCS_DERIVE) {
CK_ATTRIBUTE tmp;
tmp.type = CKA_PRIME;
tmp.pValue = NULL;
/* get size of attribute */
if (kernel_get_attribute(basekey_p, &tmp) != CKR_OK) {
return (CKR_ARGUMENTS_BAD);
}
*key_len = tmp.ulValueLen;
} else if (pMechanism->mechanism == CKM_ECDH1_DERIVE) {
*key_len = EC_MAX_VALUE_LEN;
} else {
return (CKR_ARGUMENTS_BAD);
}
break;
default:
return (CKR_ATTRIBUTE_VALUE_INVALID);
}
if (fixed_len_key && attribute_in_template(CKA_VALUE_LEN,
pTemplate, ulAttributeCount))
return (CKR_TEMPLATE_INCONSISTENT);
return (CKR_OK);
}
/* find specified attribute src template and copy to dest */
static int
copy_attribute(CK_ULONG type, CK_ATTRIBUTE_PTR src, CK_ULONG src_cnt,
CK_ATTRIBUTE_PTR dst)
{
int rv, i;
for (i = 0; i < src_cnt; i++) {
if (src[i].type == type) {
rv = get_string_from_template(dst, &src[i]);
break;
}
}
/*
* The public template didn't have attribute.
*/
if (i == src_cnt) {
rv = CKR_TEMPLATE_INCOMPLETE;
}
return (rv);
}
static void
free_attributes(caddr_t p, uint_t *countp)
{
if (*countp > 0) {
free_object_attributes(p, *countp);
*countp = 0;
}
}
CK_RV
key_gen_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulCount, kernel_session_t *session_p,
crypto_mech_type_t k_mech_type, kernel_object_t *new_objp)
{
crypto_nostore_generate_key_t obj_ngk;
char *key_buf = NULL;
CK_ATTRIBUTE_PTR newTemplate = NULL;
CK_BBOOL is_token_obj = FALSE;
CK_RV rv = CKR_OK;
ulong_t key_len = 0;
uint_t attr_count;
int r;
obj_ngk.ngk_in_count = 0;
obj_ngk.ngk_out_count = 0;
rv = get_key_len_from_template(pMechanism, pTemplate, ulCount,
NULL, &key_len);
if (rv != CRYPTO_SUCCESS)
goto failed_exit;
if ((key_buf = malloc(key_len)) == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
attr_count = ulCount + 1;
newTemplate = grow_template(pTemplate, ulCount, attr_count);
if (newTemplate == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
/* Now add the CKA_VALUE attribute to template */
newTemplate[ulCount].type = CKA_VALUE;
newTemplate[ulCount].pValue = (caddr_t)key_buf;
newTemplate[ulCount].ulValueLen = key_len;
rv = process_object_attributes(newTemplate, attr_count - 1,
&obj_ngk.ngk_in_attributes, &is_token_obj);
if (rv != CKR_OK) {
goto failed_exit;
}
rv = process_object_attributes(&newTemplate[ulCount],
1, &obj_ngk.ngk_out_attributes, &is_token_obj);
if (rv != CKR_OK) {
goto failed_exit;
}
/* Cannot create a token object with a READ-ONLY session. */
if (is_token_obj && session_p->ses_RO) {
rv = CKR_SESSION_READ_ONLY;
goto failed_exit;
}
/* Call the CRYPTO_NOSTORE_GENERATE_KEY ioctl */
obj_ngk.ngk_session = session_p->k_session;
obj_ngk.ngk_in_count = attr_count - 1;
obj_ngk.ngk_out_count = 1;
obj_ngk.ngk_mechanism.cm_type = k_mech_type;
obj_ngk.ngk_mechanism.cm_param = pMechanism->pParameter;
obj_ngk.ngk_mechanism.cm_param_len = pMechanism->ulParameterLen;
while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY,
&obj_ngk)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(obj_ngk.ngk_return_value);
}
free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
if (rv != CKR_OK) {
goto failed_exit;
}
rv = get_object_attributes(&newTemplate[ulCount], 1,
obj_ngk.ngk_out_attributes);
free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
/*
* CKA_VALUE_LEN is not stored with the secret key object,
* so we remove it by shifting attributes down one.
*/
(void) remove_one_attribute(newTemplate, CKA_VALUE_LEN,
attr_count, B_FALSE);
rv = kernel_build_object(newTemplate, attr_count - 1,
new_objp, session_p, KERNEL_GEN_KEY);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
new_objp->is_lib_obj = B_TRUE;
new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
(void) free(newTemplate);
bzero(key_buf, key_len);
(void) free(key_buf);
return (CKR_OK);
failed_exit:
free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
if (key_buf != NULL) {
bzero(key_buf, key_len);
(void) free(key_buf);
}
if (newTemplate != NULL) {
(void) free(newTemplate);
}
return (rv);
}
CK_RV
C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
{
CK_RV rv = CKR_OK;
kernel_session_t *session_p;
kernel_object_t *new_objp = NULL;
kernel_slot_t *pslot;
boolean_t ses_lock_held = B_FALSE;
CK_BBOOL is_pri_obj;
CK_BBOOL is_token_obj = FALSE;
crypto_mech_type_t k_mech_type;
int r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
/* Obtain the session pointer */
rv = handle2session(hSession, &session_p);
if (rv != CKR_OK)
return (rv);
if ((pMechanism == NULL) || (phKey == NULL)) {
rv = CKR_ARGUMENTS_BAD;
goto failed_exit;
}
if ((pTemplate == NULL) && (ulCount != 0)) {
rv = CKR_ARGUMENTS_BAD;
goto failed_exit;
}
/* Get the kernel's internal mechanism number. */
rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
if (rv != CKR_OK) {
goto failed_exit;
}
/* Create an object wrapper in the library first */
new_objp = calloc(1, sizeof (kernel_object_t));
if (new_objp == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
/*
* Special Case: if token does not support object creation,
* but does support key generation by value, then create a session
* object and initialize with value returned by token.
*/
pslot = slot_table[session_p->ses_slotid];
if (!pslot->sl_func_list.fl_object_create) {
rv = key_gen_by_value(pMechanism, pTemplate, ulCount, session_p,
k_mech_type, new_objp);
if (rv != CKR_OK)
goto failed_exit;
} else {
crypto_object_generate_key_t obj_gk;
/* Process the attributes */
rv = process_object_attributes(pTemplate, ulCount,
&obj_gk.gk_attributes, &is_token_obj);
if (rv != CKR_OK) {
goto failed_exit;
}
/* Cannot create a token object with a READ-ONLY session. */
if (is_token_obj && session_p->ses_RO) {
free_object_attributes(obj_gk.gk_attributes, ulCount);
rv = CKR_SESSION_READ_ONLY;
goto failed_exit;
}
/* Call the CRYPTO_GENERATE_KEY ioctl */
obj_gk.gk_session = session_p->k_session;
obj_gk.gk_count = ulCount;
obj_gk.gk_mechanism.cm_type = k_mech_type;
obj_gk.gk_mechanism.cm_param = pMechanism->pParameter;
obj_gk.gk_mechanism.cm_param_len = pMechanism->ulParameterLen;
while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY,
&obj_gk)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(obj_gk.gk_return_value);
}
free_object_attributes(obj_gk.gk_attributes, ulCount);
if (rv != CKR_OK) {
goto failed_exit;
}
/* Get the value of the CKA_PRIVATE attribute. */
rv = get_cka_private_value(session_p, obj_gk.gk_handle,
&is_pri_obj);
if (rv != CKR_OK) {
goto failed_exit;
}
/*
* Store the kernel object handle in the object wrapper and
* initialize the library object.
*/
new_objp->k_handle = obj_gk.gk_handle;
new_objp->is_lib_obj = B_FALSE;
new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
new_objp->extra_attrlistp = NULL;
if (is_pri_obj)
new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
else
new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
if (is_token_obj)
new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
else
new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
}
(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
/*
* Add the new object to the slot's token object list if it is a
* a token object. Otherwise, add it to the session's object list.
*/
if (is_token_obj) {
pslot = slot_table[session_p->ses_slotid];
kernel_add_token_object_to_slot(new_objp, pslot);
} else {
kernel_add_object_to_session(new_objp, session_p);
}
*phKey = (CK_OBJECT_HANDLE)new_objp;
REFRELE(session_p, ses_lock_held);
return (rv);
failed_exit:
if (new_objp != NULL) {
(void) free(new_objp);
}
REFRELE(session_p, ses_lock_held);
return (rv);
}
CK_RV
key_gen_rsa_by_value(CK_MECHANISM_PTR pMechanism,
CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
{
crypto_nostore_generate_key_pair_t obj_nkp;
CK_ATTRIBUTE_PTR pubTemplate = NULL;
CK_ATTRIBUTE_PTR priTemplate = NULL;
CK_RV rv = CKR_OK;
CK_BBOOL is_token_obj1 = FALSE;
CK_BBOOL is_token_obj2 = FALSE;
uint_t pub_attr_count, pri_attr_count;
uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
char public_modulus[512];
char public_exponent[8];
char private_exponent[512];
char private_modulus[512];
char prime_1[512];
char prime_2[512];
char exponent_1[512];
char exponent_2[512];
char coefficient[512];
CK_ULONG pub_class = CKO_PUBLIC_KEY;
CK_ULONG pri_class = CKO_PRIVATE_KEY;
CK_ULONG key_type;
CK_ULONG modulus_bytes;
boolean_t has_class, has_key_type, has_pub_exponent;
int n, r;
obj_nkp.nkp_in_public_count = 0;
obj_nkp.nkp_out_public_count = 0;
obj_nkp.nkp_in_private_count = 0;
obj_nkp.nkp_out_private_count = 0;
/* modulus bits must be present when generating a RSA key pair */
if (!attribute_in_template(CKA_MODULUS_BITS, pPublicKeyTemplate,
ulPublicKeyAttributeCount)) {
rv = CKR_TEMPLATE_INCOMPLETE;
goto failed_exit;
}
modulus_bytes = get_modulus_bytes(pPublicKeyTemplate,
ulPublicKeyAttributeCount);
/*
* Add CKA_MODULUS to the public template.
* This attribute must not be in the template.
*/
if (attribute_in_template(CKA_MODULUS, pPublicKeyTemplate,
ulPublicKeyAttributeCount)) {
rv = CKR_TEMPLATE_INCONSISTENT;
goto failed_exit;
}
has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
ulPublicKeyAttributeCount);
has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
ulPublicKeyAttributeCount);
has_pub_exponent = attribute_in_template(CKA_PUBLIC_EXPONENT,
pPublicKeyTemplate, ulPublicKeyAttributeCount);
pub_attr_count = ulPublicKeyAttributeCount + 1;
if (!has_class)
pub_attr_count++;
if (!has_key_type)
pub_attr_count++;
if (!has_pub_exponent)
pub_attr_count++;
pubTemplate = grow_template(pPublicKeyTemplate,
ulPublicKeyAttributeCount, pub_attr_count);
if (pubTemplate == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
n = ulPublicKeyAttributeCount;
if (!has_class) {
pubTemplate[n].type = CKA_CLASS;
pubTemplate[n].pValue = (caddr_t)&pub_class;
pubTemplate[n].ulValueLen = sizeof (pub_class);
n++;
}
if (!has_key_type) {
pubTemplate[n].type = CKA_KEY_TYPE;
key_type = CKK_RSA;
pubTemplate[n].pValue = (caddr_t)&key_type;
pubTemplate[n].ulValueLen = sizeof (key_type);
n++;
}
if (!has_pub_exponent) {
pubTemplate[n].type = CKA_PUBLIC_EXPONENT;
pubTemplate[n].pValue = (caddr_t)public_exponent;
pubTemplate[n].ulValueLen = modulus_bytes;
n++;
pub_out_attr_count++;
}
pubTemplate[n].type = CKA_MODULUS;
pubTemplate[n].pValue = (caddr_t)public_modulus;
pubTemplate[n].ulValueLen = modulus_bytes;
pub_out_attr_count++;
rv = process_object_attributes(pubTemplate,
pub_attr_count - pub_out_attr_count,
&obj_nkp.nkp_in_public_attributes, &is_token_obj1);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
rv = process_object_attributes(
&pubTemplate[pub_attr_count - pub_out_attr_count],
pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
&is_token_obj1);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_nkp.nkp_out_public_count = pub_out_attr_count;
/*
* Cannot create a token object with a READ-ONLY
* session.
*/
if (is_token_obj1 && session_p->ses_RO) {
rv = CKR_SESSION_READ_ONLY;
goto failed_exit;
}
/*
* Add CKA_MODULUS and CKA_PRIVATE_EXPONENT
* to the private template. These attributes
* must not be in the template.
*/
if (attribute_in_template(CKA_PRIVATE_EXPONENT,
pPrivateKeyTemplate, ulPrivateKeyAttributeCount) ||
attribute_in_template(CKA_MODULUS,
pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) {
rv = CKR_TEMPLATE_INCONSISTENT;
goto failed_exit;
}
has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount);
has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount);
pri_attr_count = ulPrivateKeyAttributeCount + 7;
if (!has_class)
pri_attr_count++;
if (!has_key_type)
pri_attr_count++;
/* allocate space for CKA_PUBLIC_EXPONENT */
priTemplate = grow_template(pPrivateKeyTemplate,
ulPrivateKeyAttributeCount, pri_attr_count + 1);
if (priTemplate == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
n = ulPrivateKeyAttributeCount;
if (!has_class) {
priTemplate[n].type = CKA_CLASS;
priTemplate[n].pValue = (caddr_t)&pri_class;
priTemplate[n].ulValueLen = sizeof (pri_class);
n++;
}
if (!has_key_type) {
priTemplate[n].type = CKA_KEY_TYPE;
key_type = CKK_RSA;
priTemplate[n].pValue = (caddr_t)&key_type;
priTemplate[n].ulValueLen = sizeof (key_type);
n++;
}
priTemplate[n].type = CKA_MODULUS;
priTemplate[n].pValue = (caddr_t)private_modulus;
priTemplate[n].ulValueLen = modulus_bytes;
pri_out_attr_count++;
n++;
priTemplate[n].type = CKA_PRIVATE_EXPONENT;
priTemplate[n].pValue = (caddr_t)private_exponent;
priTemplate[n].ulValueLen = modulus_bytes;
pri_out_attr_count++;
n++;
priTemplate[n].type = CKA_PRIME_1;
priTemplate[n].pValue = (caddr_t)prime_1;
priTemplate[n].ulValueLen = modulus_bytes/2;
pri_out_attr_count++;
n++;
priTemplate[n].type = CKA_PRIME_2;
priTemplate[n].pValue = (caddr_t)prime_2;
priTemplate[n].ulValueLen = modulus_bytes/2;
pri_out_attr_count++;
n++;
priTemplate[n].type = CKA_EXPONENT_1;
priTemplate[n].pValue = (caddr_t)exponent_1;
priTemplate[n].ulValueLen = modulus_bytes/2;
pri_out_attr_count++;
n++;
priTemplate[n].type = CKA_EXPONENT_2;
priTemplate[n].pValue = (caddr_t)exponent_2;
priTemplate[n].ulValueLen = modulus_bytes/2;
pri_out_attr_count++;
n++;
priTemplate[n].type = CKA_COEFFICIENT;
priTemplate[n].pValue = (caddr_t)coefficient;
priTemplate[n].ulValueLen = modulus_bytes/2;
pri_out_attr_count++;
rv = process_object_attributes(priTemplate,
pri_attr_count - pri_out_attr_count,
&obj_nkp.nkp_in_private_attributes, &is_token_obj2);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
rv = process_object_attributes(
&priTemplate[pri_attr_count - pri_out_attr_count],
pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
&is_token_obj2);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_nkp.nkp_out_private_count = pri_out_attr_count;
/*
* The public key and the private key need to contain the same
* attribute values for CKA_TOKEN.
*/
if (is_token_obj1 != is_token_obj2) {
rv = CKR_ATTRIBUTE_VALUE_INVALID;
goto failed_exit;
}
/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
obj_nkp.nkp_session = session_p-> k_session;
obj_nkp.nkp_mechanism.cm_type = k_mech_type;
obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
&obj_nkp)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
}
free_attributes(obj_nkp.nkp_in_public_attributes,
&obj_nkp.nkp_in_public_count);
free_attributes(obj_nkp.nkp_in_private_attributes,
&obj_nkp.nkp_in_private_count);
if (rv != CKR_OK) {
goto failed_exit;
}
rv = get_object_attributes(
&pubTemplate[pub_attr_count - pub_out_attr_count],
pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
if (rv == CRYPTO_SUCCESS) {
rv = get_object_attributes(
&priTemplate[pri_attr_count - pri_out_attr_count],
pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
}
free_attributes(obj_nkp.nkp_out_public_attributes,
&obj_nkp.nkp_out_public_count);
free_attributes(obj_nkp.nkp_out_private_attributes,
&obj_nkp.nkp_out_private_count);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
/* store generated modulus and public exponent */
rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
session_p, KERNEL_GEN_KEY);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
/*
* Copy CKA_PUBLIC_EXPONENT from the public template
* to the private template.
*/
rv = copy_attribute(CKA_PUBLIC_EXPONENT, pubTemplate,
pub_attr_count, &priTemplate[pri_attr_count]);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
rv = kernel_build_object(priTemplate, pri_attr_count + 1, new_pri_objp,
session_p, KERNEL_GEN_KEY);
(void) free(priTemplate[pri_attr_count].pValue);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
(void) free(pubTemplate);
(void) free(priTemplate);
new_pub_objp->is_lib_obj = B_TRUE;
new_pri_objp->is_lib_obj = B_TRUE;
new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
return (CKR_OK);
failed_exit:
free_attributes(obj_nkp.nkp_in_public_attributes,
&obj_nkp.nkp_in_public_count);
free_attributes(obj_nkp.nkp_out_public_attributes,
&obj_nkp.nkp_out_public_count);
free_attributes(obj_nkp.nkp_in_private_attributes,
&obj_nkp.nkp_in_private_count);
free_attributes(obj_nkp.nkp_out_private_attributes,
&obj_nkp.nkp_out_private_count);
if (pubTemplate != NULL) {
(void) free(pubTemplate);
}
if (priTemplate != NULL) {
(void) free(priTemplate);
}
return (rv);
}
CK_RV
key_gen_dh_by_value(CK_MECHANISM_PTR pMechanism,
CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
{
crypto_nostore_generate_key_pair_t obj_nkp;
CK_ATTRIBUTE_PTR pubTemplate = NULL;
CK_ATTRIBUTE_PTR priTemplate = NULL;
CK_RV rv = CKR_OK;
CK_BBOOL is_token_obj1 = FALSE;
CK_BBOOL is_token_obj2 = FALSE;
uint_t pub_attr_count, pri_attr_count;
uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
char public_value[256];
char private_value[256];
CK_ULONG pub_class = CKO_PUBLIC_KEY;
CK_ULONG pri_class = CKO_PRIVATE_KEY;
CK_ULONG key_type;
boolean_t has_class, has_key_type;
int n, r;
obj_nkp.nkp_in_public_count = 0;
obj_nkp.nkp_out_public_count = 0;
obj_nkp.nkp_in_private_count = 0;
obj_nkp.nkp_out_private_count = 0;
/*
* Add CKA_VALUE to the public template.
* This attribute must not be in the template.
*/
if (attribute_in_template(CKA_VALUE, pPublicKeyTemplate,
ulPublicKeyAttributeCount)) {
rv = CKR_TEMPLATE_INCONSISTENT;
goto failed_exit;
}
has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
ulPublicKeyAttributeCount);
has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
ulPublicKeyAttributeCount);
pub_attr_count = ulPublicKeyAttributeCount + 1;
if (!has_class)
pub_attr_count++;
if (!has_key_type)
pub_attr_count++;
pubTemplate = grow_template(pPublicKeyTemplate,
ulPublicKeyAttributeCount, pub_attr_count);
if (pubTemplate == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
n = ulPublicKeyAttributeCount;
if (!has_class) {
pubTemplate[n].type = CKA_CLASS;
pubTemplate[n].pValue = (caddr_t)&pub_class;
pubTemplate[n].ulValueLen = sizeof (pub_class);
n++;
}
if (!has_key_type) {
pubTemplate[n].type = CKA_KEY_TYPE;
key_type = CKK_DH;
pubTemplate[n].pValue = (caddr_t)&key_type;
pubTemplate[n].ulValueLen = sizeof (key_type);
n++;
}
pubTemplate[n].type = CKA_VALUE;
pubTemplate[n].pValue = (caddr_t)public_value;
pubTemplate[n].ulValueLen = sizeof (public_value);
pub_out_attr_count++;
rv = process_object_attributes(pubTemplate,
pub_attr_count - pub_out_attr_count,
&obj_nkp.nkp_in_public_attributes, &is_token_obj1);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
rv = process_object_attributes(
&pubTemplate[pub_attr_count - pub_out_attr_count],
pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
&is_token_obj1);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_nkp.nkp_out_public_count = pub_out_attr_count;
/*
* Cannot create a token object with a READ-ONLY
* session.
*/
if (is_token_obj1 && session_p->ses_RO) {
rv = CKR_SESSION_READ_ONLY;
goto failed_exit;
}
/*
* CKA_BASE, CKA_PRIME, and CKA_VALUE must not appear
* in private template.
*/
if (attribute_in_template(CKA_BASE, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount) ||
attribute_in_template(CKA_PRIME, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount) ||
attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount)) {
rv = CKR_TEMPLATE_INCONSISTENT;
goto failed_exit;
}
if (attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount)) {
rv = CKR_TEMPLATE_INCONSISTENT;
goto failed_exit;
}
has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount);
has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount);
pri_attr_count = ulPrivateKeyAttributeCount + 1;
if (!has_class)
pri_attr_count++;
if (!has_key_type)
pri_attr_count++;
/* allocate space for CKA_BASE and CKA_PRIME */
priTemplate = grow_template(pPrivateKeyTemplate,
ulPrivateKeyAttributeCount, pri_attr_count + 2);
if (priTemplate == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
n = ulPrivateKeyAttributeCount;
if (!has_class) {
priTemplate[n].type = CKA_CLASS;
priTemplate[n].pValue = (caddr_t)&pri_class;
priTemplate[n].ulValueLen = sizeof (pri_class);
n++;
}
if (!has_key_type) {
priTemplate[n].type = CKA_KEY_TYPE;
key_type = CKK_DH;
priTemplate[n].pValue = (caddr_t)&key_type;
priTemplate[n].ulValueLen = sizeof (key_type);
n++;
}
priTemplate[n].type = CKA_VALUE;
priTemplate[n].pValue = (caddr_t)private_value;
priTemplate[n].ulValueLen = sizeof (private_value);
pri_out_attr_count++;
rv = process_object_attributes(priTemplate,
pri_attr_count - pri_out_attr_count,
&obj_nkp.nkp_in_private_attributes, &is_token_obj2);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
rv = process_object_attributes(
&priTemplate[pri_attr_count - pri_out_attr_count],
pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
&is_token_obj2);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_nkp.nkp_out_private_count = pri_out_attr_count;
/*
* The public key and the private key need to contain the same
* attribute values for CKA_TOKEN.
*/
if (is_token_obj1 != is_token_obj2) {
rv = CKR_ATTRIBUTE_VALUE_INVALID;
goto failed_exit;
}
/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
obj_nkp.nkp_session = session_p-> k_session;
obj_nkp.nkp_mechanism.cm_type = k_mech_type;
obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
&obj_nkp)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
}
free_attributes(obj_nkp.nkp_in_public_attributes,
&obj_nkp.nkp_in_public_count);
free_attributes(obj_nkp.nkp_in_private_attributes,
&obj_nkp.nkp_in_private_count);
if (rv != CKR_OK) {
goto failed_exit;
}
rv = get_object_attributes(
&pubTemplate[pub_attr_count - pub_out_attr_count],
pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
if (rv == CRYPTO_SUCCESS) {
rv = get_object_attributes(
&priTemplate[pri_attr_count - pri_out_attr_count],
pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
}
free_attributes(obj_nkp.nkp_out_public_attributes,
&obj_nkp.nkp_out_public_count);
free_attributes(obj_nkp.nkp_out_private_attributes,
&obj_nkp.nkp_out_private_count);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
session_p, KERNEL_GEN_KEY);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
/*
* Copy CKA_BASE and CKA_PRIME from the public template
* to the private template.
*/
rv = copy_attribute(CKA_BASE, pubTemplate, pub_attr_count,
&priTemplate[pri_attr_count]);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
rv = copy_attribute(CKA_PRIME, pubTemplate, pub_attr_count,
&priTemplate[pri_attr_count + 1]);
if (rv != CRYPTO_SUCCESS) {
(void) free(priTemplate[pri_attr_count].pValue);
goto failed_exit;
}
/* +2 to account for CKA_BASE and CKA_PRIME */
rv = kernel_build_object(priTemplate, pri_attr_count + 2,
new_pri_objp, session_p, KERNEL_GEN_KEY);
(void) free(priTemplate[pri_attr_count].pValue);
(void) free(priTemplate[pri_attr_count + 1].pValue);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
(void) free(pubTemplate);
(void) free(priTemplate);
new_pub_objp->is_lib_obj = B_TRUE;
new_pri_objp->is_lib_obj = B_TRUE;
new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
return (CKR_OK);
failed_exit:
free_attributes(obj_nkp.nkp_in_public_attributes,
&obj_nkp.nkp_in_public_count);
free_attributes(obj_nkp.nkp_out_public_attributes,
&obj_nkp.nkp_out_public_count);
free_attributes(obj_nkp.nkp_in_private_attributes,
&obj_nkp.nkp_in_private_count);
free_attributes(obj_nkp.nkp_out_private_attributes,
&obj_nkp.nkp_out_private_count);
if (pubTemplate != NULL) {
(void) free(pubTemplate);
}
if (priTemplate != NULL) {
(void) free(priTemplate);
}
return (rv);
}
CK_RV
key_gen_ec_by_value(CK_MECHANISM_PTR pMechanism,
CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
{
crypto_nostore_generate_key_pair_t obj_nkp;
CK_ATTRIBUTE_PTR pubTemplate = NULL;
CK_ATTRIBUTE_PTR priTemplate = NULL;
CK_RV rv = CKR_OK;
CK_BBOOL is_token_obj1 = FALSE;
CK_BBOOL is_token_obj2 = FALSE;
uint_t pub_attr_count, pri_attr_count;
uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
char value[EC_MAX_VALUE_LEN];
char point[EC_MAX_POINT_LEN];
CK_ULONG pub_class = CKO_PUBLIC_KEY;
CK_ULONG pri_class = CKO_PRIVATE_KEY;
CK_ULONG key_type;
boolean_t has_class, has_key_type;
int n, r;
obj_nkp.nkp_in_public_count = 0;
obj_nkp.nkp_out_public_count = 0;
obj_nkp.nkp_in_private_count = 0;
obj_nkp.nkp_out_private_count = 0;
/*
* Add CKA_EC_POINT to the public template.
* This is the generated value Q. This attribute
* must not be in the template.
*/
if (attribute_in_template(CKA_EC_POINT, pPublicKeyTemplate,
ulPublicKeyAttributeCount)) {
rv = CKR_TEMPLATE_INCONSISTENT;
goto failed_exit;
}
has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
ulPublicKeyAttributeCount);
has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
ulPublicKeyAttributeCount);
pub_attr_count = ulPublicKeyAttributeCount + 1;
if (!has_class)
pub_attr_count++;
if (!has_key_type)
pub_attr_count++;
pubTemplate = grow_template(pPublicKeyTemplate,
ulPublicKeyAttributeCount, pub_attr_count);
if (pubTemplate == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
n = ulPublicKeyAttributeCount;
if (!has_class) {
pubTemplate[n].type = CKA_CLASS;
pubTemplate[n].pValue = (caddr_t)&pub_class;
pubTemplate[n].ulValueLen = sizeof (pub_class);
n++;
}
if (!has_key_type) {
pubTemplate[n].type = CKA_KEY_TYPE;
key_type = CKK_EC;
pubTemplate[n].pValue = (caddr_t)&key_type;
pubTemplate[n].ulValueLen = sizeof (key_type);
n++;
}
pubTemplate[n].type = CKA_EC_POINT;
pubTemplate[n].pValue = (caddr_t)point;
pubTemplate[n].ulValueLen = sizeof (point);
pub_out_attr_count++;
rv = process_object_attributes(pubTemplate,
pub_attr_count - pub_out_attr_count,
&obj_nkp.nkp_in_public_attributes, &is_token_obj1);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
rv = process_object_attributes(
&pubTemplate[pub_attr_count - pub_out_attr_count],
pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
&is_token_obj1);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_nkp.nkp_out_public_count = pub_out_attr_count;
/*
* Cannot create a token object with a READ-ONLY
* session.
*/
if (is_token_obj1 && session_p->ses_RO) {
rv = CKR_SESSION_READ_ONLY;
goto failed_exit;
}
/*
* CKA_EC_PARAMS and CKA_VALUE must not appear in
* private template.
*/
if (attribute_in_template(CKA_EC_PARAMS, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount) ||
attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount)) {
rv = CKR_TEMPLATE_INCONSISTENT;
goto failed_exit;
}
has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount);
has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount);
pri_attr_count = ulPrivateKeyAttributeCount + 1;
if (!has_class)
pri_attr_count++;
if (!has_key_type)
pri_attr_count++;
/* allocate space for CKA_EC_PARAMS */
priTemplate = grow_template(pPrivateKeyTemplate,
ulPrivateKeyAttributeCount, pri_attr_count + 1);
if (priTemplate == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
n = ulPrivateKeyAttributeCount;
if (!has_class) {
priTemplate[n].type = CKA_CLASS;
priTemplate[n].pValue = (caddr_t)&pri_class;
priTemplate[n].ulValueLen = sizeof (pri_class);
n++;
}
if (!has_key_type) {
priTemplate[n].type = CKA_KEY_TYPE;
key_type = CKK_EC;
priTemplate[n].pValue = (caddr_t)&key_type;
priTemplate[n].ulValueLen = sizeof (key_type);
n++;
}
priTemplate[n].type = CKA_VALUE;
priTemplate[n].pValue = (caddr_t)value;
priTemplate[n].ulValueLen = sizeof (value);
pri_out_attr_count++;
rv = process_object_attributes(priTemplate,
pri_attr_count - pri_out_attr_count,
&obj_nkp.nkp_in_private_attributes, &is_token_obj2);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
rv = process_object_attributes(
&priTemplate[pri_attr_count - pri_out_attr_count],
pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
&is_token_obj2);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_nkp.nkp_out_private_count = pri_out_attr_count;
/*
* The public key and the private key need to contain the same
* attribute values for CKA_TOKEN.
*/
if (is_token_obj1 != is_token_obj2) {
rv = CKR_ATTRIBUTE_VALUE_INVALID;
goto failed_exit;
}
/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
obj_nkp.nkp_session = session_p-> k_session;
obj_nkp.nkp_mechanism.cm_type = k_mech_type;
obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
&obj_nkp)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
}
free_attributes(obj_nkp.nkp_in_public_attributes,
&obj_nkp.nkp_in_public_count);
free_attributes(obj_nkp.nkp_in_private_attributes,
&obj_nkp.nkp_in_private_count);
if (rv != CKR_OK) {
goto failed_exit;
}
rv = get_object_attributes(
&pubTemplate[pub_attr_count - pub_out_attr_count],
pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
if (rv == CRYPTO_SUCCESS) {
rv = get_object_attributes(
&priTemplate[pri_attr_count - pri_out_attr_count],
pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
}
free_attributes(obj_nkp.nkp_out_public_attributes,
&obj_nkp.nkp_out_public_count);
free_attributes(obj_nkp.nkp_out_private_attributes,
&obj_nkp.nkp_out_private_count);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
session_p, KERNEL_GEN_KEY);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
/*
* Copy CKA_EC_PARAMS from the public template to the
* private template.
*/
rv = copy_attribute(CKA_EC_PARAMS, pubTemplate, pub_attr_count,
&priTemplate[pri_attr_count]);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
/* +1 to account for CKA_EC_PARAMS */
rv = kernel_build_object(priTemplate, pri_attr_count + 1,
new_pri_objp, session_p, KERNEL_GEN_KEY);
(void) free(priTemplate[pri_attr_count].pValue);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
(void) free(pubTemplate);
(void) free(priTemplate);
new_pub_objp->is_lib_obj = B_TRUE;
new_pri_objp->is_lib_obj = B_TRUE;
new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
return (CKR_OK);
failed_exit:
free_attributes(obj_nkp.nkp_in_public_attributes,
&obj_nkp.nkp_in_public_count);
free_attributes(obj_nkp.nkp_out_public_attributes,
&obj_nkp.nkp_out_public_count);
free_attributes(obj_nkp.nkp_in_private_attributes,
&obj_nkp.nkp_in_private_count);
free_attributes(obj_nkp.nkp_out_private_attributes,
&obj_nkp.nkp_out_private_count);
if (pubTemplate != NULL) {
(void) free(pubTemplate);
}
if (priTemplate != NULL) {
(void) free(priTemplate);
}
return (rv);
}
CK_RV
C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
{
CK_RV rv = CKR_OK;
kernel_session_t *session_p;
kernel_object_t *new_pub_objp = NULL;
kernel_object_t *new_pri_objp = NULL;
kernel_slot_t *pslot;
boolean_t ses_lock_held = B_FALSE;
CK_BBOOL is_pri_obj1;
CK_BBOOL is_pri_obj2;
CK_BBOOL is_token_obj1 = FALSE;
CK_BBOOL is_token_obj2 = FALSE;
crypto_mech_type_t k_mech_type;
int r;
CK_RV (*func)(CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG,
CK_ATTRIBUTE_PTR, CK_ULONG, kernel_session_t *, crypto_mech_type_t,
kernel_object_t *, kernel_object_t *);
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
/* Obtain the session pointer. */
rv = handle2session(hSession, &session_p);
if (rv != CKR_OK)
return (rv);
if ((pMechanism == NULL) || (phPublicKey == NULL) ||
(phPrivateKey == NULL)) {
rv = CKR_ARGUMENTS_BAD;
goto failed_exit;
}
if ((pPublicKeyTemplate == NULL) && (ulPublicKeyAttributeCount != 0)) {
rv = CKR_ARGUMENTS_BAD;
goto failed_exit;
}
if ((pPrivateKeyTemplate == NULL) &&
(ulPrivateKeyAttributeCount != 0)) {
rv = CKR_ARGUMENTS_BAD;
goto failed_exit;
}
/* Get the kernel's internal mechanism number. */
rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
if (rv != CKR_OK) {
goto failed_exit;
}
/* Create an object wrapper for the public key */
new_pub_objp = calloc(1, sizeof (kernel_object_t));
if (new_pub_objp == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
/* Create an object wrapper for the private key. */
new_pri_objp = calloc(1, sizeof (kernel_object_t));
if (new_pri_objp == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
/*
* Special Case: if token does not support object creation,
* but does support key generation by value, then create a session
* object and initialize with values returned by token.
*/
pslot = slot_table[session_p->ses_slotid];
if (!pslot->sl_func_list.fl_object_create) {
switch (pMechanism->mechanism) {
case CKM_RSA_PKCS_KEY_PAIR_GEN:
func = key_gen_rsa_by_value;
break;
case CKM_DH_PKCS_KEY_PAIR_GEN:
func = key_gen_dh_by_value;
break;
case CKM_EC_KEY_PAIR_GEN:
func = key_gen_ec_by_value;
break;
default:
rv = CKR_MECHANISM_INVALID;
goto failed_exit;
}
rv = (*func)(pMechanism, pPublicKeyTemplate,
ulPublicKeyAttributeCount, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount, session_p, k_mech_type,
new_pub_objp, new_pri_objp);
if (rv != CKR_OK)
goto failed_exit;
} else {
crypto_object_generate_key_pair_t obj_kp;
/* Process the public key attributes. */
rv = process_object_attributes(pPublicKeyTemplate,
ulPublicKeyAttributeCount, &obj_kp.kp_public_attributes,
&is_token_obj1);
if (rv != CKR_OK) {
goto failed_exit;
}
/* Cannot create a token object with a READ-ONLY session. */
if (is_token_obj1 && session_p->ses_RO) {
free_object_attributes(obj_kp.kp_public_attributes,
ulPublicKeyAttributeCount);
rv = CKR_SESSION_READ_ONLY;
goto failed_exit;
}
/* Process the private key attributes. */
rv = process_object_attributes(pPrivateKeyTemplate,
ulPrivateKeyAttributeCount, &obj_kp.kp_private_attributes,
&is_token_obj2);
if (rv != CKR_OK) {
free_object_attributes(obj_kp.kp_public_attributes,
ulPublicKeyAttributeCount);
goto failed_exit;
}
/*
* The public key and the private key need to contain the same
* attribute values for CKA_TOKEN.
*/
if (is_token_obj1 != is_token_obj2) {
free_object_attributes(obj_kp.kp_public_attributes,
ulPublicKeyAttributeCount);
free_object_attributes(obj_kp.kp_private_attributes,
ulPrivateKeyAttributeCount);
rv = CKR_ATTRIBUTE_VALUE_INVALID;
goto failed_exit;
}
/* Call the CRYPTO_GENERATE_KEY_PAIR ioctl. */
obj_kp.kp_session = session_p-> k_session;
obj_kp.kp_mechanism.cm_type = k_mech_type;
obj_kp.kp_mechanism.cm_param = pMechanism->pParameter;
obj_kp.kp_mechanism.cm_param_len = pMechanism->ulParameterLen;
obj_kp.kp_public_count = ulPublicKeyAttributeCount;
obj_kp.kp_private_count = ulPrivateKeyAttributeCount;
while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY_PAIR,
&obj_kp)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(obj_kp.kp_return_value);
}
free_object_attributes(obj_kp.kp_public_attributes,
ulPublicKeyAttributeCount);
free_object_attributes(obj_kp.kp_private_attributes,
ulPrivateKeyAttributeCount);
if (rv != CKR_OK)
goto failed_exit;
/* Get the CKA_PRIVATE value for the key pair. */
rv = get_cka_private_value(session_p, obj_kp.kp_public_handle,
&is_pri_obj1);
if (rv != CKR_OK) {
goto failed_exit;
}
rv = get_cka_private_value(session_p, obj_kp.kp_private_handle,
&is_pri_obj2);
if (rv != CKR_OK) {
goto failed_exit;
}
/*
* Store the kernel public key handle into the public key
* object and finish the public key object initialization.
*/
new_pub_objp->is_lib_obj = B_FALSE;
new_pub_objp->k_handle = obj_kp.kp_public_handle;
new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
new_pub_objp->extra_attrlistp = NULL;
if (is_pri_obj1)
new_pub_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
else
new_pub_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
if (is_token_obj1)
new_pub_objp->bool_attr_mask |= TOKEN_BOOL_ON;
else
new_pub_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
/*
* Store the kernel private key handle into the private key
* object and finish the private key object initialization.
*/
new_pri_objp->is_lib_obj = B_FALSE;
new_pri_objp->k_handle = obj_kp.kp_private_handle;
new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
new_pri_objp->extra_attrlistp = NULL;
if (is_pri_obj2)
new_pri_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
else
new_pri_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
if (is_token_obj2)
new_pri_objp->bool_attr_mask |= TOKEN_BOOL_ON;
else
new_pri_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
}
(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
/*
* Add the new pub/pri objects to the slot's token list if they are
* token objects. Otherwise, add them to the session's object list.
*/
if (is_token_obj1) { /* is_token_obj1 == is_token_obj2 */
pslot = slot_table[session_p->ses_slotid];
kernel_add_token_object_to_slot(new_pub_objp, pslot);
kernel_add_token_object_to_slot(new_pri_objp, pslot);
} else {
kernel_add_object_to_session(new_pub_objp, session_p);
kernel_add_object_to_session(new_pri_objp, session_p);
}
*phPublicKey = (CK_OBJECT_HANDLE)new_pub_objp;
*phPrivateKey = (CK_OBJECT_HANDLE)new_pri_objp;
REFRELE(session_p, ses_lock_held);
return (rv);
failed_exit:
if (new_pub_objp != NULL) {
(void) free(new_pub_objp);
}
if (new_pri_objp != NULL) {
(void) free(new_pri_objp);
}
REFRELE(session_p, ses_lock_held);
return (rv);
}
CK_RV
C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen)
{
CK_RV rv = CKR_OK;
kernel_session_t *session_p;
boolean_t ses_lock_held = B_FALSE;
kernel_object_t *wrappingkey_p;
kernel_object_t *key_p;
crypto_mech_type_t k_mech_type;
crypto_object_wrap_key_t obj_wrapkey;
int r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
if (pulWrappedKeyLen == NULL || pMechanism == NULL) {
return (CKR_ARGUMENTS_BAD);
}
/*
* Obtain the session pointer. Also, increment the session
* reference count.
*/
rv = handle2session(hSession, &session_p);
if (rv != CKR_OK)
return (rv);
/* Get the kernel's internal mechanism number. */
rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
if (rv != CKR_OK) {
REFRELE(session_p, ses_lock_held);
return (rv);
}
/* Obtain the wrapping key object pointer. */
HANDLE2OBJECT(hWrappingKey, wrappingkey_p, rv);
if (rv != CKR_OK) {
REFRELE(session_p, ses_lock_held);
return (rv);
}
/* Obtain the to_be_wrapped key object pointer. */
HANDLE2OBJECT(hKey, key_p, rv);
if (rv != CKR_OK) {
OBJ_REFRELE(wrappingkey_p);
REFRELE(session_p, ses_lock_held);
return (rv);
}
/* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */
obj_wrapkey.wk_session = session_p->k_session;
obj_wrapkey.wk_mechanism.cm_type = k_mech_type;
obj_wrapkey.wk_mechanism.cm_param = pMechanism->pParameter;
obj_wrapkey.wk_mechanism.cm_param_len = pMechanism->ulParameterLen;
obj_wrapkey.wk_wrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
obj_wrapkey.wk_wrapping_key.ck_obj_id = wrappingkey_p->k_handle;
obj_wrapkey.wk_object_handle = key_p->k_handle;
obj_wrapkey.wk_wrapped_key_len = *pulWrappedKeyLen;
obj_wrapkey.wk_wrapped_key = (char *)pWrappedKey;
while ((r = ioctl(kernel_fd, CRYPTO_WRAP_KEY, &obj_wrapkey)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(obj_wrapkey.wk_return_value);
}
/*
* Besides rv == CKR_OK, we will set the value of pulWrappedKeyLen
* when the applciation-supplied wrapped key buffer is too small.
* The situation that the application only asks for the length of
* the wrapped key is covered in rv == CKR_OK.
*/
if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
*pulWrappedKeyLen = obj_wrapkey.wk_wrapped_key_len;
}
OBJ_REFRELE(key_p);
OBJ_REFRELE(wrappingkey_p);
REFRELE(session_p, ses_lock_held);
return (rv);
}
CK_RV
C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey,
CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
{
CK_RV rv = CKR_OK;
kernel_session_t *session_p;
kernel_object_t *unwrappingkey_p;
kernel_object_t *new_objp = NULL;
kernel_slot_t *pslot;
boolean_t ses_lock_held = B_FALSE;
CK_BBOOL is_pri_obj;
CK_BBOOL is_token_obj = FALSE;
CK_MECHANISM_INFO info;
uint32_t k_mi_flags;
CK_BYTE *clear_key_val = NULL;
CK_ULONG ulDataLen;
CK_ATTRIBUTE_PTR newTemplate = NULL;
crypto_mech_type_t k_mech_type;
crypto_object_unwrap_key_t obj_unwrapkey;
int r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) {
return (CKR_ARGUMENTS_BAD);
}
if ((pTemplate == NULL) && (ulAttributeCount != 0)) {
return (CKR_ARGUMENTS_BAD);
}
/* Obtain the session pointer. */
rv = handle2session(hSession, &session_p);
if (rv != CKR_OK)
return (rv);
/* Obtain the wrapping key object pointer. */
HANDLE2OBJECT(hUnwrappingKey, unwrappingkey_p, rv);
if (rv != CKR_OK) {
REFRELE(session_p, ses_lock_held);
return (rv);
}
/*
* If the HW provider doesn't support C_UnwrapKey, we will try
* to emulate it in the library.
*/
pslot = slot_table[session_p->ses_slotid];
if ((!pslot->sl_func_list.fl_object_create) &&
(!pslot->sl_func_list.fl_key_unwrap)) {
rv = get_mechanism_info(pslot, pMechanism->mechanism, &info,
&k_mi_flags);
if (rv != CKR_OK) {
goto failed_exit;
}
/*
* If the mechanism flag doesn't have CKF_UNWRAP, and it's
* an unwrapping of a secret key object, then help this
* out with a decryption followed by an object creation.
*/
if (!(k_mi_flags & CRYPTO_FG_UNWRAP) &&
(k_mi_flags & CRYPTO_FG_DECRYPT) &&
(is_secret_key_template(pTemplate, ulAttributeCount))) {
/* First allocate space for the recovered key value */
clear_key_val = malloc(ulWrappedKeyLen);
if (clear_key_val == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
rv = kernel_decrypt_init(session_p, unwrappingkey_p,
pMechanism);
if (rv != CKR_OK) {
goto failed_exit;
}
ulDataLen = ulWrappedKeyLen;
rv = kernel_decrypt(session_p, pWrappedKey,
ulWrappedKeyLen, clear_key_val, &ulDataLen);
if (rv != CKR_OK) {
goto failed_exit;
}
newTemplate = grow_template(pTemplate, ulAttributeCount,
ulAttributeCount + 1);
if (newTemplate == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
/* Now add the CKA_VALUE attribute to template */
newTemplate[ulAttributeCount].type = CKA_VALUE;
newTemplate[ulAttributeCount].pValue = clear_key_val;
newTemplate[ulAttributeCount].ulValueLen = ulDataLen;
/* Finally create the key, based on the new template */
rv = kernel_add_object(newTemplate,
ulAttributeCount + 1, phKey, session_p);
(void) free(clear_key_val);
(void) free(newTemplate);
OBJ_REFRELE(unwrappingkey_p);
REFRELE(session_p, ses_lock_held);
return (rv);
} else {
rv = CKR_FUNCTION_FAILED;
goto failed_exit;
}
}
/*
* If we come here, the HW provider must have registered the unwrapkey
* entry. Therefore, the unwrap key will be performed in the HW
* provider.
*/
rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
if (rv != CKR_OK) {
goto failed_exit;
}
/* Create an object wrapper for the new key in the library first */
new_objp = calloc(1, sizeof (kernel_object_t));
if (new_objp == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
/* Process the attributes */
rv = process_object_attributes(pTemplate, ulAttributeCount,
&obj_unwrapkey.uk_attributes, &is_token_obj);
if (rv != CKR_OK) {
goto failed_exit;
}
/* Cannot create a token object with a READ-ONLY session. */
if (is_token_obj && session_p->ses_RO) {
free_object_attributes(obj_unwrapkey.uk_attributes,
ulAttributeCount);
rv = CKR_SESSION_READ_ONLY;
goto failed_exit;
}
/* Make the CRYPTO_UNWRAP_KEY ioctl call. */
obj_unwrapkey.uk_session = session_p->k_session;
obj_unwrapkey.uk_mechanism.cm_type = k_mech_type;
obj_unwrapkey.uk_mechanism.cm_param = pMechanism->pParameter;
obj_unwrapkey.uk_mechanism.cm_param_len = pMechanism->ulParameterLen;
obj_unwrapkey.uk_unwrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
obj_unwrapkey.uk_unwrapping_key.ck_obj_id = unwrappingkey_p->k_handle;
obj_unwrapkey.uk_wrapped_key = (char *)pWrappedKey;
obj_unwrapkey.uk_wrapped_key_len = ulWrappedKeyLen;
obj_unwrapkey.uk_count = ulAttributeCount;
while ((r = ioctl(kernel_fd, CRYPTO_UNWRAP_KEY, &obj_unwrapkey)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(obj_unwrapkey.uk_return_value);
}
free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount);
if (rv != CKR_OK) {
goto failed_exit;
}
/* Get the CKA_PRIVATE value for the unwrapped key. */
rv = get_cka_private_value(session_p, obj_unwrapkey.uk_object_handle,
&is_pri_obj);
if (rv != CKR_OK) {
goto failed_exit;
}
/*
* Store the kernel object handle in the new key object wrapper and
* initialize it.
*/
new_objp->k_handle = obj_unwrapkey.uk_object_handle;
new_objp->is_lib_obj = B_FALSE;
new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
new_objp->extra_attrlistp = NULL;
if (is_pri_obj)
new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
else
new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
if (is_token_obj)
new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
else
new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
/*
* Add the new object to the slot's token object list if it is a
* a token object. Otherwise, add it to the session's object list.
*/
if (is_token_obj) {
pslot = slot_table[session_p->ses_slotid];
kernel_add_token_object_to_slot(new_objp, pslot);
} else {
kernel_add_object_to_session(new_objp, session_p);
}
*phKey = (CK_OBJECT_HANDLE)new_objp;
OBJ_REFRELE(unwrappingkey_p);
REFRELE(session_p, ses_lock_held);
return (rv);
failed_exit:
OBJ_REFRELE(unwrappingkey_p);
if (new_objp != NULL)
(void) free(new_objp);
if (clear_key_val != NULL)
(void) free(clear_key_val);
if (newTemplate != NULL)
(void) free(newTemplate);
REFRELE(session_p, ses_lock_held);
return (rv);
}
/*
* Get sufficient attributes from a base key to pass by value in a
* crypto_key structure. Storage for attributes is allocated.
* For EC public keys, it is CKA_EC_PARAMS and CKA_EC_POINT.
* For EC private keys, it is CKA_EC_PARAMS and CKA_VALUE.
*/
static int
get_base_key_attributes(kernel_object_t *base_key, crypto_key_t *key_by_value)
{
CK_ATTRIBUTE tmp;
crypto_object_attribute_t *attrs = NULL;
biginteger_t *big;
int i, count = 0, rv;
switch (base_key->key_type) {
case CKK_EC:
count = 2;
attrs = malloc(count * sizeof (crypto_object_attribute_t));
if (attrs == NULL) {
rv = CKR_HOST_MEMORY;
goto out;
}
bzero(attrs, count * sizeof (crypto_object_attribute_t));
(void) pthread_mutex_lock(&base_key->object_mutex);
if (!base_key->is_lib_obj) {
rv = CRYPTO_ARGUMENTS_BAD;
goto out;
}
if (base_key->class != CKO_PUBLIC_KEY &&
base_key->class != CKO_PRIVATE_KEY) {
rv = CRYPTO_ARGUMENTS_BAD;
goto out;
}
/*
* Both public and private EC keys should have
* a CKA_EC_PARAMS attribute.
*/
tmp.type = CKA_EC_PARAMS;
tmp.pValue = NULL;
/* get size of attribute */
rv = kernel_get_attribute(base_key, &tmp);
if (rv != CKR_OK) {
goto out;
}
tmp.pValue = malloc(tmp.ulValueLen);
if (tmp.pValue == NULL) {
rv = CKR_HOST_MEMORY;
goto out;
}
rv = kernel_get_attribute(base_key, &tmp);
if (rv != CKR_OK) {
free(tmp.pValue);
goto out;
}
attrs[0].oa_type = tmp.type;
attrs[0].oa_value = tmp.pValue;
attrs[0].oa_value_len = tmp.ulValueLen;
switch (base_key->class) {
case CKO_PUBLIC_KEY:
big = OBJ_PUB_EC_POINT(base_key);
tmp.type = CKA_EC_POINT;
break;
case CKO_PRIVATE_KEY:
big = OBJ_PRI_EC_VALUE(base_key);
tmp.type = CKA_VALUE;
break;
default:
rv = CKR_ATTRIBUTE_TYPE_INVALID;
goto out;
}
tmp.ulValueLen = big->big_value_len;
tmp.pValue = malloc(tmp.ulValueLen);
if (tmp.pValue == NULL) {
rv = CKR_HOST_MEMORY;
goto out;
}
rv = kernel_get_attribute(base_key, &tmp);
if (rv != CKR_OK) {
free(tmp.pValue);
goto out;
}
attrs[1].oa_type = tmp.type;
attrs[1].oa_value = tmp.pValue;
attrs[1].oa_value_len = tmp.ulValueLen;
key_by_value->ck_attrs = attrs;
key_by_value->ck_count = 2;
break;
case CKK_DH:
count = 3;
attrs = malloc(count * sizeof (crypto_object_attribute_t));
if (attrs == NULL) {
rv = CKR_HOST_MEMORY;
goto out;
}
bzero(attrs, count * sizeof (crypto_object_attribute_t));
(void) pthread_mutex_lock(&base_key->object_mutex);
if (!base_key->is_lib_obj) {
rv = CRYPTO_ARGUMENTS_BAD;
goto out;
}
if (base_key->class != CKO_PRIVATE_KEY) {
rv = CRYPTO_ARGUMENTS_BAD;
goto out;
}
tmp.type = CKA_BASE;
tmp.pValue = NULL;
/* get size of attribute */
rv = kernel_get_attribute(base_key, &tmp);
if (rv != CKR_OK) {
goto out;
}
tmp.pValue = malloc(tmp.ulValueLen);
if (tmp.pValue == NULL) {
rv = CKR_HOST_MEMORY;
goto out;
}
rv = kernel_get_attribute(base_key, &tmp);
if (rv != CKR_OK) {
free(tmp.pValue);
goto out;
}
attrs[0].oa_type = tmp.type;
attrs[0].oa_value = tmp.pValue;
attrs[0].oa_value_len = tmp.ulValueLen;
tmp.type = CKA_PRIME;
tmp.pValue = NULL;
/* get size of attribute */
rv = kernel_get_attribute(base_key, &tmp);
if (rv != CKR_OK) {
goto out;
}
tmp.pValue = malloc(tmp.ulValueLen);
if (tmp.pValue == NULL) {
rv = CKR_HOST_MEMORY;
goto out;
}
rv = kernel_get_attribute(base_key, &tmp);
if (rv != CKR_OK) {
free(tmp.pValue);
goto out;
}
attrs[1].oa_type = tmp.type;
attrs[1].oa_value = tmp.pValue;
attrs[1].oa_value_len = tmp.ulValueLen;
big = OBJ_PRI_DH_VALUE(base_key);
tmp.type = CKA_VALUE;
tmp.ulValueLen = big->big_value_len;
tmp.pValue = malloc(tmp.ulValueLen);
if (tmp.pValue == NULL) {
rv = CKR_HOST_MEMORY;
goto out;
}
rv = kernel_get_attribute(base_key, &tmp);
if (rv != CKR_OK) {
free(tmp.pValue);
goto out;
}
attrs[2].oa_type = tmp.type;
attrs[2].oa_value = tmp.pValue;
attrs[2].oa_value_len = tmp.ulValueLen;
key_by_value->ck_attrs = attrs;
key_by_value->ck_count = 3;
break;
default:
rv = CKR_ATTRIBUTE_TYPE_INVALID;
goto out;
}
(void) pthread_mutex_unlock(&base_key->object_mutex);
return (CKR_OK);
out:
(void) pthread_mutex_unlock(&base_key->object_mutex);
if (attrs != NULL) {
for (i = 0; i < count; i++) {
if (attrs[i].oa_value != NULL)
free(attrs[i].oa_value);
}
free(attrs);
}
return (rv);
}
CK_RV
derive_key_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount, kernel_session_t *session_p,
crypto_mech_type_t k_mech_type, kernel_object_t *basekey_p,
kernel_object_t *new_objp)
{
crypto_nostore_derive_key_t obj_ndk;
char *key_buf = NULL;
CK_ATTRIBUTE_PTR newTemplate = NULL;
CK_BBOOL is_token_obj = FALSE;
CK_RV rv = CKR_OK;
CK_ULONG secret_class = CKO_SECRET_KEY;
ulong_t key_len = 0;
uint_t attr_count = 0;
boolean_t removed;
boolean_t has_class;
int r, n;
obj_ndk.ndk_in_count = 0;
obj_ndk.ndk_out_count = 0;
obj_ndk.ndk_base_key.ck_count = 0;
rv = get_key_len_from_template(pMechanism, pTemplate, ulAttributeCount,
basekey_p, &key_len);
if (rv != CKR_OK) {
goto failed_exit;
}
if ((key_buf = malloc(key_len)) == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
has_class = attribute_in_template(CKA_CLASS, pTemplate,
ulAttributeCount);
attr_count = ulAttributeCount + 1;
if (!has_class)
attr_count++;
newTemplate = grow_template(pTemplate, ulAttributeCount, attr_count);
if (newTemplate == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
n = ulAttributeCount;
if (!has_class) {
newTemplate[n].type = CKA_CLASS;
newTemplate[n].pValue = (caddr_t)&secret_class;
newTemplate[n].ulValueLen = sizeof (secret_class);
n++;
}
/* Add CKA_VALUE to the template */
newTemplate[n].type = CKA_VALUE;
newTemplate[n].pValue = (caddr_t)key_buf;
newTemplate[n].ulValueLen = key_len;
rv = process_object_attributes(newTemplate, attr_count - 1,
&obj_ndk.ndk_in_attributes, &is_token_obj);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_ndk.ndk_in_count = attr_count - 1;
rv = process_object_attributes(&newTemplate[attr_count - 1],
1, &obj_ndk.ndk_out_attributes, &is_token_obj);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_ndk.ndk_out_count = 1;
/* Cannot create a token object with a READ-ONLY session. */
if (is_token_obj && session_p->ses_RO) {
rv = CKR_SESSION_READ_ONLY;
goto failed_exit;
}
obj_ndk.ndk_session = session_p->k_session;
obj_ndk.ndk_mechanism.cm_type = k_mech_type;
obj_ndk.ndk_mechanism.cm_param = pMechanism->pParameter;
obj_ndk.ndk_mechanism.cm_param_len = pMechanism->ulParameterLen;
/*
* Obtain the attributes of base key and pass them by value.
*/
rv = get_base_key_attributes(basekey_p, &obj_ndk.ndk_base_key);
if (rv != CKR_OK) {
goto failed_exit;
}
obj_ndk.ndk_base_key.ck_format = CRYPTO_KEY_ATTR_LIST;
while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_DERIVE_KEY,
&obj_ndk)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(obj_ndk.ndk_return_value);
}
free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
&obj_ndk.ndk_base_key.ck_count);
if (rv != CKR_OK) {
goto failed_exit;
}
rv = get_object_attributes(&newTemplate[attr_count - 1],
1, obj_ndk.ndk_out_attributes);
free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
removed = remove_one_attribute(newTemplate, CKA_VALUE_LEN,
attr_count, B_FALSE);
rv = kernel_build_object(newTemplate, removed ? attr_count - 1 :
attr_count, new_objp, session_p, KERNEL_GEN_KEY);
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
free(key_buf);
free(newTemplate);
new_objp->is_lib_obj = B_TRUE;
new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
return (CKR_OK);
failed_exit:
if (key_buf != NULL)
free(key_buf);
if (newTemplate != NULL)
free(newTemplate);
free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
&obj_ndk.ndk_base_key.ck_count);
return (rv);
}
CK_RV
C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
{
CK_RV rv = CKR_OK;
kernel_session_t *session_p;
kernel_object_t *basekey_p;
kernel_object_t *new_objp;
kernel_slot_t *pslot;
boolean_t ses_lock_held = B_FALSE;
CK_BBOOL is_pri_obj;
CK_BBOOL is_token_obj = FALSE;
crypto_mech_type_t k_mech_type;
int r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
/* Obtain the session pointer. */
rv = handle2session(hSession, &session_p);
if (rv != CKR_OK)
return (rv);
if (pMechanism == NULL) {
REFRELE(session_p, ses_lock_held);
return (CKR_ARGUMENTS_BAD);
}
if ((pTemplate == NULL && ulAttributeCount != 0) ||
(pTemplate != NULL && ulAttributeCount == 0)) {
REFRELE(session_p, ses_lock_held);
return (CKR_ARGUMENTS_BAD);
}
/* Obtain the base key object pointer. */
HANDLE2OBJECT(hBaseKey, basekey_p, rv);
if (rv != CKR_OK) {
REFRELE(session_p, ses_lock_held);
return (rv);
}
/* Get the kernel's internal mechanism number. */
rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
if (rv != CKR_OK) {
goto failed_exit;
}
/* Create an object wrapper in the library for the generated key. */
new_objp = calloc(1, sizeof (kernel_object_t));
if (new_objp == NULL) {
rv = CKR_HOST_MEMORY;
goto failed_exit;
}
/*
* Special Case: if token does not support object creation,
* but does support key derivation by value, then create a session
* object and initialize with values returned by token.
*/
pslot = slot_table[session_p->ses_slotid];
if (!pslot->sl_func_list.fl_object_create) {
rv = derive_key_by_value(pMechanism, pTemplate,
ulAttributeCount, session_p, k_mech_type, basekey_p,
new_objp);
if (rv != CKR_OK)
goto failed_exit;
} else {
crypto_derive_key_t obj_dk;
rv = process_object_attributes(pTemplate, ulAttributeCount,
&obj_dk.dk_attributes, &is_token_obj);
if (rv != CKR_OK) {
goto failed_exit;
}
/* Cannot create a token object with a READ-ONLY session. */
if (is_token_obj && session_p->ses_RO) {
free_object_attributes(obj_dk.dk_attributes,
ulAttributeCount);
rv = CKR_SESSION_READ_ONLY;
goto failed_exit;
}
obj_dk.dk_session = session_p->k_session;
obj_dk.dk_mechanism.cm_type = k_mech_type;
obj_dk.dk_mechanism.cm_param = pMechanism->pParameter;
obj_dk.dk_mechanism.cm_param_len = pMechanism->ulParameterLen;
obj_dk.dk_base_key.ck_format = CRYPTO_KEY_REFERENCE;
obj_dk.dk_base_key.ck_obj_id = basekey_p->k_handle;
obj_dk.dk_count = ulAttributeCount;
while ((r = ioctl(kernel_fd, CRYPTO_DERIVE_KEY, &obj_dk)) < 0) {
if (errno != EINTR)
break;
}
if (r < 0) {
rv = CKR_FUNCTION_FAILED;
} else {
rv = crypto2pkcs11_error_number(obj_dk.dk_return_value);
}
free_object_attributes(obj_dk.dk_attributes, ulAttributeCount);
if (rv != CKR_OK) {
goto failed_exit;
}
/* Get the CKA_PRIVATE value for the derived key. */
rv = get_cka_private_value(session_p, obj_dk.dk_object_handle,
&is_pri_obj);
if (rv != CKR_OK) {
goto failed_exit;
}
/*
* Store the kernel object handle into the new derived key
* object and finish the object initialization.
*/
new_objp->is_lib_obj = B_FALSE;
new_objp->k_handle = obj_dk.dk_object_handle;
new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
new_objp->extra_attrlistp = NULL;
if (is_pri_obj)
new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
else
new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
if (is_token_obj)
new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
else
new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
}
(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
/*
* Add the new derived object to the slot's token list if it is a
* token object. Otherwise, add it to the session's object list.
*/
if (is_token_obj) {
pslot = slot_table[session_p->ses_slotid];
kernel_add_token_object_to_slot(new_objp, pslot);
} else {
kernel_add_object_to_session(new_objp, session_p);
}
*phKey = (CK_OBJECT_HANDLE)new_objp;
OBJ_REFRELE(basekey_p);
REFRELE(session_p, ses_lock_held);
return (rv);
failed_exit:
OBJ_REFRELE(basekey_p);
if (new_objp != NULL) {
(void) free(new_objp);
}
REFRELE(session_p, ses_lock_held);
return (rv);
}