view usr/src/lib/pkcs11/pkcs11_softtoken/common/softAttributeUtil.c @ 13622:e5889df1eaac

2077 lots of unreachable breaks in illumos gate Reviewed by: Dan McDonald <danmcd@nexenta.com> Reviewed by: Garrett D'Amore <garrett@damore.org> Approved by: Richard Lowe <richlowe@richlowe.net>
author Milan Jurik <milan.jurik@xylab.cz>
date Sat, 18 Feb 2012 19:52:02 +0100
parents eed00643bbdd
children
line wrap: on
line source

/*
 * 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.
 * Copyright 2012 Milan Jurik. All rights reserved.
 */

#include <stdlib.h>
#include <string.h>
#include <security/cryptoki.h>
#include <sys/crypto/common.h>
#include <arcfour.h>
#include <aes_impl.h>
#include <blowfish_impl.h>
#include <bignum.h>
#include <des_impl.h>
#include <rsa_impl.h>
#include "softGlobal.h"
#include "softObject.h"
#include "softSession.h"
#include "softKeystore.h"
#include "softKeystoreUtil.h"
#include "softCrypt.h"


/*
 * This attribute table is used by the soft_lookup_attr()
 * to validate the attributes.
 */
CK_ATTRIBUTE_TYPE attr_map[] = {
	CKA_PRIVATE,
	CKA_LABEL,
	CKA_APPLICATION,
	CKA_OBJECT_ID,
	CKA_CERTIFICATE_TYPE,
	CKA_ISSUER,
	CKA_SERIAL_NUMBER,
	CKA_AC_ISSUER,
	CKA_OWNER,
	CKA_ATTR_TYPES,
	CKA_SUBJECT,
	CKA_ID,
	CKA_SENSITIVE,
	CKA_START_DATE,
	CKA_END_DATE,
	CKA_MODULUS,
	CKA_MODULUS_BITS,
	CKA_PUBLIC_EXPONENT,
	CKA_PRIVATE_EXPONENT,
	CKA_PRIME_1,
	CKA_PRIME_2,
	CKA_EXPONENT_1,
	CKA_EXPONENT_2,
	CKA_COEFFICIENT,
	CKA_PRIME,
	CKA_SUBPRIME,
	CKA_BASE,
	CKA_EXTRACTABLE,
	CKA_LOCAL,
	CKA_NEVER_EXTRACTABLE,
	CKA_ALWAYS_SENSITIVE,
	CKA_MODIFIABLE,
	CKA_ECDSA_PARAMS,
	CKA_EC_PARAMS,
	CKA_EC_POINT,
	CKA_SECONDARY_AUTH,
	CKA_AUTH_PIN_FLAGS,
	CKA_HW_FEATURE_TYPE,
	CKA_RESET_ON_INIT,
	CKA_HAS_RESET
};

/*
 * attributes that exists only in public key objects
 * Note: some attributes may also exist in one or two
 *       other object classes, but they are also listed
 *       because not all object have them.
 */
CK_ATTRIBUTE_TYPE PUB_KEY_ATTRS[] =
{
	CKA_SUBJECT,
	CKA_ENCRYPT,
	CKA_WRAP,
	CKA_VERIFY,
	CKA_VERIFY_RECOVER,
	CKA_MODULUS,
	CKA_MODULUS_BITS,
	CKA_PUBLIC_EXPONENT,
	CKA_PRIME,
	CKA_SUBPRIME,
	CKA_BASE,
	CKA_TRUSTED,
	CKA_ECDSA_PARAMS,
	CKA_EC_PARAMS,
	CKA_EC_POINT
};

/*
 * attributes that exists only in private key objects
 * Note: some attributes may also exist in one or two
 *       other object classes, but they are also listed
 *       because not all object have them.
 */
CK_ATTRIBUTE_TYPE PRIV_KEY_ATTRS[] =
{
	CKA_DECRYPT,
	CKA_UNWRAP,
	CKA_SIGN,
	CKA_SIGN_RECOVER,
	CKA_MODULUS,
	CKA_PUBLIC_EXPONENT,
	CKA_PRIVATE_EXPONENT,
	CKA_PRIME,
	CKA_SUBPRIME,
	CKA_BASE,
	CKA_PRIME_1,
	CKA_PRIME_2,
	CKA_EXPONENT_1,
	CKA_EXPONENT_2,
	CKA_COEFFICIENT,
	CKA_VALUE_BITS,
	CKA_SUBJECT,
	CKA_SENSITIVE,
	CKA_EXTRACTABLE,
	CKA_NEVER_EXTRACTABLE,
	CKA_ALWAYS_SENSITIVE,
	CKA_EC_PARAMS
};

/*
 * attributes that exists only in secret key objects
 * Note: some attributes may also exist in one or two
 *       other object classes, but they are also listed
 *       because not all object have them.
 */
CK_ATTRIBUTE_TYPE SECRET_KEY_ATTRS[] =
{
	CKA_VALUE_LEN,
	CKA_ENCRYPT,
	CKA_DECRYPT,
	CKA_WRAP,
	CKA_UNWRAP,
	CKA_SIGN,
	CKA_VERIFY,
	CKA_SENSITIVE,
	CKA_EXTRACTABLE,
	CKA_NEVER_EXTRACTABLE,
	CKA_ALWAYS_SENSITIVE
};

/*
 * attributes that exists only in domain parameter objects
 * Note: some attributes may also exist in one or two
 *       other object classes, but they are also listed
 *       because not all object have them.
 */
CK_ATTRIBUTE_TYPE DOMAIN_ATTRS[] =
{
	CKA_PRIME,
	CKA_SUBPRIME,
	CKA_BASE,
	CKA_PRIME_BITS,
	CKA_SUBPRIME_BITS,
	CKA_SUB_PRIME_BITS
};

/*
 * attributes that exists only in hardware feature objects
 *
 */
CK_ATTRIBUTE_TYPE HARDWARE_ATTRS[] =
{
	CKA_HW_FEATURE_TYPE,
	CKA_RESET_ON_INIT,
	CKA_HAS_RESET
};

/*
 * attributes that exists only in certificate objects
 */
CK_ATTRIBUTE_TYPE CERT_ATTRS[] =
{
	CKA_CERTIFICATE_TYPE,
	CKA_TRUSTED,
	CKA_SUBJECT,
	CKA_ID,
	CKA_ISSUER,
	CKA_AC_ISSUER,
	CKA_SERIAL_NUMBER,
	CKA_OWNER,
	CKA_ATTR_TYPES
};


/*
 * Validate the attribute by using binary search algorithm.
 */
CK_RV
soft_lookup_attr(CK_ATTRIBUTE_TYPE type)
{

	size_t lower, middle, upper;

	lower = 0;
	upper = (sizeof (attr_map) / sizeof (CK_ATTRIBUTE_TYPE)) - 1;

	while (lower <= upper) {
		/* Always starts from middle. */
		middle = (lower + upper) / 2;

		if (type > attr_map[middle]) {
			/* Adjust the lower bound to upper half. */
			lower = middle + 1;
			continue;
		}

		if (type == attr_map[middle]) {
			/* Found it. */
			return (CKR_OK);
		}

		if (type < attr_map[middle]) {
			/* Adjust the upper bound to lower half. */
			upper = middle - 1;
			continue;
		}
	}

	/* Failed to find the matching attribute from the attribute table. */
	return (CKR_ATTRIBUTE_TYPE_INVALID);
}


/*
 * Validate the attribute by using the following search algorithm:
 *
 * 1) Search for the most frequently used attributes first.
 * 2) If not found, search for the usage-purpose attributes - these
 *    attributes have dense set of values, therefore compiler will
 *    optimize it with a branch table and branch to the appropriate
 *    case.
 * 3) If still not found, use binary search for the rest of the
 *    attributes in the attr_map[] table.
 */
CK_RV
soft_validate_attr(CK_ATTRIBUTE_PTR template, CK_ULONG ulAttrNum,
	CK_OBJECT_CLASS *class)
{

	CK_ULONG i;
	CK_RV rv = CKR_OK;

	for (i = 0; i < ulAttrNum; i++) {
		/* First tier search */
		switch (template[i].type) {
		case CKA_CLASS:
			*class = *((CK_OBJECT_CLASS*)template[i].pValue);
			break;
		case CKA_TOKEN:
			break;
		case CKA_KEY_TYPE:
			break;
		case CKA_VALUE:
			break;
		case CKA_VALUE_LEN:
			break;
		case CKA_VALUE_BITS:
			break;
		default:
			/* Second tier search */
			switch (template[i].type) {
			case CKA_ENCRYPT:
				break;
			case CKA_DECRYPT:
				break;
			case CKA_WRAP:
				break;
			case CKA_UNWRAP:
				break;
			case CKA_SIGN:
				break;
			case CKA_SIGN_RECOVER:
				break;
			case CKA_VERIFY:
				break;
			case CKA_VERIFY_RECOVER:
				break;
			case CKA_DERIVE:
				break;
			default:
				/* Third tier search */
				rv = soft_lookup_attr(template[i].type);
				if (rv != CKR_OK)
					return (rv);
				break;
			}
			break;
		}
	}
	return (rv);
}

static void
cleanup_cert_attr(cert_attr_t *attr)
{
	if (attr) {
		if (attr->value) {
			(void) memset(attr->value, 0, attr->length);
			free(attr->value);
		}
		attr->value = NULL;
		attr->length = 0;
	}
}

static CK_RV
copy_cert_attr(cert_attr_t *src_attr, cert_attr_t **dest_attr)
{
	CK_RV rv = CKR_OK;

	if (src_attr == NULL || dest_attr == NULL)
		return (CKR_HOST_MEMORY);

	if (src_attr->value == NULL)
		return (CKR_HOST_MEMORY);

	/* free memory if its already allocated */
	if (*dest_attr != NULL) {
		if ((*dest_attr)->value != (CK_BYTE *)NULL)
			free((*dest_attr)->value);
	} else {
		*dest_attr = malloc(sizeof (cert_attr_t));
		if (*dest_attr == NULL)
			return (CKR_HOST_MEMORY);
	}

	(*dest_attr)->value = NULL;
	(*dest_attr)->length = 0;

	if (src_attr->length) {
		(*dest_attr)->value = malloc(src_attr->length);
		if ((*dest_attr)->value == NULL) {
			free(*dest_attr);
			return (CKR_HOST_MEMORY);
		}

		(void) memcpy((*dest_attr)->value, src_attr->value,
		    src_attr->length);
		(*dest_attr)->length = src_attr->length;
	}

	return (rv);
}

void
soft_cleanup_cert_object(soft_object_t *object_p)
{
	CK_CERTIFICATE_TYPE certtype = object_p->cert_type;

	if (object_p->class != CKO_CERTIFICATE ||
	    OBJ_CERT(object_p) == NULL)
		return;

	if (certtype == CKC_X_509) {
		if (X509_CERT_SUBJECT(object_p) != NULL) {
			cleanup_cert_attr(X509_CERT_SUBJECT(object_p));
			free(X509_CERT_SUBJECT(object_p));
			X509_CERT_SUBJECT(object_p) = NULL;
		}
		if (X509_CERT_VALUE(object_p) != NULL) {
			cleanup_cert_attr(X509_CERT_VALUE(object_p));
			free(X509_CERT_VALUE(object_p));
			X509_CERT_VALUE(object_p) = NULL;
		}
		free(OBJ_CERT(object_p));
	} else if (certtype == CKC_X_509_ATTR_CERT) {
		if (X509_ATTR_CERT_VALUE(object_p) != NULL) {
			cleanup_cert_attr(X509_ATTR_CERT_VALUE(object_p));
			free(X509_ATTR_CERT_VALUE(object_p));
			X509_ATTR_CERT_VALUE(object_p) = NULL;
		}
		if (X509_ATTR_CERT_OWNER(object_p) != NULL) {
			cleanup_cert_attr(X509_ATTR_CERT_OWNER(object_p));
			free(X509_ATTR_CERT_OWNER(object_p));
			X509_ATTR_CERT_OWNER(object_p) = NULL;
		}
		free(OBJ_CERT(object_p));
	}
}

/*
 * Clean up and release all the storage in the extra attribute list
 * of an object.
 */
void
soft_cleanup_extra_attr(soft_object_t *object_p)
{

	CK_ATTRIBUTE_INFO_PTR extra_attr;
	CK_ATTRIBUTE_INFO_PTR tmp;

	extra_attr = object_p->extra_attrlistp;
	while (extra_attr) {
		tmp = extra_attr->next;
		if (extra_attr->attr.pValue)
			/*
			 * All extra attributes in the extra attribute
			 * list have pValue points to the value of the
			 * attribute (with simple byte array type).
			 * Free the storage for the value of the attribute.
			 */
			free(extra_attr->attr.pValue);

		/* Free the storage for the attribute_info struct. */
		free(extra_attr);
		extra_attr = tmp;
	}

	object_p->extra_attrlistp = NULL;
}


/*
 * Create the attribute_info struct to hold the object's attribute,
 * and add it to the extra attribute list of an object.
 */
CK_RV
soft_add_extra_attr(CK_ATTRIBUTE_PTR template, soft_object_t *object_p)
{

	CK_ATTRIBUTE_INFO_PTR attrp;

	/* Allocate the storage for the attribute_info struct. */
	attrp = calloc(1, sizeof (attribute_info_t));
	if (attrp == NULL) {
		return (CKR_HOST_MEMORY);
	}

	/* Set up attribute_info struct. */
	attrp->attr.type = template->type;
	attrp->attr.ulValueLen = template->ulValueLen;

	if ((template->pValue != NULL) &&
	    (template->ulValueLen > 0)) {
		/* Allocate storage for the value of the attribute. */
		attrp->attr.pValue = malloc(template->ulValueLen);
		if (attrp->attr.pValue == NULL) {
			free(attrp);
			return (CKR_HOST_MEMORY);
		}

		(void) memcpy(attrp->attr.pValue, template->pValue,
		    template->ulValueLen);
	} else {
		attrp->attr.pValue = NULL;
	}

	/* Insert the new attribute in front of extra attribute list. */
	if (object_p->extra_attrlistp == NULL) {
		object_p->extra_attrlistp = attrp;
		attrp->next = NULL;
	} else {
		attrp->next = object_p->extra_attrlistp;
		object_p->extra_attrlistp = attrp;
	}

	return (CKR_OK);
}

CK_RV
soft_copy_certificate(certificate_obj_t *oldcert, certificate_obj_t **newcert,
		CK_CERTIFICATE_TYPE type)
{
	CK_RV rv = CKR_OK;
	certificate_obj_t	*cert;
	x509_cert_t		x509;
	x509_attr_cert_t	x509_attr;

	cert = calloc(1, sizeof (certificate_obj_t));
	if (cert == NULL) {
		return (CKR_HOST_MEMORY);
	}

	if (type == CKC_X_509) {
		x509 = oldcert->cert_type_u.x509;
		if (x509.subject)
			if ((rv = copy_cert_attr(x509.subject,
			    &cert->cert_type_u.x509.subject)))
				return (rv);
		if (x509.value)
			if ((rv = copy_cert_attr(x509.value,
			    &cert->cert_type_u.x509.value)))
				return (rv);
	} else if (type == CKC_X_509_ATTR_CERT) {
		x509_attr = oldcert->cert_type_u.x509_attr;
		if (x509_attr.owner)
			if ((rv = copy_cert_attr(x509_attr.owner,
			    &cert->cert_type_u.x509_attr.owner)))
				return (rv);
		if (x509_attr.value)
			if ((rv = copy_cert_attr(x509_attr.value,
			    &cert->cert_type_u.x509_attr.value)))
				return (rv);
	} else {
		/* wrong certificate type */
		rv = CKR_ATTRIBUTE_TYPE_INVALID;
	}
	if (rv == CKR_OK)
		*newcert = cert;
	return (rv);
}

/*
 * Copy the attribute_info struct from the old object to a new attribute_info
 * struct, and add that new struct to the extra attribute list of the new
 * object.
 */
CK_RV
soft_copy_extra_attr(CK_ATTRIBUTE_INFO_PTR old_attrp, soft_object_t *object_p)
{
	CK_ATTRIBUTE_INFO_PTR attrp;

	/* Allocate attribute_info struct. */
	attrp = calloc(1, sizeof (attribute_info_t));
	if (attrp == NULL) {
		return (CKR_HOST_MEMORY);
	}

	attrp->attr.type = old_attrp->attr.type;
	attrp->attr.ulValueLen = old_attrp->attr.ulValueLen;

	if ((old_attrp->attr.pValue != NULL) &&
	    (old_attrp->attr.ulValueLen > 0)) {
		attrp->attr.pValue = malloc(old_attrp->attr.ulValueLen);
		if (attrp->attr.pValue == NULL) {
			free(attrp);
			return (CKR_HOST_MEMORY);
		}

		(void) memcpy(attrp->attr.pValue, old_attrp->attr.pValue,
		    old_attrp->attr.ulValueLen);
	} else {
		attrp->attr.pValue = NULL;
	}

	/* Insert the new attribute in front of extra attribute list */
	if (object_p->extra_attrlistp == NULL) {
		object_p->extra_attrlistp = attrp;
		attrp->next = NULL;
	} else {
		attrp->next = object_p->extra_attrlistp;
		object_p->extra_attrlistp = attrp;
	}

	return (CKR_OK);
}


/*
 * Get the attribute triple from the extra attribute list in the object
 * (if the specified attribute type is found), and copy it to a template.
 * Note the type of the attribute to be copied is specified by the template,
 * and the storage is pre-allocated for the atrribute value in the template
 * for doing the copy.
 */
CK_RV
get_extra_attr_from_object(soft_object_t *object_p, CK_ATTRIBUTE_PTR template)
{

	CK_ATTRIBUTE_INFO_PTR extra_attr;
	CK_ATTRIBUTE_TYPE type = template->type;

	extra_attr = object_p->extra_attrlistp;

	while (extra_attr) {
		if (type == extra_attr->attr.type) {
			/* Found it. */
			break;
		} else {
			/* Does not match, try next one. */
			extra_attr = extra_attr->next;
		}
	}

	if (extra_attr == NULL) {
		/* A valid but un-initialized attribute. */
		template->ulValueLen = 0;
		return (CKR_OK);
	}

	/*
	 * We found the attribute in the extra attribute list.
	 */
	if (template->pValue == NULL) {
		template->ulValueLen = extra_attr->attr.ulValueLen;
		return (CKR_OK);
	}

	if (template->ulValueLen >= extra_attr->attr.ulValueLen) {
		/*
		 * The buffer provided by the application is large
		 * enough to hold the value of the attribute.
		 */
		(void) memcpy(template->pValue, extra_attr->attr.pValue,
		    extra_attr->attr.ulValueLen);
		template->ulValueLen = extra_attr->attr.ulValueLen;
		return (CKR_OK);
	} else {
		/*
		 * The buffer provided by the application does
		 * not have enough space to hold the value.
		 */
		template->ulValueLen = (CK_ULONG)-1;
		return (CKR_BUFFER_TOO_SMALL);
	}
}


/*
 * Modify the attribute triple in the extra attribute list of the object
 * if the specified attribute type is found. Otherwise, just add it to
 * list.
 */
CK_RV
set_extra_attr_to_object(soft_object_t *object_p, CK_ATTRIBUTE_TYPE type,
	CK_ATTRIBUTE_PTR template)
{

	CK_ATTRIBUTE_INFO_PTR extra_attr;

	extra_attr = object_p->extra_attrlistp;

	while (extra_attr) {
		if (type == extra_attr->attr.type) {
			/* Found it. */
			break;
		} else {
			/* Does not match, try next one. */
			extra_attr = extra_attr->next;
		}
	}

	if (extra_attr == NULL) {
		/*
		 * This attribute is a new one, go ahead adding it to
		 * the extra attribute list.
		 */
		return (soft_add_extra_attr(template, object_p));
	}

	/* We found the attribute in the extra attribute list. */
	if ((template->pValue != NULL) &&
	    (template->ulValueLen > 0)) {
		if (template->ulValueLen > extra_attr->attr.ulValueLen) {
			/* The old buffer is too small to hold the new value. */
			if (extra_attr->attr.pValue != NULL)
				/* Free storage for the old attribute value. */
				free(extra_attr->attr.pValue);

			/* Allocate storage for the new attribute value. */
			extra_attr->attr.pValue = malloc(template->ulValueLen);
			if (extra_attr->attr.pValue == NULL) {
				return (CKR_HOST_MEMORY);
			}
		}

		/* Replace the attribute with new value. */
		extra_attr->attr.ulValueLen = template->ulValueLen;
		(void) memcpy(extra_attr->attr.pValue, template->pValue,
		    template->ulValueLen);
	} else {
		extra_attr->attr.pValue = NULL;
	}

	return (CKR_OK);
}


/*
 * Copy the big integer attribute value from template to a biginteger_t struct.
 */
CK_RV
get_bigint_attr_from_template(biginteger_t *big, CK_ATTRIBUTE_PTR template)
{

	if ((template->pValue != NULL) &&
	    (template->ulValueLen > 0)) {
		/* Allocate storage for the value of the attribute. */
		big->big_value = malloc(template->ulValueLen);
		if (big->big_value == NULL) {
			return (CKR_HOST_MEMORY);
		}

		(void) memcpy(big->big_value, template->pValue,
		    template->ulValueLen);
		big->big_value_len = template->ulValueLen;
	} else {
		big->big_value = NULL;
		big->big_value_len = 0;
	}

	return (CKR_OK);
}


/*
 * Copy the big integer attribute value from a biginteger_t struct in the
 * object to a template.
 */
CK_RV
get_bigint_attr_from_object(biginteger_t *big, CK_ATTRIBUTE_PTR template)
{

	if (template->pValue == NULL) {
		template->ulValueLen = big->big_value_len;
		return (CKR_OK);
	}

	if (big->big_value == NULL) {
		template->ulValueLen = 0;
		return (CKR_OK);
	}

	if (template->ulValueLen >= big->big_value_len) {
		/*
		 * The buffer provided by the application is large
		 * enough to hold the value of the attribute.
		 */
		(void) memcpy(template->pValue, big->big_value,
		    big->big_value_len);
		template->ulValueLen = big->big_value_len;
		return (CKR_OK);
	} else {
		/*
		 * The buffer provided by the application does
		 * not have enough space to hold the value.
		 */
		template->ulValueLen = (CK_ULONG)-1;
		return (CKR_BUFFER_TOO_SMALL);
	}
}


/*
 * Copy the boolean data type attribute value from an object for the
 * specified attribute to the template.
 */
CK_RV
get_bool_attr_from_object(soft_object_t *object_p, CK_ULONG bool_flag,
	CK_ATTRIBUTE_PTR template)
{

	if (template->pValue == NULL) {
		template->ulValueLen = sizeof (CK_BBOOL);
		return (CKR_OK);
	}

	if (template->ulValueLen >= sizeof (CK_BBOOL)) {
		/*
		 * The buffer provided by the application is large
		 * enough to hold the value of the attribute.
		 */
		if (object_p->bool_attr_mask & bool_flag) {
			*((CK_BBOOL *)template->pValue) = B_TRUE;
		} else {
			*((CK_BBOOL *)template->pValue) = B_FALSE;
		}

		template->ulValueLen = sizeof (CK_BBOOL);
		return (CKR_OK);
	} else {
		/*
		 * The buffer provided by the application does
		 * not have enough space to hold the value.
		 */
		template->ulValueLen = (CK_ULONG)-1;
		return (CKR_BUFFER_TOO_SMALL);
	}
}

/*
 * Set the boolean data type attribute value in the object.
 */
CK_RV
set_bool_attr_to_object(soft_object_t *object_p, CK_ULONG bool_flag,
	CK_ATTRIBUTE_PTR template)
{

	if (*(CK_BBOOL *)template->pValue)
		object_p->bool_attr_mask |= bool_flag;
	else
		object_p->bool_attr_mask &= ~bool_flag;

	return (CKR_OK);
}


/*
 * Copy the CK_ULONG data type attribute value from an object to the
 * template.
 */
CK_RV
get_ulong_attr_from_object(CK_ULONG value, CK_ATTRIBUTE_PTR template)
{

	if (template->pValue == NULL) {
		template->ulValueLen = sizeof (CK_ULONG);
		return (CKR_OK);
	}

	if (template->ulValueLen >= sizeof (CK_ULONG)) {
		/*
		 * The buffer provided by the application is large
		 * enough to hold the value of the attribute.
		 * It is also assumed to be correctly aligned.
		 */
		*(CK_ULONG_PTR)template->pValue = value;
		template->ulValueLen = sizeof (CK_ULONG);
		return (CKR_OK);
	} else {
		/*
		 * The buffer provided by the application does
		 * not have enough space to hold the value.
		 */
		template->ulValueLen = (CK_ULONG)-1;
		return (CKR_BUFFER_TOO_SMALL);
	}
}


/*
 * Copy the CK_ULONG data type attribute value from a template to the
 * object.
 */
