xref: /onnv-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelKeys.c (revision 10669:ccf9f7e81ff9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54219Smcpowers  * Common Development and Distribution License (the "License").
64219Smcpowers  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*10669SMark.Powers@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <strings.h>
270Sstevel@tonic-gate #include <errno.h>
285697Smcpowers #include <ecc_impl.h>
290Sstevel@tonic-gate #include <security/cryptoki.h>
300Sstevel@tonic-gate #include <sys/crypto/ioctl.h>
310Sstevel@tonic-gate #include "kernelGlobal.h"
320Sstevel@tonic-gate #include "kernelSession.h"
330Sstevel@tonic-gate #include "kernelObject.h"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate static boolean_t
attribute_in_template(CK_ATTRIBUTE_TYPE type,CK_ATTRIBUTE_PTR t,CK_ULONG cnt)364219Smcpowers attribute_in_template(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
374219Smcpowers {
384219Smcpowers 	int i;
394219Smcpowers 
404219Smcpowers 	for (i = 0; i < cnt; i++) {
414219Smcpowers 		if (t[i].type == type)
424219Smcpowers 			return (B_TRUE);
434219Smcpowers 	}
444219Smcpowers 	return (B_FALSE);
454219Smcpowers }
464219Smcpowers 
474219Smcpowers /*
484219Smcpowers  * This routine returns modulus bytes rounded up to the nearest 8 byte
494219Smcpowers  * chunk. This is so we don't have to pass in max sized buffers for
504219Smcpowers  * returned attributes. Every unnecessary byte that we pass in results
514219Smcpowers  * in a kernel allocation.
524219Smcpowers  */
534219Smcpowers static ulong_t
get_modulus_bytes(CK_ATTRIBUTE_PTR t,CK_ULONG cnt)544219Smcpowers get_modulus_bytes(CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
554219Smcpowers {
564219Smcpowers 	CK_ULONG modulus_len;
574219Smcpowers 	int i;
584219Smcpowers 
594219Smcpowers 	for (i = 0; i < cnt; i++) {
604219Smcpowers 		if (t[i].type == CKA_MODULUS_BITS) {
614219Smcpowers 			get_ulong_attr_from_template(&modulus_len, &t[i]);
624219Smcpowers 			/* convert from bit length to byte length */
634219Smcpowers 			modulus_len = (modulus_len - 1) / 64 + 1;
644219Smcpowers 			return (modulus_len * 8);
654219Smcpowers 		}
664219Smcpowers 	}
674219Smcpowers 	return (0);
684219Smcpowers }
694219Smcpowers 
704219Smcpowers /*
714219Smcpowers  * Remove specified attribute from array. Storage for the attribute's
724219Smcpowers  * value is freed if 'free_attr' is TRUE. Attributes are shifted so they are
734219Smcpowers  * contiguous within the array, i.e. the next attribute is shifted into
744219Smcpowers  * the position of the removed attribute. Returns TRUE if specified
754219Smcpowers  * attribute is removed.
764219Smcpowers  */
774219Smcpowers static boolean_t
remove_one_attribute(CK_ATTRIBUTE_PTR t,CK_ULONG type,uint_t count,boolean_t free_attr)784219Smcpowers remove_one_attribute(CK_ATTRIBUTE_PTR t, CK_ULONG type, uint_t count,
794219Smcpowers     boolean_t free_attr)
804219Smcpowers {
814219Smcpowers 	int i, j;
824219Smcpowers 
834219Smcpowers 	for (i = 0, j = 0; i < count; i++) {
844219Smcpowers 		if (t[i].type == type) {
854219Smcpowers 			if (free_attr) {
864219Smcpowers 				free(t[i].pValue);
874219Smcpowers 			}
884219Smcpowers 			continue;
894219Smcpowers 		}
904219Smcpowers 		if (i != j) {
914219Smcpowers 			t[j].type = t[i].type;
924219Smcpowers 			t[j].pValue = t[i].pValue;
934219Smcpowers 			t[j].ulValueLen = t[i].ulValueLen;
944219Smcpowers 		}
954219Smcpowers 		j++;
964219Smcpowers 	}
974219Smcpowers 	if (j == count)
984219Smcpowers 		return (B_FALSE);
994219Smcpowers 
1004219Smcpowers 	/* safety */
1014219Smcpowers 	t[j].pValue = NULL;
1024219Smcpowers 	t[j].ulValueLen = 0;
1034219Smcpowers 	return (B_TRUE);
1044219Smcpowers }
1054219Smcpowers 
1064219Smcpowers static boolean_t
is_secret_key_template(CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount)1070Sstevel@tonic-gate is_secret_key_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
1080Sstevel@tonic-gate {
1090Sstevel@tonic-gate 	int i;
1100Sstevel@tonic-gate 	for (i = 0; i < ulAttributeCount; i++) {
1110Sstevel@tonic-gate 		if (pTemplate[i].type == CKA_CLASS &&
1120Sstevel@tonic-gate 		    *(CK_OBJECT_CLASS *)(pTemplate[i].pValue) ==
1130Sstevel@tonic-gate 		    CKO_SECRET_KEY)
1140Sstevel@tonic-gate 			return (B_TRUE);
1150Sstevel@tonic-gate 	}
1160Sstevel@tonic-gate 	return (B_FALSE);
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate 
1194219Smcpowers /*
1204219Smcpowers  * Allocate a template with space for new_count entries and copy the
1214219Smcpowers  * specified template into the new template.
1224219Smcpowers  */
1234219Smcpowers static CK_ATTRIBUTE_PTR
grow_template(CK_ATTRIBUTE_PTR old_template,CK_ULONG old_count,CK_ULONG new_count)1244219Smcpowers grow_template(CK_ATTRIBUTE_PTR old_template, CK_ULONG old_count,
1254219Smcpowers     CK_ULONG new_count)
1264219Smcpowers {
1274219Smcpowers 	CK_ATTRIBUTE_PTR new_template;
1284219Smcpowers 
1294219Smcpowers 	new_template = malloc(new_count * sizeof (CK_ATTRIBUTE));
1304219Smcpowers 	if (new_template != NULL)
1314219Smcpowers 		bcopy(old_template, new_template,
1324219Smcpowers 		    old_count * sizeof (CK_ATTRIBUTE));
1334219Smcpowers 	return (new_template);
1344219Smcpowers }
1354219Smcpowers 
1364219Smcpowers /*
1374219Smcpowers  * For fixed length keys such as DES, return the length based on
1384219Smcpowers  * the key type. For variable length keys such as AES, take the
1394219Smcpowers  * length from the CKA_VALUE_LEN attribute.
1404219Smcpowers  */
1414219Smcpowers static int
get_key_len_from_template(CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,kernel_object_t * basekey_p,ulong_t * key_len)1424219Smcpowers get_key_len_from_template(CK_MECHANISM_PTR pMechanism,
1434219Smcpowers     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
1444219Smcpowers     kernel_object_t *basekey_p,  ulong_t *key_len)
1454219Smcpowers {
1464219Smcpowers 	boolean_t fixed_len_key = B_FALSE;
1474219Smcpowers 	ulong_t key_type;
1484219Smcpowers 	int i;
1494219Smcpowers 
1504219Smcpowers 	for (i = 0; i < ulAttributeCount; i++) {
1514219Smcpowers 		if (pTemplate[i].type == CKA_KEY_TYPE) {
1524219Smcpowers 			get_ulong_attr_from_template(&key_type, &pTemplate[i]);
1534219Smcpowers 			break;
1544219Smcpowers 		}
1554219Smcpowers 	}
1564219Smcpowers 	/* CKA_KEY_TYPE must be present */
1574219Smcpowers 	if (i == ulAttributeCount)
1584219Smcpowers 		return (CKR_TEMPLATE_INCOMPLETE);
1594219Smcpowers 
1604219Smcpowers 	switch (key_type) {
1614219Smcpowers 	case CKK_DES:
1624219Smcpowers 		*key_len = 8;
1634219Smcpowers 		fixed_len_key = B_TRUE;
1644219Smcpowers 		break;
1654219Smcpowers 	case CKK_DES3:
1664219Smcpowers 		*key_len = 24;
1674219Smcpowers 		fixed_len_key = B_TRUE;
1684219Smcpowers 		break;
1694219Smcpowers 	case CKK_AES:
1704219Smcpowers 	case CKK_BLOWFISH:
1714219Smcpowers 		for (i = 0; i < ulAttributeCount; i++) {
1724219Smcpowers 			if (pTemplate[i].type == CKA_VALUE_LEN) {
1734219Smcpowers 				get_ulong_attr_from_template(key_len,
1744219Smcpowers 				    &pTemplate[i]);
1754219Smcpowers 				break;
1764219Smcpowers 			}
1774219Smcpowers 		}
1784219Smcpowers 		/* CKA_VALUE_LEN must be present */
1794219Smcpowers 		if (i == ulAttributeCount)
1804219Smcpowers 			return (CKR_TEMPLATE_INCOMPLETE);
1814219Smcpowers 		break;
1824219Smcpowers 	case CKK_GENERIC_SECRET:
1834219Smcpowers 		/*
1844219Smcpowers 		 * The key will not be truncated, so we need to
1854219Smcpowers 		 * get the max length for the mechanism.
1864219Smcpowers 		 */
1874219Smcpowers 		if (pMechanism->mechanism == CKM_DH_PKCS_DERIVE) {
1884219Smcpowers 			CK_ATTRIBUTE tmp;
1894219Smcpowers 
1904219Smcpowers 			tmp.type = CKA_PRIME;
1914219Smcpowers 			tmp.pValue = NULL;
1924219Smcpowers 
1934219Smcpowers 			/* get size of attribute */
1944219Smcpowers 			if (kernel_get_attribute(basekey_p, &tmp) != CKR_OK) {
1954219Smcpowers 				return (CKR_ARGUMENTS_BAD);
1964219Smcpowers 			}
1974219Smcpowers 			*key_len = tmp.ulValueLen;
1985613Smcpowers 		} else if (pMechanism->mechanism == CKM_ECDH1_DERIVE) {
1995697Smcpowers 			*key_len = EC_MAX_VALUE_LEN;
2004219Smcpowers 		} else {
2014219Smcpowers 			return (CKR_ARGUMENTS_BAD);
2024219Smcpowers 		}
2034219Smcpowers 		break;
2044219Smcpowers 	default:
2054219Smcpowers 		return (CKR_ATTRIBUTE_VALUE_INVALID);
2064219Smcpowers 	}
2074219Smcpowers 
2084219Smcpowers 	if (fixed_len_key && attribute_in_template(CKA_VALUE_LEN,
2094219Smcpowers 	    pTemplate, ulAttributeCount))
2104219Smcpowers 		return (CKR_TEMPLATE_INCONSISTENT);
2114219Smcpowers 
2124219Smcpowers 	return (CKR_OK);
2134219Smcpowers }
2144219Smcpowers 
2154219Smcpowers /* find specified attribute src template and copy to dest */
2164219Smcpowers static int
copy_attribute(CK_ULONG type,CK_ATTRIBUTE_PTR src,CK_ULONG src_cnt,CK_ATTRIBUTE_PTR dst)2174219Smcpowers copy_attribute(CK_ULONG type, CK_ATTRIBUTE_PTR src, CK_ULONG src_cnt,
2184219Smcpowers     CK_ATTRIBUTE_PTR dst)
2194219Smcpowers {
2204219Smcpowers 	int rv, i;
2214219Smcpowers 
2224219Smcpowers 	for (i = 0; i < src_cnt; i++) {
2234219Smcpowers 		if (src[i].type == type) {
2244219Smcpowers 			rv = get_string_from_template(dst, &src[i]);
2254219Smcpowers 			break;
2264219Smcpowers 		}
2274219Smcpowers 	}
2284219Smcpowers 	/*
2294219Smcpowers 	 * The public template didn't have attribute.
2304219Smcpowers 	 */
2314219Smcpowers 	if (i == src_cnt) {
2324219Smcpowers 		rv = CKR_TEMPLATE_INCOMPLETE;
2334219Smcpowers 	}
2344219Smcpowers 	return (rv);
2354219Smcpowers }
2364219Smcpowers 
2374219Smcpowers static void
free_attributes(caddr_t p,uint_t * countp)2384219Smcpowers free_attributes(caddr_t p, uint_t *countp)
2394219Smcpowers {
2404219Smcpowers 	if (*countp > 0) {
2414219Smcpowers 		free_object_attributes(p, *countp);
2424219Smcpowers 		*countp = 0;
2434219Smcpowers 	}
2444219Smcpowers }
2454219Smcpowers 
2464219Smcpowers CK_RV
key_gen_by_value(CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,kernel_session_t * session_p,crypto_mech_type_t k_mech_type,kernel_object_t * new_objp)2474219Smcpowers key_gen_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
2484219Smcpowers     CK_ULONG ulCount, kernel_session_t *session_p,
2494219Smcpowers     crypto_mech_type_t k_mech_type, kernel_object_t *new_objp)
2504219Smcpowers {
2514219Smcpowers 	crypto_nostore_generate_key_t obj_ngk;
2524219Smcpowers 	char *key_buf = NULL;
2534219Smcpowers 	CK_ATTRIBUTE_PTR newTemplate = NULL;
2544219Smcpowers 	CK_BBOOL is_token_obj = FALSE;
2554219Smcpowers 	CK_RV rv = CKR_OK;
2564219Smcpowers 	ulong_t key_len = 0;
2574219Smcpowers 	uint_t attr_count;
2584219Smcpowers 	int r;
2594219Smcpowers 
2604219Smcpowers 	obj_ngk.ngk_in_count = 0;
2614219Smcpowers 	obj_ngk.ngk_out_count = 0;
2624219Smcpowers 
2634219Smcpowers 	rv = get_key_len_from_template(pMechanism, pTemplate, ulCount,
2644219Smcpowers 	    NULL, &key_len);
2654219Smcpowers 	if (rv != CRYPTO_SUCCESS)
2664219Smcpowers 		goto failed_exit;
2674219Smcpowers 
2684219Smcpowers 	if ((key_buf = malloc(key_len)) == NULL) {
2694219Smcpowers 		rv = CKR_HOST_MEMORY;
2704219Smcpowers 		goto failed_exit;
2714219Smcpowers 	}
2724219Smcpowers 
2734219Smcpowers 	attr_count = ulCount + 1;
2744219Smcpowers 	newTemplate = grow_template(pTemplate, ulCount, attr_count);
2754219Smcpowers 	if (newTemplate == NULL) {
2764219Smcpowers 		rv = CKR_HOST_MEMORY;
2774219Smcpowers 		goto failed_exit;
2784219Smcpowers 	}
2794219Smcpowers 
2804219Smcpowers 	/* Now add the CKA_VALUE attribute to template */
2814219Smcpowers 	newTemplate[ulCount].type = CKA_VALUE;
2824219Smcpowers 	newTemplate[ulCount].pValue = (caddr_t)key_buf;
2834219Smcpowers 	newTemplate[ulCount].ulValueLen = key_len;
2844219Smcpowers 
2854219Smcpowers 	rv = process_object_attributes(newTemplate, attr_count - 1,
2864219Smcpowers 	    &obj_ngk.ngk_in_attributes, &is_token_obj);
2874219Smcpowers 	if (rv != CKR_OK) {
2884219Smcpowers 		goto failed_exit;
2894219Smcpowers 	}
2904219Smcpowers 	rv = process_object_attributes(&newTemplate[ulCount],
2914219Smcpowers 	    1, &obj_ngk.ngk_out_attributes, &is_token_obj);
2924219Smcpowers 	if (rv != CKR_OK) {
2934219Smcpowers 		goto failed_exit;
2944219Smcpowers 	}
2954219Smcpowers 
2964219Smcpowers 	/* Cannot create a token object with a READ-ONLY session. */
2974219Smcpowers 	if (is_token_obj && session_p->ses_RO) {
2984219Smcpowers 		rv = CKR_SESSION_READ_ONLY;
2994219Smcpowers 		goto failed_exit;
3004219Smcpowers 	}
3014219Smcpowers 
3024219Smcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY ioctl */
3034219Smcpowers 	obj_ngk.ngk_session = session_p->k_session;
3044219Smcpowers 	obj_ngk.ngk_in_count = attr_count - 1;
3054219Smcpowers 	obj_ngk.ngk_out_count = 1;
3064219Smcpowers 	obj_ngk.ngk_mechanism.cm_type = k_mech_type;
3074219Smcpowers 	obj_ngk.ngk_mechanism.cm_param = pMechanism->pParameter;
3084219Smcpowers 	obj_ngk.ngk_mechanism.cm_param_len = pMechanism->ulParameterLen;
3094219Smcpowers 
3104219Smcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY,
3114219Smcpowers 	    &obj_ngk)) < 0) {
3124219Smcpowers 		if (errno != EINTR)
3134219Smcpowers 			break;
3144219Smcpowers 	}
3154219Smcpowers 	if (r < 0) {
3164219Smcpowers 		rv = CKR_FUNCTION_FAILED;
3174219Smcpowers 	} else {
3184219Smcpowers 		rv = crypto2pkcs11_error_number(obj_ngk.ngk_return_value);
3194219Smcpowers 	}
3204219Smcpowers 	free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
3214219Smcpowers 	if (rv != CKR_OK) {
3224219Smcpowers 		goto failed_exit;
3234219Smcpowers 	}
3244219Smcpowers 
3254219Smcpowers 	rv = get_object_attributes(&newTemplate[ulCount], 1,
3264219Smcpowers 	    obj_ngk.ngk_out_attributes);
3274219Smcpowers 	free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
3284219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
3294219Smcpowers 		goto failed_exit;
3304219Smcpowers 	}
3314219Smcpowers 
3324219Smcpowers 	/*
3334219Smcpowers 	 * CKA_VALUE_LEN is not stored with the secret key object,
3344219Smcpowers 	 * so we remove it by shifting attributes down one.
3354219Smcpowers 	 */
3364219Smcpowers 	(void) remove_one_attribute(newTemplate, CKA_VALUE_LEN,
3374219Smcpowers 	    attr_count, B_FALSE);
3384219Smcpowers 
3394219Smcpowers 	rv = kernel_build_object(newTemplate, attr_count - 1,
3404219Smcpowers 	    new_objp, session_p, KERNEL_GEN_KEY);
3414219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
3424219Smcpowers 		goto failed_exit;
3434219Smcpowers 	}
3444219Smcpowers 	new_objp->is_lib_obj = B_TRUE;
3454219Smcpowers 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
3464219Smcpowers 	(void) free(newTemplate);
3474219Smcpowers 	bzero(key_buf, key_len);
3484219Smcpowers 	(void) free(key_buf);
3494219Smcpowers 	return (CKR_OK);
3504219Smcpowers 
3514219Smcpowers failed_exit:
3524219Smcpowers 	free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
3534219Smcpowers 	free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
3544219Smcpowers 	if (key_buf != NULL) {
3554219Smcpowers 		bzero(key_buf, key_len);
3564219Smcpowers 		(void) free(key_buf);
3574219Smcpowers 	}
3584219Smcpowers 	if (newTemplate != NULL) {
3594219Smcpowers 		(void) free(newTemplate);
3604219Smcpowers 	}
3614219Smcpowers 	return (rv);
3624219Smcpowers }
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate CK_RV
C_GenerateKey(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_OBJECT_HANDLE_PTR phKey)3650Sstevel@tonic-gate C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
3660Sstevel@tonic-gate     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
3670Sstevel@tonic-gate {
3680Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
3690Sstevel@tonic-gate 	kernel_session_t	*session_p;
3700Sstevel@tonic-gate 	kernel_object_t		*new_objp = NULL;
3710Sstevel@tonic-gate 	kernel_slot_t		*pslot;
3720Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
3730Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj;
3740Sstevel@tonic-gate 	CK_BBOOL		is_token_obj = FALSE;
3750Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
3760Sstevel@tonic-gate 	int r;
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	if (!kernel_initialized)
3790Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	/* Obtain the session pointer */
3820Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
3830Sstevel@tonic-gate 	if (rv != CKR_OK)
3840Sstevel@tonic-gate 		return (rv);
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	if ((pMechanism == NULL) || (phKey == NULL)) {
3870Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
3880Sstevel@tonic-gate 		goto failed_exit;
3890Sstevel@tonic-gate 	}
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	if ((pTemplate == NULL) && (ulCount != 0)) {
3920Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
3930Sstevel@tonic-gate 		goto failed_exit;
3940Sstevel@tonic-gate 	}
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
3970Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
3980Sstevel@tonic-gate 	if (rv != CKR_OK) {
3990Sstevel@tonic-gate 		goto failed_exit;
4000Sstevel@tonic-gate 	}
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	/* Create an object wrapper in the library first */
4030Sstevel@tonic-gate 	new_objp = calloc(1, sizeof (kernel_object_t));
4040Sstevel@tonic-gate 	if (new_objp == NULL) {
4050Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
4060Sstevel@tonic-gate 		goto failed_exit;
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 
4094219Smcpowers 	/*
4104219Smcpowers 	 * Special Case: if token does not support object creation,
4114219Smcpowers 	 * but does support key generation by value, then create a session
4124219Smcpowers 	 * object and initialize with value returned by token.
4134219Smcpowers 	 */
4144219Smcpowers 	pslot = slot_table[session_p->ses_slotid];
4154219Smcpowers 	if (!pslot->sl_func_list.fl_object_create) {
4164219Smcpowers 		rv = key_gen_by_value(pMechanism, pTemplate, ulCount, session_p,
4174219Smcpowers 		    k_mech_type, new_objp);
4184219Smcpowers 		if (rv != CKR_OK)
4194219Smcpowers 			goto failed_exit;
4204219Smcpowers 	} else {
4214219Smcpowers 		crypto_object_generate_key_t obj_gk;
4220Sstevel@tonic-gate 
4234219Smcpowers 		/* Process the attributes */
4244219Smcpowers 		rv = process_object_attributes(pTemplate, ulCount,
4254219Smcpowers 		    &obj_gk.gk_attributes, &is_token_obj);
4264219Smcpowers 		if (rv != CKR_OK) {
4274219Smcpowers 			goto failed_exit;
4284219Smcpowers 		}
4294219Smcpowers 		/* Cannot create a token object with a READ-ONLY session. */
4304219Smcpowers 		if (is_token_obj && session_p->ses_RO) {
4314219Smcpowers 			free_object_attributes(obj_gk.gk_attributes, ulCount);
4324219Smcpowers 			rv = CKR_SESSION_READ_ONLY;
4334219Smcpowers 			goto failed_exit;
4344219Smcpowers 		}
4354219Smcpowers 
4364219Smcpowers 		/* Call the CRYPTO_GENERATE_KEY ioctl */
4374219Smcpowers 		obj_gk.gk_session = session_p->k_session;
4384219Smcpowers 		obj_gk.gk_count = ulCount;
4394219Smcpowers 		obj_gk.gk_mechanism.cm_type = k_mech_type;
4404219Smcpowers 		obj_gk.gk_mechanism.cm_param = pMechanism->pParameter;
4414219Smcpowers 		obj_gk.gk_mechanism.cm_param_len = pMechanism->ulParameterLen;
4420Sstevel@tonic-gate 
4434219Smcpowers 		while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY,
4444219Smcpowers 		    &obj_gk)) < 0) {
4454219Smcpowers 			if (errno != EINTR)
4464219Smcpowers 				break;
4474219Smcpowers 		}
4484219Smcpowers 		if (r < 0) {
4494219Smcpowers 			rv = CKR_FUNCTION_FAILED;
4504219Smcpowers 		} else {
4514219Smcpowers 			rv = crypto2pkcs11_error_number(obj_gk.gk_return_value);
4524219Smcpowers 		}
4534219Smcpowers 
4544219Smcpowers 		free_object_attributes(obj_gk.gk_attributes, ulCount);
4554219Smcpowers 
4564219Smcpowers 		if (rv != CKR_OK) {
4574219Smcpowers 			goto failed_exit;
4584219Smcpowers 		}
4590Sstevel@tonic-gate 
4604219Smcpowers 		/* Get the value of the CKA_PRIVATE attribute. */
4614219Smcpowers 		rv = get_cka_private_value(session_p, obj_gk.gk_handle,
4624219Smcpowers 		    &is_pri_obj);
4634219Smcpowers 		if (rv != CKR_OK) {
4644219Smcpowers 			goto failed_exit;
4654219Smcpowers 		}
4664219Smcpowers 
4674219Smcpowers 		/*
4684219Smcpowers 		 * Store the kernel object handle in the object wrapper and
4694219Smcpowers 		 * initialize the library object.
4704219Smcpowers 		 */
4714219Smcpowers 		new_objp->k_handle = obj_gk.gk_handle;
4724219Smcpowers 		new_objp->is_lib_obj = B_FALSE;
4734219Smcpowers 		new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
4744219Smcpowers 		new_objp->extra_attrlistp = NULL;
4754219Smcpowers 
4764219Smcpowers 		if (is_pri_obj)
4774219Smcpowers 			new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
4784219Smcpowers 		else
4794219Smcpowers 			new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
4804219Smcpowers 
4814219Smcpowers 		if (is_token_obj)
4824219Smcpowers 			new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
4834219Smcpowers 		else
4844219Smcpowers 			new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
4880Sstevel@tonic-gate 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	/*
4910Sstevel@tonic-gate 	 * Add the new object to the slot's token object list if it is a
4920Sstevel@tonic-gate 	 * a token object. Otherwise, add it to the session's object list.
4930Sstevel@tonic-gate 	 */
4940Sstevel@tonic-gate 	if (is_token_obj) {
4950Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
4960Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_objp, pslot);
4970Sstevel@tonic-gate 	} else {
4980Sstevel@tonic-gate 		kernel_add_object_to_session(new_objp, session_p);
4990Sstevel@tonic-gate 	}
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	*phKey = (CK_OBJECT_HANDLE)new_objp;
5020Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
5030Sstevel@tonic-gate 	return (rv);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate failed_exit:
5060Sstevel@tonic-gate 	if (new_objp != NULL) {
5070Sstevel@tonic-gate 		(void) free(new_objp);
5080Sstevel@tonic-gate 	}
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
5110Sstevel@tonic-gate 	return (rv);
5120Sstevel@tonic-gate }
5130Sstevel@tonic-gate 
5144219Smcpowers CK_RV
key_gen_rsa_by_value(CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pPublicKeyTemplate,CK_ULONG ulPublicKeyAttributeCount,CK_ATTRIBUTE_PTR pPrivateKeyTemplate,CK_ULONG ulPrivateKeyAttributeCount,kernel_session_t * session_p,crypto_mech_type_t k_mech_type,kernel_object_t * new_pub_objp,kernel_object_t * new_pri_objp)5154219Smcpowers key_gen_rsa_by_value(CK_MECHANISM_PTR pMechanism,
5164219Smcpowers     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
5174219Smcpowers     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
5184219Smcpowers     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
5194219Smcpowers     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
5204219Smcpowers {
5214219Smcpowers 	crypto_nostore_generate_key_pair_t obj_nkp;
5224219Smcpowers 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
5234219Smcpowers 	CK_ATTRIBUTE_PTR priTemplate = NULL;
5244219Smcpowers 	CK_RV rv = CKR_OK;
5254219Smcpowers 	CK_BBOOL is_token_obj1 = FALSE;
5264219Smcpowers 	CK_BBOOL is_token_obj2 = FALSE;
5274219Smcpowers 	uint_t pub_attr_count, pri_attr_count;
5284219Smcpowers 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
5294219Smcpowers 	char public_modulus[512];
5304219Smcpowers 	char public_exponent[8];
5314219Smcpowers 	char private_exponent[512];
5324219Smcpowers 	char private_modulus[512];
5334219Smcpowers 	char prime_1[512];
5344219Smcpowers 	char prime_2[512];
5354219Smcpowers 	char exponent_1[512];
5364219Smcpowers 	char exponent_2[512];
5374219Smcpowers 	char coefficient[512];
5384219Smcpowers 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
5394219Smcpowers 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
5404219Smcpowers 	CK_ULONG key_type;
5414219Smcpowers 	CK_ULONG modulus_bytes;
5424219Smcpowers 	boolean_t has_class, has_key_type, has_pub_exponent;
5434219Smcpowers 	int n, r;
5444219Smcpowers 
5454219Smcpowers 	obj_nkp.nkp_in_public_count = 0;
5464219Smcpowers 	obj_nkp.nkp_out_public_count = 0;
5474219Smcpowers 	obj_nkp.nkp_in_private_count = 0;
5484219Smcpowers 	obj_nkp.nkp_out_private_count = 0;
5494219Smcpowers 
5504219Smcpowers 	/* modulus bits must be present when generating a RSA key pair */
5514219Smcpowers 	if (!attribute_in_template(CKA_MODULUS_BITS, pPublicKeyTemplate,
5524219Smcpowers 	    ulPublicKeyAttributeCount)) {
5534219Smcpowers 		rv = CKR_TEMPLATE_INCOMPLETE;
5544219Smcpowers 		goto failed_exit;
5554219Smcpowers 	}
5564219Smcpowers 
5574219Smcpowers 	modulus_bytes = get_modulus_bytes(pPublicKeyTemplate,
5584219Smcpowers 	    ulPublicKeyAttributeCount);
5594219Smcpowers 
5604219Smcpowers 	/*
5614219Smcpowers 	 * Add CKA_MODULUS to the public template.
5624219Smcpowers 	 * This attribute must not be in the template.
5634219Smcpowers 	 */
5644219Smcpowers 	if (attribute_in_template(CKA_MODULUS, pPublicKeyTemplate,
5654219Smcpowers 	    ulPublicKeyAttributeCount)) {
5664219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
5674219Smcpowers 		goto failed_exit;
5684219Smcpowers 	}
5694219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
5704219Smcpowers 	    ulPublicKeyAttributeCount);
5714219Smcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
5724219Smcpowers 	    ulPublicKeyAttributeCount);
5734219Smcpowers 	has_pub_exponent = attribute_in_template(CKA_PUBLIC_EXPONENT,
5744219Smcpowers 	    pPublicKeyTemplate, ulPublicKeyAttributeCount);
5754219Smcpowers 
5764219Smcpowers 	pub_attr_count = ulPublicKeyAttributeCount + 1;
5774219Smcpowers 	if (!has_class)
5784219Smcpowers 		pub_attr_count++;
5794219Smcpowers 	if (!has_key_type)
5804219Smcpowers 		pub_attr_count++;
5814219Smcpowers 	if (!has_pub_exponent)
5824219Smcpowers 		pub_attr_count++;
5834219Smcpowers 	pubTemplate = grow_template(pPublicKeyTemplate,
5844219Smcpowers 	    ulPublicKeyAttributeCount, pub_attr_count);
5854219Smcpowers 	if (pubTemplate == NULL) {
5864219Smcpowers 		rv = CKR_HOST_MEMORY;
5874219Smcpowers 		goto failed_exit;
5884219Smcpowers 	}
5894219Smcpowers 
5904219Smcpowers 	n = ulPublicKeyAttributeCount;
5914219Smcpowers 	if (!has_class) {
5924219Smcpowers 		pubTemplate[n].type = CKA_CLASS;
5934219Smcpowers 		pubTemplate[n].pValue = (caddr_t)&pub_class;
5944219Smcpowers 		pubTemplate[n].ulValueLen = sizeof (pub_class);
5954219Smcpowers 		n++;
5964219Smcpowers 	}
5974219Smcpowers 	if (!has_key_type) {
5984219Smcpowers 		pubTemplate[n].type = CKA_KEY_TYPE;
5994219Smcpowers 		key_type = CKK_RSA;
6004219Smcpowers 		pubTemplate[n].pValue = (caddr_t)&key_type;
6014219Smcpowers 		pubTemplate[n].ulValueLen = sizeof (key_type);
6024219Smcpowers 		n++;
6034219Smcpowers 	}
6044219Smcpowers 	if (!has_pub_exponent) {
6054219Smcpowers 		pubTemplate[n].type = CKA_PUBLIC_EXPONENT;
6064219Smcpowers 		pubTemplate[n].pValue = (caddr_t)public_exponent;
6074219Smcpowers 		pubTemplate[n].ulValueLen = modulus_bytes;
6084219Smcpowers 		n++;
6094219Smcpowers 		pub_out_attr_count++;
6104219Smcpowers 	}
6114219Smcpowers 	pubTemplate[n].type = CKA_MODULUS;
6124219Smcpowers 	pubTemplate[n].pValue = (caddr_t)public_modulus;
6134219Smcpowers 	pubTemplate[n].ulValueLen = modulus_bytes;
6144219Smcpowers 	pub_out_attr_count++;
6154219Smcpowers 
6164219Smcpowers 	rv = process_object_attributes(pubTemplate,
6174219Smcpowers 	    pub_attr_count - pub_out_attr_count,
6184219Smcpowers 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
6194219Smcpowers 	if (rv != CKR_OK) {
6204219Smcpowers 		goto failed_exit;
6214219Smcpowers 	}
6224219Smcpowers 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
6234219Smcpowers 
6244219Smcpowers 	rv = process_object_attributes(
6254219Smcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
6264219Smcpowers 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
6274219Smcpowers 	    &is_token_obj1);
6284219Smcpowers 	if (rv != CKR_OK) {
6294219Smcpowers 		goto failed_exit;
6304219Smcpowers 	}
6314219Smcpowers 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
6324219Smcpowers 
6334219Smcpowers 	/*
6344219Smcpowers 	 * Cannot create a token object with a READ-ONLY
6354219Smcpowers 	 * session.
6364219Smcpowers 	 */
6374219Smcpowers 	if (is_token_obj1 && session_p->ses_RO) {
6384219Smcpowers 		rv = CKR_SESSION_READ_ONLY;
6394219Smcpowers 		goto failed_exit;
6404219Smcpowers 	}
6414219Smcpowers 
6424219Smcpowers 	/*
6434219Smcpowers 	 * Add CKA_MODULUS and CKA_PRIVATE_EXPONENT
6444219Smcpowers 	 * to the private template. These attributes
6454219Smcpowers 	 * must not be in the template.
6464219Smcpowers 	 */
6474219Smcpowers 	if (attribute_in_template(CKA_PRIVATE_EXPONENT,
6484219Smcpowers 	    pPrivateKeyTemplate, ulPrivateKeyAttributeCount) ||
6494219Smcpowers 	    attribute_in_template(CKA_MODULUS,
6504219Smcpowers 	    pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) {
6514219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
6524219Smcpowers 		goto failed_exit;
6534219Smcpowers 	}
6544219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
6554219Smcpowers 	    ulPrivateKeyAttributeCount);
6564219Smcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
6574219Smcpowers 	    ulPrivateKeyAttributeCount);
6584219Smcpowers 
6594219Smcpowers 	pri_attr_count = ulPrivateKeyAttributeCount + 7;
6604219Smcpowers 	if (!has_class)
6614219Smcpowers 		pri_attr_count++;
6624219Smcpowers 	if (!has_key_type)
6634219Smcpowers 		pri_attr_count++;
6644219Smcpowers 
6654219Smcpowers 	/* allocate space for CKA_PUBLIC_EXPONENT */
6664219Smcpowers 	priTemplate = grow_template(pPrivateKeyTemplate,
6674219Smcpowers 	    ulPrivateKeyAttributeCount, pri_attr_count + 1);
6684219Smcpowers 	if (priTemplate == NULL) {
6694219Smcpowers 		rv = CKR_HOST_MEMORY;
6704219Smcpowers 		goto failed_exit;
6714219Smcpowers 	}
6724219Smcpowers 	n = ulPrivateKeyAttributeCount;
6734219Smcpowers 	if (!has_class) {
6744219Smcpowers 		priTemplate[n].type = CKA_CLASS;
6754219Smcpowers 		priTemplate[n].pValue = (caddr_t)&pri_class;
6764219Smcpowers 		priTemplate[n].ulValueLen = sizeof (pri_class);
6774219Smcpowers 		n++;
6784219Smcpowers 	}
6794219Smcpowers 	if (!has_key_type) {
6804219Smcpowers 		priTemplate[n].type = CKA_KEY_TYPE;
6814219Smcpowers 		key_type = CKK_RSA;
6824219Smcpowers 		priTemplate[n].pValue = (caddr_t)&key_type;
6834219Smcpowers 		priTemplate[n].ulValueLen = sizeof (key_type);
6844219Smcpowers 		n++;
6854219Smcpowers 	}
6864219Smcpowers 	priTemplate[n].type = CKA_MODULUS;
6874219Smcpowers 	priTemplate[n].pValue = (caddr_t)private_modulus;
6884219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes;
6894219Smcpowers 	pri_out_attr_count++;
6904219Smcpowers 
6914219Smcpowers 	n++;
6924219Smcpowers 	priTemplate[n].type = CKA_PRIVATE_EXPONENT;
6934219Smcpowers 	priTemplate[n].pValue = (caddr_t)private_exponent;
6944219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes;
6954219Smcpowers 	pri_out_attr_count++;
6964219Smcpowers 
6974219Smcpowers 	n++;
6984219Smcpowers 	priTemplate[n].type = CKA_PRIME_1;
6994219Smcpowers 	priTemplate[n].pValue = (caddr_t)prime_1;
7004219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
7014219Smcpowers 	pri_out_attr_count++;
7024219Smcpowers 
7034219Smcpowers 	n++;
7044219Smcpowers 	priTemplate[n].type = CKA_PRIME_2;
7054219Smcpowers 	priTemplate[n].pValue = (caddr_t)prime_2;
7064219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
7074219Smcpowers 	pri_out_attr_count++;
7084219Smcpowers 
7094219Smcpowers 	n++;
7104219Smcpowers 	priTemplate[n].type = CKA_EXPONENT_1;
7114219Smcpowers 	priTemplate[n].pValue = (caddr_t)exponent_1;
7124219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
7134219Smcpowers 	pri_out_attr_count++;
7144219Smcpowers 
7154219Smcpowers 	n++;
7164219Smcpowers 	priTemplate[n].type = CKA_EXPONENT_2;
7174219Smcpowers 	priTemplate[n].pValue = (caddr_t)exponent_2;
7184219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
7194219Smcpowers 	pri_out_attr_count++;
7204219Smcpowers 
7214219Smcpowers 	n++;
7224219Smcpowers 	priTemplate[n].type = CKA_COEFFICIENT;
7234219Smcpowers 	priTemplate[n].pValue = (caddr_t)coefficient;
7244219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
7254219Smcpowers 	pri_out_attr_count++;
7264219Smcpowers 
7274219Smcpowers 	rv = process_object_attributes(priTemplate,
7284219Smcpowers 	    pri_attr_count - pri_out_attr_count,
7294219Smcpowers 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
7304219Smcpowers 	if (rv != CKR_OK) {
7314219Smcpowers 		goto failed_exit;
7324219Smcpowers 	}
7334219Smcpowers 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
7344219Smcpowers 
7354219Smcpowers 	rv = process_object_attributes(
7364219Smcpowers 	    &priTemplate[pri_attr_count - pri_out_attr_count],
7374219Smcpowers 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
7384219Smcpowers 	    &is_token_obj2);
7394219Smcpowers 	if (rv != CKR_OK) {
7404219Smcpowers 		goto failed_exit;
7414219Smcpowers 	}
7424219Smcpowers 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
7434219Smcpowers 
7444219Smcpowers 	/*
7454219Smcpowers 	 * The public key and the private key need to contain the same
7464219Smcpowers 	 * attribute values for CKA_TOKEN.
7474219Smcpowers 	 */
7484219Smcpowers 	if (is_token_obj1 != is_token_obj2) {
7494219Smcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
7504219Smcpowers 		goto failed_exit;
7514219Smcpowers 	}
7524219Smcpowers 
7534219Smcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
7544219Smcpowers 	obj_nkp.nkp_session = session_p-> k_session;
7554219Smcpowers 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
7564219Smcpowers 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
7574219Smcpowers 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
7584219Smcpowers 
7594219Smcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
7604219Smcpowers 	    &obj_nkp)) < 0) {
7614219Smcpowers 		if (errno != EINTR)
7624219Smcpowers 			break;
7634219Smcpowers 	}
7644219Smcpowers 	if (r < 0) {
7654219Smcpowers 		rv = CKR_FUNCTION_FAILED;
7664219Smcpowers 	} else {
7674219Smcpowers 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
7684219Smcpowers 	}
7694219Smcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
7704219Smcpowers 	    &obj_nkp.nkp_in_public_count);
7714219Smcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
7724219Smcpowers 	    &obj_nkp.nkp_in_private_count);
7734219Smcpowers 
7744219Smcpowers 	if (rv != CKR_OK) {
7754219Smcpowers 		goto failed_exit;
7764219Smcpowers 	}
7774219Smcpowers 
7784219Smcpowers 	rv = get_object_attributes(
7794219Smcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
7804219Smcpowers 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
7814219Smcpowers 	if (rv == CRYPTO_SUCCESS) {
7824219Smcpowers 		rv = get_object_attributes(
7834219Smcpowers 		    &priTemplate[pri_attr_count - pri_out_attr_count],
7844219Smcpowers 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
7854219Smcpowers 	}
7864219Smcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
7874219Smcpowers 	    &obj_nkp.nkp_out_public_count);
7884219Smcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
7894219Smcpowers 	    &obj_nkp.nkp_out_private_count);
7904219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
7914219Smcpowers 		goto failed_exit;
7924219Smcpowers 	}
7934219Smcpowers 
7944219Smcpowers 	/* store generated modulus and public exponent */
7954219Smcpowers 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
7964219Smcpowers 	    session_p, KERNEL_GEN_KEY);
7974219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
7984219Smcpowers 		goto failed_exit;
7994219Smcpowers 	}
8004219Smcpowers 
8014219Smcpowers 	/*
8024219Smcpowers 	 * Copy CKA_PUBLIC_EXPONENT from the public template
8034219Smcpowers 	 * to the private template.
8044219Smcpowers 	 */
8054219Smcpowers 	rv = copy_attribute(CKA_PUBLIC_EXPONENT, pubTemplate,
8064219Smcpowers 	    pub_attr_count, &priTemplate[pri_attr_count]);
8074219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
8084219Smcpowers 		goto failed_exit;
8094219Smcpowers 	}
8104219Smcpowers 
8114219Smcpowers 	rv = kernel_build_object(priTemplate, pri_attr_count + 1, new_pri_objp,
8124219Smcpowers 	    session_p, KERNEL_GEN_KEY);
8134219Smcpowers 	(void) free(priTemplate[pri_attr_count].pValue);
8144219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
8154219Smcpowers 		goto failed_exit;
8164219Smcpowers 	}
8174219Smcpowers 	(void) free(pubTemplate);
8184219Smcpowers 	(void) free(priTemplate);
8194219Smcpowers 
8204219Smcpowers 	new_pub_objp->is_lib_obj = B_TRUE;
8214219Smcpowers 	new_pri_objp->is_lib_obj = B_TRUE;
8224219Smcpowers 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
8234219Smcpowers 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
8244219Smcpowers 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
8254219Smcpowers 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
8264219Smcpowers 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
8274219Smcpowers 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
8284219Smcpowers 	return (CKR_OK);
8294219Smcpowers 
8304219Smcpowers failed_exit:
8314219Smcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
8324219Smcpowers 	    &obj_nkp.nkp_in_public_count);
8334219Smcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
8344219Smcpowers 	    &obj_nkp.nkp_out_public_count);
8354219Smcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
8364219Smcpowers 	    &obj_nkp.nkp_in_private_count);
8374219Smcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
8384219Smcpowers 	    &obj_nkp.nkp_out_private_count);
8394219Smcpowers 	if (pubTemplate != NULL) {
8404219Smcpowers 		(void) free(pubTemplate);
8414219Smcpowers 	}
8424219Smcpowers 	if (priTemplate != NULL) {
8434219Smcpowers 		(void) free(priTemplate);
8444219Smcpowers 	}
8454219Smcpowers 	return (rv);
8464219Smcpowers }
8474219Smcpowers 
8484219Smcpowers CK_RV
key_gen_dh_by_value(CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pPublicKeyTemplate,CK_ULONG ulPublicKeyAttributeCount,CK_ATTRIBUTE_PTR pPrivateKeyTemplate,CK_ULONG ulPrivateKeyAttributeCount,kernel_session_t * session_p,crypto_mech_type_t k_mech_type,kernel_object_t * new_pub_objp,kernel_object_t * new_pri_objp)8494219Smcpowers key_gen_dh_by_value(CK_MECHANISM_PTR pMechanism,
8504219Smcpowers     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
8514219Smcpowers     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
8524219Smcpowers     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
8534219Smcpowers     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
8544219Smcpowers {
8554219Smcpowers 	crypto_nostore_generate_key_pair_t obj_nkp;
8564219Smcpowers 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
8574219Smcpowers 	CK_ATTRIBUTE_PTR priTemplate = NULL;
8584219Smcpowers 	CK_RV rv = CKR_OK;
8594219Smcpowers 	CK_BBOOL is_token_obj1 = FALSE;
8604219Smcpowers 	CK_BBOOL is_token_obj2 = FALSE;
8614219Smcpowers 	uint_t pub_attr_count, pri_attr_count;
8624219Smcpowers 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
8634219Smcpowers 	char public_value[256];
8644219Smcpowers 	char private_value[256];
8654219Smcpowers 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
8664219Smcpowers 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
8674219Smcpowers 	CK_ULONG key_type;
8684219Smcpowers 	boolean_t has_class, has_key_type;
8694219Smcpowers 	int n, r;
8704219Smcpowers 
8714219Smcpowers 	obj_nkp.nkp_in_public_count = 0;
8724219Smcpowers 	obj_nkp.nkp_out_public_count = 0;
8734219Smcpowers 	obj_nkp.nkp_in_private_count = 0;
8744219Smcpowers 	obj_nkp.nkp_out_private_count = 0;
8754219Smcpowers 
8764219Smcpowers 	/*
8774219Smcpowers 	 * Add CKA_VALUE to the public template.
8784219Smcpowers 	 * This attribute must not be in the template.
8794219Smcpowers 	 */
8804219Smcpowers 	if (attribute_in_template(CKA_VALUE, pPublicKeyTemplate,
8814219Smcpowers 	    ulPublicKeyAttributeCount)) {
8824219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
8834219Smcpowers 		goto failed_exit;
8844219Smcpowers 	}
8854219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
8864219Smcpowers 	    ulPublicKeyAttributeCount);
8874219Smcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
8884219Smcpowers 	    ulPublicKeyAttributeCount);
8894219Smcpowers 
8904219Smcpowers 	pub_attr_count = ulPublicKeyAttributeCount + 1;
8914219Smcpowers 	if (!has_class)
8924219Smcpowers 		pub_attr_count++;
8934219Smcpowers 	if (!has_key_type)
8944219Smcpowers 		pub_attr_count++;
8954219Smcpowers 	pubTemplate = grow_template(pPublicKeyTemplate,
8964219Smcpowers 	    ulPublicKeyAttributeCount, pub_attr_count);
8974219Smcpowers 	if (pubTemplate == NULL) {
8984219Smcpowers 		rv = CKR_HOST_MEMORY;
8994219Smcpowers 		goto failed_exit;
9004219Smcpowers 	}
9014219Smcpowers 
9024219Smcpowers 	n = ulPublicKeyAttributeCount;
9034219Smcpowers 	if (!has_class) {
9044219Smcpowers 		pubTemplate[n].type = CKA_CLASS;
9054219Smcpowers 		pubTemplate[n].pValue = (caddr_t)&pub_class;
9064219Smcpowers 		pubTemplate[n].ulValueLen = sizeof (pub_class);
9074219Smcpowers 		n++;
9084219Smcpowers 	}
9094219Smcpowers 	if (!has_key_type) {
9104219Smcpowers 		pubTemplate[n].type = CKA_KEY_TYPE;
9114219Smcpowers 		key_type = CKK_DH;
9124219Smcpowers 		pubTemplate[n].pValue = (caddr_t)&key_type;
9134219Smcpowers 		pubTemplate[n].ulValueLen = sizeof (key_type);
9144219Smcpowers 		n++;
9154219Smcpowers 	}
9164219Smcpowers 	pubTemplate[n].type = CKA_VALUE;
9174219Smcpowers 	pubTemplate[n].pValue = (caddr_t)public_value;
9184219Smcpowers 	pubTemplate[n].ulValueLen = sizeof (public_value);
9194219Smcpowers 	pub_out_attr_count++;
9204219Smcpowers 
9214219Smcpowers 	rv = process_object_attributes(pubTemplate,
9224219Smcpowers 	    pub_attr_count - pub_out_attr_count,
9234219Smcpowers 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
9244219Smcpowers 	if (rv != CKR_OK) {
9254219Smcpowers 		goto failed_exit;
9264219Smcpowers 	}
9274219Smcpowers 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
9284219Smcpowers 
9294219Smcpowers 	rv = process_object_attributes(
9304219Smcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
9314219Smcpowers 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
9324219Smcpowers 	    &is_token_obj1);
9334219Smcpowers 	if (rv != CKR_OK) {
9344219Smcpowers 		goto failed_exit;
9354219Smcpowers 	}
9364219Smcpowers 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
9374219Smcpowers 
9384219Smcpowers 	/*
9394219Smcpowers 	 * Cannot create a token object with a READ-ONLY
9404219Smcpowers 	 * session.
9414219Smcpowers 	 */
9424219Smcpowers 	if (is_token_obj1 && session_p->ses_RO) {
9434219Smcpowers 		rv = CKR_SESSION_READ_ONLY;
9444219Smcpowers 		goto failed_exit;
9454219Smcpowers 	}
9464219Smcpowers 
9474219Smcpowers 	/*
9484219Smcpowers 	 * CKA_BASE, CKA_PRIME, and CKA_VALUE must not appear
9494219Smcpowers 	 * in private template.
9504219Smcpowers 	 */
9514219Smcpowers 	if (attribute_in_template(CKA_BASE, pPrivateKeyTemplate,
9524219Smcpowers 	    ulPrivateKeyAttributeCount) ||
9534219Smcpowers 	    attribute_in_template(CKA_PRIME, pPrivateKeyTemplate,
9544219Smcpowers 	    ulPrivateKeyAttributeCount) ||
9554219Smcpowers 	    attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
9564219Smcpowers 	    ulPrivateKeyAttributeCount)) {
9574219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
9584219Smcpowers 		goto failed_exit;
9594219Smcpowers 	}
9604219Smcpowers 
9614219Smcpowers 	if (attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
9624219Smcpowers 	    ulPrivateKeyAttributeCount)) {
9634219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
9644219Smcpowers 		goto failed_exit;
9654219Smcpowers 	}
9664219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
9674219Smcpowers 	    ulPrivateKeyAttributeCount);
9684219Smcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
9694219Smcpowers 	    ulPrivateKeyAttributeCount);
9704219Smcpowers 
9714219Smcpowers 	pri_attr_count = ulPrivateKeyAttributeCount + 1;
9724219Smcpowers 	if (!has_class)
9734219Smcpowers 		pri_attr_count++;
9744219Smcpowers 	if (!has_key_type)
9754219Smcpowers 		pri_attr_count++;
9764219Smcpowers 
9774219Smcpowers 	/* allocate space for CKA_BASE and CKA_PRIME */
9784219Smcpowers 	priTemplate = grow_template(pPrivateKeyTemplate,
9794219Smcpowers 	    ulPrivateKeyAttributeCount, pri_attr_count + 2);
9804219Smcpowers 	if (priTemplate == NULL) {
9814219Smcpowers 		rv = CKR_HOST_MEMORY;
9824219Smcpowers 		goto failed_exit;
9834219Smcpowers 	}
9844219Smcpowers 	n = ulPrivateKeyAttributeCount;
9854219Smcpowers 	if (!has_class) {
9864219Smcpowers 		priTemplate[n].type = CKA_CLASS;
9874219Smcpowers 		priTemplate[n].pValue = (caddr_t)&pri_class;
9884219Smcpowers 		priTemplate[n].ulValueLen = sizeof (pri_class);
9894219Smcpowers 		n++;
9904219Smcpowers 	}
9914219Smcpowers 	if (!has_key_type) {
9924219Smcpowers 		priTemplate[n].type = CKA_KEY_TYPE;
9934219Smcpowers 		key_type = CKK_DH;
9944219Smcpowers 		priTemplate[n].pValue = (caddr_t)&key_type;
9954219Smcpowers 		priTemplate[n].ulValueLen = sizeof (key_type);
9964219Smcpowers 		n++;
9974219Smcpowers 	}
9984219Smcpowers 	priTemplate[n].type = CKA_VALUE;
9994219Smcpowers 	priTemplate[n].pValue = (caddr_t)private_value;
10004219Smcpowers 	priTemplate[n].ulValueLen = sizeof (private_value);
10014219Smcpowers 	pri_out_attr_count++;
10024219Smcpowers 
10034219Smcpowers 	rv = process_object_attributes(priTemplate,
10044219Smcpowers 	    pri_attr_count - pri_out_attr_count,
10054219Smcpowers 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
10064219Smcpowers 	if (rv != CKR_OK) {
10074219Smcpowers 		goto failed_exit;
10084219Smcpowers 	}
10094219Smcpowers 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
10104219Smcpowers 
10114219Smcpowers 	rv = process_object_attributes(
10124219Smcpowers 	    &priTemplate[pri_attr_count - pri_out_attr_count],
10134219Smcpowers 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
10144219Smcpowers 	    &is_token_obj2);
10154219Smcpowers 	if (rv != CKR_OK) {
10164219Smcpowers 		goto failed_exit;
10174219Smcpowers 	}
10184219Smcpowers 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
10194219Smcpowers 
10204219Smcpowers 	/*
10214219Smcpowers 	 * The public key and the private key need to contain the same
10224219Smcpowers 	 * attribute values for CKA_TOKEN.
10234219Smcpowers 	 */
10244219Smcpowers 	if (is_token_obj1 != is_token_obj2) {
10254219Smcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
10264219Smcpowers 		goto failed_exit;
10274219Smcpowers 	}
10284219Smcpowers 
10294219Smcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
10304219Smcpowers 	obj_nkp.nkp_session = session_p-> k_session;
10314219Smcpowers 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
10324219Smcpowers 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
10334219Smcpowers 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
10344219Smcpowers 
10354219Smcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
10364219Smcpowers 	    &obj_nkp)) < 0) {
10374219Smcpowers 		if (errno != EINTR)
10384219Smcpowers 			break;
10394219Smcpowers 	}
10404219Smcpowers 	if (r < 0) {
10414219Smcpowers 		rv = CKR_FUNCTION_FAILED;
10424219Smcpowers 	} else {
10434219Smcpowers 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
10444219Smcpowers 	}
10454219Smcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
10464219Smcpowers 	    &obj_nkp.nkp_in_public_count);
10474219Smcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
10484219Smcpowers 	    &obj_nkp.nkp_in_private_count);
10494219Smcpowers 
10504219Smcpowers 	if (rv != CKR_OK) {
10514219Smcpowers 		goto failed_exit;
10524219Smcpowers 	}
10534219Smcpowers 
10544219Smcpowers 	rv = get_object_attributes(
10554219Smcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
10564219Smcpowers 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
10574219Smcpowers 	if (rv == CRYPTO_SUCCESS) {
10584219Smcpowers 		rv = get_object_attributes(
10594219Smcpowers 		    &priTemplate[pri_attr_count - pri_out_attr_count],
10604219Smcpowers 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
10614219Smcpowers 	}
10624219Smcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
10634219Smcpowers 	    &obj_nkp.nkp_out_public_count);
10644219Smcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
10654219Smcpowers 	    &obj_nkp.nkp_out_private_count);
10664219Smcpowers 
10674219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
10684219Smcpowers 		goto failed_exit;
10694219Smcpowers 	}
10704219Smcpowers 
10714219Smcpowers 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
10724219Smcpowers 	    session_p, KERNEL_GEN_KEY);
10734219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
10744219Smcpowers 		goto failed_exit;
10754219Smcpowers 	}
10764219Smcpowers 
10774219Smcpowers 	/*
10784219Smcpowers 	 * Copy CKA_BASE and CKA_PRIME from the public template
10794219Smcpowers 	 * to the private template.
10804219Smcpowers 	 */
10814219Smcpowers 	rv = copy_attribute(CKA_BASE, pubTemplate, pub_attr_count,
10824219Smcpowers 	    &priTemplate[pri_attr_count]);
10834219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
10844219Smcpowers 		goto failed_exit;
10854219Smcpowers 	}
10864219Smcpowers 	rv = copy_attribute(CKA_PRIME, pubTemplate, pub_attr_count,
10874219Smcpowers 	    &priTemplate[pri_attr_count + 1]);
10884219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
10894219Smcpowers 		(void) free(priTemplate[pri_attr_count].pValue);
10904219Smcpowers 		goto failed_exit;
10914219Smcpowers 	}
10924219Smcpowers 
10934219Smcpowers 	/* +2 to account for CKA_BASE and CKA_PRIME */
10944219Smcpowers 	rv = kernel_build_object(priTemplate, pri_attr_count + 2,
10954219Smcpowers 	    new_pri_objp, session_p, KERNEL_GEN_KEY);
10964219Smcpowers 	(void) free(priTemplate[pri_attr_count].pValue);
10974219Smcpowers 	(void) free(priTemplate[pri_attr_count + 1].pValue);
10984219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
10994219Smcpowers 		goto failed_exit;
11004219Smcpowers 	}
11014219Smcpowers 	(void) free(pubTemplate);
11024219Smcpowers 	(void) free(priTemplate);
11034219Smcpowers 
11044219Smcpowers 	new_pub_objp->is_lib_obj = B_TRUE;
11054219Smcpowers 	new_pri_objp->is_lib_obj = B_TRUE;
11064219Smcpowers 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
11074219Smcpowers 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
11084219Smcpowers 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
11094219Smcpowers 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
11104219Smcpowers 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
11114219Smcpowers 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
11124219Smcpowers 	return (CKR_OK);
11134219Smcpowers 
11144219Smcpowers failed_exit:
11154219Smcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
11164219Smcpowers 	    &obj_nkp.nkp_in_public_count);
11174219Smcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
11184219Smcpowers 	    &obj_nkp.nkp_out_public_count);
11194219Smcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
11204219Smcpowers 	    &obj_nkp.nkp_in_private_count);
11214219Smcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
11224219Smcpowers 	    &obj_nkp.nkp_out_private_count);
11234219Smcpowers 	if (pubTemplate != NULL) {
11244219Smcpowers 		(void) free(pubTemplate);
11254219Smcpowers 	}
11264219Smcpowers 	if (priTemplate != NULL) {
11274219Smcpowers 		(void) free(priTemplate);
11284219Smcpowers 	}
11294219Smcpowers 	return (rv);
11304219Smcpowers }
11314219Smcpowers 
11324219Smcpowers CK_RV
key_gen_ec_by_value(CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pPublicKeyTemplate,CK_ULONG ulPublicKeyAttributeCount,CK_ATTRIBUTE_PTR pPrivateKeyTemplate,CK_ULONG ulPrivateKeyAttributeCount,kernel_session_t * session_p,crypto_mech_type_t k_mech_type,kernel_object_t * new_pub_objp,kernel_object_t * new_pri_objp)11334219Smcpowers key_gen_ec_by_value(CK_MECHANISM_PTR pMechanism,
11344219Smcpowers     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
11354219Smcpowers     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
11364219Smcpowers     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
11374219Smcpowers     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
11384219Smcpowers {
11394219Smcpowers 	crypto_nostore_generate_key_pair_t obj_nkp;
11404219Smcpowers 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
11414219Smcpowers 	CK_ATTRIBUTE_PTR priTemplate = NULL;
11424219Smcpowers 	CK_RV rv = CKR_OK;
11434219Smcpowers 	CK_BBOOL is_token_obj1 = FALSE;
11444219Smcpowers 	CK_BBOOL is_token_obj2 = FALSE;
11454219Smcpowers 	uint_t pub_attr_count, pri_attr_count;
11464219Smcpowers 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
11475697Smcpowers 	char value[EC_MAX_VALUE_LEN];
11485697Smcpowers 	char point[EC_MAX_POINT_LEN];
11494219Smcpowers 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
11504219Smcpowers 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
11514219Smcpowers 	CK_ULONG key_type;
11524219Smcpowers 	boolean_t has_class, has_key_type;
11534219Smcpowers 	int n, r;
11544219Smcpowers 
11554219Smcpowers 	obj_nkp.nkp_in_public_count = 0;
11564219Smcpowers 	obj_nkp.nkp_out_public_count = 0;
11574219Smcpowers 	obj_nkp.nkp_in_private_count = 0;
11584219Smcpowers 	obj_nkp.nkp_out_private_count = 0;
11594219Smcpowers 
11604219Smcpowers 	/*
11614219Smcpowers 	 * Add CKA_EC_POINT to the public template.
11624219Smcpowers 	 * This is the generated value Q. This attribute
11634219Smcpowers 	 * must not be in the template.
11644219Smcpowers 	 */
11654219Smcpowers 	if (attribute_in_template(CKA_EC_POINT, pPublicKeyTemplate,
11664219Smcpowers 	    ulPublicKeyAttributeCount)) {
11674219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
11684219Smcpowers 		goto failed_exit;
11694219Smcpowers 	}
11704219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
11714219Smcpowers 	    ulPublicKeyAttributeCount);
11724219Smcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
11734219Smcpowers 	    ulPublicKeyAttributeCount);
11744219Smcpowers 
11754219Smcpowers 	pub_attr_count = ulPublicKeyAttributeCount + 1;
11764219Smcpowers 	if (!has_class)
11774219Smcpowers 		pub_attr_count++;
11784219Smcpowers 	if (!has_key_type)
11794219Smcpowers 		pub_attr_count++;
11804219Smcpowers 	pubTemplate = grow_template(pPublicKeyTemplate,
11814219Smcpowers 	    ulPublicKeyAttributeCount, pub_attr_count);
11824219Smcpowers 	if (pubTemplate == NULL) {
11834219Smcpowers 		rv = CKR_HOST_MEMORY;
11844219Smcpowers 		goto failed_exit;
11854219Smcpowers 	}
11864219Smcpowers 
11874219Smcpowers 	n = ulPublicKeyAttributeCount;
11884219Smcpowers 	if (!has_class) {
11894219Smcpowers 		pubTemplate[n].type = CKA_CLASS;
11904219Smcpowers 		pubTemplate[n].pValue = (caddr_t)&pub_class;
11914219Smcpowers 		pubTemplate[n].ulValueLen = sizeof (pub_class);
11924219Smcpowers 		n++;
11934219Smcpowers 	}
11944219Smcpowers 	if (!has_key_type) {
11954219Smcpowers 		pubTemplate[n].type = CKA_KEY_TYPE;
11964219Smcpowers 		key_type = CKK_EC;
11974219Smcpowers 		pubTemplate[n].pValue = (caddr_t)&key_type;
11984219Smcpowers 		pubTemplate[n].ulValueLen = sizeof (key_type);
11994219Smcpowers 		n++;
12004219Smcpowers 	}
12014219Smcpowers 	pubTemplate[n].type = CKA_EC_POINT;
12024219Smcpowers 	pubTemplate[n].pValue = (caddr_t)point;
12034219Smcpowers 	pubTemplate[n].ulValueLen = sizeof (point);
12044219Smcpowers 	pub_out_attr_count++;
12054219Smcpowers 
12064219Smcpowers 	rv = process_object_attributes(pubTemplate,
12074219Smcpowers 	    pub_attr_count - pub_out_attr_count,
12084219Smcpowers 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
12094219Smcpowers 	if (rv != CKR_OK) {
12104219Smcpowers 		goto failed_exit;
12114219Smcpowers 	}
12124219Smcpowers 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
12134219Smcpowers 
12144219Smcpowers 	rv = process_object_attributes(
12154219Smcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
12164219Smcpowers 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
12174219Smcpowers 	    &is_token_obj1);
12184219Smcpowers 	if (rv != CKR_OK) {
12194219Smcpowers 		goto failed_exit;
12204219Smcpowers 	}
12214219Smcpowers 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
12224219Smcpowers 
12234219Smcpowers 	/*
12244219Smcpowers 	 * Cannot create a token object with a READ-ONLY
12254219Smcpowers 	 * session.
12264219Smcpowers 	 */
12274219Smcpowers 	if (is_token_obj1 && session_p->ses_RO) {
12284219Smcpowers 		rv = CKR_SESSION_READ_ONLY;
12294219Smcpowers 		goto failed_exit;
12304219Smcpowers 	}
12314219Smcpowers 
12324219Smcpowers 	/*
12334219Smcpowers 	 * CKA_EC_PARAMS and CKA_VALUE must not appear in
12344219Smcpowers 	 * private template.
12354219Smcpowers 	 */
12364219Smcpowers 	if (attribute_in_template(CKA_EC_PARAMS, pPrivateKeyTemplate,
12374219Smcpowers 	    ulPrivateKeyAttributeCount) ||
12384219Smcpowers 	    attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
12394219Smcpowers 	    ulPrivateKeyAttributeCount)) {
12404219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
12414219Smcpowers 		goto failed_exit;
12424219Smcpowers 	}
12434219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
12444219Smcpowers 	    ulPrivateKeyAttributeCount);
12454219Smcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
12464219Smcpowers 	    ulPrivateKeyAttributeCount);
12474219Smcpowers 
12484219Smcpowers 	pri_attr_count = ulPrivateKeyAttributeCount + 1;
12494219Smcpowers 	if (!has_class)
12504219Smcpowers 		pri_attr_count++;
12514219Smcpowers 	if (!has_key_type)
12524219Smcpowers 		pri_attr_count++;
12534219Smcpowers 
12544219Smcpowers 	/* allocate space for CKA_EC_PARAMS */
12554219Smcpowers 	priTemplate = grow_template(pPrivateKeyTemplate,
12564219Smcpowers 	    ulPrivateKeyAttributeCount, pri_attr_count + 1);
12574219Smcpowers 	if (priTemplate == NULL) {
12584219Smcpowers 		rv = CKR_HOST_MEMORY;
12594219Smcpowers 		goto failed_exit;
12604219Smcpowers 	}
12614219Smcpowers 	n = ulPrivateKeyAttributeCount;
12624219Smcpowers 	if (!has_class) {
12634219Smcpowers 		priTemplate[n].type = CKA_CLASS;
12644219Smcpowers 		priTemplate[n].pValue = (caddr_t)&pri_class;
12654219Smcpowers 		priTemplate[n].ulValueLen = sizeof (pri_class);
12664219Smcpowers 		n++;
12674219Smcpowers 	}
12684219Smcpowers 	if (!has_key_type) {
12694219Smcpowers 		priTemplate[n].type = CKA_KEY_TYPE;
12704219Smcpowers 		key_type = CKK_EC;
12714219Smcpowers 		priTemplate[n].pValue = (caddr_t)&key_type;
12724219Smcpowers 		priTemplate[n].ulValueLen = sizeof (key_type);
12734219Smcpowers 		n++;
12744219Smcpowers 	}
12754219Smcpowers 	priTemplate[n].type = CKA_VALUE;
12764219Smcpowers 	priTemplate[n].pValue = (caddr_t)value;
12774219Smcpowers 	priTemplate[n].ulValueLen = sizeof (value);
12784219Smcpowers 	pri_out_attr_count++;
12794219Smcpowers 
12804219Smcpowers 	rv = process_object_attributes(priTemplate,
12814219Smcpowers 	    pri_attr_count - pri_out_attr_count,
12824219Smcpowers 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
12834219Smcpowers 	if (rv != CKR_OK) {
12844219Smcpowers 		goto failed_exit;
12854219Smcpowers 	}
12864219Smcpowers 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
12874219Smcpowers 
12884219Smcpowers 	rv = process_object_attributes(
12894219Smcpowers 	    &priTemplate[pri_attr_count - pri_out_attr_count],
12904219Smcpowers 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
12914219Smcpowers 	    &is_token_obj2);
12924219Smcpowers 	if (rv != CKR_OK) {
12934219Smcpowers 		goto failed_exit;
12944219Smcpowers 	}
12954219Smcpowers 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
12964219Smcpowers 
12974219Smcpowers 	/*
12984219Smcpowers 	 * The public key and the private key need to contain the same
12994219Smcpowers 	 * attribute values for CKA_TOKEN.
13004219Smcpowers 	 */
13014219Smcpowers 	if (is_token_obj1 != is_token_obj2) {
13024219Smcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
13034219Smcpowers 		goto failed_exit;
13044219Smcpowers 	}
13054219Smcpowers 
13064219Smcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
13074219Smcpowers 	obj_nkp.nkp_session = session_p-> k_session;
13084219Smcpowers 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
13094219Smcpowers 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
13104219Smcpowers 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
13114219Smcpowers 
13124219Smcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
13134219Smcpowers 	    &obj_nkp)) < 0) {
13144219Smcpowers 		if (errno != EINTR)
13154219Smcpowers 			break;
13164219Smcpowers 	}
13174219Smcpowers 	if (r < 0) {
13184219Smcpowers 		rv = CKR_FUNCTION_FAILED;
13194219Smcpowers 	} else {
13204219Smcpowers 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
13214219Smcpowers 	}
13224219Smcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
13234219Smcpowers 	    &obj_nkp.nkp_in_public_count);
13244219Smcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
13254219Smcpowers 	    &obj_nkp.nkp_in_private_count);
13264219Smcpowers 
13274219Smcpowers 	if (rv != CKR_OK) {
13284219Smcpowers 		goto failed_exit;
13294219Smcpowers 	}
13304219Smcpowers 
13314219Smcpowers 	rv = get_object_attributes(
13324219Smcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
13334219Smcpowers 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
13344219Smcpowers 	if (rv == CRYPTO_SUCCESS) {
13354219Smcpowers 		rv = get_object_attributes(
13364219Smcpowers 		    &priTemplate[pri_attr_count - pri_out_attr_count],
13374219Smcpowers 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
13384219Smcpowers 	}
13394219Smcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
13404219Smcpowers 	    &obj_nkp.nkp_out_public_count);
13414219Smcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
13424219Smcpowers 	    &obj_nkp.nkp_out_private_count);
13434219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
13444219Smcpowers 		goto failed_exit;
13454219Smcpowers 	}
13464219Smcpowers 
13474219Smcpowers 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
13484219Smcpowers 	    session_p, KERNEL_GEN_KEY);
13494219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
13504219Smcpowers 		goto failed_exit;
13514219Smcpowers 	}
13524219Smcpowers 
13534219Smcpowers 	/*
13544219Smcpowers 	 * Copy CKA_EC_PARAMS from the public template to the
13554219Smcpowers 	 * private template.
13564219Smcpowers 	 */
13574219Smcpowers 	rv = copy_attribute(CKA_EC_PARAMS, pubTemplate, pub_attr_count,
13584219Smcpowers 	    &priTemplate[pri_attr_count]);
13594219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
13604219Smcpowers 		goto failed_exit;
13614219Smcpowers 	}
13624219Smcpowers 
13634219Smcpowers 	/* +1 to account for CKA_EC_PARAMS */
13644219Smcpowers 	rv = kernel_build_object(priTemplate, pri_attr_count + 1,
13654219Smcpowers 	    new_pri_objp, session_p, KERNEL_GEN_KEY);
13664219Smcpowers 	(void) free(priTemplate[pri_attr_count].pValue);
13674219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
13684219Smcpowers 		goto failed_exit;
13694219Smcpowers 	}
13704219Smcpowers 	(void) free(pubTemplate);
13714219Smcpowers 	(void) free(priTemplate);
13724219Smcpowers 
13734219Smcpowers 	new_pub_objp->is_lib_obj = B_TRUE;
13744219Smcpowers 	new_pri_objp->is_lib_obj = B_TRUE;
13754219Smcpowers 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
13764219Smcpowers 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
13774219Smcpowers 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
13784219Smcpowers 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
13794219Smcpowers 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
13804219Smcpowers 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
13814219Smcpowers 	return (CKR_OK);
13824219Smcpowers 
13834219Smcpowers failed_exit:
13844219Smcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
13854219Smcpowers 	    &obj_nkp.nkp_in_public_count);
13864219Smcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
13874219Smcpowers 	    &obj_nkp.nkp_out_public_count);
13884219Smcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
13894219Smcpowers 	    &obj_nkp.nkp_in_private_count);
13904219Smcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
13914219Smcpowers 	    &obj_nkp.nkp_out_private_count);
13924219Smcpowers 	if (pubTemplate != NULL) {
13934219Smcpowers 		(void) free(pubTemplate);
13944219Smcpowers 	}
13954219Smcpowers 	if (priTemplate != NULL) {
13964219Smcpowers 		(void) free(priTemplate);
13974219Smcpowers 	}
13984219Smcpowers 	return (rv);
13994219Smcpowers }
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate CK_RV
C_GenerateKeyPair(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pPublicKeyTemplate,CK_ULONG ulPublicKeyAttributeCount,CK_ATTRIBUTE_PTR pPrivateKeyTemplate,CK_ULONG ulPrivateKeyAttributeCount,CK_OBJECT_HANDLE_PTR phPublicKey,CK_OBJECT_HANDLE_PTR phPrivateKey)14020Sstevel@tonic-gate C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
14030Sstevel@tonic-gate     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
14040Sstevel@tonic-gate     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
14050Sstevel@tonic-gate     CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
14060Sstevel@tonic-gate {
14070Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
14080Sstevel@tonic-gate 	kernel_session_t	*session_p;
14090Sstevel@tonic-gate 	kernel_object_t		*new_pub_objp = NULL;
14100Sstevel@tonic-gate 	kernel_object_t		*new_pri_objp = NULL;
14110Sstevel@tonic-gate 	kernel_slot_t		*pslot;
14120Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
14130Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj1;
14140Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj2;
14150Sstevel@tonic-gate 	CK_BBOOL		is_token_obj1 = FALSE;
14160Sstevel@tonic-gate 	CK_BBOOL		is_token_obj2 = FALSE;
14170Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
14180Sstevel@tonic-gate 	int r;
14194219Smcpowers 	CK_RV (*func)(CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG,
14204219Smcpowers 	    CK_ATTRIBUTE_PTR, CK_ULONG, kernel_session_t *, crypto_mech_type_t,
14214219Smcpowers 	    kernel_object_t *, kernel_object_t *);
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	if (!kernel_initialized)
14240Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 	/* Obtain the session pointer. */
14270Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
14280Sstevel@tonic-gate 	if (rv != CKR_OK)
14290Sstevel@tonic-gate 		return (rv);
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	if ((pMechanism == NULL) || (phPublicKey == NULL) ||
14320Sstevel@tonic-gate 	    (phPrivateKey == NULL)) {
14330Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
14340Sstevel@tonic-gate 		goto failed_exit;
14350Sstevel@tonic-gate 	}
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate 	if ((pPublicKeyTemplate == NULL) && (ulPublicKeyAttributeCount != 0)) {
14380Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
14390Sstevel@tonic-gate 		goto failed_exit;
14400Sstevel@tonic-gate 	}
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 	if ((pPrivateKeyTemplate == NULL) &&
14430Sstevel@tonic-gate 	    (ulPrivateKeyAttributeCount != 0)) {
14440Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
14450Sstevel@tonic-gate 		goto failed_exit;
14460Sstevel@tonic-gate 	}
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
14490Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
14500Sstevel@tonic-gate 	if (rv != CKR_OK) {
14510Sstevel@tonic-gate 		goto failed_exit;
14520Sstevel@tonic-gate 	}
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 	/* Create an object wrapper for the public key */
14550Sstevel@tonic-gate 	new_pub_objp = calloc(1, sizeof (kernel_object_t));
14560Sstevel@tonic-gate 	if (new_pub_objp == NULL) {
14570Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
14580Sstevel@tonic-gate 		goto failed_exit;
14590Sstevel@tonic-gate 	}
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 	/* Create an object wrapper for the private key. */
14620Sstevel@tonic-gate 	new_pri_objp = calloc(1, sizeof (kernel_object_t));
14630Sstevel@tonic-gate 	if (new_pri_objp == NULL) {
14640Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
14650Sstevel@tonic-gate 		goto failed_exit;
14660Sstevel@tonic-gate 	}
14670Sstevel@tonic-gate 
14684219Smcpowers 	/*
14694219Smcpowers 	 * Special Case: if token does not support object creation,
14704219Smcpowers 	 * but does support key generation by value, then create a session
14714219Smcpowers 	 * object and initialize with values returned by token.
14724219Smcpowers 	 */
14734219Smcpowers 	pslot = slot_table[session_p->ses_slotid];
14744219Smcpowers 	if (!pslot->sl_func_list.fl_object_create) {
14754219Smcpowers 		switch (pMechanism->mechanism) {
14764219Smcpowers 		case CKM_RSA_PKCS_KEY_PAIR_GEN:
14774219Smcpowers 			func = key_gen_rsa_by_value;
14784219Smcpowers 			break;
14794219Smcpowers 
14804219Smcpowers 		case CKM_DH_PKCS_KEY_PAIR_GEN:
14814219Smcpowers 			func = key_gen_dh_by_value;
14824219Smcpowers 			break;
14834219Smcpowers 
14844219Smcpowers 		case CKM_EC_KEY_PAIR_GEN:
14854219Smcpowers 			func = key_gen_ec_by_value;
14864219Smcpowers 			break;
14870Sstevel@tonic-gate 
14884219Smcpowers 		default:
14894219Smcpowers 			rv = CKR_MECHANISM_INVALID;
14904219Smcpowers 			goto failed_exit;
14914219Smcpowers 		}
14924219Smcpowers 		rv = (*func)(pMechanism, pPublicKeyTemplate,
14934219Smcpowers 		    ulPublicKeyAttributeCount, pPrivateKeyTemplate,
14944219Smcpowers 		    ulPrivateKeyAttributeCount, session_p, k_mech_type,
14954219Smcpowers 		    new_pub_objp, new_pri_objp);
14964219Smcpowers 		if (rv != CKR_OK)
14974219Smcpowers 			goto failed_exit;
14984219Smcpowers 	} else {
14994219Smcpowers 		crypto_object_generate_key_pair_t obj_kp;
15004219Smcpowers 
15014219Smcpowers 		/* Process the public key attributes. */
15024219Smcpowers 		rv = process_object_attributes(pPublicKeyTemplate,
15034219Smcpowers 		    ulPublicKeyAttributeCount, &obj_kp.kp_public_attributes,
15044219Smcpowers 		    &is_token_obj1);
15054219Smcpowers 		if (rv != CKR_OK) {
15064219Smcpowers 			goto failed_exit;
15074219Smcpowers 		}
15080Sstevel@tonic-gate 
15094219Smcpowers 		/* Cannot create a token object with a READ-ONLY session. */
15104219Smcpowers 		if (is_token_obj1 && session_p->ses_RO) {
15114219Smcpowers 			free_object_attributes(obj_kp.kp_public_attributes,
15124219Smcpowers 			    ulPublicKeyAttributeCount);
15134219Smcpowers 			rv = CKR_SESSION_READ_ONLY;
15144219Smcpowers 			goto failed_exit;
15154219Smcpowers 		}
15164219Smcpowers 
15174219Smcpowers 		/* Process the private key attributes. */
15184219Smcpowers 		rv = process_object_attributes(pPrivateKeyTemplate,
15194219Smcpowers 		    ulPrivateKeyAttributeCount, &obj_kp.kp_private_attributes,
15204219Smcpowers 		    &is_token_obj2);
15214219Smcpowers 		if (rv != CKR_OK) {
15224219Smcpowers 			free_object_attributes(obj_kp.kp_public_attributes,
15234219Smcpowers 			    ulPublicKeyAttributeCount);
15244219Smcpowers 			goto failed_exit;
15254219Smcpowers 		}
15260Sstevel@tonic-gate 
15274219Smcpowers 		/*
15284219Smcpowers 		 * The public key and the private key need to contain the same
15294219Smcpowers 		 * attribute values for CKA_TOKEN.
15304219Smcpowers 		 */
15314219Smcpowers 		if (is_token_obj1 != is_token_obj2) {
15324219Smcpowers 			free_object_attributes(obj_kp.kp_public_attributes,
15334219Smcpowers 			    ulPublicKeyAttributeCount);
15344219Smcpowers 			free_object_attributes(obj_kp.kp_private_attributes,
15354219Smcpowers 			    ulPrivateKeyAttributeCount);
15364219Smcpowers 			rv = CKR_ATTRIBUTE_VALUE_INVALID;
15374219Smcpowers 			goto failed_exit;
15384219Smcpowers 		}
15394219Smcpowers 
15404219Smcpowers 		/* Call the CRYPTO_GENERATE_KEY_PAIR ioctl. */
15414219Smcpowers 		obj_kp.kp_session = session_p-> k_session;
15424219Smcpowers 		obj_kp.kp_mechanism.cm_type = k_mech_type;
15434219Smcpowers 		obj_kp.kp_mechanism.cm_param = pMechanism->pParameter;
15444219Smcpowers 		obj_kp.kp_mechanism.cm_param_len = pMechanism->ulParameterLen;
15454219Smcpowers 		obj_kp.kp_public_count = ulPublicKeyAttributeCount;
15464219Smcpowers 		obj_kp.kp_private_count = ulPrivateKeyAttributeCount;
15474219Smcpowers 
15484219Smcpowers 		while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY_PAIR,
15494219Smcpowers 		    &obj_kp)) < 0) {
15504219Smcpowers 			if (errno != EINTR)
15514219Smcpowers 				break;
15524219Smcpowers 		}
15534219Smcpowers 		if (r < 0) {
15544219Smcpowers 			rv = CKR_FUNCTION_FAILED;
15554219Smcpowers 		} else {
15564219Smcpowers 			rv = crypto2pkcs11_error_number(obj_kp.kp_return_value);
15574219Smcpowers 		}
15580Sstevel@tonic-gate 		free_object_attributes(obj_kp.kp_public_attributes,
15590Sstevel@tonic-gate 		    ulPublicKeyAttributeCount);
15600Sstevel@tonic-gate 		free_object_attributes(obj_kp.kp_private_attributes,
15610Sstevel@tonic-gate 		    ulPrivateKeyAttributeCount);
15624219Smcpowers 
15634219Smcpowers 		if (rv != CKR_OK)
15644219Smcpowers 			goto failed_exit;
15654219Smcpowers 
15664219Smcpowers 		/* Get the CKA_PRIVATE value for the key pair. */
15674219Smcpowers 		rv = get_cka_private_value(session_p, obj_kp.kp_public_handle,
15684219Smcpowers 		    &is_pri_obj1);
15694219Smcpowers 		if (rv != CKR_OK) {
15704219Smcpowers 			goto failed_exit;
15714219Smcpowers 		}
15720Sstevel@tonic-gate 
15734219Smcpowers 		rv = get_cka_private_value(session_p, obj_kp.kp_private_handle,
15744219Smcpowers 		    &is_pri_obj2);
15754219Smcpowers 		if (rv != CKR_OK) {
15764219Smcpowers 			goto failed_exit;
15774219Smcpowers 		}
15784219Smcpowers 
15794219Smcpowers 		/*
15804219Smcpowers 		 * Store the kernel public key handle into the public key
15814219Smcpowers 		 * object and finish the public key object initialization.
15824219Smcpowers 		 */
15834219Smcpowers 		new_pub_objp->is_lib_obj = B_FALSE;
15844219Smcpowers 		new_pub_objp->k_handle = obj_kp.kp_public_handle;
15854219Smcpowers 		new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
15864219Smcpowers 		new_pub_objp->extra_attrlistp = NULL;
15870Sstevel@tonic-gate 
15884219Smcpowers 		if (is_pri_obj1)
15894219Smcpowers 			new_pub_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
15904219Smcpowers 		else
15914219Smcpowers 			new_pub_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
15920Sstevel@tonic-gate 
15934219Smcpowers 		if (is_token_obj1)
15944219Smcpowers 			new_pub_objp->bool_attr_mask |= TOKEN_BOOL_ON;
15954219Smcpowers 		else
15964219Smcpowers 			new_pub_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
15974219Smcpowers 
15984219Smcpowers 		(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
15994219Smcpowers 		new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
16000Sstevel@tonic-gate 
16014219Smcpowers 		/*
16024219Smcpowers 		 * Store the kernel private key handle into the private key
16034219Smcpowers 		 * object and finish the private key object initialization.
16044219Smcpowers 		 */
16054219Smcpowers 		new_pri_objp->is_lib_obj = B_FALSE;
16064219Smcpowers 		new_pri_objp->k_handle = obj_kp.kp_private_handle;
16074219Smcpowers 		new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
16084219Smcpowers 		new_pri_objp->extra_attrlistp = NULL;
16090Sstevel@tonic-gate 
16104219Smcpowers 		if (is_pri_obj2)
16114219Smcpowers 			new_pri_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
16124219Smcpowers 		else
16134219Smcpowers 			new_pri_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
16140Sstevel@tonic-gate 
16154219Smcpowers 		if (is_token_obj2)
16164219Smcpowers 			new_pri_objp->bool_attr_mask |= TOKEN_BOOL_ON;
16174219Smcpowers 		else
16184219Smcpowers 			new_pri_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
16194219Smcpowers 
16200Sstevel@tonic-gate 	}
16210Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
16220Sstevel@tonic-gate 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 	/*
16250Sstevel@tonic-gate 	 * Add the new pub/pri objects to the slot's token list if they are
16260Sstevel@tonic-gate 	 * token objects. Otherwise, add them to the session's object list.
16270Sstevel@tonic-gate 	 */
16280Sstevel@tonic-gate 	if (is_token_obj1) { /* is_token_obj1 == is_token_obj2 */
16290Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
16300Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_pub_objp, pslot);
16310Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_pri_objp, pslot);
16320Sstevel@tonic-gate 	} else {
16330Sstevel@tonic-gate 		kernel_add_object_to_session(new_pub_objp, session_p);
16340Sstevel@tonic-gate 		kernel_add_object_to_session(new_pri_objp, session_p);
16350Sstevel@tonic-gate 	}
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 	*phPublicKey = (CK_OBJECT_HANDLE)new_pub_objp;
16380Sstevel@tonic-gate 	*phPrivateKey = (CK_OBJECT_HANDLE)new_pri_objp;
16390Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
16400Sstevel@tonic-gate 	return (rv);
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate failed_exit:
16430Sstevel@tonic-gate 	if (new_pub_objp != NULL) {
16440Sstevel@tonic-gate 		(void) free(new_pub_objp);
16450Sstevel@tonic-gate 	}
16460Sstevel@tonic-gate 	if (new_pri_objp != NULL) {
16470Sstevel@tonic-gate 		(void) free(new_pri_objp);
16480Sstevel@tonic-gate 	}
16490Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
16500Sstevel@tonic-gate 	return (rv);
16510Sstevel@tonic-gate }
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate CK_RV
C_WrapKey(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hWrappingKey,CK_OBJECT_HANDLE hKey,CK_BYTE_PTR pWrappedKey,CK_ULONG_PTR pulWrappedKeyLen)16550Sstevel@tonic-gate C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
16560Sstevel@tonic-gate     CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
16570Sstevel@tonic-gate     CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen)
16580Sstevel@tonic-gate {
16590Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
16600Sstevel@tonic-gate 	kernel_session_t	*session_p;
16610Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
16620Sstevel@tonic-gate 	kernel_object_t		*wrappingkey_p;
16630Sstevel@tonic-gate 	kernel_object_t		*key_p;
16640Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
16650Sstevel@tonic-gate 	crypto_object_wrap_key_t obj_wrapkey;
16660Sstevel@tonic-gate 	int r;
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 	if (!kernel_initialized)
16690Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate 	if (pulWrappedKeyLen == NULL || pMechanism == NULL) {
16720Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
16730Sstevel@tonic-gate 	}
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 	/*
16760Sstevel@tonic-gate 	 * Obtain the session pointer.  Also, increment the session
16770Sstevel@tonic-gate 	 * reference count.
16780Sstevel@tonic-gate 	 */
16790Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
16800Sstevel@tonic-gate 	if (rv != CKR_OK)
16810Sstevel@tonic-gate 		return (rv);
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
16840Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
16850Sstevel@tonic-gate 	if (rv != CKR_OK) {
16860Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
16870Sstevel@tonic-gate 		return (rv);
16880Sstevel@tonic-gate 	}
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 	/* Obtain the wrapping key object pointer. */
16910Sstevel@tonic-gate 	HANDLE2OBJECT(hWrappingKey, wrappingkey_p, rv);
16920Sstevel@tonic-gate 	if (rv != CKR_OK) {
16930Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
16940Sstevel@tonic-gate 		return (rv);
16950Sstevel@tonic-gate 	}
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 	/* Obtain the to_be_wrapped key object pointer. */
16980Sstevel@tonic-gate 	HANDLE2OBJECT(hKey, key_p, rv);
16990Sstevel@tonic-gate 	if (rv != CKR_OK) {
1700214Smcpowers 		OBJ_REFRELE(wrappingkey_p);
17010Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
17020Sstevel@tonic-gate 		return (rv);
17030Sstevel@tonic-gate 	}
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 	/* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */
17060Sstevel@tonic-gate 	obj_wrapkey.wk_session = session_p->k_session;
17070Sstevel@tonic-gate 	obj_wrapkey.wk_mechanism.cm_type = k_mech_type;
17080Sstevel@tonic-gate 	obj_wrapkey.wk_mechanism.cm_param = pMechanism->pParameter;
17090Sstevel@tonic-gate 	obj_wrapkey.wk_mechanism.cm_param_len = pMechanism->ulParameterLen;
17100Sstevel@tonic-gate 	obj_wrapkey.wk_wrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
17110Sstevel@tonic-gate 	obj_wrapkey.wk_wrapping_key.ck_obj_id = wrappingkey_p->k_handle;
17120Sstevel@tonic-gate 	obj_wrapkey.wk_object_handle = key_p->k_handle;
17130Sstevel@tonic-gate 	obj_wrapkey.wk_wrapped_key_len = *pulWrappedKeyLen;
17140Sstevel@tonic-gate 	obj_wrapkey.wk_wrapped_key = (char *)pWrappedKey;
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_WRAP_KEY, &obj_wrapkey)) < 0) {
17170Sstevel@tonic-gate 		if (errno != EINTR)
17180Sstevel@tonic-gate 			break;
17190Sstevel@tonic-gate 	}
17200Sstevel@tonic-gate 	if (r < 0) {
17210Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
17220Sstevel@tonic-gate 	} else {
17230Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(obj_wrapkey.wk_return_value);
17240Sstevel@tonic-gate 	}
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 	/*
17270Sstevel@tonic-gate 	 * Besides rv == CKR_OK, we will set the value of pulWrappedKeyLen
17280Sstevel@tonic-gate 	 * when the applciation-supplied wrapped key buffer is too small.
17290Sstevel@tonic-gate 	 * The situation that the application only asks for the length of
17300Sstevel@tonic-gate 	 * the wrapped key is covered in rv == CKR_OK.
17310Sstevel@tonic-gate 	 */
17320Sstevel@tonic-gate 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
17330Sstevel@tonic-gate 		*pulWrappedKeyLen = obj_wrapkey.wk_wrapped_key_len;
17340Sstevel@tonic-gate 	}
17350Sstevel@tonic-gate 
1736214Smcpowers 	OBJ_REFRELE(key_p);
1737214Smcpowers 	OBJ_REFRELE(wrappingkey_p);
17380Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
17390Sstevel@tonic-gate 	return (rv);
17400Sstevel@tonic-gate }
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 
17430Sstevel@tonic-gate CK_RV
C_UnwrapKey(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hUnwrappingKey,CK_BYTE_PTR pWrappedKey,CK_ULONG ulWrappedKeyLen,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,CK_OBJECT_HANDLE_PTR phKey)17440Sstevel@tonic-gate C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
17450Sstevel@tonic-gate     CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey,
17460Sstevel@tonic-gate     CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
17470Sstevel@tonic-gate     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
17480Sstevel@tonic-gate {
17490Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
17500Sstevel@tonic-gate 	kernel_session_t	*session_p;
17510Sstevel@tonic-gate 	kernel_object_t		*unwrappingkey_p;
17520Sstevel@tonic-gate 	kernel_object_t		*new_objp = NULL;
17530Sstevel@tonic-gate 	kernel_slot_t		*pslot;
17540Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
17550Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj;
17560Sstevel@tonic-gate 	CK_BBOOL		is_token_obj = FALSE;
17570Sstevel@tonic-gate 	CK_MECHANISM_INFO	info;
17580Sstevel@tonic-gate 	uint32_t		k_mi_flags;
17590Sstevel@tonic-gate 	CK_BYTE			*clear_key_val = NULL;
17600Sstevel@tonic-gate 	CK_ULONG 		ulDataLen;
17610Sstevel@tonic-gate 	CK_ATTRIBUTE_PTR	newTemplate = NULL;
17620Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
17630Sstevel@tonic-gate 	crypto_object_unwrap_key_t obj_unwrapkey;
17640Sstevel@tonic-gate 	int r;
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 	if (!kernel_initialized)
17670Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 	if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) {
17700Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
17710Sstevel@tonic-gate 	}
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate 	if ((pTemplate == NULL) && (ulAttributeCount != 0)) {
17740Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
17750Sstevel@tonic-gate 	}
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate 	/* Obtain the session pointer. */
17780Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
17790Sstevel@tonic-gate 	if (rv != CKR_OK)
17800Sstevel@tonic-gate 		return (rv);
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate 	/* Obtain the wrapping key object pointer. */
17830Sstevel@tonic-gate 	HANDLE2OBJECT(hUnwrappingKey, unwrappingkey_p, rv);
17840Sstevel@tonic-gate 	if (rv != CKR_OK) {
1785214Smcpowers 		REFRELE(session_p, ses_lock_held);
1786214Smcpowers 		return (rv);
17870Sstevel@tonic-gate 	}
17880Sstevel@tonic-gate 
17890Sstevel@tonic-gate 	/*
17900Sstevel@tonic-gate 	 * If the HW provider doesn't support C_UnwrapKey, we will try
17910Sstevel@tonic-gate 	 * to emulate it in the library.
17920Sstevel@tonic-gate 	 */
17930Sstevel@tonic-gate 	pslot = slot_table[session_p->ses_slotid];
17944219Smcpowers 	if ((!pslot->sl_func_list.fl_object_create) &&
17954219Smcpowers 	    (!pslot->sl_func_list.fl_key_unwrap)) {
17960Sstevel@tonic-gate 		rv = get_mechanism_info(pslot, pMechanism->mechanism, &info,
17970Sstevel@tonic-gate 		    &k_mi_flags);
17980Sstevel@tonic-gate 		if (rv != CKR_OK) {
17990Sstevel@tonic-gate 			goto failed_exit;
18000Sstevel@tonic-gate 		}
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate 		/*
18030Sstevel@tonic-gate 		 * If the mechanism flag doesn't have CKF_UNWRAP, and it's
18040Sstevel@tonic-gate 		 * an unwrapping of a secret key object, then help this
18050Sstevel@tonic-gate 		 * out with a decryption followed by an object creation.
18060Sstevel@tonic-gate 		 */
18070Sstevel@tonic-gate 		if (!(k_mi_flags & CRYPTO_FG_UNWRAP) &&
18080Sstevel@tonic-gate 		    (k_mi_flags & CRYPTO_FG_DECRYPT) &&
18090Sstevel@tonic-gate 		    (is_secret_key_template(pTemplate, ulAttributeCount))) {
18100Sstevel@tonic-gate 
18110Sstevel@tonic-gate 			/* First allocate space for the recovered key value */
18120Sstevel@tonic-gate 			clear_key_val = malloc(ulWrappedKeyLen);
18130Sstevel@tonic-gate 			if (clear_key_val == NULL) {
18140Sstevel@tonic-gate 				rv = CKR_HOST_MEMORY;
18150Sstevel@tonic-gate 				goto failed_exit;
18160Sstevel@tonic-gate 			}
18170Sstevel@tonic-gate 
18180Sstevel@tonic-gate 			rv = kernel_decrypt_init(session_p, unwrappingkey_p,
18190Sstevel@tonic-gate 			    pMechanism);
18200Sstevel@tonic-gate 			if (rv != CKR_OK) {
18210Sstevel@tonic-gate 				goto failed_exit;
18220Sstevel@tonic-gate 			}
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 			ulDataLen = ulWrappedKeyLen;
18250Sstevel@tonic-gate 			rv = kernel_decrypt(session_p, pWrappedKey,
18260Sstevel@tonic-gate 			    ulWrappedKeyLen, clear_key_val, &ulDataLen);
18270Sstevel@tonic-gate 			if (rv != CKR_OK) {
18280Sstevel@tonic-gate 				goto failed_exit;
18290Sstevel@tonic-gate 			}
18300Sstevel@tonic-gate 
18314219Smcpowers 			newTemplate = grow_template(pTemplate, ulAttributeCount,
18324219Smcpowers 			    ulAttributeCount + 1);
18330Sstevel@tonic-gate 			if (newTemplate == NULL) {
18340Sstevel@tonic-gate 				rv = CKR_HOST_MEMORY;
18350Sstevel@tonic-gate 				goto failed_exit;
18360Sstevel@tonic-gate 			}
18374219Smcpowers 			/* Now add the CKA_VALUE attribute to template */
18380Sstevel@tonic-gate 			newTemplate[ulAttributeCount].type = CKA_VALUE;
18390Sstevel@tonic-gate 			newTemplate[ulAttributeCount].pValue = clear_key_val;
18400Sstevel@tonic-gate 			newTemplate[ulAttributeCount].ulValueLen = ulDataLen;
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate 			/* Finally create the key, based on the new template */
18430Sstevel@tonic-gate 			rv = kernel_add_object(newTemplate,
18440Sstevel@tonic-gate 			    ulAttributeCount + 1, phKey, session_p);
18450Sstevel@tonic-gate 			(void) free(clear_key_val);
18460Sstevel@tonic-gate 			(void) free(newTemplate);
1847214Smcpowers 			OBJ_REFRELE(unwrappingkey_p);
18480Sstevel@tonic-gate 			REFRELE(session_p, ses_lock_held);
18490Sstevel@tonic-gate 			return (rv);
18500Sstevel@tonic-gate 		} else {
18510Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
18520Sstevel@tonic-gate 			goto failed_exit;
18530Sstevel@tonic-gate 		}
18540Sstevel@tonic-gate 	}
18550Sstevel@tonic-gate 
18560Sstevel@tonic-gate 	/*
18570Sstevel@tonic-gate 	 * If we come here, the HW provider must have registered the unwrapkey
18580Sstevel@tonic-gate 	 * entry.  Therefore, the unwrap key will be performed in the HW
18590Sstevel@tonic-gate 	 * provider.
18600Sstevel@tonic-gate 	 */
18610Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
18620Sstevel@tonic-gate 	if (rv != CKR_OK) {
18630Sstevel@tonic-gate 		goto failed_exit;
18640Sstevel@tonic-gate 	}
18650Sstevel@tonic-gate 
18660Sstevel@tonic-gate 	/* Create an object wrapper for the new key in the library first */
18670Sstevel@tonic-gate 	new_objp = calloc(1, sizeof (kernel_object_t));
18680Sstevel@tonic-gate 	if (new_objp == NULL) {
18690Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
18700Sstevel@tonic-gate 		goto failed_exit;
18710Sstevel@tonic-gate 	}
18720Sstevel@tonic-gate 
18730Sstevel@tonic-gate 	/* Process the attributes */
18740Sstevel@tonic-gate 	rv = process_object_attributes(pTemplate, ulAttributeCount,
18750Sstevel@tonic-gate 	    &obj_unwrapkey.uk_attributes, &is_token_obj);
18760Sstevel@tonic-gate 	if (rv != CKR_OK) {
18770Sstevel@tonic-gate 		goto failed_exit;
18780Sstevel@tonic-gate 	}
18790Sstevel@tonic-gate 
18800Sstevel@tonic-gate 	/* Cannot create a token object with a READ-ONLY session. */
18810Sstevel@tonic-gate 	if (is_token_obj && session_p->ses_RO) {
18820Sstevel@tonic-gate 		free_object_attributes(obj_unwrapkey.uk_attributes,
18830Sstevel@tonic-gate 		    ulAttributeCount);
18840Sstevel@tonic-gate 		rv = CKR_SESSION_READ_ONLY;
18850Sstevel@tonic-gate 		goto failed_exit;
18860Sstevel@tonic-gate 	}
18870Sstevel@tonic-gate 
18880Sstevel@tonic-gate 	/* Make the CRYPTO_UNWRAP_KEY ioctl call. */
18890Sstevel@tonic-gate 	obj_unwrapkey.uk_session = session_p->k_session;
18900Sstevel@tonic-gate 	obj_unwrapkey.uk_mechanism.cm_type = k_mech_type;
18910Sstevel@tonic-gate 	obj_unwrapkey.uk_mechanism.cm_param = pMechanism->pParameter;
18920Sstevel@tonic-gate 	obj_unwrapkey.uk_mechanism.cm_param_len = pMechanism->ulParameterLen;
18930Sstevel@tonic-gate 	obj_unwrapkey.uk_unwrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
18940Sstevel@tonic-gate 	obj_unwrapkey.uk_unwrapping_key.ck_obj_id = unwrappingkey_p->k_handle;
18950Sstevel@tonic-gate 	obj_unwrapkey.uk_wrapped_key = (char *)pWrappedKey;
18960Sstevel@tonic-gate 	obj_unwrapkey.uk_wrapped_key_len = ulWrappedKeyLen;
18970Sstevel@tonic-gate 	obj_unwrapkey.uk_count = ulAttributeCount;
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_UNWRAP_KEY, &obj_unwrapkey)) < 0) {
19000Sstevel@tonic-gate 		if (errno != EINTR)
19010Sstevel@tonic-gate 			break;
19020Sstevel@tonic-gate 	}
19030Sstevel@tonic-gate 	if (r < 0) {
19040Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
19050Sstevel@tonic-gate 	} else {
19060Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(obj_unwrapkey.uk_return_value);
19070Sstevel@tonic-gate 	}
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount);
19100Sstevel@tonic-gate 	if (rv != CKR_OK) {
19110Sstevel@tonic-gate 		goto failed_exit;
19120Sstevel@tonic-gate 	}
19130Sstevel@tonic-gate 
19140Sstevel@tonic-gate 	/* Get the CKA_PRIVATE value for the unwrapped key. */
19150Sstevel@tonic-gate 	rv = get_cka_private_value(session_p, obj_unwrapkey.uk_object_handle,
19160Sstevel@tonic-gate 	    &is_pri_obj);
19170Sstevel@tonic-gate 	if (rv != CKR_OK) {
19180Sstevel@tonic-gate 		goto failed_exit;
19190Sstevel@tonic-gate 	}
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate 	/*
19220Sstevel@tonic-gate 	 * Store the kernel object handle in the new key object wrapper and
19230Sstevel@tonic-gate 	 * initialize it.
19240Sstevel@tonic-gate 	 */
19250Sstevel@tonic-gate 	new_objp->k_handle = obj_unwrapkey.uk_object_handle;
19260Sstevel@tonic-gate 	new_objp->is_lib_obj = B_FALSE;
19270Sstevel@tonic-gate 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
19280Sstevel@tonic-gate 	new_objp->extra_attrlistp = NULL;
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate 	if (is_pri_obj)
19310Sstevel@tonic-gate 		new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
19320Sstevel@tonic-gate 	else
19330Sstevel@tonic-gate 		new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 	if (is_token_obj)
19360Sstevel@tonic-gate 		new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
19370Sstevel@tonic-gate 	else
19380Sstevel@tonic-gate 		new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
19390Sstevel@tonic-gate 
19400Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
19410Sstevel@tonic-gate 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 	/*
19440Sstevel@tonic-gate 	 * Add the new object to the slot's token object list if it is a
19450Sstevel@tonic-gate 	 * a token object. Otherwise, add it to the session's object list.
19460Sstevel@tonic-gate 	 */
19470Sstevel@tonic-gate 	if (is_token_obj) {
19480Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
19490Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_objp, pslot);
19500Sstevel@tonic-gate 	} else {
19510Sstevel@tonic-gate 		kernel_add_object_to_session(new_objp, session_p);
19520Sstevel@tonic-gate 	}
19530Sstevel@tonic-gate 
19540Sstevel@tonic-gate 	*phKey = (CK_OBJECT_HANDLE)new_objp;
1955214Smcpowers 	OBJ_REFRELE(unwrappingkey_p);
19560Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
19570Sstevel@tonic-gate 	return (rv);
19580Sstevel@tonic-gate 
19590Sstevel@tonic-gate failed_exit:
1960214Smcpowers 	OBJ_REFRELE(unwrappingkey_p);
19610Sstevel@tonic-gate 	if (new_objp != NULL)
19620Sstevel@tonic-gate 		(void) free(new_objp);
19630Sstevel@tonic-gate 
19640Sstevel@tonic-gate 	if (clear_key_val != NULL)
19650Sstevel@tonic-gate 		(void) free(clear_key_val);
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate 	if (newTemplate != NULL)
19680Sstevel@tonic-gate 		(void) free(newTemplate);
19690Sstevel@tonic-gate 
19700Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
19710Sstevel@tonic-gate 	return (rv);
19720Sstevel@tonic-gate }
19730Sstevel@tonic-gate 
19744219Smcpowers /*
19754219Smcpowers  * Get sufficient attributes from a base key to pass by value in a
19764219Smcpowers  * crypto_key structure. Storage for attributes is allocated.
19774219Smcpowers  * For EC public keys, it is CKA_EC_PARAMS and CKA_EC_POINT.
19784219Smcpowers  * For EC private keys, it is CKA_EC_PARAMS and CKA_VALUE.
19794219Smcpowers  */
19804219Smcpowers static int
get_base_key_attributes(kernel_object_t * base_key,crypto_key_t * key_by_value)19814219Smcpowers get_base_key_attributes(kernel_object_t *base_key, crypto_key_t *key_by_value)
19824219Smcpowers {
19834219Smcpowers 	CK_ATTRIBUTE tmp;
1984*10669SMark.Powers@Sun.COM 	crypto_object_attribute_t *attrs = NULL;
19854219Smcpowers 	biginteger_t *big;
1986*10669SMark.Powers@Sun.COM 	int i, count = 0, rv;
19874219Smcpowers 
19884219Smcpowers 	switch (base_key->key_type) {
19894219Smcpowers 	case CKK_EC:
1990*10669SMark.Powers@Sun.COM 		count = 2;
1991*10669SMark.Powers@Sun.COM 		attrs = malloc(count * sizeof (crypto_object_attribute_t));
19924219Smcpowers 		if (attrs == NULL) {
19934219Smcpowers 			rv = CKR_HOST_MEMORY;
19944219Smcpowers 			goto out;
19954219Smcpowers 		}
1996*10669SMark.Powers@Sun.COM 		bzero(attrs, count * sizeof (crypto_object_attribute_t));
19974219Smcpowers 
19984219Smcpowers 		(void) pthread_mutex_lock(&base_key->object_mutex);
19994219Smcpowers 
20004219Smcpowers 		if (!base_key->is_lib_obj) {
20014219Smcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
20024219Smcpowers 			goto out;
20034219Smcpowers 		}
20044219Smcpowers 
20054219Smcpowers 		if (base_key->class != CKO_PUBLIC_KEY &&
20064219Smcpowers 		    base_key->class != CKO_PRIVATE_KEY) {
20074219Smcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
20084219Smcpowers 			goto out;
20094219Smcpowers 		}
20104219Smcpowers 
20114219Smcpowers 		/*
20124219Smcpowers 		 * Both public and private EC keys should have
20134219Smcpowers 		 * a CKA_EC_PARAMS attribute.
20144219Smcpowers 		 */
20154219Smcpowers 		tmp.type = CKA_EC_PARAMS;
20164219Smcpowers 		tmp.pValue = NULL;
20174219Smcpowers 
20184219Smcpowers 		/* get size of attribute */
20194219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
20204219Smcpowers 		if (rv != CKR_OK) {
20214219Smcpowers 			goto out;
20224219Smcpowers 		}
20234219Smcpowers 
20244219Smcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
20254219Smcpowers 		if (tmp.pValue == NULL) {
20264219Smcpowers 			rv = CKR_HOST_MEMORY;
20274219Smcpowers 			goto out;
20284219Smcpowers 		}
20294219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
20304219Smcpowers 		if (rv != CKR_OK) {
2031*10669SMark.Powers@Sun.COM 			free(tmp.pValue);
20324219Smcpowers 			goto out;
20334219Smcpowers 		}
20344219Smcpowers 		attrs[0].oa_type = tmp.type;
20354219Smcpowers 		attrs[0].oa_value = tmp.pValue;
20364219Smcpowers 		attrs[0].oa_value_len = tmp.ulValueLen;
20374219Smcpowers 
20384219Smcpowers 		switch (base_key->class) {
20394219Smcpowers 		case CKO_PUBLIC_KEY:
20404219Smcpowers 			big = OBJ_PUB_EC_POINT(base_key);
20414219Smcpowers 			tmp.type = CKA_EC_POINT;
20424219Smcpowers 			break;
20434219Smcpowers 
20444219Smcpowers 		case CKO_PRIVATE_KEY:
20454219Smcpowers 			big = OBJ_PRI_EC_VALUE(base_key);
20464219Smcpowers 			tmp.type = CKA_VALUE;
20474219Smcpowers 			break;
20484219Smcpowers 
20494219Smcpowers 		default:
20504219Smcpowers 			rv = CKR_ATTRIBUTE_TYPE_INVALID;
20514219Smcpowers 			goto out;
20524219Smcpowers 		}
20534219Smcpowers 		tmp.ulValueLen = big->big_value_len;
20544219Smcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
20554219Smcpowers 		if (tmp.pValue == NULL) {
20564219Smcpowers 			rv = CKR_HOST_MEMORY;
20574219Smcpowers 			goto out;
20584219Smcpowers 		}
20594219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
20604219Smcpowers 		if (rv != CKR_OK) {
2061*10669SMark.Powers@Sun.COM 			free(tmp.pValue);
20624219Smcpowers 			goto out;
20634219Smcpowers 		}
20644219Smcpowers 		attrs[1].oa_type = tmp.type;
20654219Smcpowers 		attrs[1].oa_value = tmp.pValue;
20664219Smcpowers 		attrs[1].oa_value_len = tmp.ulValueLen;
20674219Smcpowers 		key_by_value->ck_attrs = attrs;
20684219Smcpowers 		key_by_value->ck_count = 2;
20694219Smcpowers 		break;
20704219Smcpowers 
20714219Smcpowers 	case CKK_DH:
2072*10669SMark.Powers@Sun.COM 		count = 3;
2073*10669SMark.Powers@Sun.COM 		attrs = malloc(count * sizeof (crypto_object_attribute_t));
20744219Smcpowers 		if (attrs == NULL) {
20754219Smcpowers 			rv = CKR_HOST_MEMORY;
20764219Smcpowers 			goto out;
20774219Smcpowers 		}
2078*10669SMark.Powers@Sun.COM 		bzero(attrs, count * sizeof (crypto_object_attribute_t));
20794219Smcpowers 
20804219Smcpowers 		(void) pthread_mutex_lock(&base_key->object_mutex);
20814219Smcpowers 
20824219Smcpowers 		if (!base_key->is_lib_obj) {
20834219Smcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
20844219Smcpowers 			goto out;
20854219Smcpowers 		}
20864219Smcpowers 
20874219Smcpowers 		if (base_key->class != CKO_PRIVATE_KEY) {
20884219Smcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
20894219Smcpowers 			goto out;
20904219Smcpowers 		}
20914219Smcpowers 		tmp.type = CKA_BASE;
20924219Smcpowers 		tmp.pValue = NULL;
20934219Smcpowers 
20944219Smcpowers 		/* get size of attribute */
20954219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
20964219Smcpowers 		if (rv != CKR_OK) {
20974219Smcpowers 			goto out;
20984219Smcpowers 		}
20994219Smcpowers 
21004219Smcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
21014219Smcpowers 		if (tmp.pValue == NULL) {
21024219Smcpowers 			rv = CKR_HOST_MEMORY;
21034219Smcpowers 			goto out;
21044219Smcpowers 		}
21054219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
21064219Smcpowers 		if (rv != CKR_OK) {
2107*10669SMark.Powers@Sun.COM 			free(tmp.pValue);
21084219Smcpowers 			goto out;
21094219Smcpowers 		}
21104219Smcpowers 		attrs[0].oa_type = tmp.type;
21114219Smcpowers 		attrs[0].oa_value = tmp.pValue;
21124219Smcpowers 		attrs[0].oa_value_len = tmp.ulValueLen;
21134219Smcpowers 
21144219Smcpowers 		tmp.type = CKA_PRIME;
21154219Smcpowers 		tmp.pValue = NULL;
21164219Smcpowers 
21174219Smcpowers 		/* get size of attribute */
21184219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
21194219Smcpowers 		if (rv != CKR_OK) {
21204219Smcpowers 			goto out;
21214219Smcpowers 		}
21224219Smcpowers 
21234219Smcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
21244219Smcpowers 		if (tmp.pValue == NULL) {
21254219Smcpowers 			rv = CKR_HOST_MEMORY;
21264219Smcpowers 			goto out;
21274219Smcpowers 		}
21284219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
21294219Smcpowers 		if (rv != CKR_OK) {
2130*10669SMark.Powers@Sun.COM 			free(tmp.pValue);
21314219Smcpowers 			goto out;
21324219Smcpowers 		}
21334219Smcpowers 		attrs[1].oa_type = tmp.type;
21344219Smcpowers 		attrs[1].oa_value = tmp.pValue;
21354219Smcpowers 		attrs[1].oa_value_len = tmp.ulValueLen;
21364219Smcpowers 
2137*10669SMark.Powers@Sun.COM 		big = OBJ_PRI_DH_VALUE(base_key);
21384219Smcpowers 		tmp.type = CKA_VALUE;
21394219Smcpowers 
21404219Smcpowers 		tmp.ulValueLen = big->big_value_len;
21414219Smcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
21424219Smcpowers 		if (tmp.pValue == NULL) {
21434219Smcpowers 			rv = CKR_HOST_MEMORY;
21444219Smcpowers 			goto out;
21454219Smcpowers 		}
21464219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
21474219Smcpowers 		if (rv != CKR_OK) {
2148*10669SMark.Powers@Sun.COM 			free(tmp.pValue);
21494219Smcpowers 			goto out;
21504219Smcpowers 		}
21514219Smcpowers 		attrs[2].oa_type = tmp.type;
21524219Smcpowers 		attrs[2].oa_value = tmp.pValue;
21534219Smcpowers 		attrs[2].oa_value_len = tmp.ulValueLen;
21544219Smcpowers 		key_by_value->ck_attrs = attrs;
21554219Smcpowers 		key_by_value->ck_count = 3;
21564219Smcpowers 		break;
21574219Smcpowers 
21584219Smcpowers 	default:
21594219Smcpowers 		rv = CKR_ATTRIBUTE_TYPE_INVALID;
21604219Smcpowers 		goto out;
21614219Smcpowers 	}
21624219Smcpowers 	(void) pthread_mutex_unlock(&base_key->object_mutex);
21634219Smcpowers 	return (CKR_OK);
21644219Smcpowers 
21654219Smcpowers out:
21664219Smcpowers 	(void) pthread_mutex_unlock(&base_key->object_mutex);
2167*10669SMark.Powers@Sun.COM 	if (attrs != NULL) {
2168*10669SMark.Powers@Sun.COM 		for (i = 0; i < count; i++) {
2169*10669SMark.Powers@Sun.COM 			if (attrs[i].oa_value != NULL)
2170*10669SMark.Powers@Sun.COM 				free(attrs[i].oa_value);
2171*10669SMark.Powers@Sun.COM 		}
2172*10669SMark.Powers@Sun.COM 		free(attrs);
2173*10669SMark.Powers@Sun.COM 	}
21744219Smcpowers 	return (rv);
21754219Smcpowers }
21764219Smcpowers 
21774219Smcpowers CK_RV
derive_key_by_value(CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,kernel_session_t * session_p,crypto_mech_type_t k_mech_type,kernel_object_t * basekey_p,kernel_object_t * new_objp)21784219Smcpowers derive_key_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
21794219Smcpowers     CK_ULONG ulAttributeCount, kernel_session_t *session_p,
21804219Smcpowers     crypto_mech_type_t k_mech_type, kernel_object_t *basekey_p,
21814219Smcpowers     kernel_object_t *new_objp)
21824219Smcpowers {
21834219Smcpowers 	crypto_nostore_derive_key_t obj_ndk;
21844219Smcpowers 	char *key_buf = NULL;
21854219Smcpowers 	CK_ATTRIBUTE_PTR newTemplate = NULL;
21864219Smcpowers 	CK_BBOOL is_token_obj = FALSE;
21874219Smcpowers 	CK_RV rv = CKR_OK;
21884219Smcpowers 	CK_ULONG secret_class = CKO_SECRET_KEY;
21894219Smcpowers 	ulong_t key_len = 0;
21904219Smcpowers 	uint_t attr_count = 0;
21914219Smcpowers 	boolean_t removed;
21924219Smcpowers 	boolean_t has_class;
21934219Smcpowers 	int r, n;
21944219Smcpowers 
21954219Smcpowers 	obj_ndk.ndk_in_count = 0;
21964219Smcpowers 	obj_ndk.ndk_out_count = 0;
21974219Smcpowers 	obj_ndk.ndk_base_key.ck_count = 0;
21984219Smcpowers 
21994219Smcpowers 	rv = get_key_len_from_template(pMechanism, pTemplate, ulAttributeCount,
22004219Smcpowers 	    basekey_p, &key_len);
22014219Smcpowers 	if (rv != CKR_OK) {
22024219Smcpowers 		goto failed_exit;
22034219Smcpowers 	}
22044219Smcpowers 
22054219Smcpowers 	if ((key_buf = malloc(key_len)) == NULL) {
22064219Smcpowers 		rv = CKR_HOST_MEMORY;
22074219Smcpowers 		goto failed_exit;
22084219Smcpowers 	}
22094219Smcpowers 
22104219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pTemplate,
22114219Smcpowers 	    ulAttributeCount);
22124219Smcpowers 
22134219Smcpowers 	attr_count = ulAttributeCount + 1;
22144219Smcpowers 	if (!has_class)
22154219Smcpowers 		attr_count++;
22164219Smcpowers 
22174219Smcpowers 	newTemplate = grow_template(pTemplate, ulAttributeCount, attr_count);
22184219Smcpowers 	if (newTemplate == NULL) {
22194219Smcpowers 		rv = CKR_HOST_MEMORY;
22204219Smcpowers 		goto failed_exit;
22214219Smcpowers 	}
22224219Smcpowers 
22234219Smcpowers 	n = ulAttributeCount;
22244219Smcpowers 	if (!has_class) {
22254219Smcpowers 		newTemplate[n].type = CKA_CLASS;
22264219Smcpowers 		newTemplate[n].pValue = (caddr_t)&secret_class;
22274219Smcpowers 		newTemplate[n].ulValueLen = sizeof (secret_class);
22284219Smcpowers 		n++;
22294219Smcpowers 	}
22304219Smcpowers 
22314219Smcpowers 	/* Add CKA_VALUE to the template */
22324219Smcpowers 	newTemplate[n].type = CKA_VALUE;
22334219Smcpowers 	newTemplate[n].pValue = (caddr_t)key_buf;
22344219Smcpowers 	newTemplate[n].ulValueLen = key_len;
22354219Smcpowers 
22364219Smcpowers 	rv = process_object_attributes(newTemplate, attr_count - 1,
22374219Smcpowers 	    &obj_ndk.ndk_in_attributes, &is_token_obj);
22384219Smcpowers 	if (rv != CKR_OK) {
22394219Smcpowers 		goto failed_exit;
22404219Smcpowers 	}
2241*10669SMark.Powers@Sun.COM 	obj_ndk.ndk_in_count = attr_count - 1;
22424219Smcpowers 
22434219Smcpowers 	rv = process_object_attributes(&newTemplate[attr_count - 1],
22444219Smcpowers 	    1, &obj_ndk.ndk_out_attributes, &is_token_obj);
22454219Smcpowers 	if (rv != CKR_OK) {
22464219Smcpowers 		goto failed_exit;
22474219Smcpowers 	}
2248*10669SMark.Powers@Sun.COM 	obj_ndk.ndk_out_count = 1;
22494219Smcpowers 
22504219Smcpowers 	/* Cannot create a token object with a READ-ONLY session. */
22514219Smcpowers 	if (is_token_obj && session_p->ses_RO) {
22524219Smcpowers 		rv = CKR_SESSION_READ_ONLY;
22534219Smcpowers 		goto failed_exit;
22544219Smcpowers 	}
22554219Smcpowers 
22564219Smcpowers 	obj_ndk.ndk_session = session_p->k_session;
22574219Smcpowers 	obj_ndk.ndk_mechanism.cm_type = k_mech_type;
22584219Smcpowers 	obj_ndk.ndk_mechanism.cm_param = pMechanism->pParameter;
22594219Smcpowers 	obj_ndk.ndk_mechanism.cm_param_len = pMechanism->ulParameterLen;
22604219Smcpowers 
22614219Smcpowers 	/*
22624219Smcpowers 	 * Obtain the attributes of base key and pass them by value.
22634219Smcpowers 	 */
22644219Smcpowers 	rv = get_base_key_attributes(basekey_p, &obj_ndk.ndk_base_key);
22654219Smcpowers 	if (rv != CKR_OK) {
22664219Smcpowers 		goto failed_exit;
22674219Smcpowers 	}
22684219Smcpowers 
22694219Smcpowers 	obj_ndk.ndk_base_key.ck_format = CRYPTO_KEY_ATTR_LIST;
22704219Smcpowers 
22714219Smcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_DERIVE_KEY,
22724219Smcpowers 	    &obj_ndk)) < 0) {
22734219Smcpowers 		if (errno != EINTR)
22744219Smcpowers 			break;
22754219Smcpowers 	}
22764219Smcpowers 	if (r < 0) {
22774219Smcpowers 		rv = CKR_FUNCTION_FAILED;
22784219Smcpowers 	} else {
22794219Smcpowers 		rv = crypto2pkcs11_error_number(obj_ndk.ndk_return_value);
22804219Smcpowers 	}
22814219Smcpowers 	free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
22824219Smcpowers 	free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
22834219Smcpowers 	    &obj_ndk.ndk_base_key.ck_count);
22844219Smcpowers 	if (rv != CKR_OK) {
22854219Smcpowers 		goto failed_exit;
22864219Smcpowers 	}
22874219Smcpowers 
22884219Smcpowers 	rv = get_object_attributes(&newTemplate[attr_count - 1],
22894219Smcpowers 	    1, obj_ndk.ndk_out_attributes);
22904219Smcpowers 	free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
22914219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
22924219Smcpowers 		goto failed_exit;
22934219Smcpowers 	}
22944219Smcpowers 
22954219Smcpowers 	removed = remove_one_attribute(newTemplate, CKA_VALUE_LEN,
22964219Smcpowers 	    attr_count, B_FALSE);
22974219Smcpowers 
22984219Smcpowers 	rv = kernel_build_object(newTemplate, removed ? attr_count - 1 :
22994219Smcpowers 	    attr_count, new_objp, session_p, KERNEL_GEN_KEY);
23004219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
23014219Smcpowers 		goto failed_exit;
23024219Smcpowers 	}
23034219Smcpowers 
23044219Smcpowers 	free(key_buf);
23054219Smcpowers 	free(newTemplate);
23064219Smcpowers 	new_objp->is_lib_obj = B_TRUE;
23074219Smcpowers 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
23084219Smcpowers 	return (CKR_OK);
23094219Smcpowers 
23104219Smcpowers failed_exit:
23114219Smcpowers 	if (key_buf != NULL)
23124219Smcpowers 		free(key_buf);
23134219Smcpowers 	if (newTemplate != NULL)
23144219Smcpowers 		free(newTemplate);
23154219Smcpowers 	free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
23164219Smcpowers 	free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
23174219Smcpowers 	free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
23184219Smcpowers 	    &obj_ndk.ndk_base_key.ck_count);
23194219Smcpowers 	return (rv);
23204219Smcpowers }
23210Sstevel@tonic-gate 
23220Sstevel@tonic-gate CK_RV
C_DeriveKey(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hBaseKey,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,CK_OBJECT_HANDLE_PTR phKey)23230Sstevel@tonic-gate C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
23240Sstevel@tonic-gate     CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
23250Sstevel@tonic-gate     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
23260Sstevel@tonic-gate {
23270Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
23280Sstevel@tonic-gate 	kernel_session_t	*session_p;
23290Sstevel@tonic-gate 	kernel_object_t		*basekey_p;
23300Sstevel@tonic-gate 	kernel_object_t		*new_objp;
23310Sstevel@tonic-gate 	kernel_slot_t		*pslot;
23320Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
23330Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj;
23340Sstevel@tonic-gate 	CK_BBOOL		is_token_obj = FALSE;
23350Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
23360Sstevel@tonic-gate 	int r;
23370Sstevel@tonic-gate 
23380Sstevel@tonic-gate 	if (!kernel_initialized)
23390Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate 	/* Obtain the session pointer. */
23420Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
23430Sstevel@tonic-gate 	if (rv != CKR_OK)
23440Sstevel@tonic-gate 		return (rv);
23450Sstevel@tonic-gate 
2346872Sizick 	if (pMechanism == NULL) {
2347214Smcpowers 		REFRELE(session_p, ses_lock_held);
2348214Smcpowers 		return (CKR_ARGUMENTS_BAD);
23490Sstevel@tonic-gate 	}
23500Sstevel@tonic-gate 
23510Sstevel@tonic-gate 	if ((pTemplate == NULL && ulAttributeCount != 0) ||
23520Sstevel@tonic-gate 	    (pTemplate != NULL && ulAttributeCount == 0)) {
2353214Smcpowers 		REFRELE(session_p, ses_lock_held);
2354214Smcpowers 		return (CKR_ARGUMENTS_BAD);
23550Sstevel@tonic-gate 	}
23560Sstevel@tonic-gate 
23570Sstevel@tonic-gate 	/* Obtain the base key object pointer. */
23580Sstevel@tonic-gate 	HANDLE2OBJECT(hBaseKey, basekey_p, rv);
23590Sstevel@tonic-gate 	if (rv != CKR_OK) {
2360214Smcpowers 		REFRELE(session_p, ses_lock_held);
2361214Smcpowers 		return (rv);
23620Sstevel@tonic-gate 	}
23630Sstevel@tonic-gate 
23640Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
23650Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
23660Sstevel@tonic-gate 	if (rv != CKR_OK) {
23670Sstevel@tonic-gate 		goto failed_exit;
23680Sstevel@tonic-gate 	}
23690Sstevel@tonic-gate 
23700Sstevel@tonic-gate 	/* Create an object wrapper in the library for the generated key. */
23710Sstevel@tonic-gate 	new_objp = calloc(1, sizeof (kernel_object_t));
23720Sstevel@tonic-gate 	if (new_objp == NULL) {
23730Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
23740Sstevel@tonic-gate 		goto failed_exit;
23750Sstevel@tonic-gate 	}
23760Sstevel@tonic-gate 
23774219Smcpowers 	/*
23784219Smcpowers 	 * Special Case: if token does not support object creation,
23794219Smcpowers 	 * but does support key derivation by value, then create a session
23804219Smcpowers 	 * object and initialize with values returned by token.
23814219Smcpowers 	 */
23824219Smcpowers 	pslot = slot_table[session_p->ses_slotid];
23834219Smcpowers 	if (!pslot->sl_func_list.fl_object_create) {
23844219Smcpowers 		rv = derive_key_by_value(pMechanism, pTemplate,
23854219Smcpowers 		    ulAttributeCount, session_p, k_mech_type, basekey_p,
23864219Smcpowers 		    new_objp);
23874219Smcpowers 		if (rv != CKR_OK)
23884219Smcpowers 			goto failed_exit;
23894219Smcpowers 	} else {
23904219Smcpowers 		crypto_derive_key_t obj_dk;
23910Sstevel@tonic-gate 
23924219Smcpowers 		rv = process_object_attributes(pTemplate, ulAttributeCount,
23934219Smcpowers 		    &obj_dk.dk_attributes, &is_token_obj);
23944219Smcpowers 		if (rv != CKR_OK) {
23954219Smcpowers 			goto failed_exit;
23964219Smcpowers 		}
23974219Smcpowers 
23984219Smcpowers 		/* Cannot create a token object with a READ-ONLY session. */
23994219Smcpowers 		if (is_token_obj && session_p->ses_RO) {
24004219Smcpowers 			free_object_attributes(obj_dk.dk_attributes,
24014219Smcpowers 			    ulAttributeCount);
24024219Smcpowers 			rv = CKR_SESSION_READ_ONLY;
24034219Smcpowers 			goto failed_exit;
24044219Smcpowers 		}
24054219Smcpowers 
24064219Smcpowers 		obj_dk.dk_session = session_p->k_session;
24074219Smcpowers 		obj_dk.dk_mechanism.cm_type = k_mech_type;
24084219Smcpowers 		obj_dk.dk_mechanism.cm_param = pMechanism->pParameter;
24094219Smcpowers 		obj_dk.dk_mechanism.cm_param_len = pMechanism->ulParameterLen;
24104219Smcpowers 		obj_dk.dk_base_key.ck_format = CRYPTO_KEY_REFERENCE;
24114219Smcpowers 		obj_dk.dk_base_key.ck_obj_id = basekey_p->k_handle;
24124219Smcpowers 		obj_dk.dk_count = ulAttributeCount;
24130Sstevel@tonic-gate 
24144219Smcpowers 		while ((r = ioctl(kernel_fd, CRYPTO_DERIVE_KEY, &obj_dk)) < 0) {
24154219Smcpowers 			if (errno != EINTR)
24164219Smcpowers 				break;
24174219Smcpowers 		}
24184219Smcpowers 		if (r < 0) {
24194219Smcpowers 			rv = CKR_FUNCTION_FAILED;
24204219Smcpowers 		} else {
24214219Smcpowers 			rv = crypto2pkcs11_error_number(obj_dk.dk_return_value);
24224219Smcpowers 		}
24234219Smcpowers 
24244219Smcpowers 		free_object_attributes(obj_dk.dk_attributes, ulAttributeCount);
24254219Smcpowers 		if (rv != CKR_OK) {
24264219Smcpowers 			goto failed_exit;
24274219Smcpowers 		}
24280Sstevel@tonic-gate 
24294219Smcpowers 		/* Get the CKA_PRIVATE value for the derived key. */
24304219Smcpowers 		rv = get_cka_private_value(session_p, obj_dk.dk_object_handle,
24314219Smcpowers 		    &is_pri_obj);
24324219Smcpowers 		if (rv != CKR_OK) {
24334219Smcpowers 			goto failed_exit;
24344219Smcpowers 		}
24354219Smcpowers 
24364219Smcpowers 		/*
24374219Smcpowers 		 * Store the kernel object handle into the new derived key
24384219Smcpowers 		 * object and finish the object initialization.
24394219Smcpowers 		 */
24404219Smcpowers 		new_objp->is_lib_obj = B_FALSE;
24414219Smcpowers 		new_objp->k_handle = obj_dk.dk_object_handle;
24424219Smcpowers 		new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
24434219Smcpowers 		new_objp->extra_attrlistp = NULL;
24444219Smcpowers 
24454219Smcpowers 		if (is_pri_obj)
24464219Smcpowers 			new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
24474219Smcpowers 		else
24484219Smcpowers 			new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
24494219Smcpowers 
24504219Smcpowers 		if (is_token_obj)
24514219Smcpowers 			new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
24524219Smcpowers 		else
24534219Smcpowers 			new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
24540Sstevel@tonic-gate 	}
24550Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
24560Sstevel@tonic-gate 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
24570Sstevel@tonic-gate 
24580Sstevel@tonic-gate 	/*
24590Sstevel@tonic-gate 	 * Add the new derived object to the slot's token list if it is a
24600Sstevel@tonic-gate 	 * token object. Otherwise, add it to the session's object list.
24610Sstevel@tonic-gate 	 */
24620Sstevel@tonic-gate 	if (is_token_obj) {
24630Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
24640Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_objp, pslot);
24650Sstevel@tonic-gate 	} else {
24660Sstevel@tonic-gate 		kernel_add_object_to_session(new_objp, session_p);
24670Sstevel@tonic-gate 	}
24680Sstevel@tonic-gate 
24690Sstevel@tonic-gate 	*phKey = (CK_OBJECT_HANDLE)new_objp;
2470214Smcpowers 	OBJ_REFRELE(basekey_p);
24710Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
24720Sstevel@tonic-gate 	return (rv);
24730Sstevel@tonic-gate 
24740Sstevel@tonic-gate failed_exit:
2475214Smcpowers 	OBJ_REFRELE(basekey_p);
24760Sstevel@tonic-gate 	if (new_objp != NULL) {
24770Sstevel@tonic-gate 		(void) free(new_objp);
24780Sstevel@tonic-gate 	}
24790Sstevel@tonic-gate 
24800Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
24810Sstevel@tonic-gate 	return (rv);
24820Sstevel@tonic-gate }
2483