/*
* 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
* 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 "kernelGlobal.h"
#include "kernelSession.h"
#include "kernelObject.h"
static boolean_t
{
int i;
for (i = 0; i < cnt; i++) {
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
{
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 */
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
{
int i, j;
for (i = 0, j = 0; i < count; i++) {
if (free_attr) {
}
continue;
}
if (i != j) {
t[j].ulValueLen = t[i].ulValueLen;
}
j++;
}
if (j == count)
return (B_FALSE);
/* safety */
t[j].ulValueLen = 0;
return (B_TRUE);
}
static boolean_t
{
int i;
for (i = 0; i < ulAttributeCount; i++) {
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
{
if (new_template != NULL)
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
{
int i;
for (i = 0; i < ulAttributeCount; i++) {
break;
}
}
/* CKA_KEY_TYPE must be present */
if (i == ulAttributeCount)
return (CKR_TEMPLATE_INCOMPLETE);
switch (key_type) {
case CKK_DES:
*key_len = 8;
break;
case CKK_DES3:
*key_len = 24;
break;
case CKK_AES:
case CKK_BLOWFISH:
for (i = 0; i < ulAttributeCount; i++) {
&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.
*/
/* get size of attribute */
return (CKR_ARGUMENTS_BAD);
}
} else {
return (CKR_ARGUMENTS_BAD);
}
break;
default:
return (CKR_ATTRIBUTE_VALUE_INVALID);
}
return (CKR_TEMPLATE_INCONSISTENT);
return (CKR_OK);
}
/* find specified attribute src template and copy to dest */
static int
{
int rv, i;
for (i = 0; i < src_cnt; i++) {
break;
}
}
/*
* The public template didn't have attribute.
*/
if (i == src_cnt) {
}
return (rv);
}
static void
{
if (*countp > 0) {
free_object_attributes(p, *countp);
*countp = 0;
}
}
{
int r;
obj_ngk.ngk_in_count = 0;
obj_ngk.ngk_out_count = 0;
if (rv != CRYPTO_SUCCESS)
goto failed_exit;
goto failed_exit;
}
if (newTemplate == NULL) {
goto failed_exit;
}
/* Now add the CKA_VALUE attribute to template */
goto failed_exit;
}
goto failed_exit;
}
/* Cannot create a token object with a READ-ONLY session. */
goto failed_exit;
}
/* Call the CRYPTO_NOSTORE_GENERATE_KEY ioctl */
&obj_ngk)) < 0) {
break;
}
if (r < 0) {
} else {
}
goto failed_exit;
}
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.
*/
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
(void) free(newTemplate);
return (CKR_OK);
}
if (newTemplate != NULL) {
(void) free(newTemplate);
}
return (rv);
}
{
int r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
/* Obtain the session pointer */
return (rv);
goto failed_exit;
}
goto failed_exit;
}
/* Get the kernel's internal mechanism number. */
goto failed_exit;
}
/* Create an object wrapper in the library first */
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.
*/
goto failed_exit;
} else {
/* Process the attributes */
goto failed_exit;
}
/* Cannot create a token object with a READ-ONLY session. */
goto failed_exit;
}
/* Call the CRYPTO_GENERATE_KEY ioctl */
&obj_gk)) < 0) {
break;
}
if (r < 0) {
} else {
}
goto failed_exit;
}
/* Get the value of the CKA_PRIVATE attribute. */
&is_pri_obj);
goto failed_exit;
}
/*
* Store the kernel object handle in the object wrapper and
* initialize the library object.
*/
if (is_pri_obj)
else
if (is_token_obj)
else
}
/*
* 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) {
} else {
}
return (rv);
}
return (rv);
}
{
int n, r;
/* modulus bits must be present when generating a RSA key pair */
goto failed_exit;
}
/*
* Add CKA_MODULUS to the public template.
* This attribute must not be in the template.
*/
goto failed_exit;
}
if (!has_class)
if (!has_key_type)
if (!has_pub_exponent)
if (pubTemplate == NULL) {
goto failed_exit;
}
if (!has_class) {
n++;
}
if (!has_key_type) {
n++;
}
if (!has_pub_exponent) {
n++;
}
goto failed_exit;
}
goto failed_exit;
}
/*
* Cannot create a token object with a READ-ONLY
* session.
*/
goto failed_exit;
}
/*
* Add CKA_MODULUS and CKA_PRIVATE_EXPONENT
* to the private template. These attributes
* must not be in the template.
*/
goto failed_exit;
}
if (!has_class)
if (!has_key_type)
/* allocate space for CKA_PUBLIC_EXPONENT */
if (priTemplate == NULL) {
goto failed_exit;
}
if (!has_class) {
n++;
}
if (!has_key_type) {
n++;
}
n++;
n++;
n++;
n++;
n++;
n++;
goto failed_exit;
}
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) {
goto failed_exit;
}
/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
&obj_nkp)) < 0) {
break;
}
if (r < 0) {
} else {
}
goto failed_exit;
}
if (rv == CRYPTO_SUCCESS) {
}
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
/* store generated modulus and public exponent */
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
/*
* Copy CKA_PUBLIC_EXPONENT from the public template
* to the private template.
*/
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
(void) free(pubTemplate);
(void) free(priTemplate);
return (CKR_OK);
if (pubTemplate != NULL) {
(void) free(pubTemplate);
}
if (priTemplate != NULL) {
(void) free(priTemplate);
}
return (rv);
}
{
int n, r;
/*
* Add CKA_VALUE to the public template.
* This attribute must not be in the template.
*/
goto failed_exit;
}
if (!has_class)
if (!has_key_type)
if (pubTemplate == NULL) {
goto failed_exit;
}
if (!has_class) {
n++;
}
if (!has_key_type) {
n++;
}
goto failed_exit;
}
goto failed_exit;
}
/*
* Cannot create a token object with a READ-ONLY
* session.
*/
goto failed_exit;
}
/*
* CKA_BASE, CKA_PRIME, and CKA_VALUE must not appear
* in private template.
*/
goto failed_exit;
}
goto failed_exit;
}
if (!has_class)
if (!has_key_type)
/* allocate space for CKA_BASE and CKA_PRIME */
if (priTemplate == NULL) {
goto failed_exit;
}
if (!has_class) {
n++;
}
if (!has_key_type) {
n++;
}
goto failed_exit;
}
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) {
goto failed_exit;
}
/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
&obj_nkp)) < 0) {
break;
}
if (r < 0) {
} else {
}
goto failed_exit;
}
if (rv == CRYPTO_SUCCESS) {
}
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
/*
* Copy CKA_BASE and CKA_PRIME from the public template
* to the private template.
*/
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
/* +2 to account for CKA_BASE and CKA_PRIME */
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
(void) free(pubTemplate);
(void) free(priTemplate);
return (CKR_OK);
if (pubTemplate != NULL) {
(void) free(pubTemplate);
}
if (priTemplate != NULL) {
(void) free(priTemplate);
}
return (rv);
}
{
int n, r;
/*
* Add CKA_EC_POINT to the public template.
* This is the generated value Q. This attribute
* must not be in the template.
*/
goto failed_exit;
}
if (!has_class)
if (!has_key_type)
if (pubTemplate == NULL) {
goto failed_exit;
}
if (!has_class) {
n++;
}
if (!has_key_type) {
n++;
}
goto failed_exit;
}
goto failed_exit;
}
/*
* Cannot create a token object with a READ-ONLY
* session.
*/
goto failed_exit;
}
/*
* CKA_EC_PARAMS and CKA_VALUE must not appear in
* private template.
*/
goto failed_exit;
}
if (!has_class)
if (!has_key_type)
/* allocate space for CKA_EC_PARAMS */
if (priTemplate == NULL) {
goto failed_exit;
}
if (!has_class) {
n++;
}
if (!has_key_type) {
n++;
}
goto failed_exit;
}
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) {
goto failed_exit;
}
/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
&obj_nkp)) < 0) {
break;
}
if (r < 0) {
} else {
}
goto failed_exit;
}
if (rv == CRYPTO_SUCCESS) {
}
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
/*
* Copy CKA_EC_PARAMS from the public template to the
* private template.
*/
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
/* +1 to account for CKA_EC_PARAMS */
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
(void) free(pubTemplate);
(void) free(priTemplate);
return (CKR_OK);
if (pubTemplate != NULL) {
(void) free(pubTemplate);
}
if (priTemplate != NULL) {
(void) free(priTemplate);
}
return (rv);
}
{
int r;
kernel_object_t *, kernel_object_t *);
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
/* Obtain the session pointer. */
return (rv);
(phPrivateKey == NULL)) {
goto failed_exit;
}
goto failed_exit;
}
if ((pPrivateKeyTemplate == NULL) &&
(ulPrivateKeyAttributeCount != 0)) {
goto failed_exit;
}
/* Get the kernel's internal mechanism number. */
goto failed_exit;
}
/* Create an object wrapper for the public key */
if (new_pub_objp == NULL) {
goto failed_exit;
}
/* Create an object wrapper for the private key. */
if (new_pri_objp == NULL) {
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.
*/
switch (pMechanism->mechanism) {
break;
case CKM_DH_PKCS_KEY_PAIR_GEN:
break;
case CKM_EC_KEY_PAIR_GEN:
break;
default:
goto failed_exit;
}
goto failed_exit;
} else {
/* Process the public key attributes. */
goto failed_exit;
}
/* Cannot create a token object with a READ-ONLY session. */
goto failed_exit;
}
/* Process the private key attributes. */
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) {
goto failed_exit;
}
/* Call the CRYPTO_GENERATE_KEY_PAIR ioctl. */
&obj_kp)) < 0) {
break;
}
if (r < 0) {
} else {
}
goto failed_exit;
/* Get the CKA_PRIVATE value for the key pair. */
&is_pri_obj1);
goto failed_exit;
}
&is_pri_obj2);
goto failed_exit;
}
/*
* Store the kernel public key handle into the public key
* object and finish the public key object initialization.
*/
if (is_pri_obj1)
else
if (is_token_obj1)
else
/*
* Store the kernel private key handle into the private key
* object and finish the private key object initialization.
*/
if (is_pri_obj2)
else
if (is_token_obj2)
else
}
/*
* token objects. Otherwise, add them to the session's object list.
*/
if (is_token_obj1) { /* is_token_obj1 == is_token_obj2 */
} else {
}
return (rv);
if (new_pub_objp != NULL) {
(void) free(new_pub_objp);
}
if (new_pri_objp != NULL) {
(void) free(new_pri_objp);
}
return (rv);
}
{
int r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
return (CKR_ARGUMENTS_BAD);
}
/*
* Obtain the session pointer. Also, increment the session
* reference count.
*/
return (rv);
/* Get the kernel's internal mechanism number. */
return (rv);
}
/* Obtain the wrapping key object pointer. */
return (rv);
}
/* Obtain the to_be_wrapped key object pointer. */
return (rv);
}
/* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */
break;
}
if (r < 0) {
} else {
}
/*
* 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.
*/
}
return (rv);
}
{
int r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
return (CKR_ARGUMENTS_BAD);
}
return (CKR_ARGUMENTS_BAD);
}
/* Obtain the session pointer. */
return (rv);
/* Obtain the wrapping key object pointer. */
return (rv);
}
/*
* If the HW provider doesn't support C_UnwrapKey, we will try
* to emulate it in the library.
*/
&k_mi_flags);
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) &&
/* First allocate space for the recovered key value */
if (clear_key_val == NULL) {
goto failed_exit;
}
goto failed_exit;
}
goto failed_exit;
}
ulAttributeCount + 1);
if (newTemplate == NULL) {
goto failed_exit;
}
/* Now add the CKA_VALUE attribute to template */
/* Finally create the key, based on the new template */
(void) free(clear_key_val);
(void) free(newTemplate);
return (rv);
} else {
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.
*/
goto failed_exit;
}
/* Create an object wrapper for the new key in the library first */
goto failed_exit;
}
/* Process the attributes */
goto failed_exit;
}
/* Cannot create a token object with a READ-ONLY session. */
goto failed_exit;
}
/* Make the CRYPTO_UNWRAP_KEY ioctl call. */
break;
}
if (r < 0) {
} else {
}
goto failed_exit;
}
/* Get the CKA_PRIVATE value for the unwrapped key. */
&is_pri_obj);
goto failed_exit;
}
/*
* Store the kernel object handle in the new key object wrapper and
* initialize it.
*/
if (is_pri_obj)
else
if (is_token_obj)
else
/*
* 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) {
} else {
}
return (rv);
if (clear_key_val != NULL)
(void) free(clear_key_val);
if (newTemplate != NULL)
(void) free(newTemplate);
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
{
case CKK_EC:
count = 2;
goto out;
}
if (!base_key->is_lib_obj) {
goto out;
}
goto out;
}
/*
* Both public and private EC keys should have
* a CKA_EC_PARAMS attribute.
*/
/* get size of attribute */
goto out;
}
goto out;
}
goto out;
}
case CKO_PUBLIC_KEY:
break;
case CKO_PRIVATE_KEY:
break;
default:
goto out;
}
goto out;
}
goto out;
}
break;
case CKK_DH:
count = 3;
goto out;
}
if (!base_key->is_lib_obj) {
goto out;
}
goto out;
}
/* get size of attribute */
goto out;
}
goto out;
}
goto out;
}
/* get size of attribute */
goto out;
}
goto out;
}
goto out;
}
goto out;
}
goto out;
}
break;
default:
goto out;
}
return (CKR_OK);
out:
for (i = 0; i < count; i++) {
}
}
return (rv);
}
{
int r, n;
obj_ndk.ndk_in_count = 0;
obj_ndk.ndk_out_count = 0;
goto failed_exit;
}
goto failed_exit;
}
if (!has_class)
attr_count++;
if (newTemplate == NULL) {
goto failed_exit;
}
n = ulAttributeCount;
if (!has_class) {
n++;
}
/* Add CKA_VALUE to the template */
goto failed_exit;
}
goto failed_exit;
}
/* Cannot create a token object with a READ-ONLY session. */
goto failed_exit;
}
/*
* Obtain the attributes of base key and pass them by value.
*/
goto failed_exit;
}
&obj_ndk)) < 0) {
break;
}
if (r < 0) {
} else {
}
goto failed_exit;
}
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
if (rv != CRYPTO_SUCCESS) {
goto failed_exit;
}
return (CKR_OK);
if (newTemplate != NULL)
return (rv);
}
{
int r;
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
/* Obtain the session pointer. */
return (rv);
if (pMechanism == NULL) {
return (CKR_ARGUMENTS_BAD);
}
return (CKR_ARGUMENTS_BAD);
}
/* Obtain the base key object pointer. */
return (rv);
}
/* Get the kernel's internal mechanism number. */
goto failed_exit;
}
/* Create an object wrapper in the library for the generated key. */
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.
*/
new_objp);
goto failed_exit;
} else {
goto failed_exit;
}
/* Cannot create a token object with a READ-ONLY session. */
goto failed_exit;
}
break;
}
if (r < 0) {
} else {
}
goto failed_exit;
}
/* Get the CKA_PRIVATE value for the derived key. */
&is_pri_obj);
goto failed_exit;
}
/*
* Store the kernel object handle into the new derived key
* object and finish the object initialization.
*/
if (is_pri_obj)
else
if (is_token_obj)
else
}
/*
* 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) {
} else {
}
return (rv);
}
return (rv);
}