static CK_RV
get_ulong_attr_from_template(CK_ULONG *value, CK_ATTRIBUTE_PTR template)
{

	if (template->ulValueLen < sizeof (CK_ULONG))
		return (CKR_ATTRIBUTE_VALUE_INVALID);

	if (template->pValue != NULL) {
		*value = *(CK_ULONG_PTR)template->pValue;
	} else {
		*value = 0;
	}

	return (CKR_OK);
}

/*
 * Copy the big integer attribute value from source's biginteger_t to
 * destination's biginteger_t.
 */
void
copy_bigint_attr(biginteger_t *src, biginteger_t *dst)
{

	if ((src->big_value != NULL) &&
	    (src->big_value_len > 0)) {
		/*
		 * To do the copy, just have dst's big_value points
		 * to src's.
		 */
		dst->big_value = src->big_value;
		dst->big_value_len = src->big_value_len;

		/*
		 * After the copy, nullify the src's big_value pointer.
		 * It prevents any double freeing the value.
		 */
		src->big_value = NULL;
		src->big_value_len = 0;
	} else {
		dst->big_value = NULL;
		dst->big_value_len = 0;
	}
}

CK_RV
get_string_from_template(CK_ATTRIBUTE_PTR dest, CK_ATTRIBUTE_PTR src)
{
	if ((src->pValue != NULL) &&
	    (src->ulValueLen > 0)) {
		/* Allocate storage for the value of the attribute. */
		dest->pValue = malloc(src->ulValueLen);
		if (dest->pValue == NULL) {
			return (CKR_HOST_MEMORY);
		}

		(void) memcpy(dest->pValue, src->pValue,
		    src->ulValueLen);
		dest->ulValueLen = src->ulValueLen;
		dest->type = src->type;
	} else {
		dest->pValue = NULL;
		dest->ulValueLen = 0;
		dest->type = src->type;
	}

	return (CKR_OK);

}

CK_RV
get_cert_attr_from_template(cert_attr_t **dest, CK_ATTRIBUTE_PTR src)
{
	if (src->pValue != NULL && src->ulValueLen > 0) {
		/*
		 * If the attribute was already set, clear out the
		 * existing value and release the memory.
		 */
		if (*dest != NULL) {
			if ((*dest)->value != NULL) {
				(void) memset((*dest)->value, 0,
				    (*dest)->length);
				free((*dest)->value);
			}
		} else {
			*dest = malloc(sizeof (cert_attr_t));
			if (*dest == NULL) {
				return (CKR_HOST_MEMORY);
			}
			(void) memset(*dest, 0, sizeof (cert_attr_t));
		}
		(*dest)->value = malloc(src->ulValueLen);
		if ((*dest)->value == NULL) {
			free(*dest);
			*dest = NULL;
			return (CKR_HOST_MEMORY);
		}
		(void) memcpy((*dest)->value, src->pValue, src->ulValueLen);
		(*dest)->length = src->ulValueLen;
	}

	return (CKR_OK);
}

/*
 * Copy the certificate attribute information to the template.
 * If the template attribute is not big enough, set the ulValueLen=-1
 * and return CKR_BUFFER_TOO_SMALL.
 */
static CK_RV
get_cert_attr_from_object(cert_attr_t *src, CK_ATTRIBUTE_PTR template)
{
	if (template->pValue == NULL) {
		template->ulValueLen = src->length;
		return (CKR_OK);
	} else if (template->ulValueLen >= src->length) {
		/*
		 * The buffer provided by the application is large
		 * enough to hold the value of the attribute.
		 */
		(void) memcpy(template->pValue, src->value, src->length);
		template->ulValueLen = src->length;
		return (CKR_OK);
	} else {
		/*
		 * The buffer provided by the application does
		 * not have enough space to hold the value.
		 */
		template->ulValueLen = (CK_ULONG)-1;
		return (CKR_BUFFER_TOO_SMALL);
	}
}

void
string_attr_cleanup(CK_ATTRIBUTE_PTR template)
{

	if (template->pValue) {
		free(template->pValue);
		template->pValue = NULL;
		template->ulValueLen = 0;
	}
}

/*
 * Release the storage allocated for object attribute with big integer
 * value.
 */
void
bigint_attr_cleanup(biginteger_t *big)
{

	if (big == NULL)
		return;

	if (big->big_value) {
		(void) memset(big->big_value, 0, big->big_value_len);
		free(big->big_value);
		big->big_value = NULL;
		big->big_value_len = 0;
	}
}


/*
 * Clean up and release all the storage allocated to hold the big integer
 * attributes associated with the type (i.e. class) of the object. Also,
 * release the storage allocated to the type of the object.
 */
void
soft_cleanup_object_bigint_attrs(soft_object_t *object_p)
{

	CK_OBJECT_CLASS class = object_p->class;
	CK_KEY_TYPE	keytype = object_p->key_type;


	switch (class) {
	case CKO_PUBLIC_KEY:
		if (OBJ_PUB(object_p)) {
			switch (keytype) {
			case CKK_RSA:
				bigint_attr_cleanup(OBJ_PUB_RSA_MOD(
				    object_p));
				bigint_attr_cleanup(OBJ_PUB_RSA_PUBEXPO(
				    object_p));
				break;

			case CKK_DSA:
				bigint_attr_cleanup(OBJ_PUB_DSA_PRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_PUB_DSA_SUBPRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_PUB_DSA_BASE(
				    object_p));
				bigint_attr_cleanup(OBJ_PUB_DSA_VALUE(
				    object_p));
				break;

			case CKK_DH:
				bigint_attr_cleanup(OBJ_PUB_DH_PRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_PUB_DH_BASE(
				    object_p));
				bigint_attr_cleanup(OBJ_PUB_DH_VALUE(
				    object_p));
				break;

			case CKK_X9_42_DH:
				bigint_attr_cleanup(OBJ_PUB_DH942_PRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_PUB_DH942_BASE(
				    object_p));
				bigint_attr_cleanup(OBJ_PUB_DH942_SUBPRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_PUB_DH942_VALUE(
				    object_p));
				break;
			case CKK_EC:
				bigint_attr_cleanup(OBJ_PUB_EC_POINT(
				    object_p));
				break;
			}

			/* Release Public Key Object struct */
			free(OBJ_PUB(object_p));
			OBJ_PUB(object_p) = NULL;
		}
		break;

	case CKO_PRIVATE_KEY:
		if (OBJ_PRI(object_p)) {
			switch (keytype) {
			case CKK_RSA:
				bigint_attr_cleanup(OBJ_PRI_RSA_MOD(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_RSA_PUBEXPO(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_RSA_PRIEXPO(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_RSA_PRIME1(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_RSA_PRIME2(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_RSA_EXPO1(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_RSA_EXPO2(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_RSA_COEF(
				    object_p));
				break;

			case CKK_DSA:
				bigint_attr_cleanup(OBJ_PRI_DSA_PRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_DSA_SUBPRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_DSA_BASE(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_DSA_VALUE(
				    object_p));
				break;

			case CKK_DH:
				bigint_attr_cleanup(OBJ_PRI_DH_PRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_DH_BASE(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_DH_VALUE(
				    object_p));
				break;

			case CKK_X9_42_DH:
				bigint_attr_cleanup(OBJ_PRI_DH942_PRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_DH942_BASE(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_DH942_SUBPRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_PRI_DH942_VALUE(
				    object_p));
				break;

			case CKK_EC:
				bigint_attr_cleanup(OBJ_PRI_EC_VALUE(
				    object_p));
				break;
			}

			/* Release Private Key Object struct. */
			free(OBJ_PRI(object_p));
			OBJ_PRI(object_p) = NULL;
		}
		break;

	case CKO_SECRET_KEY:
		if (OBJ_SEC(object_p)) {
			/* cleanup key data area */
			if (OBJ_SEC_VALUE(object_p) != NULL &&
			    OBJ_SEC_VALUE_LEN(object_p) > 0) {
				(void) memset(OBJ_SEC_VALUE(object_p), 0,
				    OBJ_SEC_VALUE_LEN(object_p));
				free(OBJ_SEC_VALUE(object_p));
			}
			/* cleanup key schedule data area */
			if (OBJ_KEY_SCHED(object_p) != NULL &&
			    OBJ_KEY_SCHED_LEN(object_p) > 0) {
				(void) memset(OBJ_KEY_SCHED(object_p), 0,
				    OBJ_KEY_SCHED_LEN(object_p));
				free(OBJ_KEY_SCHED(object_p));
			}

			/* Release Secret Key Object struct. */
			free(OBJ_SEC(object_p));
			OBJ_SEC(object_p) = NULL;
		}
		break;

	case CKO_DOMAIN_PARAMETERS:
		if (OBJ_DOM(object_p)) {
			switch (keytype) {
			case CKK_DSA:
				bigint_attr_cleanup(OBJ_DOM_DSA_PRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_DOM_DSA_SUBPRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_DOM_DSA_BASE(
				    object_p));
				break;

			case CKK_DH:
				bigint_attr_cleanup(OBJ_DOM_DH_PRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_DOM_DH_BASE(
				    object_p));
				break;

			case CKK_X9_42_DH:
				bigint_attr_cleanup(OBJ_DOM_DH942_PRIME(
				    object_p));
				bigint_attr_cleanup(OBJ_DOM_DH942_BASE(
				    object_p));
				bigint_attr_cleanup(OBJ_DOM_DH942_SUBPRIME(
				    object_p));
				break;
			}

			/* Release Domain Parameters Object struct. */
			free(OBJ_DOM(object_p));
			OBJ_DOM(object_p) = NULL;
		}
		break;
	}
}


/*
 * Parse the common attributes. Return to caller with appropriate return
 * value to indicate if the supplied template specifies a valid attribute
 * with a valid value.
 */
CK_RV
soft_parse_common_attrs(CK_ATTRIBUTE_PTR template, uchar_t *object_type)
{

	CK_RV rv = CKR_OK;

	switch (template->type) {
	case CKA_CLASS:
		break;

	/* default boolean attributes */
	case CKA_TOKEN:
		if ((*(CK_BBOOL *)template->pValue) == B_TRUE) {
			if (!soft_keystore_status(KEYSTORE_INITIALIZED))
				return (CKR_DEVICE_REMOVED);
			*object_type |= TOKEN_OBJECT;
		}
		break;

	case CKA_PRIVATE:
		if ((*(CK_BBOOL *)template->pValue) == B_TRUE) {
			(void) pthread_mutex_lock(&soft_giant_mutex);
			if (!soft_slot.authenticated) {
				/*
				 * Check if this is the special case when
				 * the PIN is never initialized in the keystore.
				 * If true, we will let it pass here and let
				 * it fail with CKR_PIN_EXPIRED later on.
				 */
				if (!soft_slot.userpin_change_needed) {
					(void) pthread_mutex_unlock(
					    &soft_giant_mutex);
					return (CKR_USER_NOT_LOGGED_IN);
				}
			}
			(void) pthread_mutex_unlock(&soft_giant_mutex);
			*object_type |= PRIVATE_OBJECT;
		}
		break;

	case CKA_LABEL:
		break;

	default:
		rv = CKR_TEMPLATE_INCONSISTENT;
	}

	return (rv);
}


/*
 * Build a Public Key Object.
 *
 * - Parse the object's template, and when an error is detected such as
 *   invalid attribute type, invalid attribute value, etc., return
 *   with appropriate return value.
 * - Set up attribute mask field in the object for the supplied common
 *   attributes that have boolean type.
 * - Build the attribute_info struct to hold the value of each supplied
 *   attribute that has byte array type. Link attribute_info structs
 *   together to form the extra attribute list of the object.
 * - Allocate storage for the Public Key object.
 * - Build the Public Key object according to the key type. Allocate
 *   storage to hold the big integer value for the supplied attributes
 *   that are required for a certain key type.
 *
 */
CK_RV
soft_build_public_key_object(CK_ATTRIBUTE_PTR template, CK_ULONG ulAttrNum,
	soft_object_t *new_object, CK_ULONG mode, CK_KEY_TYPE key_type)
{

	ulong_t		i;
	CK_KEY_TYPE	keytype = (CK_KEY_TYPE)~0UL;
	uint64_t	attr_mask = PUBLIC_KEY_DEFAULT;
	CK_RV 		rv = CKR_OK;
	int		isLabel = 0;
	/* Must set flags */
	int		isModulus = 0;
	int		isPubExpo = 0;
	int		isPrime = 0;
	int		isSubprime = 0;
	int		isBase = 0;
	int		isValue = 0;
	int		isECParam = 0;
	int		isECPoint = 0;
	/* Must not set flags */
	int		isModulusBits = 0;
	CK_ULONG	modulus_bits = 0;

	biginteger_t	modulus;
	biginteger_t	pubexpo;
	biginteger_t	prime;
	biginteger_t	subprime;
	biginteger_t	base;
	biginteger_t	value;
	biginteger_t	point;
	CK_ATTRIBUTE	string_tmp;
	CK_ATTRIBUTE	param_tmp;

	public_key_obj_t  *pbk;
	uchar_t	object_type = 0;

	CK_ATTRIBUTE	defpubexpo = { CKA_PUBLIC_EXPONENT,
	    (CK_BYTE_PTR)DEFAULT_PUB_EXPO, DEFAULT_PUB_EXPO_Len };

	BIGNUM		n;

	/* prevent bigint_attr_cleanup from freeing invalid attr value */
	(void) memset(&modulus, 0x0, sizeof (biginteger_t));
	(void) memset(&pubexpo, 0x0, sizeof (biginteger_t));
	(void) memset(&prime, 0x0, sizeof (biginteger_t));
	(void) memset(&subprime, 0x0, sizeof (biginteger_t));
	(void) memset(&base, 0x0, sizeof (biginteger_t));
	(void) memset(&value, 0x0, sizeof (biginteger_t));
	(void) memset(&point, 0x0, sizeof (biginteger_t));
	string_tmp.pValue = NULL;
	param_tmp.pValue = NULL;

	for (i = 0; i < ulAttrNum; i++) {

		/* Public Key Object Attributes */
		switch (template[i].type) {

		/* common key attributes */
		case CKA_KEY_TYPE:
			keytype = *((CK_KEY_TYPE*)template[i].pValue);
			break;

		case CKA_ID:
		case CKA_START_DATE:
		case CKA_END_DATE:

		/* common public key attribute */
		case CKA_SUBJECT:
			/*
			 * Allocate storage to hold the attribute
			 * value with byte array type, and add it to
			 * the extra attribute list of the object.
			 */
			rv = soft_add_extra_attr(&template[i],
			    new_object);
			if (rv != CKR_OK) {
				goto fail_cleanup;
			}
			break;

		/*
		 * The following key related attribute types must
		 * not be specified by C_CreateObject, C_GenerateKey(Pair).
		 */
		case CKA_LOCAL:
		case CKA_KEY_GEN_MECHANISM:
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;

		/* Key related boolean attributes */
		case CKA_DERIVE:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= DERIVE_BOOL_ON;
			break;

		case CKA_ENCRYPT:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= ENCRYPT_BOOL_ON;
			else
				attr_mask &= ~ENCRYPT_BOOL_ON;
			break;

		case CKA_VERIFY:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= VERIFY_BOOL_ON;
			else
				attr_mask &= ~VERIFY_BOOL_ON;
			break;

		case CKA_VERIFY_RECOVER:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= VERIFY_RECOVER_BOOL_ON;
			else
				attr_mask &= ~VERIFY_RECOVER_BOOL_ON;
			break;

		case CKA_WRAP:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= WRAP_BOOL_ON;
			else
				attr_mask &= ~WRAP_BOOL_ON;
			break;

		case CKA_TRUSTED:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= TRUSTED_BOOL_ON;
			break;

		case CKA_MODIFIABLE:
			if ((*(CK_BBOOL *)template[i].pValue) == B_FALSE)
				attr_mask |= NOT_MODIFIABLE_BOOL_ON;
			break;

		/*
		 * The following key related attribute types must
		 * be specified according to the key type by
		 * C_CreateObject.
		 */
		case CKA_MODULUS:

			isModulus = 1;
			/*
			 * Copyin big integer attribute from template
			 * to a local variable.
			 */
			rv = get_bigint_attr_from_template(&modulus,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;

			/*
			 * Modulus length needs to be between min key length and
			 * max key length.
			 */
			if ((modulus.big_value_len <
			    MIN_RSA_KEYLENGTH_IN_BYTES) ||
			    (modulus.big_value_len >
			    MAX_RSA_KEYLENGTH_IN_BYTES)) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}
			break;

		case CKA_PUBLIC_EXPONENT:
			isPubExpo = 1;
			rv = get_bigint_attr_from_template(&pubexpo,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_PRIME:
			isPrime = 1;
			rv = get_bigint_attr_from_template(&prime,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_SUBPRIME:
			isSubprime = 1;
			rv = get_bigint_attr_from_template(&subprime,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_BASE:
			isBase = 1;
			rv = get_bigint_attr_from_template(&base,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_VALUE:
			isValue = 1;
			if (mode == SOFT_CREATE_OBJ) {
				if ((template[i].ulValueLen == 0) ||
				    (template[i].pValue == NULL)) {
					rv = CKR_ATTRIBUTE_VALUE_INVALID;
					goto fail_cleanup;
				}
			}

			rv = get_bigint_attr_from_template(&value,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_MODULUS_BITS:
			isModulusBits = 1;
			rv = get_ulong_attr_from_template(&modulus_bits,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_LABEL:
			isLabel = 1;
			rv = get_string_from_template(&string_tmp,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_EC_PARAMS:
			isECParam = 1;
			rv = get_string_from_template(&param_tmp, &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_EC_POINT:
			isECPoint = 1;
			rv = get_bigint_attr_from_template(&point,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		default:
			rv = soft_parse_common_attrs(&template[i],
			    &object_type);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;
		}
	} /* For */

	/* Allocate storage for Public Key Object. */
	pbk = calloc(1, sizeof (public_key_obj_t));
	if (pbk == NULL) {
		rv = CKR_HOST_MEMORY;
		goto fail_cleanup;
	}

	new_object->object_class_u.public_key = pbk;
	new_object->class = CKO_PUBLIC_KEY;

	if ((mode == SOFT_CREATE_OBJ) && (keytype == (CK_KEY_TYPE)~0UL)) {
		rv = CKR_TEMPLATE_INCOMPLETE;
		goto fail_cleanup;
	}

	if ((mode == SOFT_GEN_KEY) && (keytype == (CK_KEY_TYPE)~0UL)) {
		keytype = key_type;
	}

	if ((mode == SOFT_GEN_KEY) && (keytype != key_type)) {
		/*
		 * The key type specified in the template does not
		 * match the implied key type based on the mechanism.
		 */
		rv = CKR_TEMPLATE_INCONSISTENT;
		goto fail_cleanup;
	}

	new_object->key_type = keytype;

	/* Supported key types of the Public Key Object */
	switch (keytype) {

	case CKK_RSA:
		if (mode == SOFT_CREATE_OBJ) {
			if (isModulusBits || isPrime || isSubprime ||
			    isBase || isValue) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}

			if (isModulus && isPubExpo) {
				/*
				 * Derive modulus_bits attribute from modulus.
				 * Save modulus_bits integer value to the
				 * designated place in the public key object.
				 */
				n.malloced = 0;
#ifdef  __sparcv9
				if (big_init(&n, (int)CHARLEN2BIGNUMLEN(
				    modulus.big_value_len)) != BIG_OK) {
#else   /* !__sparcv9 */
				if (big_init(&n, CHARLEN2BIGNUMLEN(
				    modulus.big_value_len)) != BIG_OK) {
#endif  /* __sparcv9 */
					rv = CKR_HOST_MEMORY;
					big_finish(&n);
					goto fail_cleanup;
				}
				bytestring2bignum(&n, modulus.big_value,
				    modulus.big_value_len);

				modulus_bits = big_bitlength(&n);
				KEY_PUB_RSA_MOD_BITS(pbk) = modulus_bits;
				big_finish(&n);

				/*
				 * After modulus_bits has been computed,
				 * it is safe to move modulus and pubexpo
				 * big integer attribute value to the
				 * designated place in the public key object.
				 */
				copy_bigint_attr(&modulus,
				    KEY_PUB_RSA_MOD(pbk));

				copy_bigint_attr(&pubexpo,
				    KEY_PUB_RSA_PUBEXPO(pbk));
			} else {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
		} else {
			/* mode is SOFT_GEN_KEY */

			if (isModulus || isPrime || isSubprime ||
			    isBase || isValue) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}


			if (isModulusBits) {
				/*
				 * Copy big integer attribute value to the
				 * designated place in the public key object.
				 */
				KEY_PUB_RSA_MOD_BITS(pbk) = modulus_bits;
			} else {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}

			/*
			 * Use PKCS#11 default 0x010001 for public exponent
			 * if not not specified in attribute template.
			 */
			if (!isPubExpo) {
				isPubExpo = 1;
				rv = get_bigint_attr_from_template(&pubexpo,
				    &defpubexpo);
				if (rv != CKR_OK)
					goto fail_cleanup;
			}
			/*
			 * Copy big integer attribute value to the
			 * designated place in the public key object.
			 */
			copy_bigint_attr(&pubexpo, KEY_PUB_RSA_PUBEXPO(pbk));
		}

		break;

	case CKK_DSA:
		if (mode == SOFT_CREATE_OBJ) {
			if (isModulusBits || isModulus || isPubExpo) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}

			if (isPrime && isSubprime && isBase && isValue) {
				copy_bigint_attr(&value,
				    KEY_PUB_DSA_VALUE(pbk));
			} else {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
		} else {
			if (isModulusBits || isModulus || isPubExpo ||
			    isValue) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}

			if (!(isPrime && isSubprime && isBase)) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
		}

		copy_bigint_attr(&prime, KEY_PUB_DSA_PRIME(pbk));

		copy_bigint_attr(&subprime, KEY_PUB_DSA_SUBPRIME(pbk));

		copy_bigint_attr(&base, KEY_PUB_DSA_BASE(pbk));

		break;

	case CKK_DH:
		if (mode == SOFT_CREATE_OBJ) {
			if (isModulusBits || isModulus || isPubExpo ||
			    isSubprime) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}

			if (isPrime && isBase && isValue) {
				copy_bigint_attr(&value,
				    KEY_PUB_DH_VALUE(pbk));
			} else {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
		} else {
			if (isModulusBits || isModulus || isPubExpo ||
			    isSubprime || isValue) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}

			if (!(isPrime && isBase)) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
		}

		copy_bigint_attr(&prime, KEY_PUB_DH_PRIME(pbk));

		copy_bigint_attr(&base, KEY_PUB_DH_BASE(pbk));

		break;

	case CKK_X9_42_DH:
		if (mode == SOFT_CREATE_OBJ) {
			if (isModulusBits || isModulus || isPubExpo) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}

			if (isPrime && isSubprime && isBase && isValue) {
				copy_bigint_attr(&value,
				    KEY_PUB_DH942_VALUE(pbk));
			} else {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
		} else {
			if (isModulusBits || isModulus || isPubExpo ||
			    isValue) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}

			if (!(isPrime && isSubprime && isBase)) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
		}

		copy_bigint_attr(&prime, KEY_PUB_DH942_PRIME(pbk));

		copy_bigint_attr(&base, KEY_PUB_DH942_BASE(pbk));

		copy_bigint_attr(&subprime, KEY_PUB_DH942_SUBPRIME(pbk));

		break;

	case CKK_EC:
		if (mode == SOFT_CREATE_OBJ) {
			if (isModulusBits || isModulus || isPubExpo ||
			    isPrime || isSubprime || isBase || isValue) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;

			} else if (!isECParam || !isECPoint) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
		} else {
			if (isModulusBits || isModulus || isPubExpo ||
			    isPrime || isSubprime || isBase || isValue) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;

			} else if (!isECParam) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
		}

		if (isECPoint) {
			copy_bigint_attr(&point, KEY_PUB_EC_POINT(pbk));
		}
		rv = soft_add_extra_attr(&param_tmp, new_object);
		if (rv != CKR_OK)
			goto fail_cleanup;
		string_attr_cleanup(&param_tmp);
		break;

	default:
		rv = CKR_TEMPLATE_INCONSISTENT;
		goto fail_cleanup;
	}

	/* Set up object. */
	new_object->object_type = object_type;
	new_object->bool_attr_mask = attr_mask;
	if (isLabel) {
		rv = soft_add_extra_attr(&string_tmp, new_object);
		if (rv != CKR_OK)
			goto fail_cleanup;
		string_attr_cleanup(&string_tmp);
	}

	return (rv);

fail_cleanup:
	/*
	 * cleanup the storage allocated to the local variables.
	 */
	bigint_attr_cleanup(&modulus);
	bigint_attr_cleanup(&pubexpo);
	bigint_attr_cleanup(&prime);
	bigint_attr_cleanup(&subprime);
	bigint_attr_cleanup(&base);
	bigint_attr_cleanup(&value);
	bigint_attr_cleanup(&point);
	string_attr_cleanup(&string_tmp);
	string_attr_cleanup(&param_tmp);

	/*
	 * cleanup the storage allocated inside the object itself.
	 */
	soft_cleanup_object(new_object);

	return (rv);
}


/*
 * Build a Private Key Object.
 *
 * - Parse the object's template, and when an error is detected such as
 *   invalid attribute type, invalid attribute value, etc., return
 *   with appropriate return value.
 * - Set up attribute mask field in the object for the supplied common
 *   attributes that have boolean type.
 * - Build the attribute_info struct to hold the value of each supplied
 *   attribute that has byte array type. Link attribute_info structs
 *   together to form the extra attribute list of the object.
 * - Allocate storage for the Private Key object.
 * - Build the Private Key object according to the key type. Allocate
 *   storage to hold the big integer value for the supplied attributes
 *   that are required for a certain key type.
 *
 */
CK_RV
soft_build_private_key_object(CK_ATTRIBUTE_PTR template, CK_ULONG ulAttrNum,
	soft_object_t *new_object, CK_ULONG mode, CK_KEY_TYPE key_type)
{
	ulong_t		i;
	CK_KEY_TYPE	keytype = (CK_KEY_TYPE)~0UL;
	uint64_t	attr_mask = PRIVATE_KEY_DEFAULT;
	CK_RV 		rv = CKR_OK;
	int		isLabel = 0;
	int		isECParam = 0;
	/* Must set flags unless mode == SOFT_UNWRAP_KEY */
	int		isModulus = 0;
	int		isPriExpo = 0;
	int		isPrime = 0;
	int		isSubprime = 0;
	int		isBase = 0;
	/* Must set flags if mode == SOFT_GEN_KEY */
	int		isValue = 0;
	/* Must not set flags */
	int		isValueBits = 0;
	CK_ULONG	value_bits = 0;

	/* Private Key RSA optional */
	int		isPubExpo = 0;
	int		isPrime1 = 0;
	int		isPrime2 = 0;
	int		isExpo1 = 0;
	int		isExpo2 = 0;
	int		isCoef = 0;

	biginteger_t	modulus;
	biginteger_t	priexpo;
	biginteger_t	prime;
	biginteger_t	subprime;
	biginteger_t	base;
	biginteger_t	value;

	biginteger_t	pubexpo;
	biginteger_t	prime1;
	biginteger_t	prime2;
	biginteger_t	expo1;
	biginteger_t	expo2;
	biginteger_t	coef;
	CK_ATTRIBUTE	string_tmp;
	CK_ATTRIBUTE	param_tmp;
	BIGNUM	x, q;

	private_key_obj_t *pvk;
	uchar_t	object_type = 0;

	/* prevent bigint_attr_cleanup from freeing invalid attr value */
	(void) memset(&modulus, 0x0, sizeof (biginteger_t));
	(void) memset(&priexpo, 0x0, sizeof (biginteger_t));
	(void) memset(&prime, 0x0, sizeof (biginteger_t));
	(void) memset(&subprime, 0x0, sizeof (biginteger_t));
	(void) memset(&base, 0x0, sizeof (biginteger_t));
	(void) memset(&value, 0x0, sizeof (biginteger_t));
	(void) memset(&pubexpo, 0x0, sizeof (biginteger_t));
	(void) memset(&prime1, 0x0, sizeof (biginteger_t));
	(void) memset(&prime2, 0x0, sizeof (biginteger_t));
	(void) memset(&expo1, 0x0, sizeof (biginteger_t));
	(void) memset(&expo2, 0x0, sizeof (biginteger_t));
	(void) memset(&coef, 0x0, sizeof (biginteger_t));
	string_tmp.pValue = NULL;
	param_tmp.pValue = NULL;
	x.malloced = 0;
	q.malloced = 0;

	for (i = 0; i < ulAttrNum; i++) {

		/* Private Key Object Attributes */
		switch (template[i].type) {
		/* common key attributes */
		case CKA_KEY_TYPE:
			keytype = *((CK_KEY_TYPE*)template[i].pValue);
			break;

		case CKA_ID:
		case CKA_START_DATE:
		case CKA_END_DATE:

		/* common private key attribute */
		case CKA_SUBJECT:
			/*
			 * Allocate storage to hold the attribute
			 * value with byte array type, and add it to
			 * the extra attribute list of the object.
			 */
			rv = soft_add_extra_attr(&template[i],
			    new_object);
			if (rv != CKR_OK) {
				goto fail_cleanup;
			}
			break;

		/*
		 * The following key related attribute types must
		 * not be specified by C_CreateObject or C_GenerateKey(Pair).
		 */
		case CKA_LOCAL:
		case CKA_KEY_GEN_MECHANISM:
		case CKA_AUTH_PIN_FLAGS:
		case CKA_ALWAYS_SENSITIVE:
		case CKA_NEVER_EXTRACTABLE:
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;

		/* Key related boolean attributes */
		case CKA_DERIVE:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= DERIVE_BOOL_ON;
			break;

		case CKA_SENSITIVE:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= SENSITIVE_BOOL_ON;
			break;

		case CKA_SECONDARY_AUTH:
			if (*(CK_BBOOL *)template[i].pValue) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}
			break;

		case CKA_DECRYPT:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= DECRYPT_BOOL_ON;
			else
				attr_mask &= ~DECRYPT_BOOL_ON;
			break;

		case CKA_SIGN:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= SIGN_BOOL_ON;
			else
				attr_mask &= ~SIGN_BOOL_ON;
			break;

		case CKA_SIGN_RECOVER:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= SIGN_RECOVER_BOOL_ON;
			else
				attr_mask &= ~SIGN_RECOVER_BOOL_ON;
			break;

		case CKA_UNWRAP:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= UNWRAP_BOOL_ON;
			else
				attr_mask &= ~UNWRAP_BOOL_ON;
			break;

		case CKA_EXTRACTABLE:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= EXTRACTABLE_BOOL_ON;
			else
				attr_mask &= ~EXTRACTABLE_BOOL_ON;
			break;

		case CKA_MODIFIABLE:
			if ((*(CK_BBOOL *)template[i].pValue) == B_FALSE)
				attr_mask |= NOT_MODIFIABLE_BOOL_ON;
			break;

		/*
		 * The following key related attribute types must
		 * be specified according to the key type by
		 * C_CreateObject.
		 */
		case CKA_MODULUS:

			isModulus = 1;
			/*
			 * Copyin big integer attribute from template
			 * to a local variable.
			 */
			rv = get_bigint_attr_from_template(&modulus,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;

			/*
			 * Modulus length needs to be between min key length and
			 * max key length.
			 */
			if ((modulus.big_value_len <
			    MIN_RSA_KEYLENGTH_IN_BYTES) ||
			    (modulus.big_value_len >
			    MAX_RSA_KEYLENGTH_IN_BYTES)) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}
			break;

		case CKA_PUBLIC_EXPONENT:

			isPubExpo = 1;
			rv = get_bigint_attr_from_template(&pubexpo,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_PRIVATE_EXPONENT:

			isPriExpo = 1;
			rv = get_bigint_attr_from_template(&priexpo,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_PRIME_1:
			isPrime1 = 1;
			rv = get_bigint_attr_from_template(&prime1,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_PRIME_2:
			isPrime2 = 1;
			rv = get_bigint_attr_from_template(&prime2,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_EXPONENT_1:
			isExpo1 = 1;
			rv = get_bigint_attr_from_template(&expo1,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_EXPONENT_2:
			isExpo2 = 1;
			rv = get_bigint_attr_from_template(&expo2,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_COEFFICIENT:
			isCoef = 1;
			rv = get_bigint_attr_from_template(&coef,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_PRIME:
			isPrime = 1;
			rv = get_bigint_attr_from_template(&prime,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_SUBPRIME:
			isSubprime = 1;
			rv = get_bigint_attr_from_template(&subprime,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_BASE:
			isBase = 1;
			rv = get_bigint_attr_from_template(&base,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_VALUE:
			isValue = 1;
			if (mode == SOFT_CREATE_OBJ) {
				if ((template[i].ulValueLen == 0) ||
				    (template[i].pValue == NULL)) {
					rv = CKR_ATTRIBUTE_VALUE_INVALID;
					goto fail_cleanup;
				}
			}

			rv = get_bigint_attr_from_template(&value,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_VALUE_BITS:
			isValueBits = 1;
			rv = get_ulong_attr_from_template(&value_bits,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_LABEL:
			isLabel = 1;
			rv = get_string_from_template(&string_tmp,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_EC_PARAMS:
			isECParam = 1;
			rv = get_string_from_template(&param_tmp,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		default:
			rv = soft_parse_common_attrs(&template[i],
			    &object_type);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		}
	} /* For */

	/* Allocate storage for Private Key Object. */
	pvk = calloc(1, sizeof (private_key_obj_t));
	if (pvk == NULL) {
		rv = CKR_HOST_MEMORY;
		goto fail_cleanup;
	}

	new_object->object_class_u.private_key = pvk;
	new_object->class = CKO_PRIVATE_KEY;

	if ((mode == SOFT_CREATE_OBJ) && (keytype == (CK_KEY_TYPE)~0UL)) {
		rv = CKR_TEMPLATE_INCOMPLETE;
		goto fail_cleanup;
	}

	if (mode == SOFT_GEN_KEY) {
		/*
		 * The key type is not specified in the application's
		 * template, so we use the implied key type based on
		 * the mechanism.
		 */
		if (keytype == (CK_KEY_TYPE)~0UL) {
			keytype = key_type;
		}

		/* If still unspecified, template is incomplete */
		if (keytype == (CK_KEY_TYPE)~0UL) {
			rv = CKR_TEMPLATE_INCOMPLETE;
			goto fail_cleanup;
		}

		/*
		 * The key type specified in the template does not
		 * match the implied key type based on the mechanism.
		 */
		if (keytype != key_type) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}
	}

	if (mode == SOFT_UNWRAP_KEY) {
		/*
		 * Note that, for mode SOFT_UNWRAP_KEY, key type is not
		 * implied by the mechanism (key_type), so if it is not
		 * specified from the attribute template (keytype), it is
		 * incomplete.
		 */
		if (keytype == (CK_KEY_TYPE)~0UL) {
			rv = CKR_TEMPLATE_INCOMPLETE;
			goto fail_cleanup;
		}
	}

	new_object->key_type = keytype;

	/* Supported key types of the Private Key Object */
	switch (keytype) {
	case CKK_RSA:
		if (isPrime || isSubprime || isBase || isValue ||
		    isValueBits) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}

		if (mode == SOFT_GEN_KEY || mode == SOFT_UNWRAP_KEY) {
			if (isModulus || isPubExpo || isPriExpo || isPrime1 ||
			    isPrime2 || isExpo1 || isExpo2 || isCoef) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			} else
				break;
		}

		if (isModulus && isPriExpo) {
			/*
			 * Copy big integer attribute value to the
			 * designated place in the Private Key object.
			 */
			copy_bigint_attr(&modulus, KEY_PRI_RSA_MOD(pvk));

			copy_bigint_attr(&priexpo, KEY_PRI_RSA_PRIEXPO(pvk));
		} else {
			rv = CKR_TEMPLATE_INCOMPLETE;
			goto fail_cleanup;
		}

		/* The following attributes are optional. */
		if (isPubExpo) {
			copy_bigint_attr(&pubexpo, KEY_PRI_RSA_PUBEXPO(pvk));
		}

		if (isPrime1) {
			copy_bigint_attr(&prime1, KEY_PRI_RSA_PRIME1(pvk));
		}

		if (isPrime2) {
			copy_bigint_attr(&prime2, KEY_PRI_RSA_PRIME2(pvk));
		}

		if (isExpo1) {
			copy_bigint_attr(&expo1, KEY_PRI_RSA_EXPO1(pvk));
		}

		if (isExpo2) {
			copy_bigint_attr(&expo2, KEY_PRI_RSA_EXPO2(pvk));
		}

		if (isCoef) {
			copy_bigint_attr(&coef, KEY_PRI_RSA_COEF(pvk));
		}
		break;

	case CKK_DSA:
		if (isModulus || isPubExpo || isPriExpo || isPrime1 ||
		    isPrime2 || isExpo1 || isExpo2 || isCoef ||
		    isValueBits) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}

		if (mode == SOFT_GEN_KEY || mode == SOFT_UNWRAP_KEY) {
			if (isPrime || isSubprime || isBase || isValue) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			} else
				break;
		}

		if (isPrime && isSubprime && isBase && isValue) {
			/*
			 * The private value x must be less than subprime q.
			 * Size for big_init is in BIG_CHUNK_TYPE words.
			 */
#ifdef	__sparcv9
			if (big_init(&x,
			    (int)CHARLEN2BIGNUMLEN(value.big_value_len))
			    != BIG_OK) {
#else	/* !__sparcv9 */
			if (big_init(&x,
			    CHARLEN2BIGNUMLEN(value.big_value_len))
			    != BIG_OK) {
#endif	/* __sparcv9 */
				rv = CKR_HOST_MEMORY;
				goto fail_cleanup;
			}
#ifdef	__sparcv9
			if (big_init(&q,
			    (int)CHARLEN2BIGNUMLEN(subprime.big_value_len))
			    != BIG_OK) {
#else	/* !__sparcv9 */
			if (big_init(&q,
			    CHARLEN2BIGNUMLEN(subprime.big_value_len))
			    != BIG_OK) {
#endif	/* __sparcv9 */
				rv = CKR_HOST_MEMORY;
				goto fail_cleanup;
			}
			bytestring2bignum(&x, value.big_value,
			    value.big_value_len);
			bytestring2bignum(&q, subprime.big_value,
			    subprime.big_value_len);

			if (big_cmp_abs(&x, &q) > 0) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}

			copy_bigint_attr(&prime, KEY_PRI_DSA_PRIME(pvk));

			copy_bigint_attr(&subprime, KEY_PRI_DSA_SUBPRIME(pvk));

			copy_bigint_attr(&base, KEY_PRI_DSA_BASE(pvk));

			copy_bigint_attr(&value, KEY_PRI_DSA_VALUE(pvk));
		} else {
			rv = CKR_TEMPLATE_INCOMPLETE;
			goto fail_cleanup;
		}
		break;

	case CKK_DH:
		if (isModulus || isPubExpo || isPriExpo || isPrime1 ||
		    isPrime2 || isExpo1 || isExpo2 || isCoef ||
		    isSubprime) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}

		/* CKA_VALUE_BITS is for key gen but not unwrap */
		if (mode == SOFT_GEN_KEY)
			KEY_PRI_DH_VAL_BITS(pvk) = (isValueBits) ?
			    value_bits : 0;
		else if (mode == SOFT_UNWRAP_KEY) {
			if (isValueBits) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}
		}

		if (mode == SOFT_GEN_KEY || mode == SOFT_UNWRAP_KEY) {
			if (isPrime || isBase || isValue) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			} else
				break;
		}

		if (isValueBits) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}

		if (isPrime && isBase && isValue) {
			copy_bigint_attr(&prime, KEY_PRI_DH_PRIME(pvk));

			copy_bigint_attr(&base, KEY_PRI_DH_BASE(pvk));

			copy_bigint_attr(&value, KEY_PRI_DH_VALUE(pvk));
		} else {
			rv = CKR_TEMPLATE_INCOMPLETE;
			goto fail_cleanup;
		}
		break;

	case CKK_X9_42_DH:
		if (isModulus || isPubExpo || isPriExpo || isPrime1 ||
		    isPrime2 || isExpo1 || isExpo2 || isCoef ||
		    isValueBits) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}

		if (mode == SOFT_GEN_KEY || mode == SOFT_UNWRAP_KEY) {
			if (isPrime || isSubprime || isBase || isValue) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			} else
				break;
		}

		if (isPrime && isSubprime && isBase && isValue) {
			copy_bigint_attr(&prime, KEY_PRI_DH942_PRIME(pvk));

			copy_bigint_attr(&base, KEY_PRI_DH942_BASE(pvk));

			copy_bigint_attr(&subprime,
			    KEY_PRI_DH942_SUBPRIME(pvk));

			copy_bigint_attr(&value, KEY_PRI_DH942_VALUE(pvk));
		} else {
			rv = CKR_TEMPLATE_INCOMPLETE;
			goto fail_cleanup;
		}
		break;

	case CKK_EC:
		if (isModulus || isPubExpo || isPrime ||
		    isPrime1 || isPrime2 || isExpo1 || isExpo2 || isCoef ||
		    isValueBits || isBase) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;

		} else if (isECParam) {
			rv = soft_add_extra_attr(&param_tmp, new_object);
			if (rv != CKR_OK)
				goto fail_cleanup;
			string_attr_cleanup(&param_tmp);
		}
		if (isValue) {
			copy_bigint_attr(&value, KEY_PRI_EC_VALUE(pvk));
		}
		break;

	default:
		rv = CKR_TEMPLATE_INCONSISTENT;
		goto fail_cleanup;
	}

	/* Set up object. */
	new_object->object_type = object_type;
	new_object->bool_attr_mask = attr_mask;
	if (isLabel) {
		rv = soft_add_extra_attr(&string_tmp, new_object);
		if (rv != CKR_OK)
			goto fail_cleanup;
		string_attr_cleanup(&string_tmp);
	}
	big_finish(&x);
	big_finish(&q);

	return (rv);

fail_cleanup:
	/*
	 * cleanup the storage allocated to the local variables.
	 */
	bigint_attr_cleanup(&modulus);
	bigint_attr_cleanup(&priexpo);
	bigint_attr_cleanup(&prime);
	bigint_attr_cleanup(&subprime);
	bigint_attr_cleanup(&base);
	bigint_attr_cleanup(&value);
	bigint_attr_cleanup(&pubexpo);
	bigint_attr_cleanup(&prime1);
	bigint_attr_cleanup(&prime2);
	bigint_attr_cleanup(&expo1);
	bigint_attr_cleanup(&expo2);
	bigint_attr_cleanup(&coef);
	string_attr_cleanup(&string_tmp);
	string_attr_cleanup(&param_tmp);
	big_finish(&x);
	big_finish(&q);

	/*
	 * cleanup the storage allocated inside the object itself.
	 */
	soft_cleanup_object(new_object);

	return (rv);
}


/*
 * Build a Secret Key Object.
 *
 * - Parse the object's template, and when an error is detected such as
 *   invalid attribute type, invalid attribute value, etc., return
 *   with appropriate return value.
 * - Set up attribute mask field in the object for the supplied common
 *   attributes that have boolean type.
 * - Build the attribute_info struct to hold the value of each supplied
 *   attribute that has byte array type. Link attribute_info structs
 *   together to form the extra attribute list of the object.
 * - Allocate storage for the Secret Key object.
 * - Build the Secret Key object. Allocate storage to hold the big integer
 *   value for the attribute CKA_VALUE that is required for all the key
 *   types supported by secret key object.
 * This function is called internally with mode = SOFT_CREATE_OBJ_INT.
 *
 */
CK_RV
soft_build_secret_key_object(CK_ATTRIBUTE_PTR template, CK_ULONG ulAttrNum,
	soft_object_t *new_object, CK_ULONG mode, CK_ULONG key_len,
	CK_KEY_TYPE key_type)
{

	ulong_t		i;
	CK_KEY_TYPE	keytype = (CK_KEY_TYPE)~0UL;
	uint64_t	attr_mask = SECRET_KEY_DEFAULT;
	CK_RV 		rv = CKR_OK;
	int		isLabel = 0;
	/* Must set flags if mode != SOFT_UNWRAP_KEY, else must not set */
	int		isValue = 0;
	/* Must not set flags if mode != SOFT_UNWRAP_KEY, else optional */
	int		isValueLen = 0;

	CK_ATTRIBUTE	string_tmp;

	secret_key_obj_t  *sck;
	uchar_t	object_type = 0;

	string_tmp.pValue = NULL;

	/* Allocate storage for Secret Key Object. */
	sck = calloc(1, sizeof (secret_key_obj_t));
	if (sck == NULL) {
		rv = CKR_HOST_MEMORY;
		goto fail_cleanup;
	}

	new_object->object_class_u.secret_key = sck;
	new_object->class = CKO_SECRET_KEY;

	for (i = 0; i < ulAttrNum; i++) {

		/* Secret Key Object Attributes */
		switch (template[i].type) {

		/* common key attributes */
		case CKA_KEY_TYPE:
			keytype = *((CK_KEY_TYPE*)template[i].pValue);
			break;

		case CKA_ID:
		case CKA_START_DATE:
		case CKA_END_DATE:
			/*
			 * Allocate storage to hold the attribute
			 * value with byte array type, and add it to
			 * the extra attribute list of the object.
			 */
			rv = soft_add_extra_attr(&template[i],
			    new_object);
			if (rv != CKR_OK) {
				goto fail_cleanup;
			}
			break;

		/*
		 * The following key related attribute types must
		 * not be specified by C_CreateObject and C_GenerateKey.
		 */
		case CKA_LOCAL:
		case CKA_KEY_GEN_MECHANISM:
		case CKA_ALWAYS_SENSITIVE:
		case CKA_NEVER_EXTRACTABLE:
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;

		/* Key related boolean attributes */
		case CKA_DERIVE:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= DERIVE_BOOL_ON;
			break;

		case CKA_SENSITIVE:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= SENSITIVE_BOOL_ON;
			break;

		case CKA_ENCRYPT:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= ENCRYPT_BOOL_ON;
			else
				attr_mask &= ~ENCRYPT_BOOL_ON;
			break;

		case CKA_DECRYPT:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= DECRYPT_BOOL_ON;
			else
				attr_mask &= ~DECRYPT_BOOL_ON;
			break;

		case CKA_SIGN:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= SIGN_BOOL_ON;
			else
				attr_mask &= ~SIGN_BOOL_ON;
			break;

		case CKA_VERIFY:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= VERIFY_BOOL_ON;
			else
				attr_mask &= ~VERIFY_BOOL_ON;
			break;

		case CKA_WRAP:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= WRAP_BOOL_ON;
			else
				attr_mask &= ~WRAP_BOOL_ON;
			break;

		case CKA_UNWRAP:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= UNWRAP_BOOL_ON;
			else
				attr_mask &= ~UNWRAP_BOOL_ON;
			break;

		case CKA_EXTRACTABLE:
			if (*(CK_BBOOL *)template[i].pValue)
				attr_mask |= EXTRACTABLE_BOOL_ON;
			else
				attr_mask &= ~EXTRACTABLE_BOOL_ON;
			break;

		case CKA_MODIFIABLE:
			if ((*(CK_BBOOL *)template[i].pValue) == B_FALSE)
				attr_mask |= NOT_MODIFIABLE_BOOL_ON;
			break;

		case CKA_VALUE:
			isValue = 1;
			if (mode == SOFT_CREATE_OBJ) {
				if ((template[i].ulValueLen == 0) ||
				    (template[i].pValue == NULL)) {
					rv = CKR_ATTRIBUTE_VALUE_INVALID;
					goto fail_cleanup;
				}
			}

			/*
			 * Copyin attribute from template
			 * to a local variable.
			 */
			rv = get_bigint_attr_from_template((biginteger_t *)sck,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_VALUE_LEN:
			isValueLen = 1;
			rv = get_ulong_attr_from_template(&sck->sk_value_len,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_LABEL:
			isLabel = 1;
			rv = get_string_from_template(&string_tmp,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		default:
			rv = soft_parse_common_attrs(&template[i],
			    &object_type);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		}
	} /* For */

	switch (mode) {
	case SOFT_CREATE_OBJ:
	case SOFT_CREATE_OBJ_INT:
	case SOFT_DERIVE_KEY_DH:
		/*
		 * The key type must be specified in the application's
		 * template. Otherwise, returns error.
		 */
		if (keytype == (CK_KEY_TYPE)~0UL) {
			rv = CKR_TEMPLATE_INCOMPLETE;
			goto fail_cleanup;
		}
		break;

	case SOFT_GEN_KEY:
		if (keytype == (CK_KEY_TYPE)~0UL) {
			/*
			 * The key type is not specified in the application's
			 * template, so we use the implied key type based on
			 * the mechanism.
			 */
			keytype = key_type;
		} else {
			if (keytype != key_type) {
				/*
				 * The key type specified in the template
				 * does not match the implied key type based
				 * on the mechanism.
				 */
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}
		}

		/*
		 * If a key_len is passed as a parameter, it has to
		 * match the one found in the template.
		 */
		if (key_len > 0) {
			if (isValueLen && sck->sk_value_len != key_len) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}
			isValueLen = 1;
			sck->sk_value_len = key_len;
		}
		break;

	case SOFT_UNWRAP_KEY:
		/*
		 * Note that, for mode SOFT_UNWRAP_KEY, key type is not
		 * implied by the mechanism (key_type), so if it is not
		 * specified from the attribute template (keytype), it is
		 * incomplete.
		 */
		if (keytype == (CK_KEY_TYPE)~0UL) {
			rv = CKR_TEMPLATE_INCOMPLETE;
			goto fail_cleanup;
		}
		break;

	case SOFT_DERIVE_KEY_OTHER:
		/*
		 * For CKM_MD5_KEY_DERIVATION & CKM_SHA1_KEY_DERIVATION, the
		 * key type is optional.
		 */
		if (keytype == (CK_KEY_TYPE)~0UL) {
			keytype = key_type;
		}
		break;
	}

	switch (mode) {
	case SOFT_CREATE_OBJ:
	case SOFT_CREATE_OBJ_INT:
		switch (keytype) {
		case CKK_RC4:
			if (!isValue) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
			if ((sck->sk_value_len < ARCFOUR_MIN_KEY_BYTES) ||
			    (sck->sk_value_len > ARCFOUR_MAX_KEY_BYTES)) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}
			break;

		case CKK_GENERIC_SECRET:
			if (!isValue) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
			break;

		case CKK_AES:
			if (!isValue) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
			if ((sck->sk_value_len != AES_MIN_KEY_BYTES) &&
			    (sck->sk_value_len != AES_192_KEY_BYTES) &&
			    (sck->sk_value_len != AES_MAX_KEY_BYTES)) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}
			break;

		case CKK_BLOWFISH:
			if (!isValue) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
			if ((sck->sk_value_len < BLOWFISH_MINBYTES) ||
			    (sck->sk_value_len > BLOWFISH_MAXBYTES)) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}

			break;

		case CKK_DES:
			if (!isValue) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
			if (sck->sk_value_len != DES_KEYSIZE) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}
			break;

		case CKK_DES2:
			if (!isValue) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
			if (sck->sk_value_len != DES2_KEYSIZE) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}
			break;

		case CKK_DES3:
			if (!isValue) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
			if (sck->sk_value_len != DES3_KEYSIZE) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}
			break;

		default:
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}

		if (isValueLen) {
			/*
			 * Templates for internal object creation come from
			 * applications calls to C_DeriveKey(), for which it
			 * is OKey to pass a CKA_VALUE_LEN attribute, as
			 * long as it does not conflict with the length of the
			 * CKA_VALUE attribute.
			 */
			if ((mode != SOFT_CREATE_OBJ_INT) ||
			    ((key_len > 0) && sck->sk_value_len != key_len)) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}
		}
		break;

	case SOFT_GEN_KEY:
		/* CKA_VALUE must not be specified */
		if (isValue) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}

		switch (keytype) {
		/*
		 * CKA_VALUE_LEN must be specified by C_GenerateKey
		 * if mech is CKK_RC4, CKK_AES, CKK_GENERIC_SECRET.
		 */
		case CKK_RC4:
			if (!isValueLen) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
			;
			if ((sck->sk_value_len < ARCFOUR_MIN_KEY_BYTES) ||
			    (sck->sk_value_len > ARCFOUR_MAX_KEY_BYTES)) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}
			break;

		case CKK_GENERIC_SECRET:
			/* arbitrary key length - no length checking */
			if (!isValueLen) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
			break;

		case CKK_AES:
			if (!isValueLen) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}

			if ((sck->sk_value_len != AES_MIN_KEY_BYTES) &&
			    (sck->sk_value_len != AES_192_KEY_BYTES) &&
			    (sck->sk_value_len != AES_MAX_KEY_BYTES)) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}

			break;

		case CKK_BLOWFISH:
			if (!isValueLen) {
				rv = CKR_TEMPLATE_INCOMPLETE;
				goto fail_cleanup;
			}
			if ((sck->sk_value_len < BLOWFISH_MINBYTES) ||
			    (sck->sk_value_len > BLOWFISH_MAXBYTES)) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}

			break;

		case CKK_DES:
		case CKK_DES2:
		case CKK_DES3:
			/* CKA_VALUE_LEN attribute does not apply to DES<n> */
			if (isValueLen) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}
			break;

		default:
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}
		break;

	case SOFT_UNWRAP_KEY:
		/*
		 * According to v2.11 of PKCS#11 spec, neither CKA_VALUE nor
		 * CKA_VALUE_LEN can be be specified; however v2.20 has this
		 * restriction removed, perhaps because it makes it hard to
		 * determine variable-length key sizes.  This case statement
		 * complied with v2.20.
		 */
		if (isValue) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}

		switch (keytype) {
		/*
		 * CKA_VALUE_LEN is optional
		 * if key is CKK_RC4, CKK_AES, CKK_GENERIC_SECRET
		 * and the unwrapping mech is *_CBC_PAD.
		 *
		 * CKA_VALUE_LEN is required
		 * if key is CKK_RC4, CKK_AES, CKK_GENERIC_SECRET
		 * and the unwrapping mech is *_ECB or *_CBC.
		 *
		 * since mech is not known at this point, CKA_VALUE_LEN is
		 * treated as optional and the caller needs to enforce it.
		 */
		case CKK_RC4:
			if (isValueLen) {
				if ((sck->sk_value_len <
				    ARCFOUR_MIN_KEY_BYTES) ||
				    (sck->sk_value_len >
				    ARCFOUR_MAX_KEY_BYTES)) {
					rv = CKR_ATTRIBUTE_VALUE_INVALID;
					goto fail_cleanup;
				}
			}
			break;

		case CKK_GENERIC_SECRET:
			/* arbitrary key length - no length checking */
			break;

		case CKK_AES:
			if (isValueLen) {
				if ((sck->sk_value_len != AES_MIN_KEY_BYTES) &&
				    (sck->sk_value_len != AES_192_KEY_BYTES) &&
				    (sck->sk_value_len != AES_MAX_KEY_BYTES)) {
					rv = CKR_ATTRIBUTE_VALUE_INVALID;
					goto fail_cleanup;
				}
			}
			break;

		case CKK_BLOWFISH:
			if (isValueLen &&
			    ((sck->sk_value_len < BLOWFISH_MINBYTES) ||
			    (sck->sk_value_len > BLOWFISH_MAXBYTES))) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}
			break;

		case CKK_DES:
		case CKK_DES2:
		case CKK_DES3:
			/* CKA_VALUE_LEN attribute does not apply to DES<n> */
			if (isValueLen) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}
			break;

		default:
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}
		break;

	case SOFT_DERIVE_KEY_DH:
		/* CKA_VALUE must not be specified */
		if (isValue) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}

		switch (keytype) {
		/*
		 * CKA_VALUE_LEN is optional
		 * if mech is CKK_RC4, CKK_AES, CKK_GENERIC_SECRET.
		 */
		case CKK_RC4:
			if (isValueLen) {
				if ((sck->sk_value_len <
				    ARCFOUR_MIN_KEY_BYTES) ||
				    (sck->sk_value_len >
				    ARCFOUR_MAX_KEY_BYTES)) {
					rv = CKR_ATTRIBUTE_VALUE_INVALID;
					goto fail_cleanup;
				}
			}
			break;

		case CKK_GENERIC_SECRET:
			/* arbitrary key length - no length checking */
			break;

		case CKK_AES:
			if (isValueLen) {
				if ((sck->sk_value_len != AES_MIN_KEY_BYTES) &&
				    (sck->sk_value_len != AES_192_KEY_BYTES) &&
				    (sck->sk_value_len != AES_MAX_KEY_BYTES)) {
					rv = CKR_ATTRIBUTE_VALUE_INVALID;
					goto fail_cleanup;
				}
			}

			break;

		case CKK_BLOWFISH:
			if (isValueLen &&
			    ((sck->sk_value_len < BLOWFISH_MINBYTES) ||
			    (sck->sk_value_len > BLOWFISH_MAXBYTES))) {
				rv = CKR_ATTRIBUTE_VALUE_INVALID;
				goto fail_cleanup;
			}
			break;

		case CKK_DES:
		case CKK_DES2:
		case CKK_DES3:
			/* CKA_VALUE_LEN attribute does not apply to DES<n> */
			if (isValueLen) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}
			break;

		default:
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}
		break;

	case SOFT_DERIVE_KEY_OTHER:
		/* CKA_VALUE must not be specified */
		if (isValue) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}

		switch (keytype) {
		/*
		 * CKA_VALUE_LEN is an optional attribute for
		 * CKM_SHA1_KEY_DERIVATION and CKM_MD5_KEY_DERIVATION
		 * if mech is CKK_RC4, CKK_AES, CKK_GENERIC_SECRET.
		 */
		case CKK_RC4:
		case CKK_GENERIC_SECRET:
		case CKK_AES:
		case CKK_BLOWFISH:
			/*
			 * No need to check key length value here, it will be
			 * validated later in soft_key_derive_check_length().
			 */
			break;

		case CKK_DES:
		case CKK_DES2:
		case CKK_DES3:
			/* CKA_VALUE_LEN attribute does not apply to DES<n> */
			if (isValueLen) {
				rv = CKR_TEMPLATE_INCONSISTENT;
				goto fail_cleanup;
			}
			break;

		default:
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}
		break;
	}

	/* Set up object. */
	new_object->key_type = keytype;
	new_object->object_type = object_type;
	new_object->bool_attr_mask = attr_mask;
	if (isLabel) {
		rv = soft_add_extra_attr(&string_tmp, new_object);
		if (rv != CKR_OK)
			goto fail_cleanup;
		string_attr_cleanup(&string_tmp);
	}
	return (rv);

fail_cleanup:
	/*
	 * cleanup the storage allocated to the local variables.
	 */
	bigint_attr_cleanup((biginteger_t *)sck);
	string_attr_cleanup(&string_tmp);

	/*
	 * cleanup the storage allocated inside the object itself.
	 */
	soft_cleanup_object(new_object);

	return (rv);
}


/*
 * Build a Domain Parameter Object.
 *
 * - Parse the object's template, and when an error is detected such as
 *   invalid attribute type, invalid attribute value, etc., return
 *   with appropriate return value.
 * - Allocate storage for the Domain Parameter object.
 * - Build the Domain Parameter object according to the key type. Allocate
 *   storage to hold the big integer value for the supplied attributes
 *   that are required for a certain key type.
 *
 */
CK_RV
soft_build_domain_parameters_object(CK_ATTRIBUTE_PTR template,
	CK_ULONG ulAttrNum, soft_object_t *new_object)
{

	ulong_t		i;
	CK_KEY_TYPE	keytype = (CK_KEY_TYPE)~0UL;
	CK_RV 		rv = CKR_OK;
	int		isLabel = 0;
	/* Must set flags */
	int		isPrime = 0;
	int		isSubprime = 0;
	int		isBase = 0;
	/* Must not set flags */
	int		isPrimeBits = 0;
	int		isSubPrimeBits = 0;

	biginteger_t	prime;
	biginteger_t	subprime;
	biginteger_t	base;
	CK_ATTRIBUTE	string_tmp;

	domain_obj_t	*dom;
	uchar_t	object_type = 0;

	/* prevent bigint_attr_cleanup from freeing invalid attr value */
	(void) memset(&prime, 0x0, sizeof (biginteger_t));
	(void) memset(&subprime, 0x0, sizeof (biginteger_t));
	(void) memset(&base, 0x0, sizeof (biginteger_t));
	string_tmp.pValue = NULL;

	for (i = 0; i < ulAttrNum; i++) {

		/* Domain Parameters Object Attributes */
		switch (template[i].type) {

		/* common domain parameter attribute */
		case CKA_KEY_TYPE:
			keytype = *((CK_KEY_TYPE*)template[i].pValue);
			break;

		/*
		 * The following common domain parameter attribute
		 * must not be specified by C_CreateObject.
		 */
		case CKA_LOCAL:
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;

		/*
		 * The following domain parameter attributes must be
		 * specified according to the key type by
		 * C_CreateObject.
		 */
		case CKA_PRIME:
			isPrime = 1;
			/*
			 * Copyin big integer attribute from template
			 * to a local variable.
			 */
			rv = get_bigint_attr_from_template(&prime,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_SUBPRIME:
			isSubprime = 1;
			rv = get_bigint_attr_from_template(&subprime,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_BASE:
			isBase = 1;
			rv = get_bigint_attr_from_template(&base,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		case CKA_PRIME_BITS:
			isPrimeBits = 1;
			break;

		case CKA_SUB_PRIME_BITS:
			isSubPrimeBits = 1;
			break;

		case CKA_LABEL:
			isLabel = 1;
			rv = get_string_from_template(&string_tmp,
			    &template[i]);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		default:
			rv = soft_parse_common_attrs(&template[i],
			    &object_type);
			if (rv != CKR_OK)
				goto fail_cleanup;
			break;

		}
	} /* For */

	/* Allocate storage for Domain Parameters Object. */
	dom = calloc(1, sizeof (domain_obj_t));
	if (dom == NULL) {
		rv = CKR_HOST_MEMORY;
		goto fail_cleanup;
	}

	new_object->object_class_u.domain = dom;
	new_object->class = CKO_DOMAIN_PARAMETERS;

	if (keytype == (CK_KEY_TYPE)~0UL) {
		rv = CKR_TEMPLATE_INCOMPLETE;
		goto fail_cleanup;
	}

	new_object->key_type = keytype;

	/* Supported key types of the Domain Parameters Object */
	switch (keytype) {
	case CKK_DSA:
		if (isPrimeBits || isSubPrimeBits) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}

		if (isPrime && isSubprime && isBase) {
			/*
			 * Copy big integer attribute value to the
			 * designated place in the domain parameter
			 * object.
			 */
			copy_bigint_attr(&prime, KEY_DOM_DSA_PRIME(dom));

			copy_bigint_attr(&subprime, KEY_DOM_DSA_SUBPRIME(dom));

			copy_bigint_attr(&base, KEY_DOM_DSA_BASE(dom));
		} else {
			rv = CKR_TEMPLATE_INCOMPLETE;
			goto fail_cleanup;
		}
		break;

	case CKK_DH:
		if (isPrimeBits || isSubprime || isSubPrimeBits) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}

		if (isPrime && isBase) {
			copy_bigint_attr(&prime, KEY_DOM_DH_PRIME(dom));

			copy_bigint_attr(&base, KEY_DOM_DH_BASE(dom));
		} else {
			rv = CKR_TEMPLATE_INCOMPLETE;
			goto fail_cleanup;
		}
		break;

	case CKK_X9_42_DH:
		if (isPrimeBits || isSubPrimeBits) {
			rv = CKR_TEMPLATE_INCONSISTENT;
			goto fail_cleanup;
		}

		if (isPrime && isSubprime && isBase) {
			copy_bigint_attr(&prime, KEY_DOM_DH942_PRIME(dom));

			copy_bigint_attr(&base, KEY_DOM_DH942_BASE(dom));

			copy_bigint_attr(&subprime,
			    KEY_DOM_DH942_SUBPRIME(dom));
		} else {
			rv = CKR_TEMPLATE_INCOMPLETE;
			goto fail_cleanup;
		}
		break;

	default:
		rv = CKR_TEMPLATE_INCONSISTENT;
		goto fail_cleanup;
	}

	new_object->object_type = object_type;

	if (isLabel) {
		rv = soft_add_extra_attr(&string_tmp, new_object);
		if (rv != CKR_OK)
			goto fail_cleanup;
		string_attr_cleanup(&string_tmp);
	}

	return (rv);

fail_cleanup:
	/*
	 * cleanup the storage allocated to the local variables.
	 */
	bigint_attr_cleanup(&prime);
	bigint_attr_cleanup(&subprime);
	bigint_attr_cleanup(&base);
	string_attr_cleanup(&string_tmp);

	/*
	 * cleanup the storage allocated inside the object itself.
	 */
	soft_cleanup_object(new_object);

	return (rv);
}

/*
 * Build a Certificate Object
 *
 * - Parse the object's template, and when an error is detected such as
 *   invalid attribute type, invalid attribute value, etc., return
 *   with appropriate return value.
 * - Allocate storage for the Certificate object
 */
static CK_RV
soft_build_certificate_object(CK_ATTRIBUTE_PTR template,
	CK_ULONG ulAttrNum, soft_object_t *new_object,
	CK_CERTIFICATE_TYPE cert_type)
{
	uint64_t	attr_mask = 0;
	CK_RV 		rv = CKR_OK;
	CK_ULONG	i;
	int		owner_set = 0;
	int		value_set = 0;
	int		subject_set = 0;
	certificate_obj_t *cert;
	/* certificate type defaults to the value given as a parameter */
	CK_CERTIFICATE_TYPE certtype = cert_type;
	CK_ATTRIBUTE	string_tmp;
	int		isLabel = 0;
	uchar_t		object_type = 0;

	/*
	 * Look for the certificate type attribute and do some
	 * sanity checking before creating the structures.
	 */
	for (i = 0; i < ulAttrNum; i++) {
		/* Certificate Object Attributes */
		switch (template[i].type) {
			case CKA_CERTIFICATE_TYPE:
				certtype =
				    *((CK_CERTIFICATE_TYPE*)template[i].pValue);
				break;
			case CKA_SUBJECT:
				subject_set = 1;
				break;
			case CKA_OWNER:
				owner_set = 1;
				break;
			case CKA_VALUE:
				value_set = 1;
				break;
		}
	}

	/* The certificate type MUST be specified */
	if (certtype != CKC_X_509 && certtype != CKC_X_509_ATTR_CERT)
		return (CKR_TEMPLATE_INCOMPLETE);

	/*
	 * For X.509 certs, the CKA_SUBJECT and CKA_VALUE
	 * must be present at creation time.
	 */
	if (certtype == CKC_X_509 &&
	    (!subject_set || !value_set))
		return (CKR_TEMPLATE_INCOMPLETE);

	/*
	 * For X.509 Attribute certs, the CKA_OWNER and CKA_VALUE
	 * must be present at creation time.
	 */
	if (certtype == CKC_X_509_ATTR_CERT &&
	    (!owner_set || !value_set))
		return (CKR_TEMPLATE_INCOMPLETE);

	string_tmp.pValue = NULL;
	cert = calloc(1, sizeof (certificate_obj_t));
	if (cert == NULL) {
		return (CKR_HOST_MEMORY);
	}
	cert->certificate_type = certtype;

	for (i = 0; i < ulAttrNum; i++) {
		/* Certificate Object Attributes */
		switch (certtype) {
			case CKC_X_509:
			switch (template[i].type) {
				case CKA_SUBJECT:
					rv = get_cert_attr_from_template(
					    &cert->cert_type_u.x509.subject,
					    &template[i]);
					break;
				case CKA_VALUE:
					rv = get_cert_attr_from_template(
					    &cert->cert_type_u.x509.value,
					    &template[i]);
					break;
				case CKA_LABEL:
					isLabel = 1;
					rv = get_string_from_template(
					    &string_tmp,
					    &template[i]);
					if (rv != CKR_OK)
						goto fail_cleanup;
					break;
				case CKA_ID:
				case CKA_ISSUER:
				case CKA_SERIAL_NUMBER:
					rv = soft_add_extra_attr(&template[i],
					    new_object);
					break;
				case CKA_MODIFIABLE:
					if ((*(CK_BBOOL *)template[i].pValue) ==
					    B_FALSE)
						attr_mask |=
						    NOT_MODIFIABLE_BOOL_ON;
					break;
				case CKA_CERTIFICATE_TYPE:
					break;
				default:
					rv = soft_parse_common_attrs(
					    &template[i], &object_type);
					if (rv != CKR_OK)
						goto fail_cleanup;
			}
			break;
			case CKC_X_509_ATTR_CERT:
			switch (template[i].type) {
				case CKA_OWNER:
					rv = get_cert_attr_from_template(
					    &cert->cert_type_u.x509_attr.owner,
					    &template[i]);
					break;
				case CKA_VALUE:
					rv = get_cert_attr_from_template(
					    &cert->cert_type_u.x509_attr.value,
					    &template[i]);
					break;
				case CKA_LABEL:
					isLabel = 1;
					rv = get_string_from_template(
					    &string_tmp, &template[i]);
					if (rv != CKR_OK)
						goto fail_cleanup;
					break;
				case CKA_SERIAL_NUMBER:
				case CKA_AC_ISSUER:
				case CKA_ATTR_TYPES:
					rv = soft_add_extra_attr(&template[i],
					    new_object);
					break;

				case CKA_MODIFIABLE:
					if ((*(CK_BBOOL *)template[i].pValue) ==
					    B_FALSE)
						attr_mask |=
						    NOT_MODIFIABLE_BOOL_ON;
					break;
				case CKA_CERTIFICATE_TYPE:
					break;
				default:
					rv = soft_parse_common_attrs(
					    &template[i], &object_type);
					if (rv != CKR_OK)
						goto fail_cleanup;
					break;
			}
			break;
			default:
				rv = CKR_TEMPLATE_INCOMPLETE;
				break;
		}
	}

	if (rv == CKR_OK) {
		new_object->object_class_u.certificate = cert;
		new_object->class = CKO_CERTIFICATE;
		new_object->object_type = object_type;
		new_object->cert_type = certtype;
		new_object->bool_attr_mask = attr_mask;
		if (isLabel) {
			rv = soft_add_extra_attr(&string_tmp, new_object);
			if (rv != CKR_OK)
				goto fail_cleanup;
			string_attr_cleanup(&string_tmp);
		}
	}

fail_cleanup:
	if (rv != CKR_OK) {
		soft_cleanup_cert_object(new_object);
	}
	return (rv);
}


/*
 * Validate the attribute types in the object's template. Then,
 * call the appropriate build function according to the class of
 * the object specified in the template.
 *
 * Note: The following classes of objects are supported:
 * - CKO_PUBLIC_KEY
 * - CKO_PRIVATE_KEY
 * - CKO_SECRET_KEY
 * - CKO_DOMAIN_PARAMETERS
 * - CKO_CERTIFICATE
 *
 */
CK_RV
soft_build_object(CK_ATTRIBUTE_PTR template, CK_ULONG ulAttrNum,
	soft_object_t *new_object)
{

	CK_OBJECT_CLASS class = (CK_OBJECT_CLASS)~0UL;
	CK_RV 		rv = CKR_OK;

	if (template == NULL) {
		return (CKR_ARGUMENTS_BAD);
	}

	/* Validate the attribute type in the template. */
	rv = soft_validate_attr(template, ulAttrNum, &class);
	if (rv != CKR_OK)
		return (rv);
	/*
	 * CKA_CLASS is a mandatory attribute for C_CreateObject
	 */
	if (class == (CK_OBJECT_CLASS)~0UL)
		return (CKR_TEMPLATE_INCOMPLETE);

	/*
	 * Call the appropriate function based on the supported class
	 * of the object.
	 */
	switch (class) {
	case CKO_PUBLIC_KEY:
		rv = soft_build_public_key_object(template, ulAttrNum,
		    new_object, SOFT_CREATE_OBJ, (CK_KEY_TYPE)~0UL);
		break;

	case CKO_PRIVATE_KEY:
		rv = soft_build_private_key_object(template, ulAttrNum,
		    new_object, SOFT_CREATE_OBJ, (CK_KEY_TYPE)~0UL);
		break;

	case CKO_SECRET_KEY:
		rv = soft_build_secret_key_object(template, ulAttrNum,
		    new_object, SOFT_CREATE_OBJ, 0, (CK_KEY_TYPE)~0UL);
		break;

	case CKO_DOMAIN_PARAMETERS:
		rv = soft_build_domain_parameters_object(template, ulAttrNum,
		    new_object);
		break;

	case CKO_CERTIFICATE:
		rv = soft_build_certificate_object(template, ulAttrNum,
		    new_object, (CK_CERTIFICATE_TYPE)~0UL);
		break;

	case CKO_DATA:
	case CKO_HW_FEATURE:
	case CKO_VENDOR_DEFINED:
	default:
		return (CKR_ATTRIBUTE_VALUE_INVALID);
	}

	return (rv);
}

/*
 * Validate the attribute types in the object's template. Then,
 * call the appropriate build function according to the class of
 * the object specified in the template.
 *
 */
CK_RV
soft_build_key(CK_ATTRIBUTE_PTR template, CK_ULONG ulAttrNum,
	soft_object_t *new_object, CK_OBJECT_CLASS class, CK_KEY_TYPE key_type,
	CK_ULONG key_len, CK_ULONG mode)
{

	CK_RV 		rv = CKR_OK;
	CK_OBJECT_CLASS temp_class = (CK_OBJECT_CLASS)~0UL;

	/* Validate the attribute type in the template. */
	if ((template != NULL) && (ulAttrNum != 0)) {
		rv = soft_validate_attr(template, ulAttrNum, &temp_class);
		if (rv != CKR_OK)
			return (rv);
	}

	/*
	 * If either the class from the parameter list ("class") or
	 * the class from the template ("temp_class") is not specified,
	 * try to use the other one.
	 */
	if (temp_class == (CK_OBJECT_CLASS)~0UL) {
		temp_class = class;
	} else if (class == (CK_OBJECT_CLASS)~0UL) {
		class = temp_class;
	}

	/* If object class is still not specified, template is incomplete. */
	if (class == (CK_OBJECT_CLASS)~0UL)
		return (CKR_TEMPLATE_INCOMPLETE);

	/* Class should match if specified in both parameters and template. */
	if (class != temp_class)
		return (CKR_TEMPLATE_INCONSISTENT);

	/*
	 * Call the appropriate function based on the supported class
	 * of the object.
	 */
	switch (class) {
	case CKO_PUBLIC_KEY:

		/* Unwrapping public keys is not supported. */
		if (mode == SOFT_UNWRAP_KEY) {
			rv = CKR_ATTRIBUTE_VALUE_INVALID;
			break;
		}

		rv = soft_build_public_key_object(template, ulAttrNum,
		    new_object, mode, key_type);
		break;

	case CKO_PRIVATE_KEY:

		rv = soft_build_private_key_object(template, ulAttrNum,
		    new_object, mode, key_type);
		break;

	case CKO_SECRET_KEY:

		rv = soft_build_secret_key_object(template, ulAttrNum,
		    new_object, mode, key_len, key_type);
		break;

	case CKO_DOMAIN_PARAMETERS:

		/* Unwrapping domain parameters is not supported. */
		if (mode == SOFT_UNWRAP_KEY) {
			rv = CKR_ATTRIBUTE_VALUE_INVALID;
			break;
		}

		rv = soft_build_domain_parameters_object(template, ulAttrNum,
		    new_object);
		break;

	case CKO_DATA:
	case CKO_CERTIFICATE:
	case CKO_HW_FEATURE:
	case CKO_VENDOR_DEFINED:
	default:
		return (CKR_ATTRIBUTE_VALUE_INVALID);
	}

	return (rv);
}


/*
 * Get the value of a requested attribute that is common to all supported
 * classes (i.e. public key, private key, secret key, domain parameters,
 * and certificate classes).
 */
CK_RV
soft_get_common_attrs(soft_object_t *object_p, CK_ATTRIBUTE_PTR template,
    uchar_t object_type)
{

	CK_RV rv = CKR_OK;

	switch (template->type) {

	case CKA_CLASS:
		return (get_ulong_attr_from_object(object_p->class,
		    template));

	/* default boolean attributes */
	case CKA_TOKEN:
		template->ulValueLen = sizeof (CK_BBOOL);
		if (template->pValue == NULL) {
			return (CKR_OK);
		}
		if (object_type & TOKEN_OBJECT)
			*((CK_BBOOL *)template->pValue) = B_TRUE;
		else
			*((CK_BBOOL *)template->pValue) = B_FALSE;
		break;

	case CKA_PRIVATE:

		template->ulValueLen = sizeof (CK_BBOOL);
		if (template->pValue == NULL) {
			return (CKR_OK);
		}
		if (object_type & PRIVATE_OBJECT)
			*((CK_BBOOL *)template->pValue) = B_TRUE;
		else
			*((CK_BBOOL *)template->pValue) = B_FALSE;
		break;

	case CKA_MODIFIABLE:
		template->ulValueLen = sizeof (CK_BBOOL);
		if (template->pValue == NULL) {
			return (CKR_OK);
		}
		if ((object_p->bool_attr_mask) & NOT_MODIFIABLE_BOOL_ON)
			*((CK_BBOOL *)template->pValue) = B_FALSE;
		else
			*((CK_BBOOL *)template->pValue) = B_TRUE;
		break;

	case CKA_LABEL:
		return (get_extra_attr_from_object(object_p,
		    template));

	default:
		/*
		 * The specified attribute for the object is invalid.
		 * (the object does not possess such an attribute.)
		 */
		template->ulValueLen = (CK_ULONG)-1;
		return (CKR_ATTRIBUTE_TYPE_INVALID);
	}

	return (rv);
}

/*
 * Get the value of a requested attribute that is common to all key objects
 * (i.e. public key, private key and secret key).
 */
CK_RV
soft_get_common_key_attrs(soft_object_t *object_p, CK_ATTRIBUTE_PTR template)
{

	switch (template->type) {

	case CKA_KEY_TYPE:
		return (get_ulong_attr_from_object(object_p->key_type,
		    template));

	case CKA_ID:
	case CKA_START_DATE:
	case CKA_END_DATE:
		/*
		 * The above extra attributes have byte array type.
		 */
		return (get_extra_attr_from_object(object_p,
		    template));

	/* Key related boolean attributes */
	case CKA_LOCAL:
		return (get_bool_attr_from_object(object_p,
		    LOCAL_BOOL_ON, template));

	case CKA_DERIVE:
		return (get_bool_attr_from_object(object_p,
		    DERIVE_BOOL_ON, template));

	case CKA_KEY_GEN_MECHANISM:
		return (get_ulong_attr_from_object(object_p->mechanism,
		    template));

	default:
		return (CKR_ATTRIBUTE_TYPE_INVALID);
	}
}

/*
 * Get the value of a requested attribute of a Public Key Object.
 *
 * Rule: All the attributes in the public key object can be revealed.
 */
CK_RV
soft_get_public_key_attribute(soft_object_t *object_p,
	CK_ATTRIBUTE_PTR template)
{

	CK_RV		rv = CKR_OK;
	CK_KEY_TYPE	keytype = object_p->key_type;

	switch (template->type) {

	case CKA_SUBJECT:
	case CKA_EC_PARAMS:
		/*
		 * The above extra attributes have byte array type.
		 */
		return (get_extra_attr_from_object(object_p,
		    template));

	/* Key related boolean attributes */
	case CKA_ENCRYPT:
		return (get_bool_attr_from_object(object_p,
		    ENCRYPT_BOOL_ON, template));

	case CKA_VERIFY:
		return (get_bool_attr_from_object(object_p,
		    VERIFY_BOOL_ON, template));

	case CKA_VERIFY_RECOVER:
		return (get_bool_attr_from_object(object_p,
		    VERIFY_RECOVER_BOOL_ON, template));

	case CKA_WRAP:
		return (get_bool_attr_from_object(object_p,
		    WRAP_BOOL_ON, template));

	case CKA_TRUSTED:
		return (get_bool_attr_from_object(object_p,
		    TRUSTED_BOOL_ON, template));

	case CKA_MODULUS:
		/*
		 * This attribute is valid only for RSA public key
		 * object.
		 */
		if (keytype == CKK_RSA) {
			return (get_bigint_attr_from_object(
			    OBJ_PUB_RSA_MOD(object_p), template));
		} else {
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	case CKA_PUBLIC_EXPONENT:
		if (keytype == CKK_RSA) {
			return (get_bigint_attr_from_object(
			    OBJ_PUB_RSA_PUBEXPO(object_p), template));
		} else {
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	case CKA_MODULUS_BITS:
		if (keytype == CKK_RSA) {
			return (get_ulong_attr_from_object(
			    OBJ_PUB_RSA_MOD_BITS(object_p), template));
		} else {
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	case CKA_PRIME:
		switch (keytype) {
		case CKK_DSA:
			return (get_bigint_attr_from_object(
			    OBJ_PUB_DSA_PRIME(object_p), template));

		case CKK_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PUB_DH_PRIME(object_p), template));

		case CKK_X9_42_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PUB_DH942_PRIME(object_p), template));

		default:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	case CKA_SUBPRIME:
		switch (keytype) {
		case CKK_DSA:
			return (get_bigint_attr_from_object(
			    OBJ_PUB_DSA_SUBPRIME(object_p), template));

		case CKK_X9_42_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PUB_DH942_SUBPRIME(object_p), template));

		default:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	case CKA_BASE:
		switch (keytype) {
		case CKK_DSA:
			return (get_bigint_attr_from_object(
			    OBJ_PUB_DSA_BASE(object_p), template));

		case CKK_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PUB_DH_BASE(object_p), template));

		case CKK_X9_42_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PUB_DH942_BASE(object_p), template));

		default:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	case CKA_EC_POINT:
		return (get_bigint_attr_from_object(
		    OBJ_PUB_EC_POINT(object_p), template));

	case CKA_VALUE:
		switch (keytype) {
		case CKK_DSA:
			return (get_bigint_attr_from_object(
			    OBJ_PUB_DSA_VALUE(object_p), template));

		case CKK_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PUB_DH_VALUE(object_p), template));

		case CKK_X9_42_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PUB_DH942_VALUE(object_p), template));

		default:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	default:
		/*
		 * First, get the value of the request attribute defined
		 * in the list of common key attributes. If the request
		 * attribute is not found in that list, then get the
		 * attribute from the list of common attributes.
		 */
		rv = soft_get_common_key_attrs(object_p, template);
		if (rv == CKR_ATTRIBUTE_TYPE_INVALID) {
			rv = soft_get_common_attrs(object_p, template,
			    object_p->object_type);
		}
		break;
	}

	return (rv);
}


/*
 * Get the value of a requested attribute of a Private Key Object.
 *
 * Rule: All the attributes in the private key object can be revealed
 *       except those marked with footnote number "7" when the object
 *       has its CKA_SENSITIVE attribute set to TRUE or its
 *       CKA_EXTRACTABLE attribute set to FALSE (p.88 in PKCS11 spec.).
 */
CK_RV
soft_get_private_key_attribute(soft_object_t *object_p,
	CK_ATTRIBUTE_PTR template)
{

	CK_RV		rv = CKR_OK;
	CK_KEY_TYPE	keytype = object_p->key_type;


	/*
	 * If the following specified attributes for the private key
	 * object cannot be revealed because the object is sensitive
	 * or unextractable, then the ulValueLen is set to -1.
	 */
	if ((object_p->bool_attr_mask & SENSITIVE_BOOL_ON) ||
	    !(object_p->bool_attr_mask & EXTRACTABLE_BOOL_ON)) {

		switch (template->type) {
		case CKA_PRIVATE_EXPONENT:
		case CKA_PRIME_1:
		case CKA_PRIME_2:
		case CKA_EXPONENT_1:
		case CKA_EXPONENT_2:
		case CKA_COEFFICIENT:
		case CKA_VALUE:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_SENSITIVE);
		}
	}

	switch (template->type) {

	case CKA_SUBJECT:
	case CKA_EC_PARAMS:
		/*
		 * The above extra attributes have byte array type.
		 */
		return (get_extra_attr_from_object(object_p,
		    template));

	/* Key related boolean attributes */
	case CKA_SENSITIVE:
		return (get_bool_attr_from_object(object_p,
		    SENSITIVE_BOOL_ON, template));

	case CKA_SECONDARY_AUTH:
		return (get_bool_attr_from_object(object_p,
		    SECONDARY_AUTH_BOOL_ON, template));

	case CKA_DECRYPT:
		return (get_bool_attr_from_object(object_p,
		    DECRYPT_BOOL_ON, template));

	case CKA_SIGN:
		return (get_bool_attr_from_object(object_p,
		    SIGN_BOOL_ON, template));

	case CKA_SIGN_RECOVER:
		return (get_bool_attr_from_object(object_p,
		    SIGN_RECOVER_BOOL_ON, template));

	case CKA_UNWRAP:
		return (get_bool_attr_from_object(object_p,
		    UNWRAP_BOOL_ON, template));

	case CKA_EXTRACTABLE:
		return (get_bool_attr_from_object(object_p,
		    EXTRACTABLE_BOOL_ON, template));

	case CKA_ALWAYS_SENSITIVE:
		return (get_bool_attr_from_object(object_p,
		    ALWAYS_SENSITIVE_BOOL_ON, template));

	case CKA_NEVER_EXTRACTABLE:
		return (get_bool_attr_from_object(object_p,
		    NEVER_EXTRACTABLE_BOOL_ON, template));

	case CKA_MODULUS:
		if (keytype == CKK_RSA) {
			return (get_bigint_attr_from_object(
			    OBJ_PRI_RSA_MOD(object_p), template));
		} else {
			template->ulValueLen = (CK_ULONG)-1;
			rv = CKR_ATTRIBUTE_TYPE_INVALID;
			break;
		}

	case CKA_PUBLIC_EXPONENT:
		if (keytype == CKK_RSA) {
			return (get_bigint_attr_from_object(
			    OBJ_PRI_RSA_PUBEXPO(object_p), template));
		} else {
			template->ulValueLen = (CK_ULONG)-1;
			rv = CKR_ATTRIBUTE_TYPE_INVALID;
			break;
		}

	case CKA_PRIVATE_EXPONENT:
		if (keytype == CKK_RSA) {
			return (get_bigint_attr_from_object(
			    OBJ_PRI_RSA_PRIEXPO(object_p), template));
		} else {
			template->ulValueLen = (CK_ULONG)-1;
			rv = CKR_ATTRIBUTE_TYPE_INVALID;
			break;
		}

	case CKA_PRIME_1:
		if (keytype == CKK_RSA) {
			return (get_bigint_attr_from_object(
			    OBJ_PRI_RSA_PRIME1(object_p), template));
		} else {
			template->ulValueLen = (CK_ULONG)-1;
			rv = CKR_ATTRIBUTE_TYPE_INVALID;
			break;
		}

	case CKA_PRIME_2:
		if (keytype == CKK_RSA) {
			return (get_bigint_attr_from_object(
			    OBJ_PRI_RSA_PRIME2(object_p), template));
		} else {
			template->ulValueLen = (CK_ULONG)-1;
			rv = CKR_ATTRIBUTE_TYPE_INVALID;
			break;
		}

	case CKA_EXPONENT_1:
		if (keytype == CKK_RSA) {
			return (get_bigint_attr_from_object(
			    OBJ_PRI_RSA_EXPO1(object_p), template));
		} else {
			template->ulValueLen = (CK_ULONG)-1;
			rv = CKR_ATTRIBUTE_TYPE_INVALID;
			break;
		}

	case CKA_EXPONENT_2:
		if (keytype == CKK_RSA) {
			return (get_bigint_attr_from_object(
			    OBJ_PRI_RSA_EXPO2(object_p), template));
		} else {
			template->ulValueLen = (CK_ULONG)-1;
			rv = CKR_ATTRIBUTE_TYPE_INVALID;
			break;
		}

	case CKA_COEFFICIENT:
		if (keytype == CKK_RSA) {
			return (get_bigint_attr_from_object(
			    OBJ_PRI_RSA_COEF(object_p), template));
		} else {
			template->ulValueLen = (CK_ULONG)-1;
			rv = CKR_ATTRIBUTE_TYPE_INVALID;
			break;
		}

	case CKA_VALUE_BITS:
		if (keytype == CKK_DH) {
			return (get_ulong_attr_from_object(
			    OBJ_PRI_DH_VAL_BITS(object_p), template));
		} else {
			template->ulValueLen = (CK_ULONG)-1;
			rv = CKR_ATTRIBUTE_TYPE_INVALID;
			break;
		}

	case CKA_PRIME:
		switch (keytype) {
		case CKK_DSA:
			return (get_bigint_attr_from_object(
			    OBJ_PRI_DSA_PRIME(object_p), template));

		case CKK_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PRI_DH_PRIME(object_p), template));

		case CKK_X9_42_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PRI_DH942_PRIME(object_p), template));

		default:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	case CKA_SUBPRIME:
		switch (keytype) {
		case CKK_DSA:
			return (get_bigint_attr_from_object(
			    OBJ_PRI_DSA_SUBPRIME(object_p), template));

		case CKK_X9_42_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PRI_DH942_SUBPRIME(object_p), template));

		default:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	case CKA_BASE:
		switch (keytype) {
		case CKK_DSA:
			return (get_bigint_attr_from_object(
			    OBJ_PRI_DSA_BASE(object_p), template));

		case CKK_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PRI_DH_BASE(object_p), template));

		case CKK_X9_42_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PRI_DH942_BASE(object_p), template));

		default:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	case CKA_VALUE:
		switch (keytype) {
		case CKK_DSA:
			return (get_bigint_attr_from_object(
			    OBJ_PRI_DSA_VALUE(object_p), template));

		case CKK_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PRI_DH_VALUE(object_p), template));

		case CKK_X9_42_DH:
			return (get_bigint_attr_from_object(
			    OBJ_PRI_DH942_VALUE(object_p), template));

		case CKK_EC:
			return (get_bigint_attr_from_object(
			    OBJ_PRI_EC_VALUE(object_p), template));

		default:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	default:
		/*
		 * First, get the value of the request attribute defined
		 * in the list of common key attributes. If the request
		 * attribute is not found in that list, then get the
		 * attribute from the list of common attributes.
		 */
		rv = soft_get_common_key_attrs(object_p, template);
		if (rv == CKR_ATTRIBUTE_TYPE_INVALID) {
			rv = soft_get_common_attrs(object_p, template,
			    object_p->object_type);
		}
		break;
	}

	return (rv);
}


/*
 * Get the value of a requested attribute of a Secret Key Object.
 *
 * Rule: All the attributes in the secret key object can be revealed
 *       except those marked with footnote number "7" when the object
 *       has its CKA_SENSITIVE attribute set to TRUE or its
 *       CKA_EXTRACTABLE attribute set to FALSE (p.88 in PKCS11 spec.).
 */
CK_RV
soft_get_secret_key_attribute(soft_object_t *object_p,
	CK_ATTRIBUTE_PTR template)
{

	CK_RV		rv = CKR_OK;
	CK_KEY_TYPE	keytype = object_p->key_type;

	switch (template->type) {

	/* Key related boolean attributes */
	case CKA_SENSITIVE:
		return (get_bool_attr_from_object(object_p,
		    SENSITIVE_BOOL_ON, template));

	case CKA_ENCRYPT:
		return (get_bool_attr_from_object(object_p,
		    ENCRYPT_BOOL_ON, template));

	case CKA_DECRYPT:
		return (get_bool_attr_from_object(object_p,
		    DECRYPT_BOOL_ON, template));

	case CKA_SIGN:
		return (get_bool_attr_from_object(object_p,
		    SIGN_BOOL_ON, template));

	case CKA_VERIFY:
		return (get_bool_attr_from_object(object_p,
		    VERIFY_BOOL_ON, template));

	case CKA_WRAP:
		return (get_bool_attr_from_object(object_p,
		    WRAP_BOOL_ON, template));

	case CKA_UNWRAP:
		return (get_bool_attr_from_object(object_p,
		    UNWRAP_BOOL_ON, template));

	case CKA_EXTRACTABLE:
		return (get_bool_attr_from_object(object_p,
		    EXTRACTABLE_BOOL_ON, template));

	case CKA_ALWAYS_SENSITIVE:
		return (get_bool_attr_from_object(object_p,
		    ALWAYS_SENSITIVE_BOOL_ON, template));

	case CKA_NEVER_EXTRACTABLE:
		return (get_bool_attr_from_object(object_p,
		    NEVER_EXTRACTABLE_BOOL_ON, template));

	case CKA_VALUE:
	case CKA_VALUE_LEN:
		/*
		 * If the specified attribute for the secret key object
		 * cannot be revealed because the object is sensitive
		 * or unextractable, then the ulValueLen is set to -1.
		 */
		if ((object_p->bool_attr_mask & SENSITIVE_BOOL_ON) ||
		    !(object_p->bool_attr_mask & EXTRACTABLE_BOOL_ON)) {
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_SENSITIVE);
		}

		switch (keytype) {
		case CKK_RC4:
		case CKK_GENERIC_SECRET:
		case CKK_RC5:
		case CKK_DES:
		case CKK_DES2:
		case CKK_DES3:
		case CKK_CDMF:
		case CKK_AES:
		case CKK_BLOWFISH:
			if (template->type == CKA_VALUE_LEN) {
				return (get_ulong_attr_from_object(
				    OBJ_SEC_VALUE_LEN(object_p),
				    template));
			} else {
				return (get_bigint_attr_from_object(
				    (biginteger_t *)OBJ_SEC(object_p),
				    template));
			}
		default:
			template->ulValueLen = (CK_ULONG)-1;
			rv = CKR_ATTRIBUTE_TYPE_INVALID;
			break;
		}
		break;

	default:
		/*
		 * First, get the value of the request attribute defined
		 * in the list of common key attributes. If the request
		 * attribute is not found in that list, then get the
		 * attribute from the list of common attributes.
		 */
		rv = soft_get_common_key_attrs(object_p, template);
		if (rv == CKR_ATTRIBUTE_TYPE_INVALID) {
			rv = soft_get_common_attrs(object_p, template,
			    object_p->object_type);
		}
		break;
	}

	return (rv);
}


/*
 * Get the value of a requested attribute of a Domain Parameters Object.
 *
 * Rule: All the attributes in the domain parameters object can be revealed.
 */
CK_RV
soft_get_domain_parameters_attribute(soft_object_t *object_p,
	CK_ATTRIBUTE_PTR template)
{

	CK_RV		rv = CKR_OK;
	CK_KEY_TYPE	keytype = object_p->key_type;

	switch (template->type) {

	case CKA_KEY_TYPE:
		return (get_ulong_attr_from_object(keytype,
		    template));

	case CKA_LOCAL:
		return (get_bool_attr_from_object(object_p,
		    LOCAL_BOOL_ON, template));

	case CKA_PRIME:
		switch (keytype) {
		case CKK_DSA:
			return (get_bigint_attr_from_object(
			    OBJ_DOM_DSA_PRIME(object_p), template));

		case CKK_DH:
			return (get_bigint_attr_from_object(
			    OBJ_DOM_DH_PRIME(object_p), template));

		case CKK_X9_42_DH:
			return (get_bigint_attr_from_object(
			    OBJ_DOM_DH942_PRIME(object_p), template));

		default:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	case CKA_SUBPRIME:
		switch (keytype) {
		case CKK_DSA:
			return (get_bigint_attr_from_object(
			    OBJ_DOM_DSA_SUBPRIME(object_p), template));

		case CKK_X9_42_DH:
			return (get_bigint_attr_from_object(
			    OBJ_DOM_DH942_SUBPRIME(object_p), template));

		default:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	case CKA_BASE:
		switch (keytype) {
		case CKK_DSA:
			return (get_bigint_attr_from_object(
			    OBJ_DOM_DSA_BASE(object_p), template));

		case CKK_DH:
			return (get_bigint_attr_from_object(
			    OBJ_DOM_DH_BASE(object_p), template));

		case CKK_X9_42_DH:
			return (get_bigint_attr_from_object(
			    OBJ_DOM_DH942_BASE(object_p), template));

		default:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	case CKA_PRIME_BITS:
		switch (keytype) {
		case CKK_DSA:
			return (get_ulong_attr_from_object(
			    OBJ_DOM_DSA_PRIME_BITS(object_p), template));

		case CKK_DH:
			return (get_ulong_attr_from_object(
			    OBJ_DOM_DH_PRIME_BITS(object_p), template));

		case CKK_X9_42_DH:
			return (get_ulong_attr_from_object(
			    OBJ_DOM_DH942_PRIME_BITS(object_p), template));

		default:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	case CKA_SUB_PRIME_BITS:
		switch (keytype) {
		case CKK_X9_42_DH:
			return (get_ulong_attr_from_object(
			    OBJ_DOM_DH942_SUBPRIME_BITS(object_p), template));

		default:
			template->ulValueLen = (CK_ULONG)-1;
			return (CKR_ATTRIBUTE_TYPE_INVALID);
		}

	default:
		/*
		 * Get the value of a common attribute.
		 */
		rv = soft_get_common_attrs(object_p, template,
		    object_p->object_type);
		break;
	}

	return (rv);
}

/*
 * Get certificate attributes from an object.
 * return CKR_ATTRIBUTE_TYPE_INVALID if the requested type
 * does not exist in the certificate.
 */
CK_RV
soft_get_certificate_attribute(soft_object_t *object_p,
	CK_ATTRIBUTE_PTR template)
{
	CK_CERTIFICATE_TYPE certtype = object_p->cert_type;
	cert_attr_t src;

	switch (template->type) {
		case CKA_SUBJECT:
			if (certtype == CKC_X_509) {
				return (get_cert_attr_from_object(
				    X509_CERT_SUBJECT(object_p), template));
			}
			break;
		case CKA_VALUE:
			if (certtype == CKC_X_509) {
				return (get_cert_attr_from_object(
				    X509_CERT_VALUE(object_p), template));
			} else if (certtype == CKC_X_509_ATTR_CERT) {
				return (get_cert_attr_from_object(
				    X509_ATTR_CERT_VALUE(object_p), template));
			}
			break;
		case CKA_OWNER:
			if (certtype == CKC_X_509_ATTR_CERT) {
				return (get_cert_attr_from_object(
				    X509_ATTR_CERT_OWNER(object_p), template));
			}
			break;
		case CKA_CERTIFICATE_TYPE:
			src.value = (CK_BYTE *)&certtype;
			src.length = sizeof (certtype);
			return (get_cert_attr_from_object(&src, template));
		case CKA_TRUSTED:
			return (get_bool_attr_from_object(object_p,
			    TRUSTED_BOOL_ON, template));
		case CKA_ID:
		case CKA_ISSUER:
		case CKA_SERIAL_NUMBER:
		case CKA_AC_ISSUER:
		case CKA_ATTR_TYPES:
			return (get_extra_attr_from_object(object_p,
			    template));
		default:
			return (soft_get_common_attrs(object_p, template,
			    object_p->object_type));
	}

	/*
	 * If we got this far, then the combination of certificate type
	 * and requested attribute is invalid.
	 */
	return (CKR_ATTRIBUTE_TYPE_INVALID);
}

CK_RV
soft_set_certificate_attribute(soft_object_t *object_p,
	CK_ATTRIBUTE_PTR template, boolean_t copy)
{
	CK_CERTIFICATE_TYPE certtype = object_p->cert_type;

	switch (template->type) {
		case CKA_SUBJECT:
			if (certtype == CKC_X_509) {
				/* SUBJECT attr cannot be modified. */
				return (CKR_ATTRIBUTE_READ_ONLY);
			}
			break;
		case CKA_OWNER:
			if (certtype == CKC_X_509_ATTR_CERT) {
				/* OWNER attr cannot be modified. */
				return (CKR_ATTRIBUTE_READ_ONLY);
			}
			break;
		case CKA_VALUE:
			/* VALUE attr cannot be modified. */
			return (CKR_ATTRIBUTE_READ_ONLY);
		case CKA_ID:
		case CKA_ISSUER:
			if (certtype == CKC_X_509) {
				return (set_extra_attr_to_object(object_p,
				    template->type, template));
			}
			break;
		case CKA_AC_ISSUER:
		case CKA_ATTR_TYPES:
			if (certtype == CKC_X_509_ATTR_CERT) {
				return (set_extra_attr_to_object(object_p,
				    template->type, template));
			}
			break;
		case CKA_SERIAL_NUMBER:
		case CKA_LABEL:
			return (set_extra_attr_to_object(object_p,
			    template->type, template));
		default:
			return (soft_set_common_storage_attribute(
			    object_p, template, copy));
	}

	/*
	 * If we got this far, then the combination of certificate type
	 * and requested attribute is invalid.
	 */
	return (CKR_ATTRIBUTE_TYPE_INVALID);
}

/*
 * Call the appropriate get attribute function according to the class
 * of object.
 *
 * The caller of this function holds the lock on the object.
 */
CK_RV
soft_get_attribute(soft_object_t *object_p, CK_ATTRIBUTE_PTR template)
{

	CK_RV		rv = CKR_OK;
	CK_OBJECT_CLASS class = object_p->class;

	switch (class) {
	case CKO_PUBLIC_KEY:
		rv = soft_get_public_key_attribute(object_p, template);
		break;

	case CKO_PRIVATE_KEY:
		rv = soft_get_private_key_attribute(object_p, template);
		break;

	case CKO_SECRET_KEY:
		rv = soft_get_secret_key_attribute(object_p, template);
		break;

	case CKO_DOMAIN_PARAMETERS:
		rv = soft_get_domain_parameters_attribute(object_p, template);
		break;

	case CKO_CERTIFICATE:
		rv = soft_get_certificate_attribute(object_p, template);
		break;

	default:
		/*
		 * If the specified attribute for the object is invalid
		 * (the object does not possess such as attribute), then
		 * the ulValueLen is modified to hold the value -1.
		 */
		template->ulValueLen = (CK_ULONG)-1;
		return (CKR_ATTRIBUTE_TYPE_INVALID);
	}

	return (rv);

}

CK_RV
soft_set_common_storage_attribute(soft_object_t *object_p,
	CK_ATTRIBUTE_PTR template, boolean_t copy)
{

	CK_RV rv = CKR_OK;

	switch (template->type) {

	case CKA_TOKEN:
		if (copy) {
			if ((*(CK_BBOOL *)template->pValue) == B_TRUE) {
				if (!soft_keystore_status(KEYSTORE_INITIALIZED))
					return (CKR_DEVICE_REMOVED);
				object_p->object_type |= TOKEN_OBJECT;
			}
		} else {
			rv = CKR_ATTRIBUTE_READ_ONLY;
		}

		break;

	case CKA_PRIVATE:
		if (copy) {
			if ((*(CK_BBOOL *)template->pValue) == B_TRUE) {
				(void) pthread_mutex_lock(&soft_giant_mutex);
				if (!soft_slot.authenticated) {
					/*
					 * Check if this is the special case
					 * when the PIN is never initialized
					 * in the keystore. If true, we will
					 * let it pass here and let it fail
					 * with CKR_PIN_EXPIRED later on.
					 */
					if (!soft_slot.userpin_change_needed) {
						(void) pthread_mutex_unlock(
						    &soft_giant_mutex);
						return (CKR_USER_NOT_LOGGED_IN);
					}
				}
				(void) pthread_mutex_unlock(&soft_giant_mutex);
				object_p->object_type |= PRIVATE_OBJECT;
			}
		} else {
			rv = CKR_ATTRIBUTE_READ_ONLY;
		}
		break;

	case CKA_MODIFIABLE:
		if (copy) {
			if ((*(CK_BBOOL *)template->pValue) == TRUE)
				object_p->bool_attr_mask &=
				    ~NOT_MODIFIABLE_BOOL_ON;
			else
				object_p->bool_attr_mask |=
				    NOT_MODIFIABLE_BOOL_ON;
		} else {
			rv = CKR_ATTRIBUTE_READ_ONLY;
		}
		break;

	case CKA_CLASS:
		rv = CKR_ATTRIBUTE_READ_ONLY;
		break;

	default:
		rv = CKR_TEMPLATE_INCONSISTENT;
	}

	return (rv);
}

/*
 * Set the value of an attribute that is common to all key objects
 * (i.e. public key, private key and secret key).
 */
CK_RV
soft_set_common_key_attribute(soft_object_t *object_p,
	CK_ATTRIBUTE_PTR template, boolean_t copy)
{

	switch (template->type) {

	case CKA_LABEL:
		/*
		 * Only the LABEL can be modified in the common storage
		 * object attributes after the object is created.
		 */
		return (set_extra_attr_to_object(object_p,
		    CKA_LABEL, template));

	case CKA_ID:
		return (set_extra_attr_to_object(object_p,
		    CKA_ID, template));

	case CKA_START_DATE:
		return (set_extra_attr_to_object(object_p,
		    CKA_START_DATE, template));

	case CKA_END_DATE:
		return (set_extra_attr_to_object(object_p,
		    CKA_END_DATE, template));

	case CKA_DERIVE:
		return (set_bool_attr_to_object(object_p,
		    DERIVE_BOOL_ON, template));

	case CKA_KEY_TYPE:
	case CKA_LOCAL:
	case CKA_KEY_GEN_MECHANISM:
		return (CKR_ATTRIBUTE_READ_ONLY);

	default:
		return (soft_set_common_storage_attribute(object_p,
		    template, copy));

	}

}


/*
 * Set the value of an attribute of a Public Key Object.
 *
 * Rule: The attributes marked with footnote number "8" in the PKCS11
 *       spec may be modified (p.88 in PKCS11 spec.).
 */
CK_RV
soft_set_public_key_attribute(soft_object_t *object_p,
	CK_ATTRIBUTE_PTR template, boolean_t copy)
{
	CK_KEY_TYPE	keytype = object_p->key_type;

	switch (template->type) {

	case CKA_SUBJECT:
		return (set_extra_attr_to_object(object_p,
		    CKA_SUBJECT, template));

	case CKA_ENCRYPT:
		return (set_bool_attr_to_object(object_p,
		    ENCRYPT_BOOL_ON, template));

	case CKA_VERIFY:
		return (set_bool_attr_to_object(object_p,
		    VERIFY_BOOL_ON, template));

	case CKA_VERIFY_RECOVER:
		return (set_bool_attr_to_object(object_p,
		    VERIFY_RECOVER_BOOL_ON, template));

	case CKA_WRAP:
		return (set_bool_attr_to_object(object_p,
		    WRAP_BOOL_ON, template));

	case CKA_MODULUS:
	case CKA_MODULUS_BITS:
	case CKA_PUBLIC_EXPONENT:
		if (keytype == CKK_RSA)
			return (CKR_ATTRIBUTE_READ_ONLY);
		break;

	case CKA_SUBPRIME:
		if ((keytype == CKK_DSA) ||
		    (keytype == CKK_X9_42_DH))
			return (CKR_ATTRIBUTE_READ_ONLY);
		break;

	case CKA_PRIME:
	case CKA_BASE:
	case CKA_VALUE:
		if ((keytype == CKK_DSA) ||
		    (keytype == CKK_DH) ||
		    (keytype == CKK_X9_42_DH))
			return (CKR_ATTRIBUTE_READ_ONLY);
		break;

	default:
		/*
		 * Set the value of a common key attribute.
		 */
		return (soft_set_common_key_attribute(object_p,
		    template, copy));

	}
	/*
	 * If we got this far, then the combination of key type
	 * and requested attribute is invalid.
	 */
	return (CKR_ATTRIBUTE_TYPE_INVALID);
}


/*
 * Set the value of an attribute of a Private Key Object.
 *
 * Rule: The attributes marked with footnote number "8" in the PKCS11
 *       spec may be modified (p.88 in PKCS11 spec.).
 */
CK_RV
soft_set_private_key_attribute(soft_object_t *object_p,
	CK_ATTRIBUTE_PTR template, boolean_t copy)
{
	CK_KEY_TYPE	keytype = object_p->key_type;

	switch (template->type) {

	case CKA_SUBJECT:
		return (set_extra_attr_to_object(object_p,
		    CKA_SUBJECT, template));

	case CKA_SENSITIVE:
		/*
		 * Cannot set SENSITIVE to FALSE if it is already ON.
		 */
		if (((*(CK_BBOOL *)template->pValue) == B_FALSE) &&
		    (object_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
			return (CKR_ATTRIBUTE_READ_ONLY);
		}

		if (*(CK_BBOOL *)template->pValue)
			object_p->bool_attr_mask |= SENSITIVE_BOOL_ON;
		return (CKR_OK);

	case CKA_DECRYPT:
		return (set_bool_attr_to_object(object_p,
		    DECRYPT_BOOL_ON, template));

	case CKA_SIGN:
		return (set_bool_attr_to_object(object_p,
		    SIGN_BOOL_ON, template));

	case CKA_SIGN_RECOVER:
		return (set_bool_attr_to_object(object_p,
		    SIGN_RECOVER_BOOL_ON, template));

	case CKA_UNWRAP:
		return (set_bool_attr_to_object(object_p,
		    UNWRAP_BOOL_ON, template));

	case CKA_EXTRACTABLE:
		/*
		 * Cannot set EXTRACTABLE to TRUE if it is already OFF.
		 */
		if ((*(CK_BBOOL *)template->pValue) &&
		    !(object_p->bool_attr_mask & EXTRACTABLE_BOOL_ON)) {
			return (CKR_ATTRIBUTE_READ_ONLY);
		}

		if ((*(CK_BBOOL *)template->pValue) == B_FALSE)
			object_p->bool_attr_mask &= ~EXTRACTABLE_BOOL_ON;
		return (CKR_OK);

	case CKA_MODULUS:
	case CKA_PUBLIC_EXPONENT:
	case CKA_PRIVATE_EXPONENT:
	case CKA_PRIME_1:
	case CKA_PRIME_2:
	case CKA_EXPONENT_1:
	case CKA_EXPONENT_2:
	case CKA_COEFFICIENT:
		if (keytype == CKK_RSA) {
			return (CKR_ATTRIBUTE_READ_ONLY);
		}
		break;

	case CKA_SUBPRIME:
		if ((keytype == CKK_DSA) ||
		    (keytype == CKK_X9_42_DH))
			return (CKR_ATTRIBUTE_READ_ONLY);
		break;

	case CKA_PRIME:
	case CKA_BASE:
	case CKA_VALUE:
		if ((keytype == CKK_DSA) ||
		    (keytype == CKK_DH) ||
		    (keytype == CKK_X9_42_DH))
			return (CKR_ATTRIBUTE_READ_ONLY);
		break;

	case CKA_VALUE_BITS:
		if (keytype == CKK_DH)
			return (CKR_ATTRIBUTE_READ_ONLY);
		break;

	default:
		/*
		 * Set the value of a common key attribute.
		 */
		return (soft_set_common_key_attribute(object_p,
		    template, copy));
	}

	/*
	 * If we got this far, then the combination of key type
	 * and requested attribute is invalid.
	 */
	return (CKR_ATTRIBUTE_TYPE_INVALID);
}

/*
 * Set the value of an attribute of a Secret Key Object.
 *
 * Rule: The attributes marked with footnote number "8" in the PKCS11
 *       spec may be modified (p.88 in PKCS11 spec.).
 */
CK_RV
soft_set_secret_key_attribute(soft_object_t *object_p,
	CK_ATTRIBUTE_PTR template, boolean_t copy)
{
	CK_KEY_TYPE	keytype = object_p->key_type;

	switch (template->type) {

	case CKA_SENSITIVE:
		/*
		 * Cannot set SENSITIVE to FALSE if it is already ON.
		 */
		if (((*(CK_BBOOL *)template->pValue) == B_FALSE) &&
		    (object_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
			return (CKR_ATTRIBUTE_READ_ONLY);
		}

		if (*(CK_BBOOL *)template->pValue)
			object_p->bool_attr_mask |= SENSITIVE_BOOL_ON;
		return (CKR_OK);

	case CKA_ENCRYPT:
		return (set_bool_attr_to_object(object_p,
		    ENCRYPT_BOOL_ON, template));

	case CKA_DECRYPT:
		return (set_bool_attr_to_object(object_p,
		    DECRYPT_BOOL_ON, template));

	case CKA_SIGN:
		return (set_bool_attr_to_object(object_p,
		    SIGN_BOOL_ON, template));

	case CKA_VERIFY:
		return (set_bool_attr_to_object(object_p,
		    VERIFY_BOOL_ON, template));

	case CKA_WRAP:
		return (set_bool_attr_to_object(object_p,
		    WRAP_BOOL_ON, template));

	case CKA_UNWRAP:
		return (set_bool_attr_to_object(object_p,
		    UNWRAP_BOOL_ON, template));

	case CKA_EXTRACTABLE:
		/*
		 * Cannot set EXTRACTABLE to TRUE if it is already OFF.
		 */
		if ((*(CK_BBOOL *)template->pValue) &&
		    !(object_p->bool_attr_mask & EXTRACTABLE_BOOL_ON)) {
			return (CKR_ATTRIBUTE_READ_ONLY);
		}

		if ((*(CK_BBOOL *)template->pValue) == B_FALSE)
			object_p->bool_attr_mask &= ~EXTRACTABLE_BOOL_ON;
		return (CKR_OK);

	case CKA_VALUE:
		return (CKR_ATTRIBUTE_READ_ONLY);

	case CKA_VALUE_LEN:
		if ((keytype == CKK_RC4) ||
		    (keytype == CKK_GENERIC_SECRET) ||
		    (keytype == CKK_AES) ||
		    (keytype == CKK_BLOWFISH))
			return (CKR_ATTRIBUTE_READ_ONLY);
		break;

	default:
		/*
		 * Set the value of a common key attribute.
		 */
		return (soft_set_common_key_attribute(object_p,
		    template, copy));

	}
	/*
	 * If we got this far, then the combination of key type
	 * and requested attribute is invalid.
	 */
	return (CKR_ATTRIBUTE_TYPE_INVALID);
}


/*
 * Call the appropriate set attribute function according to the class
 * of object.
 *
 * The caller of this function does not hold the lock on the original
 * object, since this function is setting the attribute on the new object
 * that is being modified.
 *
 * Argument copy: TRUE when called by C_CopyObject,
 *		  FALSE when called by C_SetAttributeValue.
 */
CK_RV
soft_set_attribute(soft_object_t *object_p, CK_ATTRIBUTE_PTR template,
    boolean_t copy)
{

	CK_RV		rv = CKR_OK;
	CK_OBJECT_CLASS	class = object_p->class;

	switch (class) {

	case CKO_PUBLIC_KEY:
		rv = soft_set_public_key_attribute(object_p, template, copy);
		break;

	case CKO_PRIVATE_KEY:
		rv = soft_set_private_key_attribute(object_p, template, copy);
		break;

	case CKO_SECRET_KEY:
		rv = soft_set_secret_key_attribute(object_p, template, copy);
		break;

	case CKO_DOMAIN_PARAMETERS:
		switch (template->type) {
		case CKA_LABEL:
			/*
			 * Only the LABEL can be modified in the common
			 * storage object attributes after the object is
			 * created.
			 */
			return (set_extra_attr_to_object(object_p,
			    CKA_LABEL, template));
		default:
			return (CKR_TEMPLATE_INCONSISTENT);
		}
	case CKO_CERTIFICATE:
		rv = soft_set_certificate_attribute(object_p, template, copy);
		break;

	default:
		/*
		 * If the template specifies a value of an attribute
		 * which is incompatible with other existing attributes
		 * of the object, then fails with return code
		 * CKR_TEMPLATE_INCONSISTENT.
		 */
		rv = CKR_TEMPLATE_INCONSISTENT;
		break;
	}

	return (rv);
}

CK_RV
soft_get_public_value(soft_object_t *key, CK_ATTRIBUTE_TYPE type,
    uchar_t *value, uint32_t *value_len)
{
	uint32_t len = 0;
	switch (type) {

	/* The following attributes belong to RSA */
	case CKA_MODULUS:
#ifdef	__sparcv9
		len =
		    /* LINTED */
		    (uint32_t)
		    ((biginteger_t *)OBJ_PUB_RSA_MOD(key))->big_value_len;
#else	/* !__sparcv9 */
		len =
		    ((biginteger_t *)OBJ_PUB_RSA_MOD(key))->big_value_len;
#endif	/* __sparcv9 */

		/* This attribute MUST BE set */
		if (len == 0 || len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		(void) memcpy(value,
		    ((biginteger_t *)OBJ_PUB_RSA_MOD(key))->big_value,
		    *value_len);

		break;

	case CKA_PUBLIC_EXPONENT:
#ifdef	__sparcv9
		len =
		    /* LINTED */
		    (uint32_t)
		    ((biginteger_t *)OBJ_PUB_RSA_PUBEXPO(key))->big_value_len;
#else	/* !__sparcv9 */
		len =
		    ((biginteger_t *)OBJ_PUB_RSA_PUBEXPO(key))->big_value_len;
#endif	/* __sparcv9 */

		/* This attribute MUST BE set */
		if (len == 0 || len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		(void) memcpy(value,
		    ((biginteger_t *)OBJ_PUB_RSA_PUBEXPO(key))->big_value,
		    *value_len);

		break;

	/* The following attributes belong to DSA and DH */
	case CKA_PRIME:

		if (key->key_type == CKK_DSA)
#ifdef	__sparcv9
			len =
			    /* LINTED */
			    (uint32_t)
			    ((biginteger_t *)OBJ_PUB_DSA_PRIME(key))->
			    big_value_len;
#else	/* !__sparcv9 */
			len =
			    ((biginteger_t *)OBJ_PUB_DSA_PRIME(key))->
			    big_value_len;
#endif	/* __sparcv9 */
		else
#ifdef	__sparcv9
			len =
			    /* LINTED */
			    (uint32_t)
			    ((biginteger_t *)OBJ_PUB_DH_PRIME(key))->
			    big_value_len;
#else	/* !__sparcv9 */
			len =
			    ((biginteger_t *)OBJ_PUB_DH_PRIME(key))->
			    big_value_len;
#endif	/* __sparcv9 */

		/* This attribute MUST BE set */
		if (len == 0 || len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		if (key->key_type == CKK_DSA)
			(void) memcpy(value,
			    ((biginteger_t *)OBJ_PUB_DSA_PRIME(key))->big_value,
			    *value_len);
		else
			(void) memcpy(value,
			    ((biginteger_t *)OBJ_PUB_DH_PRIME(key))->big_value,
			    *value_len);

		break;

	case CKA_SUBPRIME:
#ifdef	__sparcv9
		len =
		    /* LINTED */
		    (uint32_t)
		    ((biginteger_t *)OBJ_PUB_DSA_SUBPRIME(key))->big_value_len;
#else	/* !__sparcv9 */
		len =
		    ((biginteger_t *)OBJ_PUB_DSA_SUBPRIME(key))->big_value_len;
#endif	/* __sparcv9 */

		/* This attribute MUST BE set */
		if (len == 0 || len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		(void) memcpy(value,
		    ((biginteger_t *)OBJ_PUB_DSA_SUBPRIME(key))->big_value,
		    *value_len);

		break;

	case CKA_BASE:

		if (key->key_type == CKK_DSA)
#ifdef	__sparcv9
			len =
			    /* LINTED */
			    (uint32_t)
			    ((biginteger_t *)OBJ_PUB_DSA_BASE(key))->
			    big_value_len;
#else	/* !__sparcv9 */
			len =
			    ((biginteger_t *)OBJ_PUB_DSA_BASE(key))->
			    big_value_len;
#endif	/* __sparcv9 */
		else
#ifdef	__sparcv9
			len =
			    /* LINTED */
			    (uint32_t)
			    ((biginteger_t *)OBJ_PUB_DH_BASE(key))->
			    big_value_len;
#else	/* !__sparcv9 */
			len =
			    ((biginteger_t *)OBJ_PUB_DH_BASE(key))->
			    big_value_len;
#endif	/* __sparcv9 */

		/* This attribute MUST BE set */
		if (len == 0 || len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		if (key->key_type == CKK_DSA)
			(void) memcpy(value,
			    ((biginteger_t *)OBJ_PUB_DSA_BASE(key))->big_value,
			    *value_len);
		else
			(void) memcpy(value,
			    ((biginteger_t *)OBJ_PUB_DH_BASE(key))->big_value,
			    *value_len);
		break;

	case CKA_VALUE:

		if (key->key_type == CKK_DSA)
#ifdef	__sparcv9
			len =
			    /* LINTED */
			    (uint32_t)
			    ((biginteger_t *)OBJ_PUB_DSA_VALUE(key))->
			    big_value_len;
#else	/* !__sparcv9 */
			len =
			    ((biginteger_t *)OBJ_PUB_DSA_VALUE(key))->
			    big_value_len;
#endif	/* __sparcv9 */
		else
#ifdef	__sparcv9
			len =
			    /* LINTED */
			    (uint32_t)
			    ((biginteger_t *)OBJ_PUB_DH_VALUE(key))->
			    big_value_len;
#else	/* !__sparcv9 */
			len =
			    ((biginteger_t *)OBJ_PUB_DH_VALUE(key))->
			    big_value_len;
#endif	/* __sparcv9 */

		/* This attribute MUST BE set */
		if (len == 0 || len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		if (key->key_type == CKK_DSA)
			(void) memcpy(value,
			    ((biginteger_t *)OBJ_PUB_DSA_VALUE(key))->big_value,
			    *value_len);
		else
			(void) memcpy(value,
			    ((biginteger_t *)OBJ_PUB_DH_VALUE(key))->big_value,
			    *value_len);

		break;
	}

	return (CKR_OK);
}


CK_RV
soft_get_private_value(soft_object_t *key, CK_ATTRIBUTE_TYPE type,
    uchar_t *value, uint32_t *value_len)
{

	uint32_t len = 0;

	switch (type) {

	/* The following attributes belong to RSA */
	case CKA_MODULUS:
#ifdef	__sparcv9
		len =
		    /* LINTED */
		    (uint32_t)
		    ((biginteger_t *)OBJ_PRI_RSA_MOD(key))->big_value_len;
#else	/* !__sparcv9 */
		len =
		    ((biginteger_t *)OBJ_PRI_RSA_MOD(key))->big_value_len;
#endif	/* __sparcv9 */

		/* This attribute MUST BE set */
		if (len == 0 || len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		(void) memcpy(value,
		    ((biginteger_t *)OBJ_PRI_RSA_MOD(key))->big_value,
		    *value_len);

		break;

	case CKA_PRIVATE_EXPONENT:
#ifdef	__sparcv9
		len =
		    /* LINTED */
		    (uint32_t)
		    ((biginteger_t *)OBJ_PRI_RSA_PRIEXPO(key))->big_value_len;
#else	/* !__sparcv9 */
		len =
		    ((biginteger_t *)OBJ_PRI_RSA_PRIEXPO(key))->big_value_len;
#endif	/* __sparcv9 */

		/* This attribute MUST BE set */
		if (len == 0 || len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		(void) memcpy(value,
		    ((biginteger_t *)OBJ_PRI_RSA_PRIEXPO(key))->big_value,
		    *value_len);

		break;

	case CKA_PRIME_1:
#ifdef	__sparcv9
		len =
		    /* LINTED */
		    (uint32_t)
		    ((biginteger_t *)OBJ_PRI_RSA_PRIME1(key))->big_value_len;
#else	/* !__sparcv9 */
		len =
		    ((biginteger_t *)OBJ_PRI_RSA_PRIME1(key))->big_value_len;
#endif	/* __sparcv9 */

		if (len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		if (*value_len == 0) {
			return (CKR_OK);
		}

		(void) memcpy(value,
		    ((biginteger_t *)OBJ_PRI_RSA_PRIME1(key))->big_value,
		    *value_len);

		break;

	case CKA_PRIME_2:
#ifdef	__sparcv9
		len =
		    /* LINTED */
		    (uint32_t)
		    ((biginteger_t *)OBJ_PRI_RSA_PRIME2(key))->big_value_len;
#else	/* !__sparcv9 */
		len =
		    ((biginteger_t *)OBJ_PRI_RSA_PRIME2(key))->big_value_len;
#endif	/* __sparcv9 */

		if (len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		if (*value_len == 0) {
			return (CKR_OK);
		}

		(void) memcpy(value,
		    ((biginteger_t *)OBJ_PRI_RSA_PRIME2(key))->big_value,
		    *value_len);

		break;

	case CKA_EXPONENT_1:
#ifdef	__sparcv9
		len =
		    /* LINTED */
		    (uint32_t)
		    ((biginteger_t *)OBJ_PRI_RSA_EXPO1(key))->big_value_len;
#else	/* !__sparcv9 */
		len =
		    ((biginteger_t *)OBJ_PRI_RSA_EXPO1(key))->big_value_len;
#endif	/* __sparcv9 */

		if (len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		if (*value_len == 0) {
			return (CKR_OK);
		}

		(void) memcpy(value,
		    ((biginteger_t *)OBJ_PRI_RSA_EXPO1(key))->big_value,
		    *value_len);

		break;

	case CKA_EXPONENT_2:
#ifdef	__sparcv9
		len =
		    /* LINTED */
		    (uint32_t)
		    ((biginteger_t *)OBJ_PRI_RSA_EXPO2(key))->big_value_len;
#else	/* !__sparcv9 */
		len =
		    ((biginteger_t *)OBJ_PRI_RSA_EXPO2(key))->big_value_len;
#endif	/* __sparcv9 */

		if (len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		if (*value_len == 0) {
			return (CKR_OK);
		}

		(void) memcpy(value,
		    ((biginteger_t *)OBJ_PRI_RSA_EXPO2(key))->big_value,
		    *value_len);

		break;

	case CKA_COEFFICIENT:
#ifdef	__sparcv9
		len =
		    /* LINTED */
		    (uint32_t)
		    ((biginteger_t *)OBJ_PRI_RSA_COEF(key))->big_value_len;
#else	/* !__sparcv9 */
		len =
		    ((biginteger_t *)OBJ_PRI_RSA_COEF(key))->big_value_len;
#endif	/* __sparcv9 */

		if (len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		if (*value_len == 0) {
			return (CKR_OK);
		}

		(void) memcpy(value,
		    ((biginteger_t *)OBJ_PRI_RSA_COEF(key))->big_value,
		    *value_len);

		break;

	/* The following attributes belong to DSA and DH */
	case CKA_PRIME:

		if (key->key_type == CKK_DSA)
#ifdef	__sparcv9
			len =
			    /* LINTED */
			    (uint32_t)
			    ((biginteger_t *)OBJ_PRI_DSA_PRIME(key))->
			    big_value_len;
#else	/* !__sparcv9 */
			len =
			    ((biginteger_t *)OBJ_PRI_DSA_PRIME(key))->
			    big_value_len;
#endif	/* __sparcv9 */
		else
#ifdef	__sparcv9
			len =
			    /* LINTED */
			    (uint32_t)
			    ((biginteger_t *)OBJ_PRI_DH_PRIME(key))->
			    big_value_len;
#else	/* !__sparcv9 */
			len =
			    ((biginteger_t *)OBJ_PRI_DH_PRIME(key))->
			    big_value_len;
#endif	/* __sparcv9 */

		/* This attribute MUST BE set */
		if (len == 0 || len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		if (key->key_type == CKK_DSA)
			(void) memcpy(value,
			    ((biginteger_t *)OBJ_PRI_DSA_PRIME(key))->big_value,
			    *value_len);
		else
			(void) memcpy(value,
			    ((biginteger_t *)OBJ_PRI_DH_PRIME(key))->big_value,
			    *value_len);

		break;

	case CKA_SUBPRIME:
#ifdef	__sparcv9
		len =
		    /* LINTED */
		    (uint32_t)
		    ((biginteger_t *)OBJ_PRI_DSA_SUBPRIME(key))->big_value_len;
#else	/* !__sparcv9 */
		len =
		    ((biginteger_t *)OBJ_PRI_DSA_SUBPRIME(key))->big_value_len;
#endif	/* __sparcv9 */

		/* This attribute MUST BE set */
		if (len == 0 || len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		(void) memcpy(value,
		    ((biginteger_t *)OBJ_PRI_DSA_SUBPRIME(key))->big_value,
		    *value_len);

		break;

	case CKA_BASE:

		if (key->key_type == CKK_DSA)
#ifdef	__sparcv9
			len =
			    /* LINTED */
			    (uint32_t)
			    ((biginteger_t *)OBJ_PRI_DSA_BASE(key))->
			    big_value_len;
#else	/* !__sparcv9 */
			len =
			    ((biginteger_t *)OBJ_PRI_DSA_BASE(key))->
			    big_value_len;
#endif	/* __sparcv9 */
		else
#ifdef	__sparcv9
			len =
			    /* LINTED */
			    (uint32_t)
			    ((biginteger_t *)OBJ_PRI_DH_BASE(key))->
			    big_value_len;
#else	/* !__sparcv9 */
			len =
			    ((biginteger_t *)OBJ_PRI_DH_BASE(key))->
			    big_value_len;
#endif	/* __sparcv9 */

		/* This attribute MUST BE set */
		if (len == 0 || len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		if (key->key_type == CKK_DSA)
			(void) memcpy(value,
			    ((biginteger_t *)OBJ_PRI_DSA_BASE(key))->big_value,
			    *value_len);
		else
			(void) memcpy(value,
			    ((biginteger_t *)OBJ_PRI_DH_BASE(key))->big_value,
			    *value_len);
		break;

	case CKA_VALUE:

		if (key->key_type == CKK_DSA) {
#ifdef	__sparcv9
			len =
			    /* LINTED */
			    (uint32_t)
			    ((biginteger_t *)OBJ_PRI_DSA_VALUE(key))->
			    big_value_len;
#else	/* !__sparcv9 */
			len =
			    ((biginteger_t *)OBJ_PRI_DSA_VALUE(key))->
			    big_value_len;
#endif	/* __sparcv9 */
		} else if (key->key_type == CKK_DH) {
#ifdef	__sparcv9
			len =
			    /* LINTED */
			    (uint32_t)
			    ((biginteger_t *)OBJ_PRI_DH_VALUE(key))->
			    big_value_len;
#else	/* !__sparcv9 */
			len =
			    ((biginteger_t *)OBJ_PRI_DH_VALUE(key))->
			    big_value_len;
#endif	/* __sparcv9 */
		} else {
#ifdef	__sparcv9
			len =
			    /* LINTED */
			    (uint32_t)
			    ((biginteger_t *)OBJ_PRI_EC_VALUE(key))->
			    big_value_len;
#else	/* !__sparcv9 */
			len =
			    ((biginteger_t *)OBJ_PRI_EC_VALUE(key))->
			    big_value_len;
#endif	/* __sparcv9 */
		}

		/* This attribute MUST BE set */
		if (len == 0 || len > *value_len) {
			return (CKR_ATTRIBUTE_VALUE_INVALID);
		}
		*value_len = len;

		if (key->key_type == CKK_DSA) {
			(void) memcpy(value,
			    ((biginteger_t *)OBJ_PRI_DSA_VALUE(key))->big_value,
			    *value_len);
		} else if (key->key_type == CKK_DH) {
			(void) memcpy(value,
			    ((biginteger_t *)OBJ_PRI_DH_VALUE(key))->big_value,
			    *value_len);
		} else {
			(void) memcpy(value,
			    ((biginteger_t *)OBJ_PRI_EC_VALUE(key))->big_value,
			    *value_len);
		}

		break;
	}

	return (CKR_OK);

}

static CK_RV
copy_bigint(biginteger_t *new_bigint, biginteger_t *old_bigint)
{
	new_bigint->big_value =
	    malloc((sizeof (CK_BYTE) * new_bigint->big_value_len));

	if (new_bigint->big_value == NULL) {
		return (CKR_HOST_MEMORY);
	}

	(void) memcpy(new_bigint->big_value, old_bigint->big_value,
	    (sizeof (CK_BYTE) * new_bigint->big_value_len));

	return (CKR_OK);
}

static void
free_public_key_attr(public_key_obj_t *pbk, CK_KEY_TYPE key_type)
{
	if (pbk == NULL) {
		return;
	}

	switch (key_type) {
		case CKK_RSA:
			bigint_attr_cleanup(KEY_PUB_RSA_MOD(pbk));
			bigint_attr_cleanup(KEY_PUB_RSA_PUBEXPO(pbk));
			break;
		case CKK_DSA:
			bigint_attr_cleanup(KEY_PUB_DSA_PRIME(pbk));
			bigint_attr_cleanup(KEY_PUB_DSA_SUBPRIME(pbk));
			bigint_attr_cleanup(KEY_PUB_DSA_BASE(pbk));
			bigint_attr_cleanup(KEY_PUB_DSA_VALUE(pbk));
			break;
		case CKK_DH:
			bigint_attr_cleanup(KEY_PUB_DH_PRIME(pbk));
			bigint_attr_cleanup(KEY_PUB_DH_BASE(pbk));
			bigint_attr_cleanup(KEY_PUB_DH_VALUE(pbk));
			break;
		case CKK_EC:
			bigint_attr_cleanup(KEY_PUB_EC_POINT(pbk));
			break;
		case CKK_X9_42_DH:
			bigint_attr_cleanup(KEY_PUB_DH942_PRIME(pbk));
			bigint_attr_cleanup(KEY_PUB_DH942_SUBPRIME(pbk));
			bigint_attr_cleanup(KEY_PUB_DH942_BASE(pbk));
			bigint_attr_cleanup(KEY_PUB_DH942_VALUE(pbk));
			break;
		default:
			break;
	}
	free(pbk);
}

CK_RV
soft_copy_public_key_attr(public_key_obj_t *old_pub_key_obj_p,
    public_key_obj_t **new_pub_key_obj_p, CK_KEY_TYPE key_type)
{

	public_key_obj_t *pbk;
	CK_RV rv = CKR_OK;

	pbk = calloc(1, sizeof (public_key_obj_t));
	if (pbk == NULL) {
		return (CKR_HOST_MEMORY);
	}

	switch (key_type) {
		case CKK_RSA:
			(void) memcpy(KEY_PUB_RSA(pbk),
			    KEY_PUB_RSA(old_pub_key_obj_p),
			    sizeof (rsa_pub_key_t));
			/* copy modulus */
			rv = copy_bigint(KEY_PUB_RSA_MOD(pbk),
			    KEY_PUB_RSA_MOD(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}
			/* copy public exponent */
			rv = copy_bigint(KEY_PUB_RSA_PUBEXPO(pbk),
			    KEY_PUB_RSA_PUBEXPO(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}
			break;
		case CKK_DSA:
			(void) memcpy(KEY_PUB_DSA(pbk),
			    KEY_PUB_DSA(old_pub_key_obj_p),
			    sizeof (dsa_pub_key_t));

			/* copy prime */
			rv = copy_bigint(KEY_PUB_DSA_PRIME(pbk),
			    KEY_PUB_DSA_PRIME(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy subprime */
			rv = copy_bigint(KEY_PUB_DSA_SUBPRIME(pbk),
			    KEY_PUB_DSA_SUBPRIME(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy base */
			rv = copy_bigint(KEY_PUB_DSA_BASE(pbk),
			    KEY_PUB_DSA_BASE(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy value */
			rv = copy_bigint(KEY_PUB_DSA_VALUE(pbk),
			    KEY_PUB_DSA_VALUE(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}
			break;
		case CKK_DH:
			(void) memcpy(KEY_PUB_DH(pbk),
			    KEY_PUB_DH(old_pub_key_obj_p),
			    sizeof (dh_pub_key_t));

			/* copy prime */
			rv = copy_bigint(KEY_PUB_DH_PRIME(pbk),
			    KEY_PUB_DH_PRIME(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy base */
			rv = copy_bigint(KEY_PUB_DH_BASE(pbk),
			    KEY_PUB_DH_BASE(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy value */
			rv = copy_bigint(KEY_PUB_DH_VALUE(pbk),
			    KEY_PUB_DH_VALUE(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}
			break;
		case CKK_EC:
			(void) memcpy(KEY_PUB_EC(pbk),
			    KEY_PUB_EC(old_pub_key_obj_p),
			    sizeof (ec_pub_key_t));

			/* copy point */
			rv = copy_bigint(KEY_PUB_EC_POINT(pbk),
			    KEY_PUB_EC_POINT(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}
			break;
		case CKK_X9_42_DH:
			(void) memcpy(KEY_PUB_DH942(pbk),
			    KEY_PUB_DH942(old_pub_key_obj_p),
			    sizeof (dh942_pub_key_t));

			/* copy prime */
			rv = copy_bigint(KEY_PUB_DH942_PRIME(pbk),
			    KEY_PUB_DH942_PRIME(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy subprime */
			rv = copy_bigint(KEY_PUB_DH942_SUBPRIME(pbk),
			    KEY_PUB_DH942_SUBPRIME(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy base */
			rv = copy_bigint(KEY_PUB_DH942_BASE(pbk),
			    KEY_PUB_DH942_BASE(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy value */
			rv = copy_bigint(KEY_PUB_DH942_VALUE(pbk),
			    KEY_PUB_DH942_VALUE(old_pub_key_obj_p));
			if (rv != CKR_OK) {
				free_public_key_attr(pbk, key_type);
				return (rv);
			}
			break;
		default:
			break;
	}
	*new_pub_key_obj_p = pbk;
	return (rv);
}

static void
free_private_key_attr(private_key_obj_t *pbk, CK_KEY_TYPE key_type)
{
	if (pbk == NULL) {
		return;
	}

	switch (key_type) {
		case CKK_RSA:
			bigint_attr_cleanup(KEY_PRI_RSA_MOD(pbk));
			bigint_attr_cleanup(KEY_PRI_RSA_PUBEXPO(pbk));
			bigint_attr_cleanup(KEY_PRI_RSA_PRIEXPO(pbk));
			bigint_attr_cleanup(KEY_PRI_RSA_PRIME1(pbk));
			bigint_attr_cleanup(KEY_PRI_RSA_PRIME2(pbk));
			bigint_attr_cleanup(KEY_PRI_RSA_EXPO1(pbk));
			bigint_attr_cleanup(KEY_PRI_RSA_EXPO2(pbk));
			bigint_attr_cleanup(KEY_PRI_RSA_COEF(pbk));
			break;
		case CKK_DSA:
			bigint_attr_cleanup(KEY_PRI_DSA_PRIME(pbk));
			bigint_attr_cleanup(KEY_PRI_DSA_SUBPRIME(pbk));
			bigint_attr_cleanup(KEY_PRI_DSA_BASE(pbk));
			bigint_attr_cleanup(KEY_PRI_DSA_VALUE(pbk));
			break;
		case CKK_DH:
			bigint_attr_cleanup(KEY_PRI_DH_PRIME(pbk));
			bigint_attr_cleanup(KEY_PRI_DH_BASE(pbk));
			bigint_attr_cleanup(KEY_PRI_DH_VALUE(pbk));
			break;
		case CKK_EC:
			bigint_attr_cleanup(KEY_PRI_EC_VALUE(pbk));
			break;
		case CKK_X9_42_DH:
			bigint_attr_cleanup(KEY_PRI_DH942_PRIME(pbk));
			bigint_attr_cleanup(KEY_PRI_DH942_SUBPRIME(pbk));
			bigint_attr_cleanup(KEY_PRI_DH942_BASE(pbk));
			bigint_attr_cleanup(KEY_PRI_DH942_VALUE(pbk));
			break;
		default:
			break;
	}
	free(pbk);
}

CK_RV
soft_copy_private_key_attr(private_key_obj_t *old_pri_key_obj_p,
    private_key_obj_t **new_pri_key_obj_p, CK_KEY_TYPE key_type)
{
	CK_RV rv = CKR_OK;
	private_key_obj_t *pbk;

	pbk = calloc(1, sizeof (private_key_obj_t));
	if (pbk == NULL) {
		return (CKR_HOST_MEMORY);
	}

	switch (key_type) {
		case CKK_RSA:
			(void) memcpy(KEY_PRI_RSA(pbk),
			    KEY_PRI_RSA(old_pri_key_obj_p),
			    sizeof (rsa_pri_key_t));
			/* copy modulus */
			rv = copy_bigint(KEY_PRI_RSA_MOD(pbk),
			    KEY_PRI_RSA_MOD(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}
			/* copy public exponent */
			rv = copy_bigint(KEY_PRI_RSA_PUBEXPO(pbk),
			    KEY_PRI_RSA_PUBEXPO(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}
			/* copy private exponent */
			rv = copy_bigint(KEY_PRI_RSA_PRIEXPO(pbk),
			    KEY_PRI_RSA_PRIEXPO(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}
			/* copy prime_1 */
			rv = copy_bigint(KEY_PRI_RSA_PRIME1(pbk),
			    KEY_PRI_RSA_PRIME1(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}
			/* copy prime_2 */
			rv = copy_bigint(KEY_PRI_RSA_PRIME2(pbk),
			    KEY_PRI_RSA_PRIME2(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}
			/* copy exponent_1 */
			rv = copy_bigint(KEY_PRI_RSA_EXPO1(pbk),
			    KEY_PRI_RSA_EXPO1(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}
			/* copy exponent_2 */
			rv = copy_bigint(KEY_PRI_RSA_EXPO2(pbk),
			    KEY_PRI_RSA_EXPO2(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}
			/* copy coefficient */
			rv = copy_bigint(KEY_PRI_RSA_COEF(pbk),
			    KEY_PRI_RSA_COEF(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}
			break;
		case CKK_DSA:
			(void) memcpy(KEY_PRI_DSA(pbk),
			    KEY_PRI_DSA(old_pri_key_obj_p),
			    sizeof (dsa_pri_key_t));

			/* copy prime */
			rv = copy_bigint(KEY_PRI_DSA_PRIME(pbk),
			    KEY_PRI_DSA_PRIME(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy subprime */
			rv = copy_bigint(KEY_PRI_DSA_SUBPRIME(pbk),
			    KEY_PRI_DSA_SUBPRIME(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy base */
			rv = copy_bigint(KEY_PRI_DSA_BASE(pbk),
			    KEY_PRI_DSA_BASE(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy value */
			rv = copy_bigint(KEY_PRI_DSA_VALUE(pbk),
			    KEY_PRI_DSA_VALUE(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}
			break;
		case CKK_DH:
			(void) memcpy(KEY_PRI_DH(pbk),
			    KEY_PRI_DH(old_pri_key_obj_p),
			    sizeof (dh_pri_key_t));

			/* copy prime */
			rv = copy_bigint(KEY_PRI_DH_PRIME(pbk),
			    KEY_PRI_DH_PRIME(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy base */
			rv = copy_bigint(KEY_PRI_DH_BASE(pbk),
			    KEY_PRI_DH_BASE(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy value */
			rv = copy_bigint(KEY_PRI_DH_VALUE(pbk),
			    KEY_PRI_DH_VALUE(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}
			break;
		case CKK_EC:
			(void) memcpy(KEY_PRI_EC(pbk),
			    KEY_PRI_EC(old_pri_key_obj_p),
			    sizeof (ec_pri_key_t));

			/* copy value */
			rv = copy_bigint(KEY_PRI_EC_VALUE(pbk),
			    KEY_PRI_EC_VALUE(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}
			break;
		case CKK_X9_42_DH:
			(void) memcpy(KEY_PRI_DH942(pbk),
			    KEY_PRI_DH942(old_pri_key_obj_p),
			    sizeof (dh942_pri_key_t));

			/* copy prime */
			rv = copy_bigint(KEY_PRI_DH942_PRIME(pbk),
			    KEY_PRI_DH942_PRIME(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy subprime */
			rv = copy_bigint(KEY_PRI_DH942_SUBPRIME(pbk),
			    KEY_PRI_DH942_SUBPRIME(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy base */
			rv = copy_bigint(KEY_PRI_DH942_BASE(pbk),
			    KEY_PRI_DH942_BASE(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}

			/* copy value */
			rv = copy_bigint(KEY_PRI_DH942_VALUE(pbk),
			    KEY_PRI_DH942_VALUE(old_pri_key_obj_p));
			if (rv != CKR_OK) {
				free_private_key_attr(pbk, key_type);
				return (rv);
			}
			break;
		default:
			break;
	}
	*new_pri_key_obj_p = pbk;
	return (rv);
}

static void
free_domain_attr(domain_obj_t *domain, CK_KEY_TYPE key_type)
{
	if (domain == NULL) {
		return;
	}

	switch (key_type) {
		case CKK_DSA:
			bigint_attr_cleanup(KEY_DOM_DSA_PRIME(domain));
			bigint_attr_cleanup(KEY_DOM_DSA_SUBPRIME(domain));
			bigint_attr_cleanup(KEY_DOM_DSA_BASE(domain));
			break;
		case CKK_DH:
			bigint_attr_cleanup(KEY_DOM_DH_PRIME(domain));
			bigint_attr_cleanup(KEY_DOM_DH_BASE(domain));
			break;
		case CKK_X9_42_DH:
			bigint_attr_cleanup(KEY_DOM_DH942_PRIME(domain));
			bigint_attr_cleanup(KEY_DOM_DH942_SUBPRIME(domain));
			bigint_attr_cleanup(KEY_DOM_DH942_BASE(domain));
			break;
		default:
			break;
	}
	free(domain);
}

CK_RV
soft_copy_domain_attr(domain_obj_t *old_domain_obj_p,
    domain_obj_t **new_domain_obj_p, CK_KEY_TYPE key_type)
{
	CK_RV rv = CKR_OK;
	domain_obj_t *domain;

	domain = calloc(1, sizeof (domain_obj_t));
	if (domain == NULL) {
		return (CKR_HOST_MEMORY);
	}

	switch (key_type) {
		case CKK_DSA:
			(void) memcpy(KEY_DOM_DSA(domain),
			    KEY_DOM_DSA(old_domain_obj_p),
			    sizeof (dsa_dom_key_t));

			/* copy prime */
			rv = copy_bigint(KEY_DOM_DSA_PRIME(domain),
			    KEY_DOM_DSA_PRIME(old_domain_obj_p));
			if (rv != CKR_OK) {
				free_domain_attr(domain, key_type);
				return (rv);
			}

			/* copy subprime */
			rv = copy_bigint(KEY_DOM_DSA_SUBPRIME(domain),
			    KEY_DOM_DSA_SUBPRIME(old_domain_obj_p));
			if (rv != CKR_OK) {
				free_domain_attr(domain, key_type);
				return (rv);
			}

			/* copy base */
			rv = copy_bigint(KEY_DOM_DSA_BASE(domain),
			    KEY_DOM_DSA_BASE(old_domain_obj_p));
			if (rv != CKR_OK) {
				free_domain_attr(domain, key_type);
				return (rv);
			}

			break;
		case CKK_DH:
			(void) memcpy(KEY_DOM_DH(domain),
			    KEY_DOM_DH(old_domain_obj_p),
			    sizeof (dh_dom_key_t));

			/* copy prime */
			rv = copy_bigint(KEY_DOM_DH_PRIME(domain),
			    KEY_DOM_DH_PRIME(old_domain_obj_p));
			if (rv != CKR_OK) {
				free_domain_attr(domain, key_type);
				return (rv);
			}

			/* copy base */
			rv = copy_bigint(KEY_DOM_DH_BASE(domain),
			    KEY_DOM_DH_BASE(old_domain_obj_p));
			if (rv != CKR_OK) {
				free_domain_attr(domain, key_type);
				return (rv);
			}

			break;
		case CKK_X9_42_DH:
			(void) memcpy(KEY_DOM_DH942(domain),
			    KEY_DOM_DH942(old_domain_obj_p),
			    sizeof (dh942_dom_key_t));

			/* copy prime */
			rv = copy_bigint(KEY_DOM_DH942_PRIME(domain),
			    KEY_DOM_DH942_PRIME(old_domain_obj_p));
			if (rv != CKR_OK) {
				free_domain_attr(domain, key_type);
				return (rv);
			}

			/* copy subprime */
			rv = copy_bigint(KEY_DOM_DH942_SUBPRIME(domain),
			    KEY_DOM_DH942_SUBPRIME(old_domain_obj_p));
			if (rv != CKR_OK) {
				free_domain_attr(domain, key_type);
				return (rv);
			}

			/* copy base */
			rv = copy_bigint(KEY_DOM_DH942_BASE(domain),
			    KEY_DOM_DH942_BASE(old_domain_obj_p));
			if (rv != CKR_OK) {
				free_domain_attr(domain, key_type);
				return (rv);
			}

			break;
		default:
			break;
	}
	*new_domain_obj_p = domain;
	return (rv);
}

CK_RV
soft_copy_secret_key_attr(secret_key_obj_t *old_secret_key_obj_p,
    secret_key_obj_t **new_secret_key_obj_p)
{
	secret_key_obj_t *sk;

	sk = malloc(sizeof (secret_key_obj_t));
	if (sk == NULL) {
		return (CKR_HOST_MEMORY);
	}
	(void) memcpy(sk, old_secret_key_obj_p, sizeof (secret_key_obj_t));

	/* copy the secret key value */
	sk->sk_value = malloc((sizeof (CK_BYTE) * sk->sk_value_len));
	if (sk->sk_value == NULL) {
		free(sk);
		return (CKR_HOST_MEMORY);
	}
	(void) memcpy(sk->sk_value, old_secret_key_obj_p->sk_value,
	    (sizeof (CK_BYTE) * sk->sk_value_len));

	/*
	 * Copy the pre-expanded key schedule.
	 */
	if (old_secret_key_obj_p->key_sched != NULL &&
	    old_secret_key_obj_p->keysched_len > 0) {
		sk->key_sched = malloc(old_secret_key_obj_p->keysched_len);
		if (sk->key_sched == NULL) {
			free(sk);
			return (CKR_HOST_MEMORY);
		}
		sk->keysched_len = old_secret_key_obj_p->keysched_len;
		(void) memcpy(sk->key_sched, old_secret_key_obj_p->key_sched,
		    sk->keysched_len);
	}

	*new_secret_key_obj_p = sk;

	return (CKR_OK);
}

/*
 * If CKA_CLASS not given, guess CKA_CLASS using
 * attributes on template .
 *
 * Some attributes are specific to an object class.  If one or more
 * of these attributes are in the template, make a list of classes
 * that can have these attributes.  This would speed up the search later,
 * because we can immediately skip an object if the class of that
 * object can not possibly contain one of the attributes.
 *
 */
void
soft_process_find_attr(CK_OBJECT_CLASS *pclasses,
    CK_ULONG *num_result_pclasses, CK_ATTRIBUTE_PTR pTemplate,
    CK_ULONG ulCount)
{
	ulong_t i;
	int j;
	boolean_t pub_found = B_FALSE,
	    priv_found = B_FALSE,
	    secret_found = B_FALSE,
	    domain_found = B_FALSE,
	    hardware_found = B_FALSE,
	    cert_found = B_FALSE;
	int num_pub_key_attrs, num_priv_key_attrs,
	    num_secret_key_attrs, num_domain_attrs,
	    num_hardware_attrs, num_cert_attrs;
	int num_pclasses = 0;

	for (i = 0; i < ulCount; i++) {
		if (pTemplate[i].type == CKA_CLASS) {
			/*
			 * don't need to guess the class, it is specified.
			 * Just record the class, and return.
			 */
			pclasses[0] =
			    (*((CK_OBJECT_CLASS *)pTemplate[i].pValue));
			*num_result_pclasses = 1;
			return;
		}
	}

	num_pub_key_attrs =
	    sizeof (PUB_KEY_ATTRS) / sizeof (CK_ATTRIBUTE_TYPE);
	num_priv_key_attrs =
	    sizeof (PRIV_KEY_ATTRS) / sizeof (CK_ATTRIBUTE_TYPE);
	num_secret_key_attrs =
	    sizeof (SECRET_KEY_ATTRS) / sizeof (CK_ATTRIBUTE_TYPE);
	num_domain_attrs =
	    sizeof (DOMAIN_ATTRS) / sizeof (CK_ATTRIBUTE_TYPE);
	num_hardware_attrs =
	    sizeof (HARDWARE_ATTRS) / sizeof (CK_ATTRIBUTE_TYPE);
	num_cert_attrs =
	    sizeof (CERT_ATTRS) / sizeof (CK_ATTRIBUTE_TYPE);

	/*
	 * Get the list of objects class that might contain
	 * some attributes.
	 */
	for (i = 0; i < ulCount; i++) {
		/*
		 * only check if this attribute can belong to public key object
		 * class if public key object isn't already in the list
		 */
		if (!pub_found) {
			for (j = 0; j < num_pub_key_attrs; j++) {
				if (pTemplate[i].type == PUB_KEY_ATTRS[j]) {
					pub_found = B_TRUE;
					pclasses[num_pclasses++] =
					    CKO_PUBLIC_KEY;
					break;
				}
			}
		}

		if (!priv_found) {
			for (j = 0; j < num_priv_key_attrs; j++) {
				if (pTemplate[i].type == PRIV_KEY_ATTRS[j]) {
					priv_found = B_TRUE;
					pclasses[num_pclasses++] =
					    CKO_PRIVATE_KEY;
					break;
				}
			}
		}

		if (!secret_found) {
			for (j = 0; j < num_secret_key_attrs; j++) {
				if (pTemplate[i].type == SECRET_KEY_ATTRS[j]) {
					secret_found = B_TRUE;
					pclasses[num_pclasses++] =
					    CKO_SECRET_KEY;
					break;
				}
			}
		}

		if (!domain_found) {
			for (j = 0; j < num_domain_attrs; j++) {
				if (pTemplate[i].type == DOMAIN_ATTRS[j]) {
					domain_found = B_TRUE;
					pclasses[num_pclasses++] =
					    CKO_DOMAIN_PARAMETERS;
					break;
				}
			}
		}

		if (!hardware_found) {
			for (j = 0; j < num_hardware_attrs; j++) {
				if (pTemplate[i].type == HARDWARE_ATTRS[j]) {
					hardware_found = B_TRUE;
					pclasses[num_pclasses++] =
					    CKO_HW_FEATURE;
					break;
				}
			}
		}

		if (!cert_found) {
			for (j = 0; j < num_cert_attrs; j++) {
				if (pTemplate[i].type == CERT_ATTRS[j]) {
					cert_found = B_TRUE;
					pclasses[num_pclasses++] =
					    CKO_CERTIFICATE;
					break;
				}
			}
		}
	}
	*num_result_pclasses = num_pclasses;
}

boolean_t
soft_find_match_attrs(soft_object_t *obj, CK_OBJECT_CLASS *pclasses,
    CK_ULONG num_pclasses, CK_ATTRIBUTE *template, CK_ULONG num_attr)
{
	ulong_t i;
	CK_ATTRIBUTE *tmpl_attr, *obj_attr;
	cert_attr_t *cert_attr;
	uint64_t attr_mask;
	biginteger_t *bigint;
	boolean_t compare_attr, compare_bigint, compare_boolean;
	boolean_t compare_cert_val, compare_cert_type;

	/*
	 * Check if the class of this object match with any
	 * of object classes that can possibly contain the
	 * requested attributes.
	 */
	if (num_pclasses > 0) {
		for (i = 0; i < num_pclasses; i++) {
			if (obj->class == pclasses[i]) {
				break;
			}
		}
		if (i == num_pclasses) {
			/*
			 * this object can't possibly contain one or
			 * more attributes, don't need to check this object
			 */
			return (B_FALSE);
		}
	}

	/* need to examine everything */
	for (i = 0; i < num_attr; i++) {
		tmpl_attr = &(template[i]);
		compare_attr = B_FALSE;
		compare_bigint = B_FALSE;
		compare_boolean = B_FALSE;
		compare_cert_val = B_FALSE;
		compare_cert_type = B_FALSE;
		switch (tmpl_attr->type) {
		/* First, check the most common attributes */
		case CKA_CLASS:
			if (*((CK_OBJECT_CLASS *)tmpl_attr->pValue) !=
			    obj->class) {
				return (B_FALSE);
			}
			break;
		case CKA_KEY_TYPE:
			if (*((CK_KEY_TYPE *)tmpl_attr->pValue) !=
			    obj->key_type) {
				return (B_FALSE);
			}
			break;
		case CKA_ENCRYPT:
			attr_mask = (obj->bool_attr_mask) & ENCRYPT_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_DECRYPT:
			attr_mask = (obj->bool_attr_mask) & DECRYPT_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_WRAP:
			attr_mask = (obj->bool_attr_mask) & WRAP_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_UNWRAP:
			attr_mask = (obj->bool_attr_mask) & UNWRAP_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_SIGN:
			attr_mask = (obj->bool_attr_mask) & SIGN_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_SIGN_RECOVER:
			attr_mask = (obj->bool_attr_mask) &
			    SIGN_RECOVER_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_VERIFY:
			attr_mask = (obj->bool_attr_mask) & VERIFY_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_VERIFY_RECOVER:
			attr_mask = (obj->bool_attr_mask) &
			    VERIFY_RECOVER_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_DERIVE:
			attr_mask = (obj->bool_attr_mask) & DERIVE_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_LOCAL:
			attr_mask = (obj->bool_attr_mask) & LOCAL_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_SENSITIVE:
			attr_mask = (obj->bool_attr_mask) & SENSITIVE_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_SECONDARY_AUTH:
			attr_mask = (obj->bool_attr_mask) &
			    SECONDARY_AUTH_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_TRUSTED:
			attr_mask = (obj->bool_attr_mask) & TRUSTED_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_EXTRACTABLE:
			attr_mask = (obj->bool_attr_mask) &
			    EXTRACTABLE_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_ALWAYS_SENSITIVE:
			attr_mask = (obj->bool_attr_mask) &
			    ALWAYS_SENSITIVE_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_NEVER_EXTRACTABLE:
			attr_mask = (obj->bool_attr_mask) &
			    NEVER_EXTRACTABLE_BOOL_ON;
			compare_boolean = B_TRUE;
			break;
		case CKA_TOKEN:
			attr_mask = (obj->object_type) & TOKEN_OBJECT;
			compare_boolean = B_TRUE;
			break;
		case CKA_PRIVATE:
			attr_mask = (obj->object_type) & PRIVATE_OBJECT;
			compare_boolean = B_TRUE;
			break;
		case CKA_MODIFIABLE:
		{
			CK_BBOOL bval;
			attr_mask = (obj->bool_attr_mask) &
			    NOT_MODIFIABLE_BOOL_ON;

			if (attr_mask) {
				bval = FALSE;
			} else {
				bval = TRUE;
			}
			if (bval != *((CK_BBOOL *)tmpl_attr->pValue)) {
				return (B_FALSE);
			}
			break;
		}
		case CKA_OWNER:
			/*
			 * For X.509 attribute certificate object, get its
			 * CKA_OWNER attribute from the x509_attr_cert_t struct.
			 */
			if ((obj->class == CKO_CERTIFICATE) &&
			    (obj->cert_type == CKC_X_509_ATTR_CERT)) {
				cert_attr = X509_ATTR_CERT_OWNER(obj);
				compare_cert_val = B_TRUE;
			}
			break;
		case CKA_SUBJECT:
			/*
			 * For X.509 certificate object, get its CKA_SUBJECT
			 * attribute from the x509_cert_t struct (not from
			 * the extra_attrlistp).
			 */
			if ((obj->class == CKO_CERTIFICATE) &&
			    (obj->cert_type == CKC_X_509)) {
				cert_attr = X509_CERT_SUBJECT(obj);
				compare_cert_val = B_TRUE;
				break;
			}
			/*FALLTHRU*/
		case CKA_ID:
		case CKA_START_DATE:
		case CKA_END_DATE:
		case CKA_KEY_GEN_MECHANISM:
		case CKA_LABEL:
		case CKA_ISSUER:
		case CKA_SERIAL_NUMBER:
		case CKA_AC_ISSUER:
		case CKA_ATTR_TYPES:
			/* find these attributes from extra_attrlistp */
			obj_attr = get_extra_attr(tmpl_attr->type, obj);
			compare_attr = B_TRUE;
			break;
		case CKA_CERTIFICATE_TYPE:
			compare_cert_type = B_TRUE;
			break;
		case CKA_VALUE_LEN:
			/* only secret key has this attribute */
			if (obj->class == CKO_SECRET_KEY) {
				if (*((CK_ULONG *)tmpl_attr->pValue) !=
				    OBJ_SEC_VALUE_LEN(obj)) {
					return (B_FALSE);
				}
			} else {
				return (B_FALSE);
			}
			break;
		case CKA_VALUE:
			switch (obj->class) {
			case CKO_SECRET_KEY:
				/*
				 * secret_key_obj_t is the same as
				 * biginteger_t
				 */
				bigint = (biginteger_t *)OBJ_SEC(obj);
				compare_bigint = B_TRUE;
				break;
			case CKO_PRIVATE_KEY:
				if (obj->key_type == CKK_DSA) {
					bigint = OBJ_PRI_DSA_VALUE(obj);
				} else if (obj->key_type == CKK_DH) {
					bigint = OBJ_PRI_DH_VALUE(obj);
				} else if (obj->key_type == CKK_X9_42_DH) {
					bigint = OBJ_PRI_DH942_VALUE(obj);
				} else {
					return (B_FALSE);
				}
				compare_bigint = B_TRUE;
				break;
			case CKO_PUBLIC_KEY:
				if (obj->key_type == CKK_DSA) {
					bigint = OBJ_PUB_DSA_VALUE(obj);
				} else if (obj->key_type == CKK_DH) {
					bigint = OBJ_PUB_DH_VALUE(obj);
				} else if (obj->key_type == CKK_X9_42_DH) {
					bigint = OBJ_PUB_DH942_VALUE(obj);
				} else {
					return (B_FALSE);
				}
				compare_bigint = B_TRUE;
				break;
			case CKO_CERTIFICATE:
				if (obj->cert_type == CKC_X_509) {
					cert_attr = X509_CERT_VALUE(obj);
				} else if (obj->cert_type ==
				    CKC_X_509_ATTR_CERT) {
					cert_attr = X509_ATTR_CERT_VALUE(obj);
				}
				compare_cert_val = B_TRUE;
				break;
			default:
				return (B_FALSE);
			}
			break;
		case CKA_MODULUS:
			/* only RSA public and private key have this attr */
			if (obj->key_type == CKK_RSA) {
				if (obj->class == CKO_PUBLIC_KEY) {
					bigint = OBJ_PUB_RSA_MOD(obj);
				} else if (obj->class == CKO_PRIVATE_KEY) {
					bigint = OBJ_PRI_RSA_MOD(obj);
				} else {
					return (B_FALSE);
				}
				compare_bigint = B_TRUE;
			} else {
				return (B_FALSE);
			}
			break;
		case CKA_MODULUS_BITS:
			/* only RSA public key has this attribute */
			if ((obj->key_type == CKK_RSA) &&
			    (obj->class == CKO_PUBLIC_KEY)) {
				CK_ULONG mod_bits = OBJ_PUB_RSA_MOD_BITS(obj);
				if (mod_bits !=
				    *((CK_ULONG *)tmpl_attr->pValue)) {
					return (B_FALSE);
				}
			} else {
				return (B_FALSE);
			}
			break;
		case CKA_PUBLIC_EXPONENT:
			/* only RSA public and private key have this attr */
			if (obj->key_type == CKK_RSA) {
				if (obj->class == CKO_PUBLIC_KEY) {
					bigint = OBJ_PUB_RSA_PUBEXPO(obj);
				} else if (obj->class == CKO_PRIVATE_KEY) {
					bigint = OBJ_PRI_RSA_PUBEXPO(obj);
				} else {
					return (B_FALSE);
				}
				compare_bigint = B_TRUE;
			} else {
				return (B_FALSE);
			}
			break;
		case CKA_PRIVATE_EXPONENT:
			/* only RSA private key has this attribute */
			if ((obj->key_type == CKK_RSA) &&
			    (obj->class == CKO_PRIVATE_KEY)) {
				bigint = OBJ_PRI_RSA_PRIEXPO(obj);
				compare_bigint = B_TRUE;
			} else {
				return (B_FALSE);
			}
			break;
		case CKA_PRIME_1:
			/* only RSA private key has this attribute */
			if ((obj->key_type == CKK_RSA) &&
			    (obj->class == CKO_PRIVATE_KEY)) {
				bigint = OBJ_PRI_RSA_PRIME1(obj);
				compare_bigint = B_TRUE;
			} else {
				return (B_FALSE);
			}
			break;
		case CKA_PRIME_2:
			/* only RSA private key has this attribute */
			if ((obj->key_type == CKK_RSA) &&
			    (obj->class == CKO_PRIVATE_KEY)) {
				bigint = OBJ_PRI_RSA_PRIME2(obj);
				compare_bigint = B_TRUE;
			} else {
				return (B_FALSE);
			}
			break;
		case CKA_EXPONENT_1:
			/* only RSA private key has this attribute */
			if ((obj->key_type == CKK_RSA) &&
			    (obj->class == CKO_PRIVATE_KEY)) {
				bigint = OBJ_PRI_RSA_EXPO1(obj);
				compare_bigint = B_TRUE;
			} else {
				return (B_FALSE);
			}
			break;
		case CKA_EXPONENT_2:
			/* only RSA private key has this attribute */
			if ((obj->key_type == CKK_RSA) &&
			    (obj->class == CKO_PRIVATE_KEY)) {
				bigint = OBJ_PRI_RSA_EXPO2(obj);
				compare_bigint = B_TRUE;
			} else {
				return (B_FALSE);
			}
			break;
		case CKA_COEFFICIENT:
			/* only RSA private key has this attribute */
			if ((obj->key_type == CKK_RSA) &&
			    (obj->class == CKO_PRIVATE_KEY)) {
				bigint = OBJ_PRI_RSA_COEF(obj);
				compare_bigint = B_TRUE;
			} else {
				return (B_FALSE);
			}
			break;
		case CKA_VALUE_BITS:
			/* only Diffie-Hellman private key has this attr */
			if ((obj->key_type == CKK_DH) &&
			    (obj->class == CKO_PRIVATE_KEY)) {
				CK_ULONG val_bits = OBJ_PRI_DH_VAL_BITS(obj);
				if (val_bits !=
				    *((CK_ULONG *)tmpl_attr->pValue)) {
					return (B_FALSE);
				}
			} else {
				return (B_FALSE);
			}
			break;
		case CKA_PRIME:
			if (obj->class == CKO_PUBLIC_KEY) {
				switch (obj->key_type) {
				case CKK_DSA:
					bigint = OBJ_PUB_DSA_PRIME(obj);
					break;
				case CKK_DH:
					bigint = OBJ_PUB_DH_PRIME(obj);
					break;
				case CKK_X9_42_DH:
					bigint = OBJ_PUB_DH942_PRIME(obj);
					break;
				default:
					return (B_FALSE);
				}
			} else if (obj->class == CKO_PRIVATE_KEY) {
				switch (obj->key_type) {
				case CKK_DSA:
					bigint = OBJ_PRI_DSA_PRIME(obj);
					break;
				case CKK_DH:
					bigint = OBJ_PRI_DH_PRIME(obj);
					break;
				case CKK_X9_42_DH:
					bigint = OBJ_PRI_DH942_PRIME(obj);
					break;
				default:
					return (B_FALSE);
				}
			} else if (obj->class == CKO_DOMAIN_PARAMETERS) {
				switch (obj->key_type) {
				case CKK_DSA:
					bigint = OBJ_DOM_DSA_PRIME(obj);
					break;
				case CKK_DH:
					bigint = OBJ_DOM_DH_PRIME(obj);
					break;
				case CKK_X9_42_DH:
					bigint = OBJ_DOM_DH942_PRIME(obj);
					break;
				default:
					return (B_FALSE);
				}
			} else {
				return (B_FALSE);
			}
			compare_bigint = B_TRUE;
			break;
		case CKA_SUBPRIME:
			if (obj->class == CKO_PUBLIC_KEY) {
				switch (obj->key_type) {
				case CKK_DSA:
					bigint = OBJ_PUB_DSA_SUBPRIME(obj);
					break;
				case CKK_X9_42_DH:
					bigint = OBJ_PUB_DH942_SUBPRIME(obj);
					break;
				default:
					return (B_FALSE);
				}
			} else if (obj->class == CKO_PRIVATE_KEY) {
				switch (obj->key_type) {
				case CKK_DSA:
					bigint = OBJ_PRI_DSA_SUBPRIME(obj);
					break;
				case CKK_X9_42_DH:
					bigint = OBJ_PRI_DH942_SUBPRIME(obj);
					break;
				default:
					return (B_FALSE);
				}
			} else if (obj->class == CKO_DOMAIN_PARAMETERS) {
				switch (obj->key_type) {
				case CKK_DSA:
					bigint = OBJ_DOM_DSA_SUBPRIME(obj);
					break;
				case CKK_X9_42_DH:
					bigint = OBJ_DOM_DH942_SUBPRIME(obj);
					break;
				default:
					return (B_FALSE);
				}
			} else {
				return (B_FALSE);
			}
			compare_bigint = B_TRUE;
			break;
		case CKA_BASE:
			if (obj->class == CKO_PUBLIC_KEY) {
				switch (obj->key_type) {
				case CKK_DSA:
					bigint = OBJ_PUB_DSA_BASE(obj);
					break;
				case CKK_DH:
					bigint = OBJ_PUB_DH_BASE(obj);
					break;
				case CKK_X9_42_DH:
					bigint = OBJ_PUB_DH942_BASE(obj);
					break;
				default:
					return (B_FALSE);
				}
			} else if (obj->class == CKO_PRIVATE_KEY) {
				switch (obj->key_type) {
				case CKK_DSA:
					bigint = OBJ_PRI_DSA_BASE(obj);
					break;
				case CKK_DH:
					bigint = OBJ_PRI_DH_BASE(obj);
					break;
				case CKK_X9_42_DH:
					bigint = OBJ_PRI_DH942_BASE(obj);
					break;
				default:
					return (B_FALSE);
				}
			} else if (obj->class == CKO_DOMAIN_PARAMETERS) {
				switch (obj->key_type) {
				case CKK_DSA:
					bigint = OBJ_DOM_DSA_BASE(obj);
					break;
				case CKK_DH:
					bigint = OBJ_DOM_DH_BASE(obj);
					break;
				case CKK_X9_42_DH:
					bigint = OBJ_DOM_DH942_BASE(obj);
					break;
				default:
					return (B_FALSE);
				}
			} else {
				return (B_FALSE);
			}
			compare_bigint = B_TRUE;
			break;
		case CKA_PRIME_BITS:
			if (obj->class == CKO_DOMAIN_PARAMETERS) {
				CK_ULONG prime_bits;
				if (obj->key_type == CKK_DSA) {
					prime_bits =
					    OBJ_DOM_DSA_PRIME_BITS(obj);
				} else if (obj->key_type == CKK_DH) {
					prime_bits =
					    OBJ_DOM_DH_PRIME_BITS(obj);
				} else if (obj->key_type == CKK_X9_42_DH) {
					prime_bits =
					    OBJ_DOM_DH942_PRIME_BITS(obj);
				} else {
					return (B_FALSE);
				}
				if (prime_bits !=
				    *((CK_ULONG *)tmpl_attr->pValue)) {
					return (B_FALSE);
				}
			} else {
				return (B_FALSE);
			}
			break;
		case CKA_SUBPRIME_BITS:
			if ((obj->class == CKO_DOMAIN_PARAMETERS) &&
			    (obj->key_type == CKK_X9_42_DH)) {
				CK_ULONG subprime_bits =
				    OBJ_DOM_DH942_SUBPRIME_BITS(obj);
				if (subprime_bits !=
				    *((CK_ULONG *)tmpl_attr->pValue)) {
					return (B_FALSE);
				}
			} else {
				return (B_FALSE);
			}
			break;
		default:
			/*
			 * any other attributes are currently not supported.
			 * so, it's not possible for them to be in the
			 * object
			 */
			return (B_FALSE);
		}
		if (compare_boolean) {
			CK_BBOOL bval;

			if (attr_mask) {
				bval = TRUE;
			} else {
				bval = FALSE;
			}
			if (bval != *((CK_BBOOL *)tmpl_attr->pValue)) {
				return (B_FALSE);
			}
		} else if (compare_bigint) {
			if (bigint == NULL) {
				return (B_FALSE);
			}
			if (tmpl_attr->ulValueLen != bigint->big_value_len) {
				return (B_FALSE);
			}
			if (memcmp(tmpl_attr->pValue, bigint->big_value,
			    tmpl_attr->ulValueLen) != 0) {
				return (B_FALSE);
			}
		} else if (compare_attr) {
			if (obj_attr == NULL) {
				/*
				 * The attribute type is valid, and its value
				 * has not been initialized in the object. In
				 * this case, it only matches the template's
				 * attribute if the template's value length
				 * is 0.
				 */
				if (tmpl_attr->ulValueLen != 0)
					return (B_FALSE);
			} else {
				if (tmpl_attr->ulValueLen !=
				    obj_attr->ulValueLen) {
					return (B_FALSE);
				}
				if (memcmp(tmpl_attr->pValue, obj_attr->pValue,
				    tmpl_attr->ulValueLen) != 0) {
					return (B_FALSE);
				}
			}
		} else if (compare_cert_val) {
			if (cert_attr == NULL) {
				/* specific attribute not found */
				return (B_FALSE);
			}
			if (tmpl_attr->ulValueLen != cert_attr->length) {
				return (B_FALSE);
			}
			if (memcmp(tmpl_attr->pValue, cert_attr->value,
			    tmpl_attr->ulValueLen) != 0) {
				return (B_FALSE);
			}
		} else if (compare_cert_type) {
			if (memcmp(tmpl_attr->pValue, &(obj->cert_type),
			    tmpl_attr->ulValueLen) != 0) {
				return (B_FALSE);
			}
		}
	}
	return (B_TRUE);
}

CK_ATTRIBUTE_PTR
get_extra_attr(CK_ATTRIBUTE_TYPE type, soft_object_t *obj)
{
	CK_ATTRIBUTE_INFO_PTR tmp;

	tmp = obj->extra_attrlistp;
	while (tmp != NULL) {
		if (tmp->attr.type == type) {
			return (&(tmp->attr));
		}
		tmp = tmp->next;
	}
	/* if get there, the specified attribute is not found */
	return (NULL);
}