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
5*4219Smcpowers  * Common Development and Distribution License (the "License").
6*4219Smcpowers  * 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*4219Smcpowers  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <strings.h>
290Sstevel@tonic-gate #include <errno.h>
300Sstevel@tonic-gate #include <security/cryptoki.h>
310Sstevel@tonic-gate #include <sys/crypto/ioctl.h>
320Sstevel@tonic-gate #include "kernelGlobal.h"
330Sstevel@tonic-gate #include "kernelSession.h"
340Sstevel@tonic-gate #include "kernelObject.h"
350Sstevel@tonic-gate 
360Sstevel@tonic-gate static boolean_t
37*4219Smcpowers attribute_in_template(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
38*4219Smcpowers {
39*4219Smcpowers 	int i;
40*4219Smcpowers 
41*4219Smcpowers 	for (i = 0; i < cnt; i++) {
42*4219Smcpowers 		if (t[i].type == type)
43*4219Smcpowers 			return (B_TRUE);
44*4219Smcpowers 	}
45*4219Smcpowers 	return (B_FALSE);
46*4219Smcpowers }
47*4219Smcpowers 
48*4219Smcpowers /*
49*4219Smcpowers  * This routine returns modulus bytes rounded up to the nearest 8 byte
50*4219Smcpowers  * chunk. This is so we don't have to pass in max sized buffers for
51*4219Smcpowers  * returned attributes. Every unnecessary byte that we pass in results
52*4219Smcpowers  * in a kernel allocation.
53*4219Smcpowers  */
54*4219Smcpowers static ulong_t
55*4219Smcpowers get_modulus_bytes(CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
56*4219Smcpowers {
57*4219Smcpowers 	CK_ULONG modulus_len;
58*4219Smcpowers 	int i;
59*4219Smcpowers 
60*4219Smcpowers 	for (i = 0; i < cnt; i++) {
61*4219Smcpowers 		if (t[i].type == CKA_MODULUS_BITS) {
62*4219Smcpowers 			get_ulong_attr_from_template(&modulus_len, &t[i]);
63*4219Smcpowers 			/* convert from bit length to byte length */
64*4219Smcpowers 			modulus_len = (modulus_len - 1) / 64 + 1;
65*4219Smcpowers 			return (modulus_len * 8);
66*4219Smcpowers 		}
67*4219Smcpowers 	}
68*4219Smcpowers 	return (0);
69*4219Smcpowers }
70*4219Smcpowers 
71*4219Smcpowers /*
72*4219Smcpowers  * Remove specified attribute from array. Storage for the attribute's
73*4219Smcpowers  * value is freed if 'free_attr' is TRUE. Attributes are shifted so they are
74*4219Smcpowers  * contiguous within the array, i.e. the next attribute is shifted into
75*4219Smcpowers  * the position of the removed attribute. Returns TRUE if specified
76*4219Smcpowers  * attribute is removed.
77*4219Smcpowers  */
78*4219Smcpowers static boolean_t
79*4219Smcpowers remove_one_attribute(CK_ATTRIBUTE_PTR t, CK_ULONG type, uint_t count,
80*4219Smcpowers     boolean_t free_attr)
81*4219Smcpowers {
82*4219Smcpowers 	int i, j;
83*4219Smcpowers 
84*4219Smcpowers 	for (i = 0, j = 0; i < count; i++) {
85*4219Smcpowers 		if (t[i].type == type) {
86*4219Smcpowers 			if (free_attr) {
87*4219Smcpowers 				free(t[i].pValue);
88*4219Smcpowers 			}
89*4219Smcpowers 			continue;
90*4219Smcpowers 		}
91*4219Smcpowers 		if (i != j) {
92*4219Smcpowers 			t[j].type = t[i].type;
93*4219Smcpowers 			t[j].pValue = t[i].pValue;
94*4219Smcpowers 			t[j].ulValueLen = t[i].ulValueLen;
95*4219Smcpowers 		}
96*4219Smcpowers 		j++;
97*4219Smcpowers 	}
98*4219Smcpowers 	if (j == count)
99*4219Smcpowers 		return (B_FALSE);
100*4219Smcpowers 
101*4219Smcpowers 	/* safety */
102*4219Smcpowers 	t[j].pValue = NULL;
103*4219Smcpowers 	t[j].ulValueLen = 0;
104*4219Smcpowers 	return (B_TRUE);
105*4219Smcpowers }
106*4219Smcpowers 
107*4219Smcpowers static boolean_t
1080Sstevel@tonic-gate is_secret_key_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate 	int i;
1110Sstevel@tonic-gate 	for (i = 0; i < ulAttributeCount; i++) {
1120Sstevel@tonic-gate 		if (pTemplate[i].type == CKA_CLASS &&
1130Sstevel@tonic-gate 		    *(CK_OBJECT_CLASS *)(pTemplate[i].pValue) ==
1140Sstevel@tonic-gate 		    CKO_SECRET_KEY)
1150Sstevel@tonic-gate 			return (B_TRUE);
1160Sstevel@tonic-gate 	}
1170Sstevel@tonic-gate 	return (B_FALSE);
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate 
120*4219Smcpowers /*
121*4219Smcpowers  * Allocate a template with space for new_count entries and copy the
122*4219Smcpowers  * specified template into the new template.
123*4219Smcpowers  */
124*4219Smcpowers static CK_ATTRIBUTE_PTR
125*4219Smcpowers grow_template(CK_ATTRIBUTE_PTR old_template, CK_ULONG old_count,
126*4219Smcpowers     CK_ULONG new_count)
127*4219Smcpowers {
128*4219Smcpowers 	CK_ATTRIBUTE_PTR new_template;
129*4219Smcpowers 
130*4219Smcpowers 	new_template = malloc(new_count * sizeof (CK_ATTRIBUTE));
131*4219Smcpowers 	if (new_template != NULL)
132*4219Smcpowers 		bcopy(old_template, new_template,
133*4219Smcpowers 		    old_count * sizeof (CK_ATTRIBUTE));
134*4219Smcpowers 	return (new_template);
135*4219Smcpowers }
136*4219Smcpowers 
137*4219Smcpowers /*
138*4219Smcpowers  * For fixed length keys such as DES, return the length based on
139*4219Smcpowers  * the key type. For variable length keys such as AES, take the
140*4219Smcpowers  * length from the CKA_VALUE_LEN attribute.
141*4219Smcpowers  */
142*4219Smcpowers static int
143*4219Smcpowers get_key_len_from_template(CK_MECHANISM_PTR pMechanism,
144*4219Smcpowers     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
145*4219Smcpowers     kernel_object_t *basekey_p,  ulong_t *key_len)
146*4219Smcpowers {
147*4219Smcpowers 	boolean_t fixed_len_key = B_FALSE;
148*4219Smcpowers 	ulong_t key_type;
149*4219Smcpowers 	int i;
150*4219Smcpowers 
151*4219Smcpowers 	for (i = 0; i < ulAttributeCount; i++) {
152*4219Smcpowers 		if (pTemplate[i].type == CKA_KEY_TYPE) {
153*4219Smcpowers 			get_ulong_attr_from_template(&key_type, &pTemplate[i]);
154*4219Smcpowers 			break;
155*4219Smcpowers 		}
156*4219Smcpowers 	}
157*4219Smcpowers 	/* CKA_KEY_TYPE must be present */
158*4219Smcpowers 	if (i == ulAttributeCount)
159*4219Smcpowers 		return (CKR_TEMPLATE_INCOMPLETE);
160*4219Smcpowers 
161*4219Smcpowers 	switch (key_type) {
162*4219Smcpowers 	case CKK_DES:
163*4219Smcpowers 		*key_len = 8;
164*4219Smcpowers 		fixed_len_key = B_TRUE;
165*4219Smcpowers 		break;
166*4219Smcpowers 	case CKK_DES3:
167*4219Smcpowers 		*key_len = 24;
168*4219Smcpowers 		fixed_len_key = B_TRUE;
169*4219Smcpowers 		break;
170*4219Smcpowers 	case CKK_AES:
171*4219Smcpowers 	case CKK_BLOWFISH:
172*4219Smcpowers 		for (i = 0; i < ulAttributeCount; i++) {
173*4219Smcpowers 			if (pTemplate[i].type == CKA_VALUE_LEN) {
174*4219Smcpowers 				get_ulong_attr_from_template(key_len,
175*4219Smcpowers 				    &pTemplate[i]);
176*4219Smcpowers 				break;
177*4219Smcpowers 			}
178*4219Smcpowers 		}
179*4219Smcpowers 		/* CKA_VALUE_LEN must be present */
180*4219Smcpowers 		if (i == ulAttributeCount)
181*4219Smcpowers 			return (CKR_TEMPLATE_INCOMPLETE);
182*4219Smcpowers 		break;
183*4219Smcpowers 	case CKK_GENERIC_SECRET:
184*4219Smcpowers 		/*
185*4219Smcpowers 		 * The key will not be truncated, so we need to
186*4219Smcpowers 		 * get the max length for the mechanism.
187*4219Smcpowers 		 */
188*4219Smcpowers 		if (pMechanism->mechanism == CKM_DH_PKCS_DERIVE) {
189*4219Smcpowers 			CK_ATTRIBUTE tmp;
190*4219Smcpowers 
191*4219Smcpowers 			tmp.type = CKA_PRIME;
192*4219Smcpowers 			tmp.pValue = NULL;
193*4219Smcpowers 
194*4219Smcpowers 			/* get size of attribute */
195*4219Smcpowers 			if (kernel_get_attribute(basekey_p, &tmp) != CKR_OK) {
196*4219Smcpowers 				return (CKR_ARGUMENTS_BAD);
197*4219Smcpowers 			}
198*4219Smcpowers 			*key_len = tmp.ulValueLen;
199*4219Smcpowers 		} else {
200*4219Smcpowers 			return (CKR_ARGUMENTS_BAD);
201*4219Smcpowers 		}
202*4219Smcpowers 		break;
203*4219Smcpowers 	default:
204*4219Smcpowers 		return (CKR_ATTRIBUTE_VALUE_INVALID);
205*4219Smcpowers 	}
206*4219Smcpowers 
207*4219Smcpowers 	if (fixed_len_key && attribute_in_template(CKA_VALUE_LEN,
208*4219Smcpowers 	    pTemplate, ulAttributeCount))
209*4219Smcpowers 		return (CKR_TEMPLATE_INCONSISTENT);
210*4219Smcpowers 
211*4219Smcpowers 	return (CKR_OK);
212*4219Smcpowers }
213*4219Smcpowers 
214*4219Smcpowers /* find specified attribute src template and copy to dest */
215*4219Smcpowers static int
216*4219Smcpowers copy_attribute(CK_ULONG type, CK_ATTRIBUTE_PTR src, CK_ULONG src_cnt,
217*4219Smcpowers     CK_ATTRIBUTE_PTR dst)
218*4219Smcpowers {
219*4219Smcpowers 	int rv, i;
220*4219Smcpowers 
221*4219Smcpowers 	for (i = 0; i < src_cnt; i++) {
222*4219Smcpowers 		if (src[i].type == type) {
223*4219Smcpowers 			rv = get_string_from_template(dst, &src[i]);
224*4219Smcpowers 			break;
225*4219Smcpowers 		}
226*4219Smcpowers 	}
227*4219Smcpowers 	/*
228*4219Smcpowers 	 * The public template didn't have attribute.
229*4219Smcpowers 	 */
230*4219Smcpowers 	if (i == src_cnt) {
231*4219Smcpowers 		rv = CKR_TEMPLATE_INCOMPLETE;
232*4219Smcpowers 	}
233*4219Smcpowers 	return (rv);
234*4219Smcpowers }
235*4219Smcpowers 
236*4219Smcpowers static void
237*4219Smcpowers free_attributes(caddr_t p, uint_t *countp)
238*4219Smcpowers {
239*4219Smcpowers 	if (*countp > 0) {
240*4219Smcpowers 		free_object_attributes(p, *countp);
241*4219Smcpowers 		*countp = 0;
242*4219Smcpowers 	}
243*4219Smcpowers }
244*4219Smcpowers 
245*4219Smcpowers CK_RV
246*4219Smcpowers key_gen_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
247*4219Smcpowers     CK_ULONG ulCount, kernel_session_t *session_p,
248*4219Smcpowers     crypto_mech_type_t k_mech_type, kernel_object_t *new_objp)
249*4219Smcpowers {
250*4219Smcpowers 	crypto_nostore_generate_key_t obj_ngk;
251*4219Smcpowers 	char *key_buf = NULL;
252*4219Smcpowers 	CK_ATTRIBUTE_PTR newTemplate = NULL;
253*4219Smcpowers 	CK_BBOOL is_token_obj = FALSE;
254*4219Smcpowers 	CK_RV rv = CKR_OK;
255*4219Smcpowers 	ulong_t key_len = 0;
256*4219Smcpowers 	uint_t attr_count;
257*4219Smcpowers 	int r;
258*4219Smcpowers 
259*4219Smcpowers 	obj_ngk.ngk_in_count = 0;
260*4219Smcpowers 	obj_ngk.ngk_out_count = 0;
261*4219Smcpowers 
262*4219Smcpowers 	rv = get_key_len_from_template(pMechanism, pTemplate, ulCount,
263*4219Smcpowers 	    NULL, &key_len);
264*4219Smcpowers 	if (rv != CRYPTO_SUCCESS)
265*4219Smcpowers 		goto failed_exit;
266*4219Smcpowers 
267*4219Smcpowers 	if ((key_buf = malloc(key_len)) == NULL) {
268*4219Smcpowers 		rv = CKR_HOST_MEMORY;
269*4219Smcpowers 		goto failed_exit;
270*4219Smcpowers 	}
271*4219Smcpowers 
272*4219Smcpowers 	attr_count = ulCount + 1;
273*4219Smcpowers 	newTemplate = grow_template(pTemplate, ulCount, attr_count);
274*4219Smcpowers 	if (newTemplate == NULL) {
275*4219Smcpowers 		rv = CKR_HOST_MEMORY;
276*4219Smcpowers 		goto failed_exit;
277*4219Smcpowers 	}
278*4219Smcpowers 
279*4219Smcpowers 	/* Now add the CKA_VALUE attribute to template */
280*4219Smcpowers 	newTemplate[ulCount].type = CKA_VALUE;
281*4219Smcpowers 	newTemplate[ulCount].pValue = (caddr_t)key_buf;
282*4219Smcpowers 	newTemplate[ulCount].ulValueLen = key_len;
283*4219Smcpowers 
284*4219Smcpowers 	rv = process_object_attributes(newTemplate, attr_count - 1,
285*4219Smcpowers 	    &obj_ngk.ngk_in_attributes, &is_token_obj);
286*4219Smcpowers 	if (rv != CKR_OK) {
287*4219Smcpowers 		goto failed_exit;
288*4219Smcpowers 	}
289*4219Smcpowers 	rv = process_object_attributes(&newTemplate[ulCount],
290*4219Smcpowers 	    1, &obj_ngk.ngk_out_attributes, &is_token_obj);
291*4219Smcpowers 	if (rv != CKR_OK) {
292*4219Smcpowers 		goto failed_exit;
293*4219Smcpowers 	}
294*4219Smcpowers 
295*4219Smcpowers 	/* Cannot create a token object with a READ-ONLY session. */
296*4219Smcpowers 	if (is_token_obj && session_p->ses_RO) {
297*4219Smcpowers 		rv = CKR_SESSION_READ_ONLY;
298*4219Smcpowers 		goto failed_exit;
299*4219Smcpowers 	}
300*4219Smcpowers 
301*4219Smcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY ioctl */
302*4219Smcpowers 	obj_ngk.ngk_session = session_p->k_session;
303*4219Smcpowers 	obj_ngk.ngk_in_count = attr_count - 1;
304*4219Smcpowers 	obj_ngk.ngk_out_count = 1;
305*4219Smcpowers 	obj_ngk.ngk_mechanism.cm_type = k_mech_type;
306*4219Smcpowers 	obj_ngk.ngk_mechanism.cm_param = pMechanism->pParameter;
307*4219Smcpowers 	obj_ngk.ngk_mechanism.cm_param_len = pMechanism->ulParameterLen;
308*4219Smcpowers 
309*4219Smcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY,
310*4219Smcpowers 	    &obj_ngk)) < 0) {
311*4219Smcpowers 		if (errno != EINTR)
312*4219Smcpowers 			break;
313*4219Smcpowers 	}
314*4219Smcpowers 	if (r < 0) {
315*4219Smcpowers 		rv = CKR_FUNCTION_FAILED;
316*4219Smcpowers 	} else {
317*4219Smcpowers 		rv = crypto2pkcs11_error_number(obj_ngk.ngk_return_value);
318*4219Smcpowers 	}
319*4219Smcpowers 	free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
320*4219Smcpowers 	if (rv != CKR_OK) {
321*4219Smcpowers 		goto failed_exit;
322*4219Smcpowers 	}
323*4219Smcpowers 
324*4219Smcpowers 	rv = get_object_attributes(&newTemplate[ulCount], 1,
325*4219Smcpowers 	    obj_ngk.ngk_out_attributes);
326*4219Smcpowers 	free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
327*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
328*4219Smcpowers 		goto failed_exit;
329*4219Smcpowers 	}
330*4219Smcpowers 
331*4219Smcpowers 	/*
332*4219Smcpowers 	 * CKA_VALUE_LEN is not stored with the secret key object,
333*4219Smcpowers 	 * so we remove it by shifting attributes down one.
334*4219Smcpowers 	 */
335*4219Smcpowers 	(void) remove_one_attribute(newTemplate, CKA_VALUE_LEN,
336*4219Smcpowers 	    attr_count, B_FALSE);
337*4219Smcpowers 
338*4219Smcpowers 	rv = kernel_build_object(newTemplate, attr_count - 1,
339*4219Smcpowers 	    new_objp, session_p, KERNEL_GEN_KEY);
340*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
341*4219Smcpowers 		goto failed_exit;
342*4219Smcpowers 	}
343*4219Smcpowers 	new_objp->is_lib_obj = B_TRUE;
344*4219Smcpowers 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
345*4219Smcpowers 	(void) free(newTemplate);
346*4219Smcpowers 	bzero(key_buf, key_len);
347*4219Smcpowers 	(void) free(key_buf);
348*4219Smcpowers 	return (CKR_OK);
349*4219Smcpowers 
350*4219Smcpowers failed_exit:
351*4219Smcpowers 	free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
352*4219Smcpowers 	free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
353*4219Smcpowers 	if (key_buf != NULL) {
354*4219Smcpowers 		bzero(key_buf, key_len);
355*4219Smcpowers 		(void) free(key_buf);
356*4219Smcpowers 	}
357*4219Smcpowers 	if (newTemplate != NULL) {
358*4219Smcpowers 		(void) free(newTemplate);
359*4219Smcpowers 	}
360*4219Smcpowers 	return (rv);
361*4219Smcpowers }
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate CK_RV
3640Sstevel@tonic-gate C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
3650Sstevel@tonic-gate     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
3660Sstevel@tonic-gate {
3670Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
3680Sstevel@tonic-gate 	kernel_session_t	*session_p;
3690Sstevel@tonic-gate 	kernel_object_t		*new_objp = NULL;
3700Sstevel@tonic-gate 	kernel_slot_t		*pslot;
3710Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
3720Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj;
3730Sstevel@tonic-gate 	CK_BBOOL		is_token_obj = FALSE;
3740Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
3750Sstevel@tonic-gate 	int r;
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	if (!kernel_initialized)
3780Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	/* Obtain the session pointer */
3810Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
3820Sstevel@tonic-gate 	if (rv != CKR_OK)
3830Sstevel@tonic-gate 		return (rv);
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	if ((pMechanism == NULL) || (phKey == NULL)) {
3860Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
3870Sstevel@tonic-gate 		goto failed_exit;
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	if ((pTemplate == NULL) && (ulCount != 0)) {
3910Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
3920Sstevel@tonic-gate 		goto failed_exit;
3930Sstevel@tonic-gate 	}
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
3960Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
3970Sstevel@tonic-gate 	if (rv != CKR_OK) {
3980Sstevel@tonic-gate 		goto failed_exit;
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	/* Create an object wrapper in the library first */
4020Sstevel@tonic-gate 	new_objp = calloc(1, sizeof (kernel_object_t));
4030Sstevel@tonic-gate 	if (new_objp == NULL) {
4040Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
4050Sstevel@tonic-gate 		goto failed_exit;
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 
408*4219Smcpowers 	/*
409*4219Smcpowers 	 * Special Case: if token does not support object creation,
410*4219Smcpowers 	 * but does support key generation by value, then create a session
411*4219Smcpowers 	 * object and initialize with value returned by token.
412*4219Smcpowers 	 */
413*4219Smcpowers 	pslot = slot_table[session_p->ses_slotid];
414*4219Smcpowers 	if (!pslot->sl_func_list.fl_object_create) {
415*4219Smcpowers 		rv = key_gen_by_value(pMechanism, pTemplate, ulCount, session_p,
416*4219Smcpowers 		    k_mech_type, new_objp);
417*4219Smcpowers 		if (rv != CKR_OK)
418*4219Smcpowers 			goto failed_exit;
419*4219Smcpowers 	} else {
420*4219Smcpowers 		crypto_object_generate_key_t obj_gk;
4210Sstevel@tonic-gate 
422*4219Smcpowers 		/* Process the attributes */
423*4219Smcpowers 		rv = process_object_attributes(pTemplate, ulCount,
424*4219Smcpowers 		    &obj_gk.gk_attributes, &is_token_obj);
425*4219Smcpowers 		if (rv != CKR_OK) {
426*4219Smcpowers 			goto failed_exit;
427*4219Smcpowers 		}
428*4219Smcpowers 		/* Cannot create a token object with a READ-ONLY session. */
429*4219Smcpowers 		if (is_token_obj && session_p->ses_RO) {
430*4219Smcpowers 			free_object_attributes(obj_gk.gk_attributes, ulCount);
431*4219Smcpowers 			rv = CKR_SESSION_READ_ONLY;
432*4219Smcpowers 			goto failed_exit;
433*4219Smcpowers 		}
434*4219Smcpowers 
435*4219Smcpowers 		/* Call the CRYPTO_GENERATE_KEY ioctl */
436*4219Smcpowers 		obj_gk.gk_session = session_p->k_session;
437*4219Smcpowers 		obj_gk.gk_count = ulCount;
438*4219Smcpowers 		obj_gk.gk_mechanism.cm_type = k_mech_type;
439*4219Smcpowers 		obj_gk.gk_mechanism.cm_param = pMechanism->pParameter;
440*4219Smcpowers 		obj_gk.gk_mechanism.cm_param_len = pMechanism->ulParameterLen;
4410Sstevel@tonic-gate 
442*4219Smcpowers 		while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY,
443*4219Smcpowers 		    &obj_gk)) < 0) {
444*4219Smcpowers 			if (errno != EINTR)
445*4219Smcpowers 				break;
446*4219Smcpowers 		}
447*4219Smcpowers 		if (r < 0) {
448*4219Smcpowers 			rv = CKR_FUNCTION_FAILED;
449*4219Smcpowers 		} else {
450*4219Smcpowers 			rv = crypto2pkcs11_error_number(obj_gk.gk_return_value);
451*4219Smcpowers 		}
452*4219Smcpowers 
453*4219Smcpowers 		free_object_attributes(obj_gk.gk_attributes, ulCount);
454*4219Smcpowers 
455*4219Smcpowers 		if (rv != CKR_OK) {
456*4219Smcpowers 			goto failed_exit;
457*4219Smcpowers 		}
4580Sstevel@tonic-gate 
459*4219Smcpowers 		/* Get the value of the CKA_PRIVATE attribute. */
460*4219Smcpowers 		rv = get_cka_private_value(session_p, obj_gk.gk_handle,
461*4219Smcpowers 		    &is_pri_obj);
462*4219Smcpowers 		if (rv != CKR_OK) {
463*4219Smcpowers 			goto failed_exit;
464*4219Smcpowers 		}
465*4219Smcpowers 
466*4219Smcpowers 		/*
467*4219Smcpowers 		 * Store the kernel object handle in the object wrapper and
468*4219Smcpowers 		 * initialize the library object.
469*4219Smcpowers 		 */
470*4219Smcpowers 		new_objp->k_handle = obj_gk.gk_handle;
471*4219Smcpowers 		new_objp->is_lib_obj = B_FALSE;
472*4219Smcpowers 		new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
473*4219Smcpowers 		new_objp->extra_attrlistp = NULL;
474*4219Smcpowers 
475*4219Smcpowers 		if (is_pri_obj)
476*4219Smcpowers 			new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
477*4219Smcpowers 		else
478*4219Smcpowers 			new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
479*4219Smcpowers 
480*4219Smcpowers 		if (is_token_obj)
481*4219Smcpowers 			new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
482*4219Smcpowers 		else
483*4219Smcpowers 			new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
4840Sstevel@tonic-gate 	}
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
4870Sstevel@tonic-gate 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	/*
4900Sstevel@tonic-gate 	 * Add the new object to the slot's token object list if it is a
4910Sstevel@tonic-gate 	 * a token object. Otherwise, add it to the session's object list.
4920Sstevel@tonic-gate 	 */
4930Sstevel@tonic-gate 	if (is_token_obj) {
4940Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
4950Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_objp, pslot);
4960Sstevel@tonic-gate 	} else {
4970Sstevel@tonic-gate 		kernel_add_object_to_session(new_objp, session_p);
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	*phKey = (CK_OBJECT_HANDLE)new_objp;
5010Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
5020Sstevel@tonic-gate 	return (rv);
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate failed_exit:
5050Sstevel@tonic-gate 	if (new_objp != NULL) {
5060Sstevel@tonic-gate 		(void) free(new_objp);
5070Sstevel@tonic-gate 	}
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
5100Sstevel@tonic-gate 	return (rv);
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate 
513*4219Smcpowers CK_RV
514*4219Smcpowers key_gen_rsa_by_value(CK_MECHANISM_PTR pMechanism,
515*4219Smcpowers     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
516*4219Smcpowers     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
517*4219Smcpowers     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
518*4219Smcpowers     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
519*4219Smcpowers {
520*4219Smcpowers 	crypto_nostore_generate_key_pair_t obj_nkp;
521*4219Smcpowers 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
522*4219Smcpowers 	CK_ATTRIBUTE_PTR priTemplate = NULL;
523*4219Smcpowers 	CK_RV rv = CKR_OK;
524*4219Smcpowers 	CK_BBOOL is_token_obj1 = FALSE;
525*4219Smcpowers 	CK_BBOOL is_token_obj2 = FALSE;
526*4219Smcpowers 	uint_t pub_attr_count, pri_attr_count;
527*4219Smcpowers 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
528*4219Smcpowers 	char public_modulus[512];
529*4219Smcpowers 	char public_exponent[8];
530*4219Smcpowers 	char private_exponent[512];
531*4219Smcpowers 	char private_modulus[512];
532*4219Smcpowers 	char prime_1[512];
533*4219Smcpowers 	char prime_2[512];
534*4219Smcpowers 	char exponent_1[512];
535*4219Smcpowers 	char exponent_2[512];
536*4219Smcpowers 	char coefficient[512];
537*4219Smcpowers 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
538*4219Smcpowers 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
539*4219Smcpowers 	CK_ULONG key_type;
540*4219Smcpowers 	CK_ULONG modulus_bytes;
541*4219Smcpowers 	boolean_t has_class, has_key_type, has_pub_exponent;
542*4219Smcpowers 	int n, r;
543*4219Smcpowers 
544*4219Smcpowers 	obj_nkp.nkp_in_public_count = 0;
545*4219Smcpowers 	obj_nkp.nkp_out_public_count = 0;
546*4219Smcpowers 	obj_nkp.nkp_in_private_count = 0;
547*4219Smcpowers 	obj_nkp.nkp_out_private_count = 0;
548*4219Smcpowers 
549*4219Smcpowers 	/* modulus bits must be present when generating a RSA key pair */
550*4219Smcpowers 	if (!attribute_in_template(CKA_MODULUS_BITS, pPublicKeyTemplate,
551*4219Smcpowers 	    ulPublicKeyAttributeCount)) {
552*4219Smcpowers 		rv = CKR_TEMPLATE_INCOMPLETE;
553*4219Smcpowers 		goto failed_exit;
554*4219Smcpowers 	}
555*4219Smcpowers 
556*4219Smcpowers 	modulus_bytes = get_modulus_bytes(pPublicKeyTemplate,
557*4219Smcpowers 	    ulPublicKeyAttributeCount);
558*4219Smcpowers 
559*4219Smcpowers 	/*
560*4219Smcpowers 	 * Add CKA_MODULUS to the public template.
561*4219Smcpowers 	 * This attribute must not be in the template.
562*4219Smcpowers 	 */
563*4219Smcpowers 	if (attribute_in_template(CKA_MODULUS, pPublicKeyTemplate,
564*4219Smcpowers 	    ulPublicKeyAttributeCount)) {
565*4219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
566*4219Smcpowers 		goto failed_exit;
567*4219Smcpowers 	}
568*4219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
569*4219Smcpowers 	    ulPublicKeyAttributeCount);
570*4219Smcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
571*4219Smcpowers 	    ulPublicKeyAttributeCount);
572*4219Smcpowers 	has_pub_exponent = attribute_in_template(CKA_PUBLIC_EXPONENT,
573*4219Smcpowers 	    pPublicKeyTemplate, ulPublicKeyAttributeCount);
574*4219Smcpowers 
575*4219Smcpowers 	pub_attr_count = ulPublicKeyAttributeCount + 1;
576*4219Smcpowers 	if (!has_class)
577*4219Smcpowers 		pub_attr_count++;
578*4219Smcpowers 	if (!has_key_type)
579*4219Smcpowers 		pub_attr_count++;
580*4219Smcpowers 	if (!has_pub_exponent)
581*4219Smcpowers 		pub_attr_count++;
582*4219Smcpowers 	pubTemplate = grow_template(pPublicKeyTemplate,
583*4219Smcpowers 	    ulPublicKeyAttributeCount, pub_attr_count);
584*4219Smcpowers 	if (pubTemplate == NULL) {
585*4219Smcpowers 		rv = CKR_HOST_MEMORY;
586*4219Smcpowers 		goto failed_exit;
587*4219Smcpowers 	}
588*4219Smcpowers 
589*4219Smcpowers 	n = ulPublicKeyAttributeCount;
590*4219Smcpowers 	if (!has_class) {
591*4219Smcpowers 		pubTemplate[n].type = CKA_CLASS;
592*4219Smcpowers 		pubTemplate[n].pValue = (caddr_t)&pub_class;
593*4219Smcpowers 		pubTemplate[n].ulValueLen = sizeof (pub_class);
594*4219Smcpowers 		n++;
595*4219Smcpowers 	}
596*4219Smcpowers 	if (!has_key_type) {
597*4219Smcpowers 		pubTemplate[n].type = CKA_KEY_TYPE;
598*4219Smcpowers 		key_type = CKK_RSA;
599*4219Smcpowers 		pubTemplate[n].pValue = (caddr_t)&key_type;
600*4219Smcpowers 		pubTemplate[n].ulValueLen = sizeof (key_type);
601*4219Smcpowers 		n++;
602*4219Smcpowers 	}
603*4219Smcpowers 	if (!has_pub_exponent) {
604*4219Smcpowers 		pubTemplate[n].type = CKA_PUBLIC_EXPONENT;
605*4219Smcpowers 		pubTemplate[n].pValue = (caddr_t)public_exponent;
606*4219Smcpowers 		pubTemplate[n].ulValueLen = modulus_bytes;
607*4219Smcpowers 		n++;
608*4219Smcpowers 		pub_out_attr_count++;
609*4219Smcpowers 	}
610*4219Smcpowers 	pubTemplate[n].type = CKA_MODULUS;
611*4219Smcpowers 	pubTemplate[n].pValue = (caddr_t)public_modulus;
612*4219Smcpowers 	pubTemplate[n].ulValueLen = modulus_bytes;
613*4219Smcpowers 	pub_out_attr_count++;
614*4219Smcpowers 
615*4219Smcpowers 	rv = process_object_attributes(pubTemplate,
616*4219Smcpowers 	    pub_attr_count - pub_out_attr_count,
617*4219Smcpowers 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
618*4219Smcpowers 	if (rv != CKR_OK) {
619*4219Smcpowers 		goto failed_exit;
620*4219Smcpowers 	}
621*4219Smcpowers 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
622*4219Smcpowers 
623*4219Smcpowers 	rv = process_object_attributes(
624*4219Smcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
625*4219Smcpowers 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
626*4219Smcpowers 	    &is_token_obj1);
627*4219Smcpowers 	if (rv != CKR_OK) {
628*4219Smcpowers 		goto failed_exit;
629*4219Smcpowers 	}
630*4219Smcpowers 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
631*4219Smcpowers 
632*4219Smcpowers 	/*
633*4219Smcpowers 	 * Cannot create a token object with a READ-ONLY
634*4219Smcpowers 	 * session.
635*4219Smcpowers 	 */
636*4219Smcpowers 	if (is_token_obj1 && session_p->ses_RO) {
637*4219Smcpowers 		rv = CKR_SESSION_READ_ONLY;
638*4219Smcpowers 		goto failed_exit;
639*4219Smcpowers 	}
640*4219Smcpowers 
641*4219Smcpowers 	/*
642*4219Smcpowers 	 * Add CKA_MODULUS and CKA_PRIVATE_EXPONENT
643*4219Smcpowers 	 * to the private template. These attributes
644*4219Smcpowers 	 * must not be in the template.
645*4219Smcpowers 	 */
646*4219Smcpowers 	if (attribute_in_template(CKA_PRIVATE_EXPONENT,
647*4219Smcpowers 	    pPrivateKeyTemplate, ulPrivateKeyAttributeCount) ||
648*4219Smcpowers 	    attribute_in_template(CKA_MODULUS,
649*4219Smcpowers 	    pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) {
650*4219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
651*4219Smcpowers 		goto failed_exit;
652*4219Smcpowers 	}
653*4219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
654*4219Smcpowers 	    ulPrivateKeyAttributeCount);
655*4219Smcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
656*4219Smcpowers 	    ulPrivateKeyAttributeCount);
657*4219Smcpowers 
658*4219Smcpowers 	pri_attr_count = ulPrivateKeyAttributeCount + 7;
659*4219Smcpowers 	if (!has_class)
660*4219Smcpowers 		pri_attr_count++;
661*4219Smcpowers 	if (!has_key_type)
662*4219Smcpowers 		pri_attr_count++;
663*4219Smcpowers 
664*4219Smcpowers 	/* allocate space for CKA_PUBLIC_EXPONENT */
665*4219Smcpowers 	priTemplate = grow_template(pPrivateKeyTemplate,
666*4219Smcpowers 	    ulPrivateKeyAttributeCount, pri_attr_count + 1);
667*4219Smcpowers 	if (priTemplate == NULL) {
668*4219Smcpowers 		rv = CKR_HOST_MEMORY;
669*4219Smcpowers 		goto failed_exit;
670*4219Smcpowers 	}
671*4219Smcpowers 	n = ulPrivateKeyAttributeCount;
672*4219Smcpowers 	if (!has_class) {
673*4219Smcpowers 		priTemplate[n].type = CKA_CLASS;
674*4219Smcpowers 		priTemplate[n].pValue = (caddr_t)&pri_class;
675*4219Smcpowers 		priTemplate[n].ulValueLen = sizeof (pri_class);
676*4219Smcpowers 		n++;
677*4219Smcpowers 	}
678*4219Smcpowers 	if (!has_key_type) {
679*4219Smcpowers 		priTemplate[n].type = CKA_KEY_TYPE;
680*4219Smcpowers 		key_type = CKK_RSA;
681*4219Smcpowers 		priTemplate[n].pValue = (caddr_t)&key_type;
682*4219Smcpowers 		priTemplate[n].ulValueLen = sizeof (key_type);
683*4219Smcpowers 		n++;
684*4219Smcpowers 	}
685*4219Smcpowers 	priTemplate[n].type = CKA_MODULUS;
686*4219Smcpowers 	priTemplate[n].pValue = (caddr_t)private_modulus;
687*4219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes;
688*4219Smcpowers 	pri_out_attr_count++;
689*4219Smcpowers 
690*4219Smcpowers 	n++;
691*4219Smcpowers 	priTemplate[n].type = CKA_PRIVATE_EXPONENT;
692*4219Smcpowers 	priTemplate[n].pValue = (caddr_t)private_exponent;
693*4219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes;
694*4219Smcpowers 	pri_out_attr_count++;
695*4219Smcpowers 
696*4219Smcpowers 	n++;
697*4219Smcpowers 	priTemplate[n].type = CKA_PRIME_1;
698*4219Smcpowers 	priTemplate[n].pValue = (caddr_t)prime_1;
699*4219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
700*4219Smcpowers 	pri_out_attr_count++;
701*4219Smcpowers 
702*4219Smcpowers 	n++;
703*4219Smcpowers 	priTemplate[n].type = CKA_PRIME_2;
704*4219Smcpowers 	priTemplate[n].pValue = (caddr_t)prime_2;
705*4219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
706*4219Smcpowers 	pri_out_attr_count++;
707*4219Smcpowers 
708*4219Smcpowers 	n++;
709*4219Smcpowers 	priTemplate[n].type = CKA_EXPONENT_1;
710*4219Smcpowers 	priTemplate[n].pValue = (caddr_t)exponent_1;
711*4219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
712*4219Smcpowers 	pri_out_attr_count++;
713*4219Smcpowers 
714*4219Smcpowers 	n++;
715*4219Smcpowers 	priTemplate[n].type = CKA_EXPONENT_2;
716*4219Smcpowers 	priTemplate[n].pValue = (caddr_t)exponent_2;
717*4219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
718*4219Smcpowers 	pri_out_attr_count++;
719*4219Smcpowers 
720*4219Smcpowers 	n++;
721*4219Smcpowers 	priTemplate[n].type = CKA_COEFFICIENT;
722*4219Smcpowers 	priTemplate[n].pValue = (caddr_t)coefficient;
723*4219Smcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
724*4219Smcpowers 	pri_out_attr_count++;
725*4219Smcpowers 
726*4219Smcpowers 	rv = process_object_attributes(priTemplate,
727*4219Smcpowers 	    pri_attr_count - pri_out_attr_count,
728*4219Smcpowers 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
729*4219Smcpowers 	if (rv != CKR_OK) {
730*4219Smcpowers 		goto failed_exit;
731*4219Smcpowers 	}
732*4219Smcpowers 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
733*4219Smcpowers 
734*4219Smcpowers 	rv = process_object_attributes(
735*4219Smcpowers 	    &priTemplate[pri_attr_count - pri_out_attr_count],
736*4219Smcpowers 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
737*4219Smcpowers 	    &is_token_obj2);
738*4219Smcpowers 	if (rv != CKR_OK) {
739*4219Smcpowers 		goto failed_exit;
740*4219Smcpowers 	}
741*4219Smcpowers 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
742*4219Smcpowers 
743*4219Smcpowers 	/*
744*4219Smcpowers 	 * The public key and the private key need to contain the same
745*4219Smcpowers 	 * attribute values for CKA_TOKEN.
746*4219Smcpowers 	 */
747*4219Smcpowers 	if (is_token_obj1 != is_token_obj2) {
748*4219Smcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
749*4219Smcpowers 		goto failed_exit;
750*4219Smcpowers 	}
751*4219Smcpowers 
752*4219Smcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
753*4219Smcpowers 	obj_nkp.nkp_session = session_p-> k_session;
754*4219Smcpowers 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
755*4219Smcpowers 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
756*4219Smcpowers 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
757*4219Smcpowers 
758*4219Smcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
759*4219Smcpowers 	    &obj_nkp)) < 0) {
760*4219Smcpowers 		if (errno != EINTR)
761*4219Smcpowers 			break;
762*4219Smcpowers 	}
763*4219Smcpowers 	if (r < 0) {
764*4219Smcpowers 		rv = CKR_FUNCTION_FAILED;
765*4219Smcpowers 	} else {
766*4219Smcpowers 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
767*4219Smcpowers 	}
768*4219Smcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
769*4219Smcpowers 	    &obj_nkp.nkp_in_public_count);
770*4219Smcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
771*4219Smcpowers 	    &obj_nkp.nkp_in_private_count);
772*4219Smcpowers 
773*4219Smcpowers 	if (rv != CKR_OK) {
774*4219Smcpowers 		goto failed_exit;
775*4219Smcpowers 	}
776*4219Smcpowers 
777*4219Smcpowers 	rv = get_object_attributes(
778*4219Smcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
779*4219Smcpowers 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
780*4219Smcpowers 	if (rv == CRYPTO_SUCCESS) {
781*4219Smcpowers 		rv = get_object_attributes(
782*4219Smcpowers 		    &priTemplate[pri_attr_count - pri_out_attr_count],
783*4219Smcpowers 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
784*4219Smcpowers 	}
785*4219Smcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
786*4219Smcpowers 	    &obj_nkp.nkp_out_public_count);
787*4219Smcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
788*4219Smcpowers 	    &obj_nkp.nkp_out_private_count);
789*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
790*4219Smcpowers 		goto failed_exit;
791*4219Smcpowers 	}
792*4219Smcpowers 
793*4219Smcpowers 	/* store generated modulus and public exponent */
794*4219Smcpowers 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
795*4219Smcpowers 	    session_p, KERNEL_GEN_KEY);
796*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
797*4219Smcpowers 		goto failed_exit;
798*4219Smcpowers 	}
799*4219Smcpowers 
800*4219Smcpowers 	/*
801*4219Smcpowers 	 * Copy CKA_PUBLIC_EXPONENT from the public template
802*4219Smcpowers 	 * to the private template.
803*4219Smcpowers 	 */
804*4219Smcpowers 	rv = copy_attribute(CKA_PUBLIC_EXPONENT, pubTemplate,
805*4219Smcpowers 	    pub_attr_count, &priTemplate[pri_attr_count]);
806*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
807*4219Smcpowers 		goto failed_exit;
808*4219Smcpowers 	}
809*4219Smcpowers 
810*4219Smcpowers 	rv = kernel_build_object(priTemplate, pri_attr_count + 1, new_pri_objp,
811*4219Smcpowers 	    session_p, KERNEL_GEN_KEY);
812*4219Smcpowers 	(void) free(priTemplate[pri_attr_count].pValue);
813*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
814*4219Smcpowers 		goto failed_exit;
815*4219Smcpowers 	}
816*4219Smcpowers 	(void) free(pubTemplate);
817*4219Smcpowers 	(void) free(priTemplate);
818*4219Smcpowers 
819*4219Smcpowers 	new_pub_objp->is_lib_obj = B_TRUE;
820*4219Smcpowers 	new_pri_objp->is_lib_obj = B_TRUE;
821*4219Smcpowers 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
822*4219Smcpowers 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
823*4219Smcpowers 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
824*4219Smcpowers 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
825*4219Smcpowers 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
826*4219Smcpowers 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
827*4219Smcpowers 	return (CKR_OK);
828*4219Smcpowers 
829*4219Smcpowers failed_exit:
830*4219Smcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
831*4219Smcpowers 	    &obj_nkp.nkp_in_public_count);
832*4219Smcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
833*4219Smcpowers 	    &obj_nkp.nkp_out_public_count);
834*4219Smcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
835*4219Smcpowers 	    &obj_nkp.nkp_in_private_count);
836*4219Smcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
837*4219Smcpowers 	    &obj_nkp.nkp_out_private_count);
838*4219Smcpowers 	if (pubTemplate != NULL) {
839*4219Smcpowers 		(void) free(pubTemplate);
840*4219Smcpowers 	}
841*4219Smcpowers 	if (priTemplate != NULL) {
842*4219Smcpowers 		(void) free(priTemplate);
843*4219Smcpowers 	}
844*4219Smcpowers 	return (rv);
845*4219Smcpowers }
846*4219Smcpowers 
847*4219Smcpowers CK_RV
848*4219Smcpowers key_gen_dh_by_value(CK_MECHANISM_PTR pMechanism,
849*4219Smcpowers     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
850*4219Smcpowers     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
851*4219Smcpowers     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
852*4219Smcpowers     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
853*4219Smcpowers {
854*4219Smcpowers 	crypto_nostore_generate_key_pair_t obj_nkp;
855*4219Smcpowers 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
856*4219Smcpowers 	CK_ATTRIBUTE_PTR priTemplate = NULL;
857*4219Smcpowers 	CK_RV rv = CKR_OK;
858*4219Smcpowers 	CK_BBOOL is_token_obj1 = FALSE;
859*4219Smcpowers 	CK_BBOOL is_token_obj2 = FALSE;
860*4219Smcpowers 	uint_t pub_attr_count, pri_attr_count;
861*4219Smcpowers 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
862*4219Smcpowers 	char public_value[256];
863*4219Smcpowers 	char private_value[256];
864*4219Smcpowers 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
865*4219Smcpowers 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
866*4219Smcpowers 	CK_ULONG key_type;
867*4219Smcpowers 	boolean_t has_class, has_key_type;
868*4219Smcpowers 	int n, r;
869*4219Smcpowers 
870*4219Smcpowers 	obj_nkp.nkp_in_public_count = 0;
871*4219Smcpowers 	obj_nkp.nkp_out_public_count = 0;
872*4219Smcpowers 	obj_nkp.nkp_in_private_count = 0;
873*4219Smcpowers 	obj_nkp.nkp_out_private_count = 0;
874*4219Smcpowers 
875*4219Smcpowers 	/*
876*4219Smcpowers 	 * Add CKA_VALUE to the public template.
877*4219Smcpowers 	 * This attribute must not be in the template.
878*4219Smcpowers 	 */
879*4219Smcpowers 	if (attribute_in_template(CKA_VALUE, pPublicKeyTemplate,
880*4219Smcpowers 	    ulPublicKeyAttributeCount)) {
881*4219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
882*4219Smcpowers 		goto failed_exit;
883*4219Smcpowers 	}
884*4219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
885*4219Smcpowers 	    ulPublicKeyAttributeCount);
886*4219Smcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
887*4219Smcpowers 	    ulPublicKeyAttributeCount);
888*4219Smcpowers 
889*4219Smcpowers 	pub_attr_count = ulPublicKeyAttributeCount + 1;
890*4219Smcpowers 	if (!has_class)
891*4219Smcpowers 		pub_attr_count++;
892*4219Smcpowers 	if (!has_key_type)
893*4219Smcpowers 		pub_attr_count++;
894*4219Smcpowers 	pubTemplate = grow_template(pPublicKeyTemplate,
895*4219Smcpowers 	    ulPublicKeyAttributeCount, pub_attr_count);
896*4219Smcpowers 	if (pubTemplate == NULL) {
897*4219Smcpowers 		rv = CKR_HOST_MEMORY;
898*4219Smcpowers 		goto failed_exit;
899*4219Smcpowers 	}
900*4219Smcpowers 
901*4219Smcpowers 	n = ulPublicKeyAttributeCount;
902*4219Smcpowers 	if (!has_class) {
903*4219Smcpowers 		pubTemplate[n].type = CKA_CLASS;
904*4219Smcpowers 		pubTemplate[n].pValue = (caddr_t)&pub_class;
905*4219Smcpowers 		pubTemplate[n].ulValueLen = sizeof (pub_class);
906*4219Smcpowers 		n++;
907*4219Smcpowers 	}
908*4219Smcpowers 	if (!has_key_type) {
909*4219Smcpowers 		pubTemplate[n].type = CKA_KEY_TYPE;
910*4219Smcpowers 		key_type = CKK_DH;
911*4219Smcpowers 		pubTemplate[n].pValue = (caddr_t)&key_type;
912*4219Smcpowers 		pubTemplate[n].ulValueLen = sizeof (key_type);
913*4219Smcpowers 		n++;
914*4219Smcpowers 	}
915*4219Smcpowers 	pubTemplate[n].type = CKA_VALUE;
916*4219Smcpowers 	pubTemplate[n].pValue = (caddr_t)public_value;
917*4219Smcpowers 	pubTemplate[n].ulValueLen = sizeof (public_value);
918*4219Smcpowers 	pub_out_attr_count++;
919*4219Smcpowers 
920*4219Smcpowers 	rv = process_object_attributes(pubTemplate,
921*4219Smcpowers 	    pub_attr_count - pub_out_attr_count,
922*4219Smcpowers 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
923*4219Smcpowers 	if (rv != CKR_OK) {
924*4219Smcpowers 		goto failed_exit;
925*4219Smcpowers 	}
926*4219Smcpowers 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
927*4219Smcpowers 
928*4219Smcpowers 	rv = process_object_attributes(
929*4219Smcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
930*4219Smcpowers 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
931*4219Smcpowers 	    &is_token_obj1);
932*4219Smcpowers 	if (rv != CKR_OK) {
933*4219Smcpowers 		goto failed_exit;
934*4219Smcpowers 	}
935*4219Smcpowers 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
936*4219Smcpowers 
937*4219Smcpowers 	/*
938*4219Smcpowers 	 * Cannot create a token object with a READ-ONLY
939*4219Smcpowers 	 * session.
940*4219Smcpowers 	 */
941*4219Smcpowers 	if (is_token_obj1 && session_p->ses_RO) {
942*4219Smcpowers 		rv = CKR_SESSION_READ_ONLY;
943*4219Smcpowers 		goto failed_exit;
944*4219Smcpowers 	}
945*4219Smcpowers 
946*4219Smcpowers 	/*
947*4219Smcpowers 	 * CKA_BASE, CKA_PRIME, and CKA_VALUE must not appear
948*4219Smcpowers 	 * in private template.
949*4219Smcpowers 	 */
950*4219Smcpowers 	if (attribute_in_template(CKA_BASE, pPrivateKeyTemplate,
951*4219Smcpowers 	    ulPrivateKeyAttributeCount) ||
952*4219Smcpowers 	    attribute_in_template(CKA_PRIME, pPrivateKeyTemplate,
953*4219Smcpowers 	    ulPrivateKeyAttributeCount) ||
954*4219Smcpowers 	    attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
955*4219Smcpowers 	    ulPrivateKeyAttributeCount)) {
956*4219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
957*4219Smcpowers 		goto failed_exit;
958*4219Smcpowers 	}
959*4219Smcpowers 
960*4219Smcpowers 	if (attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
961*4219Smcpowers 	    ulPrivateKeyAttributeCount)) {
962*4219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
963*4219Smcpowers 		goto failed_exit;
964*4219Smcpowers 	}
965*4219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
966*4219Smcpowers 	    ulPrivateKeyAttributeCount);
967*4219Smcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
968*4219Smcpowers 	    ulPrivateKeyAttributeCount);
969*4219Smcpowers 
970*4219Smcpowers 	pri_attr_count = ulPrivateKeyAttributeCount + 1;
971*4219Smcpowers 	if (!has_class)
972*4219Smcpowers 		pri_attr_count++;
973*4219Smcpowers 	if (!has_key_type)
974*4219Smcpowers 		pri_attr_count++;
975*4219Smcpowers 
976*4219Smcpowers 	/* allocate space for CKA_BASE and CKA_PRIME */
977*4219Smcpowers 	priTemplate = grow_template(pPrivateKeyTemplate,
978*4219Smcpowers 	    ulPrivateKeyAttributeCount, pri_attr_count + 2);
979*4219Smcpowers 	if (priTemplate == NULL) {
980*4219Smcpowers 		rv = CKR_HOST_MEMORY;
981*4219Smcpowers 		goto failed_exit;
982*4219Smcpowers 	}
983*4219Smcpowers 	n = ulPrivateKeyAttributeCount;
984*4219Smcpowers 	if (!has_class) {
985*4219Smcpowers 		priTemplate[n].type = CKA_CLASS;
986*4219Smcpowers 		priTemplate[n].pValue = (caddr_t)&pri_class;
987*4219Smcpowers 		priTemplate[n].ulValueLen = sizeof (pri_class);
988*4219Smcpowers 		n++;
989*4219Smcpowers 	}
990*4219Smcpowers 	if (!has_key_type) {
991*4219Smcpowers 		priTemplate[n].type = CKA_KEY_TYPE;
992*4219Smcpowers 		key_type = CKK_DH;
993*4219Smcpowers 		priTemplate[n].pValue = (caddr_t)&key_type;
994*4219Smcpowers 		priTemplate[n].ulValueLen = sizeof (key_type);
995*4219Smcpowers 		n++;
996*4219Smcpowers 	}
997*4219Smcpowers 	priTemplate[n].type = CKA_VALUE;
998*4219Smcpowers 	priTemplate[n].pValue = (caddr_t)private_value;
999*4219Smcpowers 	priTemplate[n].ulValueLen = sizeof (private_value);
1000*4219Smcpowers 	pri_out_attr_count++;
1001*4219Smcpowers 
1002*4219Smcpowers 	rv = process_object_attributes(priTemplate,
1003*4219Smcpowers 	    pri_attr_count - pri_out_attr_count,
1004*4219Smcpowers 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
1005*4219Smcpowers 	if (rv != CKR_OK) {
1006*4219Smcpowers 		goto failed_exit;
1007*4219Smcpowers 	}
1008*4219Smcpowers 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
1009*4219Smcpowers 
1010*4219Smcpowers 	rv = process_object_attributes(
1011*4219Smcpowers 	    &priTemplate[pri_attr_count - pri_out_attr_count],
1012*4219Smcpowers 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
1013*4219Smcpowers 	    &is_token_obj2);
1014*4219Smcpowers 	if (rv != CKR_OK) {
1015*4219Smcpowers 		goto failed_exit;
1016*4219Smcpowers 	}
1017*4219Smcpowers 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
1018*4219Smcpowers 
1019*4219Smcpowers 	/*
1020*4219Smcpowers 	 * The public key and the private key need to contain the same
1021*4219Smcpowers 	 * attribute values for CKA_TOKEN.
1022*4219Smcpowers 	 */
1023*4219Smcpowers 	if (is_token_obj1 != is_token_obj2) {
1024*4219Smcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
1025*4219Smcpowers 		goto failed_exit;
1026*4219Smcpowers 	}
1027*4219Smcpowers 
1028*4219Smcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
1029*4219Smcpowers 	obj_nkp.nkp_session = session_p-> k_session;
1030*4219Smcpowers 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
1031*4219Smcpowers 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
1032*4219Smcpowers 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1033*4219Smcpowers 
1034*4219Smcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
1035*4219Smcpowers 	    &obj_nkp)) < 0) {
1036*4219Smcpowers 		if (errno != EINTR)
1037*4219Smcpowers 			break;
1038*4219Smcpowers 	}
1039*4219Smcpowers 	if (r < 0) {
1040*4219Smcpowers 		rv = CKR_FUNCTION_FAILED;
1041*4219Smcpowers 	} else {
1042*4219Smcpowers 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
1043*4219Smcpowers 	}
1044*4219Smcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
1045*4219Smcpowers 	    &obj_nkp.nkp_in_public_count);
1046*4219Smcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
1047*4219Smcpowers 	    &obj_nkp.nkp_in_private_count);
1048*4219Smcpowers 
1049*4219Smcpowers 	if (rv != CKR_OK) {
1050*4219Smcpowers 		goto failed_exit;
1051*4219Smcpowers 	}
1052*4219Smcpowers 
1053*4219Smcpowers 	rv = get_object_attributes(
1054*4219Smcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
1055*4219Smcpowers 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
1056*4219Smcpowers 	if (rv == CRYPTO_SUCCESS) {
1057*4219Smcpowers 		rv = get_object_attributes(
1058*4219Smcpowers 		    &priTemplate[pri_attr_count - pri_out_attr_count],
1059*4219Smcpowers 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
1060*4219Smcpowers 	}
1061*4219Smcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
1062*4219Smcpowers 	    &obj_nkp.nkp_out_public_count);
1063*4219Smcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
1064*4219Smcpowers 	    &obj_nkp.nkp_out_private_count);
1065*4219Smcpowers 
1066*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
1067*4219Smcpowers 		goto failed_exit;
1068*4219Smcpowers 	}
1069*4219Smcpowers 
1070*4219Smcpowers 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
1071*4219Smcpowers 	    session_p, KERNEL_GEN_KEY);
1072*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
1073*4219Smcpowers 		goto failed_exit;
1074*4219Smcpowers 	}
1075*4219Smcpowers 
1076*4219Smcpowers 	/*
1077*4219Smcpowers 	 * Copy CKA_BASE and CKA_PRIME from the public template
1078*4219Smcpowers 	 * to the private template.
1079*4219Smcpowers 	 */
1080*4219Smcpowers 	rv = copy_attribute(CKA_BASE, pubTemplate, pub_attr_count,
1081*4219Smcpowers 	    &priTemplate[pri_attr_count]);
1082*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
1083*4219Smcpowers 		goto failed_exit;
1084*4219Smcpowers 	}
1085*4219Smcpowers 	rv = copy_attribute(CKA_PRIME, pubTemplate, pub_attr_count,
1086*4219Smcpowers 	    &priTemplate[pri_attr_count + 1]);
1087*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
1088*4219Smcpowers 		(void) free(priTemplate[pri_attr_count].pValue);
1089*4219Smcpowers 		goto failed_exit;
1090*4219Smcpowers 	}
1091*4219Smcpowers 
1092*4219Smcpowers 	/* +2 to account for CKA_BASE and CKA_PRIME */
1093*4219Smcpowers 	rv = kernel_build_object(priTemplate, pri_attr_count + 2,
1094*4219Smcpowers 	    new_pri_objp, session_p, KERNEL_GEN_KEY);
1095*4219Smcpowers 	(void) free(priTemplate[pri_attr_count].pValue);
1096*4219Smcpowers 	(void) free(priTemplate[pri_attr_count + 1].pValue);
1097*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
1098*4219Smcpowers 		goto failed_exit;
1099*4219Smcpowers 	}
1100*4219Smcpowers 	(void) free(pubTemplate);
1101*4219Smcpowers 	(void) free(priTemplate);
1102*4219Smcpowers 
1103*4219Smcpowers 	new_pub_objp->is_lib_obj = B_TRUE;
1104*4219Smcpowers 	new_pri_objp->is_lib_obj = B_TRUE;
1105*4219Smcpowers 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1106*4219Smcpowers 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1107*4219Smcpowers 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1108*4219Smcpowers 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1109*4219Smcpowers 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1110*4219Smcpowers 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1111*4219Smcpowers 	return (CKR_OK);
1112*4219Smcpowers 
1113*4219Smcpowers failed_exit:
1114*4219Smcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
1115*4219Smcpowers 	    &obj_nkp.nkp_in_public_count);
1116*4219Smcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
1117*4219Smcpowers 	    &obj_nkp.nkp_out_public_count);
1118*4219Smcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
1119*4219Smcpowers 	    &obj_nkp.nkp_in_private_count);
1120*4219Smcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
1121*4219Smcpowers 	    &obj_nkp.nkp_out_private_count);
1122*4219Smcpowers 	if (pubTemplate != NULL) {
1123*4219Smcpowers 		(void) free(pubTemplate);
1124*4219Smcpowers 	}
1125*4219Smcpowers 	if (priTemplate != NULL) {
1126*4219Smcpowers 		(void) free(priTemplate);
1127*4219Smcpowers 	}
1128*4219Smcpowers 	return (rv);
1129*4219Smcpowers }
1130*4219Smcpowers 
1131*4219Smcpowers CK_RV
1132*4219Smcpowers key_gen_ec_by_value(CK_MECHANISM_PTR pMechanism,
1133*4219Smcpowers     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
1134*4219Smcpowers     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
1135*4219Smcpowers     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
1136*4219Smcpowers     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
1137*4219Smcpowers {
1138*4219Smcpowers 	crypto_nostore_generate_key_pair_t obj_nkp;
1139*4219Smcpowers 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
1140*4219Smcpowers 	CK_ATTRIBUTE_PTR priTemplate = NULL;
1141*4219Smcpowers 	CK_RV rv = CKR_OK;
1142*4219Smcpowers 	CK_BBOOL is_token_obj1 = FALSE;
1143*4219Smcpowers 	CK_BBOOL is_token_obj2 = FALSE;
1144*4219Smcpowers 	uint_t pub_attr_count, pri_attr_count;
1145*4219Smcpowers 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
1146*4219Smcpowers 	char value[32];
1147*4219Smcpowers 	char point[128];
1148*4219Smcpowers 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
1149*4219Smcpowers 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
1150*4219Smcpowers 	CK_ULONG key_type;
1151*4219Smcpowers 	boolean_t has_class, has_key_type;
1152*4219Smcpowers 	int n, r;
1153*4219Smcpowers 
1154*4219Smcpowers 	obj_nkp.nkp_in_public_count = 0;
1155*4219Smcpowers 	obj_nkp.nkp_out_public_count = 0;
1156*4219Smcpowers 	obj_nkp.nkp_in_private_count = 0;
1157*4219Smcpowers 	obj_nkp.nkp_out_private_count = 0;
1158*4219Smcpowers 
1159*4219Smcpowers 	/*
1160*4219Smcpowers 	 * Add CKA_EC_POINT to the public template.
1161*4219Smcpowers 	 * This is the generated value Q. This attribute
1162*4219Smcpowers 	 * must not be in the template.
1163*4219Smcpowers 	 */
1164*4219Smcpowers 	if (attribute_in_template(CKA_EC_POINT, pPublicKeyTemplate,
1165*4219Smcpowers 	    ulPublicKeyAttributeCount)) {
1166*4219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
1167*4219Smcpowers 		goto failed_exit;
1168*4219Smcpowers 	}
1169*4219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
1170*4219Smcpowers 	    ulPublicKeyAttributeCount);
1171*4219Smcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
1172*4219Smcpowers 	    ulPublicKeyAttributeCount);
1173*4219Smcpowers 
1174*4219Smcpowers 	pub_attr_count = ulPublicKeyAttributeCount + 1;
1175*4219Smcpowers 	if (!has_class)
1176*4219Smcpowers 		pub_attr_count++;
1177*4219Smcpowers 	if (!has_key_type)
1178*4219Smcpowers 		pub_attr_count++;
1179*4219Smcpowers 	pubTemplate = grow_template(pPublicKeyTemplate,
1180*4219Smcpowers 	    ulPublicKeyAttributeCount, pub_attr_count);
1181*4219Smcpowers 	if (pubTemplate == NULL) {
1182*4219Smcpowers 		rv = CKR_HOST_MEMORY;
1183*4219Smcpowers 		goto failed_exit;
1184*4219Smcpowers 	}
1185*4219Smcpowers 
1186*4219Smcpowers 	n = ulPublicKeyAttributeCount;
1187*4219Smcpowers 	if (!has_class) {
1188*4219Smcpowers 		pubTemplate[n].type = CKA_CLASS;
1189*4219Smcpowers 		pubTemplate[n].pValue = (caddr_t)&pub_class;
1190*4219Smcpowers 		pubTemplate[n].ulValueLen = sizeof (pub_class);
1191*4219Smcpowers 		n++;
1192*4219Smcpowers 	}
1193*4219Smcpowers 	if (!has_key_type) {
1194*4219Smcpowers 		pubTemplate[n].type = CKA_KEY_TYPE;
1195*4219Smcpowers 		key_type = CKK_EC;
1196*4219Smcpowers 		pubTemplate[n].pValue = (caddr_t)&key_type;
1197*4219Smcpowers 		pubTemplate[n].ulValueLen = sizeof (key_type);
1198*4219Smcpowers 		n++;
1199*4219Smcpowers 	}
1200*4219Smcpowers 	pubTemplate[n].type = CKA_EC_POINT;
1201*4219Smcpowers 	pubTemplate[n].pValue = (caddr_t)point;
1202*4219Smcpowers 	pubTemplate[n].ulValueLen = sizeof (point);
1203*4219Smcpowers 	pub_out_attr_count++;
1204*4219Smcpowers 
1205*4219Smcpowers 	rv = process_object_attributes(pubTemplate,
1206*4219Smcpowers 	    pub_attr_count - pub_out_attr_count,
1207*4219Smcpowers 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
1208*4219Smcpowers 	if (rv != CKR_OK) {
1209*4219Smcpowers 		goto failed_exit;
1210*4219Smcpowers 	}
1211*4219Smcpowers 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
1212*4219Smcpowers 
1213*4219Smcpowers 	rv = process_object_attributes(
1214*4219Smcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
1215*4219Smcpowers 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
1216*4219Smcpowers 	    &is_token_obj1);
1217*4219Smcpowers 	if (rv != CKR_OK) {
1218*4219Smcpowers 		goto failed_exit;
1219*4219Smcpowers 	}
1220*4219Smcpowers 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
1221*4219Smcpowers 
1222*4219Smcpowers 	/*
1223*4219Smcpowers 	 * Cannot create a token object with a READ-ONLY
1224*4219Smcpowers 	 * session.
1225*4219Smcpowers 	 */
1226*4219Smcpowers 	if (is_token_obj1 && session_p->ses_RO) {
1227*4219Smcpowers 		rv = CKR_SESSION_READ_ONLY;
1228*4219Smcpowers 		goto failed_exit;
1229*4219Smcpowers 	}
1230*4219Smcpowers 
1231*4219Smcpowers 	/*
1232*4219Smcpowers 	 * CKA_EC_PARAMS and CKA_VALUE must not appear in
1233*4219Smcpowers 	 * private template.
1234*4219Smcpowers 	 */
1235*4219Smcpowers 	if (attribute_in_template(CKA_EC_PARAMS, pPrivateKeyTemplate,
1236*4219Smcpowers 	    ulPrivateKeyAttributeCount) ||
1237*4219Smcpowers 	    attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
1238*4219Smcpowers 	    ulPrivateKeyAttributeCount)) {
1239*4219Smcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
1240*4219Smcpowers 		goto failed_exit;
1241*4219Smcpowers 	}
1242*4219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
1243*4219Smcpowers 	    ulPrivateKeyAttributeCount);
1244*4219Smcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
1245*4219Smcpowers 	    ulPrivateKeyAttributeCount);
1246*4219Smcpowers 
1247*4219Smcpowers 	pri_attr_count = ulPrivateKeyAttributeCount + 1;
1248*4219Smcpowers 	if (!has_class)
1249*4219Smcpowers 		pri_attr_count++;
1250*4219Smcpowers 	if (!has_key_type)
1251*4219Smcpowers 		pri_attr_count++;
1252*4219Smcpowers 
1253*4219Smcpowers 	/* allocate space for CKA_EC_PARAMS */
1254*4219Smcpowers 	priTemplate = grow_template(pPrivateKeyTemplate,
1255*4219Smcpowers 	    ulPrivateKeyAttributeCount, pri_attr_count + 1);
1256*4219Smcpowers 	if (priTemplate == NULL) {
1257*4219Smcpowers 		rv = CKR_HOST_MEMORY;
1258*4219Smcpowers 		goto failed_exit;
1259*4219Smcpowers 	}
1260*4219Smcpowers 	n = ulPrivateKeyAttributeCount;
1261*4219Smcpowers 	if (!has_class) {
1262*4219Smcpowers 		priTemplate[n].type = CKA_CLASS;
1263*4219Smcpowers 		priTemplate[n].pValue = (caddr_t)&pri_class;
1264*4219Smcpowers 		priTemplate[n].ulValueLen = sizeof (pri_class);
1265*4219Smcpowers 		n++;
1266*4219Smcpowers 	}
1267*4219Smcpowers 	if (!has_key_type) {
1268*4219Smcpowers 		priTemplate[n].type = CKA_KEY_TYPE;
1269*4219Smcpowers 		key_type = CKK_EC;
1270*4219Smcpowers 		priTemplate[n].pValue = (caddr_t)&key_type;
1271*4219Smcpowers 		priTemplate[n].ulValueLen = sizeof (key_type);
1272*4219Smcpowers 		n++;
1273*4219Smcpowers 	}
1274*4219Smcpowers 	priTemplate[n].type = CKA_VALUE;
1275*4219Smcpowers 	priTemplate[n].pValue = (caddr_t)value;
1276*4219Smcpowers 	priTemplate[n].ulValueLen = sizeof (value);
1277*4219Smcpowers 	pri_out_attr_count++;
1278*4219Smcpowers 
1279*4219Smcpowers 	rv = process_object_attributes(priTemplate,
1280*4219Smcpowers 	    pri_attr_count - pri_out_attr_count,
1281*4219Smcpowers 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
1282*4219Smcpowers 	if (rv != CKR_OK) {
1283*4219Smcpowers 		goto failed_exit;
1284*4219Smcpowers 	}
1285*4219Smcpowers 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
1286*4219Smcpowers 
1287*4219Smcpowers 	rv = process_object_attributes(
1288*4219Smcpowers 	    &priTemplate[pri_attr_count - pri_out_attr_count],
1289*4219Smcpowers 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
1290*4219Smcpowers 	    &is_token_obj2);
1291*4219Smcpowers 	if (rv != CKR_OK) {
1292*4219Smcpowers 		goto failed_exit;
1293*4219Smcpowers 	}
1294*4219Smcpowers 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
1295*4219Smcpowers 
1296*4219Smcpowers 	/*
1297*4219Smcpowers 	 * The public key and the private key need to contain the same
1298*4219Smcpowers 	 * attribute values for CKA_TOKEN.
1299*4219Smcpowers 	 */
1300*4219Smcpowers 	if (is_token_obj1 != is_token_obj2) {
1301*4219Smcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
1302*4219Smcpowers 		goto failed_exit;
1303*4219Smcpowers 	}
1304*4219Smcpowers 
1305*4219Smcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
1306*4219Smcpowers 	obj_nkp.nkp_session = session_p-> k_session;
1307*4219Smcpowers 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
1308*4219Smcpowers 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
1309*4219Smcpowers 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1310*4219Smcpowers 
1311*4219Smcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
1312*4219Smcpowers 	    &obj_nkp)) < 0) {
1313*4219Smcpowers 		if (errno != EINTR)
1314*4219Smcpowers 			break;
1315*4219Smcpowers 	}
1316*4219Smcpowers 	if (r < 0) {
1317*4219Smcpowers 		rv = CKR_FUNCTION_FAILED;
1318*4219Smcpowers 	} else {
1319*4219Smcpowers 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
1320*4219Smcpowers 	}
1321*4219Smcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
1322*4219Smcpowers 	    &obj_nkp.nkp_in_public_count);
1323*4219Smcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
1324*4219Smcpowers 	    &obj_nkp.nkp_in_private_count);
1325*4219Smcpowers 
1326*4219Smcpowers 	if (rv != CKR_OK) {
1327*4219Smcpowers 		goto failed_exit;
1328*4219Smcpowers 	}
1329*4219Smcpowers 
1330*4219Smcpowers 	rv = get_object_attributes(
1331*4219Smcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
1332*4219Smcpowers 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
1333*4219Smcpowers 	if (rv == CRYPTO_SUCCESS) {
1334*4219Smcpowers 		rv = get_object_attributes(
1335*4219Smcpowers 		    &priTemplate[pri_attr_count - pri_out_attr_count],
1336*4219Smcpowers 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
1337*4219Smcpowers 	}
1338*4219Smcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
1339*4219Smcpowers 	    &obj_nkp.nkp_out_public_count);
1340*4219Smcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
1341*4219Smcpowers 	    &obj_nkp.nkp_out_private_count);
1342*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
1343*4219Smcpowers 		goto failed_exit;
1344*4219Smcpowers 	}
1345*4219Smcpowers 
1346*4219Smcpowers 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
1347*4219Smcpowers 	    session_p, KERNEL_GEN_KEY);
1348*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
1349*4219Smcpowers 		goto failed_exit;
1350*4219Smcpowers 	}
1351*4219Smcpowers 
1352*4219Smcpowers 	/*
1353*4219Smcpowers 	 * Copy CKA_EC_PARAMS from the public template to the
1354*4219Smcpowers 	 * private template.
1355*4219Smcpowers 	 */
1356*4219Smcpowers 	rv = copy_attribute(CKA_EC_PARAMS, pubTemplate, pub_attr_count,
1357*4219Smcpowers 	    &priTemplate[pri_attr_count]);
1358*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
1359*4219Smcpowers 		goto failed_exit;
1360*4219Smcpowers 	}
1361*4219Smcpowers 
1362*4219Smcpowers 	/* +1 to account for CKA_EC_PARAMS */
1363*4219Smcpowers 	rv = kernel_build_object(priTemplate, pri_attr_count + 1,
1364*4219Smcpowers 	    new_pri_objp, session_p, KERNEL_GEN_KEY);
1365*4219Smcpowers 	(void) free(priTemplate[pri_attr_count].pValue);
1366*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
1367*4219Smcpowers 		goto failed_exit;
1368*4219Smcpowers 	}
1369*4219Smcpowers 	(void) free(pubTemplate);
1370*4219Smcpowers 	(void) free(priTemplate);
1371*4219Smcpowers 
1372*4219Smcpowers 	new_pub_objp->is_lib_obj = B_TRUE;
1373*4219Smcpowers 	new_pri_objp->is_lib_obj = B_TRUE;
1374*4219Smcpowers 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1375*4219Smcpowers 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1376*4219Smcpowers 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1377*4219Smcpowers 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1378*4219Smcpowers 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1379*4219Smcpowers 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1380*4219Smcpowers 	return (CKR_OK);
1381*4219Smcpowers 
1382*4219Smcpowers failed_exit:
1383*4219Smcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
1384*4219Smcpowers 	    &obj_nkp.nkp_in_public_count);
1385*4219Smcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
1386*4219Smcpowers 	    &obj_nkp.nkp_out_public_count);
1387*4219Smcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
1388*4219Smcpowers 	    &obj_nkp.nkp_in_private_count);
1389*4219Smcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
1390*4219Smcpowers 	    &obj_nkp.nkp_out_private_count);
1391*4219Smcpowers 	if (pubTemplate != NULL) {
1392*4219Smcpowers 		(void) free(pubTemplate);
1393*4219Smcpowers 	}
1394*4219Smcpowers 	if (priTemplate != NULL) {
1395*4219Smcpowers 		(void) free(priTemplate);
1396*4219Smcpowers 	}
1397*4219Smcpowers 	return (rv);
1398*4219Smcpowers }
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate CK_RV
14010Sstevel@tonic-gate C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
14020Sstevel@tonic-gate     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
14030Sstevel@tonic-gate     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
14040Sstevel@tonic-gate     CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
14050Sstevel@tonic-gate {
14060Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
14070Sstevel@tonic-gate 	kernel_session_t	*session_p;
14080Sstevel@tonic-gate 	kernel_object_t		*new_pub_objp = NULL;
14090Sstevel@tonic-gate 	kernel_object_t		*new_pri_objp = NULL;
14100Sstevel@tonic-gate 	kernel_slot_t		*pslot;
14110Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
14120Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj1;
14130Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj2;
14140Sstevel@tonic-gate 	CK_BBOOL		is_token_obj1 = FALSE;
14150Sstevel@tonic-gate 	CK_BBOOL		is_token_obj2 = FALSE;
14160Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
14170Sstevel@tonic-gate 	int r;
1418*4219Smcpowers 	CK_RV (*func)(CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG,
1419*4219Smcpowers 	    CK_ATTRIBUTE_PTR, CK_ULONG, kernel_session_t *, crypto_mech_type_t,
1420*4219Smcpowers 	    kernel_object_t *, kernel_object_t *);
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate 	if (!kernel_initialized)
14230Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate 	/* Obtain the session pointer. */
14260Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
14270Sstevel@tonic-gate 	if (rv != CKR_OK)
14280Sstevel@tonic-gate 		return (rv);
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 	if ((pMechanism == NULL) || (phPublicKey == NULL) ||
14310Sstevel@tonic-gate 	    (phPrivateKey == NULL)) {
14320Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
14330Sstevel@tonic-gate 		goto failed_exit;
14340Sstevel@tonic-gate 	}
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 	if ((pPublicKeyTemplate == NULL) && (ulPublicKeyAttributeCount != 0)) {
14370Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
14380Sstevel@tonic-gate 		goto failed_exit;
14390Sstevel@tonic-gate 	}
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	if ((pPrivateKeyTemplate == NULL) &&
14420Sstevel@tonic-gate 	    (ulPrivateKeyAttributeCount != 0)) {
14430Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
14440Sstevel@tonic-gate 		goto failed_exit;
14450Sstevel@tonic-gate 	}
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
14480Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
14490Sstevel@tonic-gate 	if (rv != CKR_OK) {
14500Sstevel@tonic-gate 		goto failed_exit;
14510Sstevel@tonic-gate 	}
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	/* Create an object wrapper for the public key */
14540Sstevel@tonic-gate 	new_pub_objp = calloc(1, sizeof (kernel_object_t));
14550Sstevel@tonic-gate 	if (new_pub_objp == NULL) {
14560Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
14570Sstevel@tonic-gate 		goto failed_exit;
14580Sstevel@tonic-gate 	}
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 	/* Create an object wrapper for the private key. */
14610Sstevel@tonic-gate 	new_pri_objp = calloc(1, sizeof (kernel_object_t));
14620Sstevel@tonic-gate 	if (new_pri_objp == NULL) {
14630Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
14640Sstevel@tonic-gate 		goto failed_exit;
14650Sstevel@tonic-gate 	}
14660Sstevel@tonic-gate 
1467*4219Smcpowers 	/*
1468*4219Smcpowers 	 * Special Case: if token does not support object creation,
1469*4219Smcpowers 	 * but does support key generation by value, then create a session
1470*4219Smcpowers 	 * object and initialize with values returned by token.
1471*4219Smcpowers 	 */
1472*4219Smcpowers 	pslot = slot_table[session_p->ses_slotid];
1473*4219Smcpowers 	if (!pslot->sl_func_list.fl_object_create) {
1474*4219Smcpowers 		switch (pMechanism->mechanism) {
1475*4219Smcpowers 		case CKM_RSA_PKCS_KEY_PAIR_GEN:
1476*4219Smcpowers 			func = key_gen_rsa_by_value;
1477*4219Smcpowers 			break;
1478*4219Smcpowers 
1479*4219Smcpowers 		case CKM_DH_PKCS_KEY_PAIR_GEN:
1480*4219Smcpowers 			func = key_gen_dh_by_value;
1481*4219Smcpowers 			break;
1482*4219Smcpowers 
1483*4219Smcpowers 		case CKM_EC_KEY_PAIR_GEN:
1484*4219Smcpowers 			func = key_gen_ec_by_value;
1485*4219Smcpowers 			break;
14860Sstevel@tonic-gate 
1487*4219Smcpowers 		default:
1488*4219Smcpowers 			rv = CKR_MECHANISM_INVALID;
1489*4219Smcpowers 			goto failed_exit;
1490*4219Smcpowers 		}
1491*4219Smcpowers 		rv = (*func)(pMechanism, pPublicKeyTemplate,
1492*4219Smcpowers 		    ulPublicKeyAttributeCount, pPrivateKeyTemplate,
1493*4219Smcpowers 		    ulPrivateKeyAttributeCount, session_p, k_mech_type,
1494*4219Smcpowers 		    new_pub_objp, new_pri_objp);
1495*4219Smcpowers 		if (rv != CKR_OK)
1496*4219Smcpowers 			goto failed_exit;
1497*4219Smcpowers 	} else {
1498*4219Smcpowers 		crypto_object_generate_key_pair_t obj_kp;
1499*4219Smcpowers 
1500*4219Smcpowers 		/* Process the public key attributes. */
1501*4219Smcpowers 		rv = process_object_attributes(pPublicKeyTemplate,
1502*4219Smcpowers 		    ulPublicKeyAttributeCount, &obj_kp.kp_public_attributes,
1503*4219Smcpowers 		    &is_token_obj1);
1504*4219Smcpowers 		if (rv != CKR_OK) {
1505*4219Smcpowers 			goto failed_exit;
1506*4219Smcpowers 		}
15070Sstevel@tonic-gate 
1508*4219Smcpowers 		/* Cannot create a token object with a READ-ONLY session. */
1509*4219Smcpowers 		if (is_token_obj1 && session_p->ses_RO) {
1510*4219Smcpowers 			free_object_attributes(obj_kp.kp_public_attributes,
1511*4219Smcpowers 			    ulPublicKeyAttributeCount);
1512*4219Smcpowers 			rv = CKR_SESSION_READ_ONLY;
1513*4219Smcpowers 			goto failed_exit;
1514*4219Smcpowers 		}
1515*4219Smcpowers 
1516*4219Smcpowers 		/* Process the private key attributes. */
1517*4219Smcpowers 		rv = process_object_attributes(pPrivateKeyTemplate,
1518*4219Smcpowers 		    ulPrivateKeyAttributeCount, &obj_kp.kp_private_attributes,
1519*4219Smcpowers 		    &is_token_obj2);
1520*4219Smcpowers 		if (rv != CKR_OK) {
1521*4219Smcpowers 			free_object_attributes(obj_kp.kp_public_attributes,
1522*4219Smcpowers 			    ulPublicKeyAttributeCount);
1523*4219Smcpowers 			goto failed_exit;
1524*4219Smcpowers 		}
15250Sstevel@tonic-gate 
1526*4219Smcpowers 		/*
1527*4219Smcpowers 		 * The public key and the private key need to contain the same
1528*4219Smcpowers 		 * attribute values for CKA_TOKEN.
1529*4219Smcpowers 		 */
1530*4219Smcpowers 		if (is_token_obj1 != is_token_obj2) {
1531*4219Smcpowers 			free_object_attributes(obj_kp.kp_public_attributes,
1532*4219Smcpowers 			    ulPublicKeyAttributeCount);
1533*4219Smcpowers 			free_object_attributes(obj_kp.kp_private_attributes,
1534*4219Smcpowers 			    ulPrivateKeyAttributeCount);
1535*4219Smcpowers 			rv = CKR_ATTRIBUTE_VALUE_INVALID;
1536*4219Smcpowers 			goto failed_exit;
1537*4219Smcpowers 		}
1538*4219Smcpowers 
1539*4219Smcpowers 		/* Call the CRYPTO_GENERATE_KEY_PAIR ioctl. */
1540*4219Smcpowers 		obj_kp.kp_session = session_p-> k_session;
1541*4219Smcpowers 		obj_kp.kp_mechanism.cm_type = k_mech_type;
1542*4219Smcpowers 		obj_kp.kp_mechanism.cm_param = pMechanism->pParameter;
1543*4219Smcpowers 		obj_kp.kp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1544*4219Smcpowers 		obj_kp.kp_public_count = ulPublicKeyAttributeCount;
1545*4219Smcpowers 		obj_kp.kp_private_count = ulPrivateKeyAttributeCount;
1546*4219Smcpowers 
1547*4219Smcpowers 		while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY_PAIR,
1548*4219Smcpowers 		    &obj_kp)) < 0) {
1549*4219Smcpowers 			if (errno != EINTR)
1550*4219Smcpowers 				break;
1551*4219Smcpowers 		}
1552*4219Smcpowers 		if (r < 0) {
1553*4219Smcpowers 			rv = CKR_FUNCTION_FAILED;
1554*4219Smcpowers 		} else {
1555*4219Smcpowers 			rv = crypto2pkcs11_error_number(obj_kp.kp_return_value);
1556*4219Smcpowers 		}
15570Sstevel@tonic-gate 		free_object_attributes(obj_kp.kp_public_attributes,
15580Sstevel@tonic-gate 		    ulPublicKeyAttributeCount);
15590Sstevel@tonic-gate 		free_object_attributes(obj_kp.kp_private_attributes,
15600Sstevel@tonic-gate 		    ulPrivateKeyAttributeCount);
1561*4219Smcpowers 
1562*4219Smcpowers 		if (rv != CKR_OK)
1563*4219Smcpowers 			goto failed_exit;
1564*4219Smcpowers 
1565*4219Smcpowers 		/* Get the CKA_PRIVATE value for the key pair. */
1566*4219Smcpowers 		rv = get_cka_private_value(session_p, obj_kp.kp_public_handle,
1567*4219Smcpowers 		    &is_pri_obj1);
1568*4219Smcpowers 		if (rv != CKR_OK) {
1569*4219Smcpowers 			goto failed_exit;
1570*4219Smcpowers 		}
15710Sstevel@tonic-gate 
1572*4219Smcpowers 		rv = get_cka_private_value(session_p, obj_kp.kp_private_handle,
1573*4219Smcpowers 		    &is_pri_obj2);
1574*4219Smcpowers 		if (rv != CKR_OK) {
1575*4219Smcpowers 			goto failed_exit;
1576*4219Smcpowers 		}
1577*4219Smcpowers 
1578*4219Smcpowers 		/*
1579*4219Smcpowers 		 * Store the kernel public key handle into the public key
1580*4219Smcpowers 		 * object and finish the public key object initialization.
1581*4219Smcpowers 		 */
1582*4219Smcpowers 		new_pub_objp->is_lib_obj = B_FALSE;
1583*4219Smcpowers 		new_pub_objp->k_handle = obj_kp.kp_public_handle;
1584*4219Smcpowers 		new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1585*4219Smcpowers 		new_pub_objp->extra_attrlistp = NULL;
15860Sstevel@tonic-gate 
1587*4219Smcpowers 		if (is_pri_obj1)
1588*4219Smcpowers 			new_pub_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
1589*4219Smcpowers 		else
1590*4219Smcpowers 			new_pub_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
15910Sstevel@tonic-gate 
1592*4219Smcpowers 		if (is_token_obj1)
1593*4219Smcpowers 			new_pub_objp->bool_attr_mask |= TOKEN_BOOL_ON;
1594*4219Smcpowers 		else
1595*4219Smcpowers 			new_pub_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
1596*4219Smcpowers 
1597*4219Smcpowers 		(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1598*4219Smcpowers 		new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
15990Sstevel@tonic-gate 
1600*4219Smcpowers 		/*
1601*4219Smcpowers 		 * Store the kernel private key handle into the private key
1602*4219Smcpowers 		 * object and finish the private key object initialization.
1603*4219Smcpowers 		 */
1604*4219Smcpowers 		new_pri_objp->is_lib_obj = B_FALSE;
1605*4219Smcpowers 		new_pri_objp->k_handle = obj_kp.kp_private_handle;
1606*4219Smcpowers 		new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1607*4219Smcpowers 		new_pri_objp->extra_attrlistp = NULL;
16080Sstevel@tonic-gate 
1609*4219Smcpowers 		if (is_pri_obj2)
1610*4219Smcpowers 			new_pri_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
1611*4219Smcpowers 		else
1612*4219Smcpowers 			new_pri_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
16130Sstevel@tonic-gate 
1614*4219Smcpowers 		if (is_token_obj2)
1615*4219Smcpowers 			new_pri_objp->bool_attr_mask |= TOKEN_BOOL_ON;
1616*4219Smcpowers 		else
1617*4219Smcpowers 			new_pri_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
1618*4219Smcpowers 
16190Sstevel@tonic-gate 	}
16200Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
16210Sstevel@tonic-gate 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate 	/*
16240Sstevel@tonic-gate 	 * Add the new pub/pri objects to the slot's token list if they are
16250Sstevel@tonic-gate 	 * token objects. Otherwise, add them to the session's object list.
16260Sstevel@tonic-gate 	 */
16270Sstevel@tonic-gate 	if (is_token_obj1) { /* is_token_obj1 == is_token_obj2 */
16280Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
16290Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_pub_objp, pslot);
16300Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_pri_objp, pslot);
16310Sstevel@tonic-gate 	} else {
16320Sstevel@tonic-gate 		kernel_add_object_to_session(new_pub_objp, session_p);
16330Sstevel@tonic-gate 		kernel_add_object_to_session(new_pri_objp, session_p);
16340Sstevel@tonic-gate 	}
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	*phPublicKey = (CK_OBJECT_HANDLE)new_pub_objp;
16370Sstevel@tonic-gate 	*phPrivateKey = (CK_OBJECT_HANDLE)new_pri_objp;
16380Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
16390Sstevel@tonic-gate 	return (rv);
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate failed_exit:
16420Sstevel@tonic-gate 	if (new_pub_objp != NULL) {
16430Sstevel@tonic-gate 		(void) free(new_pub_objp);
16440Sstevel@tonic-gate 	}
16450Sstevel@tonic-gate 	if (new_pri_objp != NULL) {
16460Sstevel@tonic-gate 		(void) free(new_pri_objp);
16470Sstevel@tonic-gate 	}
16480Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
16490Sstevel@tonic-gate 	return (rv);
16500Sstevel@tonic-gate }
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate CK_RV
16540Sstevel@tonic-gate C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
16550Sstevel@tonic-gate     CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
16560Sstevel@tonic-gate     CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen)
16570Sstevel@tonic-gate {
16580Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
16590Sstevel@tonic-gate 	kernel_session_t	*session_p;
16600Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
16610Sstevel@tonic-gate 	kernel_object_t		*wrappingkey_p;
16620Sstevel@tonic-gate 	kernel_object_t		*key_p;
16630Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
16640Sstevel@tonic-gate 	crypto_object_wrap_key_t obj_wrapkey;
16650Sstevel@tonic-gate 	int r;
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate 	if (!kernel_initialized)
16680Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate 	if (pulWrappedKeyLen == NULL || pMechanism == NULL) {
16710Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
16720Sstevel@tonic-gate 	}
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	/*
16750Sstevel@tonic-gate 	 * Obtain the session pointer.  Also, increment the session
16760Sstevel@tonic-gate 	 * reference count.
16770Sstevel@tonic-gate 	 */
16780Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
16790Sstevel@tonic-gate 	if (rv != CKR_OK)
16800Sstevel@tonic-gate 		return (rv);
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
16830Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
16840Sstevel@tonic-gate 	if (rv != CKR_OK) {
16850Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
16860Sstevel@tonic-gate 		return (rv);
16870Sstevel@tonic-gate 	}
16880Sstevel@tonic-gate 
16890Sstevel@tonic-gate 	/* Obtain the wrapping key object pointer. */
16900Sstevel@tonic-gate 	HANDLE2OBJECT(hWrappingKey, wrappingkey_p, rv);
16910Sstevel@tonic-gate 	if (rv != CKR_OK) {
16920Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
16930Sstevel@tonic-gate 		return (rv);
16940Sstevel@tonic-gate 	}
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 	/* Obtain the to_be_wrapped key object pointer. */
16970Sstevel@tonic-gate 	HANDLE2OBJECT(hKey, key_p, rv);
16980Sstevel@tonic-gate 	if (rv != CKR_OK) {
1699214Smcpowers 		OBJ_REFRELE(wrappingkey_p);
17000Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
17010Sstevel@tonic-gate 		return (rv);
17020Sstevel@tonic-gate 	}
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate 	/* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */
17050Sstevel@tonic-gate 	obj_wrapkey.wk_session = session_p->k_session;
17060Sstevel@tonic-gate 	obj_wrapkey.wk_mechanism.cm_type = k_mech_type;
17070Sstevel@tonic-gate 	obj_wrapkey.wk_mechanism.cm_param = pMechanism->pParameter;
17080Sstevel@tonic-gate 	obj_wrapkey.wk_mechanism.cm_param_len = pMechanism->ulParameterLen;
17090Sstevel@tonic-gate 	obj_wrapkey.wk_wrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
17100Sstevel@tonic-gate 	obj_wrapkey.wk_wrapping_key.ck_obj_id = wrappingkey_p->k_handle;
17110Sstevel@tonic-gate 	obj_wrapkey.wk_object_handle = key_p->k_handle;
17120Sstevel@tonic-gate 	obj_wrapkey.wk_wrapped_key_len = *pulWrappedKeyLen;
17130Sstevel@tonic-gate 	obj_wrapkey.wk_wrapped_key = (char *)pWrappedKey;
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_WRAP_KEY, &obj_wrapkey)) < 0) {
17160Sstevel@tonic-gate 		if (errno != EINTR)
17170Sstevel@tonic-gate 			break;
17180Sstevel@tonic-gate 	}
17190Sstevel@tonic-gate 	if (r < 0) {
17200Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
17210Sstevel@tonic-gate 	} else {
17220Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(obj_wrapkey.wk_return_value);
17230Sstevel@tonic-gate 	}
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 	/*
17260Sstevel@tonic-gate 	 * Besides rv == CKR_OK, we will set the value of pulWrappedKeyLen
17270Sstevel@tonic-gate 	 * when the applciation-supplied wrapped key buffer is too small.
17280Sstevel@tonic-gate 	 * The situation that the application only asks for the length of
17290Sstevel@tonic-gate 	 * the wrapped key is covered in rv == CKR_OK.
17300Sstevel@tonic-gate 	 */
17310Sstevel@tonic-gate 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
17320Sstevel@tonic-gate 		*pulWrappedKeyLen = obj_wrapkey.wk_wrapped_key_len;
17330Sstevel@tonic-gate 	}
17340Sstevel@tonic-gate 
1735214Smcpowers 	OBJ_REFRELE(key_p);
1736214Smcpowers 	OBJ_REFRELE(wrappingkey_p);
17370Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
17380Sstevel@tonic-gate 	return (rv);
17390Sstevel@tonic-gate }
17400Sstevel@tonic-gate 
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate CK_RV
17430Sstevel@tonic-gate C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
17440Sstevel@tonic-gate     CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey,
17450Sstevel@tonic-gate     CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
17460Sstevel@tonic-gate     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
17470Sstevel@tonic-gate {
17480Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
17490Sstevel@tonic-gate 	kernel_session_t	*session_p;
17500Sstevel@tonic-gate 	kernel_object_t		*unwrappingkey_p;
17510Sstevel@tonic-gate 	kernel_object_t		*new_objp = NULL;
17520Sstevel@tonic-gate 	kernel_slot_t		*pslot;
17530Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
17540Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj;
17550Sstevel@tonic-gate 	CK_BBOOL		is_token_obj = FALSE;
17560Sstevel@tonic-gate 	CK_MECHANISM_INFO	info;
17570Sstevel@tonic-gate 	uint32_t		k_mi_flags;
17580Sstevel@tonic-gate 	CK_BYTE			*clear_key_val = NULL;
17590Sstevel@tonic-gate 	CK_ULONG 		ulDataLen;
17600Sstevel@tonic-gate 	CK_ATTRIBUTE_PTR	newTemplate = NULL;
17610Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
17620Sstevel@tonic-gate 	crypto_object_unwrap_key_t obj_unwrapkey;
17630Sstevel@tonic-gate 	int r;
17640Sstevel@tonic-gate 
17650Sstevel@tonic-gate 	if (!kernel_initialized)
17660Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
17670Sstevel@tonic-gate 
17680Sstevel@tonic-gate 	if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) {
17690Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
17700Sstevel@tonic-gate 	}
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 	if ((pTemplate == NULL) && (ulAttributeCount != 0)) {
17730Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
17740Sstevel@tonic-gate 	}
17750Sstevel@tonic-gate 
17760Sstevel@tonic-gate 	/* Obtain the session pointer. */
17770Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
17780Sstevel@tonic-gate 	if (rv != CKR_OK)
17790Sstevel@tonic-gate 		return (rv);
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 	/* Obtain the wrapping key object pointer. */
17820Sstevel@tonic-gate 	HANDLE2OBJECT(hUnwrappingKey, unwrappingkey_p, rv);
17830Sstevel@tonic-gate 	if (rv != CKR_OK) {
1784214Smcpowers 		REFRELE(session_p, ses_lock_held);
1785214Smcpowers 		return (rv);
17860Sstevel@tonic-gate 	}
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 	/*
17890Sstevel@tonic-gate 	 * If the HW provider doesn't support C_UnwrapKey, we will try
17900Sstevel@tonic-gate 	 * to emulate it in the library.
17910Sstevel@tonic-gate 	 */
17920Sstevel@tonic-gate 	pslot = slot_table[session_p->ses_slotid];
1793*4219Smcpowers 	if ((!pslot->sl_func_list.fl_object_create) &&
1794*4219Smcpowers 	    (!pslot->sl_func_list.fl_key_unwrap)) {
17950Sstevel@tonic-gate 		rv = get_mechanism_info(pslot, pMechanism->mechanism, &info,
17960Sstevel@tonic-gate 		    &k_mi_flags);
17970Sstevel@tonic-gate 		if (rv != CKR_OK) {
17980Sstevel@tonic-gate 			goto failed_exit;
17990Sstevel@tonic-gate 		}
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate 		/*
18020Sstevel@tonic-gate 		 * If the mechanism flag doesn't have CKF_UNWRAP, and it's
18030Sstevel@tonic-gate 		 * an unwrapping of a secret key object, then help this
18040Sstevel@tonic-gate 		 * out with a decryption followed by an object creation.
18050Sstevel@tonic-gate 		 */
18060Sstevel@tonic-gate 		if (!(k_mi_flags & CRYPTO_FG_UNWRAP) &&
18070Sstevel@tonic-gate 		    (k_mi_flags & CRYPTO_FG_DECRYPT) &&
18080Sstevel@tonic-gate 		    (is_secret_key_template(pTemplate, ulAttributeCount))) {
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate 			/* First allocate space for the recovered key value */
18110Sstevel@tonic-gate 			clear_key_val = malloc(ulWrappedKeyLen);
18120Sstevel@tonic-gate 			if (clear_key_val == NULL) {
18130Sstevel@tonic-gate 				rv = CKR_HOST_MEMORY;
18140Sstevel@tonic-gate 				goto failed_exit;
18150Sstevel@tonic-gate 			}
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate 			rv = kernel_decrypt_init(session_p, unwrappingkey_p,
18180Sstevel@tonic-gate 			    pMechanism);
18190Sstevel@tonic-gate 			if (rv != CKR_OK) {
18200Sstevel@tonic-gate 				goto failed_exit;
18210Sstevel@tonic-gate 			}
18220Sstevel@tonic-gate 
18230Sstevel@tonic-gate 			ulDataLen = ulWrappedKeyLen;
18240Sstevel@tonic-gate 			rv = kernel_decrypt(session_p, pWrappedKey,
18250Sstevel@tonic-gate 			    ulWrappedKeyLen, clear_key_val, &ulDataLen);
18260Sstevel@tonic-gate 			if (rv != CKR_OK) {
18270Sstevel@tonic-gate 				goto failed_exit;
18280Sstevel@tonic-gate 			}
18290Sstevel@tonic-gate 
1830*4219Smcpowers 			newTemplate = grow_template(pTemplate, ulAttributeCount,
1831*4219Smcpowers 			    ulAttributeCount + 1);
18320Sstevel@tonic-gate 			if (newTemplate == NULL) {
18330Sstevel@tonic-gate 				rv = CKR_HOST_MEMORY;
18340Sstevel@tonic-gate 				goto failed_exit;
18350Sstevel@tonic-gate 			}
1836*4219Smcpowers 			/* Now add the CKA_VALUE attribute to template */
18370Sstevel@tonic-gate 			newTemplate[ulAttributeCount].type = CKA_VALUE;
18380Sstevel@tonic-gate 			newTemplate[ulAttributeCount].pValue = clear_key_val;
18390Sstevel@tonic-gate 			newTemplate[ulAttributeCount].ulValueLen = ulDataLen;
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate 			/* Finally create the key, based on the new template */
18420Sstevel@tonic-gate 			rv = kernel_add_object(newTemplate,
18430Sstevel@tonic-gate 			    ulAttributeCount + 1, phKey, session_p);
18440Sstevel@tonic-gate 			(void) free(clear_key_val);
18450Sstevel@tonic-gate 			(void) free(newTemplate);
1846214Smcpowers 			OBJ_REFRELE(unwrappingkey_p);
18470Sstevel@tonic-gate 			REFRELE(session_p, ses_lock_held);
18480Sstevel@tonic-gate 			return (rv);
18490Sstevel@tonic-gate 		} else {
18500Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
18510Sstevel@tonic-gate 			goto failed_exit;
18520Sstevel@tonic-gate 		}
18530Sstevel@tonic-gate 	}
18540Sstevel@tonic-gate 
18550Sstevel@tonic-gate 	/*
18560Sstevel@tonic-gate 	 * If we come here, the HW provider must have registered the unwrapkey
18570Sstevel@tonic-gate 	 * entry.  Therefore, the unwrap key will be performed in the HW
18580Sstevel@tonic-gate 	 * provider.
18590Sstevel@tonic-gate 	 */
18600Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
18610Sstevel@tonic-gate 	if (rv != CKR_OK) {
18620Sstevel@tonic-gate 		goto failed_exit;
18630Sstevel@tonic-gate 	}
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 	/* Create an object wrapper for the new key in the library first */
18660Sstevel@tonic-gate 	new_objp = calloc(1, sizeof (kernel_object_t));
18670Sstevel@tonic-gate 	if (new_objp == NULL) {
18680Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
18690Sstevel@tonic-gate 		goto failed_exit;
18700Sstevel@tonic-gate 	}
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate 	/* Process the attributes */
18730Sstevel@tonic-gate 	rv = process_object_attributes(pTemplate, ulAttributeCount,
18740Sstevel@tonic-gate 	    &obj_unwrapkey.uk_attributes, &is_token_obj);
18750Sstevel@tonic-gate 	if (rv != CKR_OK) {
18760Sstevel@tonic-gate 		goto failed_exit;
18770Sstevel@tonic-gate 	}
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate 	/* Cannot create a token object with a READ-ONLY session. */
18800Sstevel@tonic-gate 	if (is_token_obj && session_p->ses_RO) {
18810Sstevel@tonic-gate 		free_object_attributes(obj_unwrapkey.uk_attributes,
18820Sstevel@tonic-gate 		    ulAttributeCount);
18830Sstevel@tonic-gate 		rv = CKR_SESSION_READ_ONLY;
18840Sstevel@tonic-gate 		goto failed_exit;
18850Sstevel@tonic-gate 	}
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 	/* Make the CRYPTO_UNWRAP_KEY ioctl call. */
18880Sstevel@tonic-gate 	obj_unwrapkey.uk_session = session_p->k_session;
18890Sstevel@tonic-gate 	obj_unwrapkey.uk_mechanism.cm_type = k_mech_type;
18900Sstevel@tonic-gate 	obj_unwrapkey.uk_mechanism.cm_param = pMechanism->pParameter;
18910Sstevel@tonic-gate 	obj_unwrapkey.uk_mechanism.cm_param_len = pMechanism->ulParameterLen;
18920Sstevel@tonic-gate 	obj_unwrapkey.uk_unwrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
18930Sstevel@tonic-gate 	obj_unwrapkey.uk_unwrapping_key.ck_obj_id = unwrappingkey_p->k_handle;
18940Sstevel@tonic-gate 	obj_unwrapkey.uk_wrapped_key = (char *)pWrappedKey;
18950Sstevel@tonic-gate 	obj_unwrapkey.uk_wrapped_key_len = ulWrappedKeyLen;
18960Sstevel@tonic-gate 	obj_unwrapkey.uk_count = ulAttributeCount;
18970Sstevel@tonic-gate 
18980Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_UNWRAP_KEY, &obj_unwrapkey)) < 0) {
18990Sstevel@tonic-gate 		if (errno != EINTR)
19000Sstevel@tonic-gate 			break;
19010Sstevel@tonic-gate 	}
19020Sstevel@tonic-gate 	if (r < 0) {
19030Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
19040Sstevel@tonic-gate 	} else {
19050Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(obj_unwrapkey.uk_return_value);
19060Sstevel@tonic-gate 	}
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 	free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount);
19090Sstevel@tonic-gate 	if (rv != CKR_OK) {
19100Sstevel@tonic-gate 		goto failed_exit;
19110Sstevel@tonic-gate 	}
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate 	/* Get the CKA_PRIVATE value for the unwrapped key. */
19140Sstevel@tonic-gate 	rv = get_cka_private_value(session_p, obj_unwrapkey.uk_object_handle,
19150Sstevel@tonic-gate 	    &is_pri_obj);
19160Sstevel@tonic-gate 	if (rv != CKR_OK) {
19170Sstevel@tonic-gate 		goto failed_exit;
19180Sstevel@tonic-gate 	}
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate 	/*
19210Sstevel@tonic-gate 	 * Store the kernel object handle in the new key object wrapper and
19220Sstevel@tonic-gate 	 * initialize it.
19230Sstevel@tonic-gate 	 */
19240Sstevel@tonic-gate 	new_objp->k_handle = obj_unwrapkey.uk_object_handle;
19250Sstevel@tonic-gate 	new_objp->is_lib_obj = B_FALSE;
19260Sstevel@tonic-gate 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
19270Sstevel@tonic-gate 	new_objp->extra_attrlistp = NULL;
19280Sstevel@tonic-gate 
19290Sstevel@tonic-gate 	if (is_pri_obj)
19300Sstevel@tonic-gate 		new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
19310Sstevel@tonic-gate 	else
19320Sstevel@tonic-gate 		new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
19330Sstevel@tonic-gate 
19340Sstevel@tonic-gate 	if (is_token_obj)
19350Sstevel@tonic-gate 		new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
19360Sstevel@tonic-gate 	else
19370Sstevel@tonic-gate 		new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
19400Sstevel@tonic-gate 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 	/*
19430Sstevel@tonic-gate 	 * Add the new object to the slot's token object list if it is a
19440Sstevel@tonic-gate 	 * a token object. Otherwise, add it to the session's object list.
19450Sstevel@tonic-gate 	 */
19460Sstevel@tonic-gate 	if (is_token_obj) {
19470Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
19480Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_objp, pslot);
19490Sstevel@tonic-gate 	} else {
19500Sstevel@tonic-gate 		kernel_add_object_to_session(new_objp, session_p);
19510Sstevel@tonic-gate 	}
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate 	*phKey = (CK_OBJECT_HANDLE)new_objp;
1954214Smcpowers 	OBJ_REFRELE(unwrappingkey_p);
19550Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
19560Sstevel@tonic-gate 	return (rv);
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate failed_exit:
1959214Smcpowers 	OBJ_REFRELE(unwrappingkey_p);
19600Sstevel@tonic-gate 	if (new_objp != NULL)
19610Sstevel@tonic-gate 		(void) free(new_objp);
19620Sstevel@tonic-gate 
19630Sstevel@tonic-gate 	if (clear_key_val != NULL)
19640Sstevel@tonic-gate 		(void) free(clear_key_val);
19650Sstevel@tonic-gate 
19660Sstevel@tonic-gate 	if (newTemplate != NULL)
19670Sstevel@tonic-gate 		(void) free(newTemplate);
19680Sstevel@tonic-gate 
19690Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
19700Sstevel@tonic-gate 	return (rv);
19710Sstevel@tonic-gate }
19720Sstevel@tonic-gate 
1973*4219Smcpowers /*
1974*4219Smcpowers  * Get sufficient attributes from a base key to pass by value in a
1975*4219Smcpowers  * crypto_key structure. Storage for attributes is allocated.
1976*4219Smcpowers  * For EC public keys, it is CKA_EC_PARAMS and CKA_EC_POINT.
1977*4219Smcpowers  * For EC private keys, it is CKA_EC_PARAMS and CKA_VALUE.
1978*4219Smcpowers  */
1979*4219Smcpowers static int
1980*4219Smcpowers get_base_key_attributes(kernel_object_t *base_key, crypto_key_t *key_by_value)
1981*4219Smcpowers {
1982*4219Smcpowers 	CK_ATTRIBUTE tmp;
1983*4219Smcpowers 	crypto_object_attribute_t *attrs;
1984*4219Smcpowers 	biginteger_t *big;
1985*4219Smcpowers 	int rv;
1986*4219Smcpowers 
1987*4219Smcpowers 	switch (base_key->key_type) {
1988*4219Smcpowers 	case CKK_EC:
1989*4219Smcpowers 		attrs = malloc(2 * sizeof (crypto_object_attribute_t));
1990*4219Smcpowers 		if (attrs == NULL) {
1991*4219Smcpowers 			rv = CKR_HOST_MEMORY;
1992*4219Smcpowers 			goto out;
1993*4219Smcpowers 		}
1994*4219Smcpowers 		bzero(attrs, 2 * sizeof (crypto_object_attribute_t));
1995*4219Smcpowers 
1996*4219Smcpowers 		(void) pthread_mutex_lock(&base_key->object_mutex);
1997*4219Smcpowers 
1998*4219Smcpowers 		if (!base_key->is_lib_obj) {
1999*4219Smcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
2000*4219Smcpowers 			goto out;
2001*4219Smcpowers 		}
2002*4219Smcpowers 
2003*4219Smcpowers 		if (base_key->class != CKO_PUBLIC_KEY &&
2004*4219Smcpowers 		    base_key->class != CKO_PRIVATE_KEY) {
2005*4219Smcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
2006*4219Smcpowers 			goto out;
2007*4219Smcpowers 		}
2008*4219Smcpowers 
2009*4219Smcpowers 		/*
2010*4219Smcpowers 		 * Both public and private EC keys should have
2011*4219Smcpowers 		 * a CKA_EC_PARAMS attribute.
2012*4219Smcpowers 		 */
2013*4219Smcpowers 		tmp.type = CKA_EC_PARAMS;
2014*4219Smcpowers 		tmp.pValue = NULL;
2015*4219Smcpowers 
2016*4219Smcpowers 		/* get size of attribute */
2017*4219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2018*4219Smcpowers 		if (rv != CKR_OK) {
2019*4219Smcpowers 			goto out;
2020*4219Smcpowers 		}
2021*4219Smcpowers 
2022*4219Smcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2023*4219Smcpowers 		if (tmp.pValue == NULL) {
2024*4219Smcpowers 			rv = CKR_HOST_MEMORY;
2025*4219Smcpowers 			goto out;
2026*4219Smcpowers 		}
2027*4219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2028*4219Smcpowers 		if (rv != CKR_OK) {
2029*4219Smcpowers 			goto out;
2030*4219Smcpowers 		}
2031*4219Smcpowers 		attrs[0].oa_type = tmp.type;
2032*4219Smcpowers 		attrs[0].oa_value = tmp.pValue;
2033*4219Smcpowers 		attrs[0].oa_value_len = tmp.ulValueLen;
2034*4219Smcpowers 
2035*4219Smcpowers 		switch (base_key->class) {
2036*4219Smcpowers 		case CKO_PUBLIC_KEY:
2037*4219Smcpowers 			big = OBJ_PUB_EC_POINT(base_key);
2038*4219Smcpowers 			tmp.type = CKA_EC_POINT;
2039*4219Smcpowers 			break;
2040*4219Smcpowers 
2041*4219Smcpowers 		case CKO_PRIVATE_KEY:
2042*4219Smcpowers 			big = OBJ_PRI_EC_VALUE(base_key);
2043*4219Smcpowers 			tmp.type = CKA_VALUE;
2044*4219Smcpowers 			break;
2045*4219Smcpowers 
2046*4219Smcpowers 		default:
2047*4219Smcpowers 			rv = CKR_ATTRIBUTE_TYPE_INVALID;
2048*4219Smcpowers 			goto out;
2049*4219Smcpowers 		}
2050*4219Smcpowers 		tmp.ulValueLen = big->big_value_len;
2051*4219Smcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2052*4219Smcpowers 		if (tmp.pValue == NULL) {
2053*4219Smcpowers 			rv = CKR_HOST_MEMORY;
2054*4219Smcpowers 			goto out;
2055*4219Smcpowers 		}
2056*4219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2057*4219Smcpowers 		if (rv != CKR_OK) {
2058*4219Smcpowers 			goto out;
2059*4219Smcpowers 		}
2060*4219Smcpowers 		attrs[1].oa_type = tmp.type;
2061*4219Smcpowers 		attrs[1].oa_value = tmp.pValue;
2062*4219Smcpowers 		attrs[1].oa_value_len = tmp.ulValueLen;
2063*4219Smcpowers 		key_by_value->ck_attrs = attrs;
2064*4219Smcpowers 		key_by_value->ck_count = 2;
2065*4219Smcpowers 		break;
2066*4219Smcpowers 
2067*4219Smcpowers 	case CKK_DH:
2068*4219Smcpowers 		attrs = malloc(3 * sizeof (crypto_object_attribute_t));
2069*4219Smcpowers 		if (attrs == NULL) {
2070*4219Smcpowers 			rv = CKR_HOST_MEMORY;
2071*4219Smcpowers 			goto out;
2072*4219Smcpowers 		}
2073*4219Smcpowers 		bzero(attrs, 3 * sizeof (crypto_object_attribute_t));
2074*4219Smcpowers 
2075*4219Smcpowers 		(void) pthread_mutex_lock(&base_key->object_mutex);
2076*4219Smcpowers 
2077*4219Smcpowers 		if (!base_key->is_lib_obj) {
2078*4219Smcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
2079*4219Smcpowers 			goto out;
2080*4219Smcpowers 		}
2081*4219Smcpowers 
2082*4219Smcpowers 		if (base_key->class != CKO_PRIVATE_KEY) {
2083*4219Smcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
2084*4219Smcpowers 			goto out;
2085*4219Smcpowers 		}
2086*4219Smcpowers 		tmp.type = CKA_BASE;
2087*4219Smcpowers 		tmp.pValue = NULL;
2088*4219Smcpowers 
2089*4219Smcpowers 		/* get size of attribute */
2090*4219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2091*4219Smcpowers 		if (rv != CKR_OK) {
2092*4219Smcpowers 			goto out;
2093*4219Smcpowers 		}
2094*4219Smcpowers 
2095*4219Smcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2096*4219Smcpowers 		if (tmp.pValue == NULL) {
2097*4219Smcpowers 			rv = CKR_HOST_MEMORY;
2098*4219Smcpowers 			goto out;
2099*4219Smcpowers 		}
2100*4219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2101*4219Smcpowers 		if (rv != CKR_OK) {
2102*4219Smcpowers 			goto out;
2103*4219Smcpowers 		}
2104*4219Smcpowers 		attrs[0].oa_type = tmp.type;
2105*4219Smcpowers 		attrs[0].oa_value = tmp.pValue;
2106*4219Smcpowers 		attrs[0].oa_value_len = tmp.ulValueLen;
2107*4219Smcpowers 
2108*4219Smcpowers 		tmp.type = CKA_PRIME;
2109*4219Smcpowers 		tmp.pValue = NULL;
2110*4219Smcpowers 
2111*4219Smcpowers 		/* get size of attribute */
2112*4219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2113*4219Smcpowers 		if (rv != CKR_OK) {
2114*4219Smcpowers 			goto out;
2115*4219Smcpowers 		}
2116*4219Smcpowers 
2117*4219Smcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2118*4219Smcpowers 		if (tmp.pValue == NULL) {
2119*4219Smcpowers 			rv = CKR_HOST_MEMORY;
2120*4219Smcpowers 			goto out;
2121*4219Smcpowers 		}
2122*4219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2123*4219Smcpowers 		if (rv != CKR_OK) {
2124*4219Smcpowers 			goto out;
2125*4219Smcpowers 		}
2126*4219Smcpowers 		attrs[1].oa_type = tmp.type;
2127*4219Smcpowers 		attrs[1].oa_value = tmp.pValue;
2128*4219Smcpowers 		attrs[1].oa_value_len = tmp.ulValueLen;
2129*4219Smcpowers 
2130*4219Smcpowers 		big = OBJ_PRI_EC_VALUE(base_key);
2131*4219Smcpowers 		tmp.type = CKA_VALUE;
2132*4219Smcpowers 
2133*4219Smcpowers 		tmp.ulValueLen = big->big_value_len;
2134*4219Smcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2135*4219Smcpowers 		if (tmp.pValue == NULL) {
2136*4219Smcpowers 			rv = CKR_HOST_MEMORY;
2137*4219Smcpowers 			goto out;
2138*4219Smcpowers 		}
2139*4219Smcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2140*4219Smcpowers 		if (rv != CKR_OK) {
2141*4219Smcpowers 			goto out;
2142*4219Smcpowers 		}
2143*4219Smcpowers 		attrs[2].oa_type = tmp.type;
2144*4219Smcpowers 		attrs[2].oa_value = tmp.pValue;
2145*4219Smcpowers 		attrs[2].oa_value_len = tmp.ulValueLen;
2146*4219Smcpowers 		key_by_value->ck_attrs = attrs;
2147*4219Smcpowers 		key_by_value->ck_count = 3;
2148*4219Smcpowers 		break;
2149*4219Smcpowers 
2150*4219Smcpowers 	default:
2151*4219Smcpowers 		rv = CKR_ATTRIBUTE_TYPE_INVALID;
2152*4219Smcpowers 		goto out;
2153*4219Smcpowers 	}
2154*4219Smcpowers 	(void) pthread_mutex_unlock(&base_key->object_mutex);
2155*4219Smcpowers 	return (CKR_OK);
2156*4219Smcpowers 
2157*4219Smcpowers out:
2158*4219Smcpowers 	(void) pthread_mutex_unlock(&base_key->object_mutex);
2159*4219Smcpowers 	return (rv);
2160*4219Smcpowers }
2161*4219Smcpowers 
2162*4219Smcpowers CK_RV
2163*4219Smcpowers derive_key_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
2164*4219Smcpowers     CK_ULONG ulAttributeCount, kernel_session_t *session_p,
2165*4219Smcpowers     crypto_mech_type_t k_mech_type, kernel_object_t *basekey_p,
2166*4219Smcpowers     kernel_object_t *new_objp)
2167*4219Smcpowers {
2168*4219Smcpowers 	crypto_nostore_derive_key_t obj_ndk;
2169*4219Smcpowers 	char *key_buf = NULL;
2170*4219Smcpowers 	CK_ATTRIBUTE_PTR newTemplate = NULL;
2171*4219Smcpowers 	CK_BBOOL is_token_obj = FALSE;
2172*4219Smcpowers 	CK_RV rv = CKR_OK;
2173*4219Smcpowers 	CK_ULONG secret_class = CKO_SECRET_KEY;
2174*4219Smcpowers 	ulong_t key_len = 0;
2175*4219Smcpowers 	uint_t attr_count = 0;
2176*4219Smcpowers 	boolean_t removed;
2177*4219Smcpowers 	boolean_t has_class;
2178*4219Smcpowers 	int r, n;
2179*4219Smcpowers 
2180*4219Smcpowers 	obj_ndk.ndk_in_count = 0;
2181*4219Smcpowers 	obj_ndk.ndk_out_count = 0;
2182*4219Smcpowers 	obj_ndk.ndk_base_key.ck_count = 0;
2183*4219Smcpowers 
2184*4219Smcpowers 	rv = get_key_len_from_template(pMechanism, pTemplate, ulAttributeCount,
2185*4219Smcpowers 	    basekey_p, &key_len);
2186*4219Smcpowers 	if (rv != CKR_OK) {
2187*4219Smcpowers 		goto failed_exit;
2188*4219Smcpowers 	}
2189*4219Smcpowers 
2190*4219Smcpowers 	if ((key_buf = malloc(key_len)) == NULL) {
2191*4219Smcpowers 		rv = CKR_HOST_MEMORY;
2192*4219Smcpowers 		goto failed_exit;
2193*4219Smcpowers 	}
2194*4219Smcpowers 
2195*4219Smcpowers 	has_class = attribute_in_template(CKA_CLASS, pTemplate,
2196*4219Smcpowers 	    ulAttributeCount);
2197*4219Smcpowers 
2198*4219Smcpowers 	attr_count = ulAttributeCount + 1;
2199*4219Smcpowers 	if (!has_class)
2200*4219Smcpowers 		attr_count++;
2201*4219Smcpowers 
2202*4219Smcpowers 	newTemplate = grow_template(pTemplate, ulAttributeCount, attr_count);
2203*4219Smcpowers 	if (newTemplate == NULL) {
2204*4219Smcpowers 		rv = CKR_HOST_MEMORY;
2205*4219Smcpowers 		goto failed_exit;
2206*4219Smcpowers 	}
2207*4219Smcpowers 
2208*4219Smcpowers 	n = ulAttributeCount;
2209*4219Smcpowers 	if (!has_class) {
2210*4219Smcpowers 		newTemplate[n].type = CKA_CLASS;
2211*4219Smcpowers 		newTemplate[n].pValue = (caddr_t)&secret_class;
2212*4219Smcpowers 		newTemplate[n].ulValueLen = sizeof (secret_class);
2213*4219Smcpowers 		n++;
2214*4219Smcpowers 	}
2215*4219Smcpowers 
2216*4219Smcpowers 	/* Add CKA_VALUE to the template */
2217*4219Smcpowers 	newTemplate[n].type = CKA_VALUE;
2218*4219Smcpowers 	newTemplate[n].pValue = (caddr_t)key_buf;
2219*4219Smcpowers 	newTemplate[n].ulValueLen = key_len;
2220*4219Smcpowers 
2221*4219Smcpowers 	rv = process_object_attributes(newTemplate, attr_count - 1,
2222*4219Smcpowers 	    &obj_ndk.ndk_in_attributes, &is_token_obj);
2223*4219Smcpowers 	if (rv != CKR_OK) {
2224*4219Smcpowers 		goto failed_exit;
2225*4219Smcpowers 	}
2226*4219Smcpowers 
2227*4219Smcpowers 	rv = process_object_attributes(&newTemplate[attr_count - 1],
2228*4219Smcpowers 	    1, &obj_ndk.ndk_out_attributes, &is_token_obj);
2229*4219Smcpowers 	if (rv != CKR_OK) {
2230*4219Smcpowers 		goto failed_exit;
2231*4219Smcpowers 	}
2232*4219Smcpowers 
2233*4219Smcpowers 	/* Cannot create a token object with a READ-ONLY session. */
2234*4219Smcpowers 	if (is_token_obj && session_p->ses_RO) {
2235*4219Smcpowers 		rv = CKR_SESSION_READ_ONLY;
2236*4219Smcpowers 		goto failed_exit;
2237*4219Smcpowers 	}
2238*4219Smcpowers 
2239*4219Smcpowers 	obj_ndk.ndk_session = session_p->k_session;
2240*4219Smcpowers 	obj_ndk.ndk_mechanism.cm_type = k_mech_type;
2241*4219Smcpowers 	obj_ndk.ndk_mechanism.cm_param = pMechanism->pParameter;
2242*4219Smcpowers 	obj_ndk.ndk_mechanism.cm_param_len = pMechanism->ulParameterLen;
2243*4219Smcpowers 
2244*4219Smcpowers 	/*
2245*4219Smcpowers 	 * Obtain the attributes of base key and pass them by value.
2246*4219Smcpowers 	 */
2247*4219Smcpowers 	rv = get_base_key_attributes(basekey_p, &obj_ndk.ndk_base_key);
2248*4219Smcpowers 	if (rv != CKR_OK) {
2249*4219Smcpowers 		goto failed_exit;
2250*4219Smcpowers 	}
2251*4219Smcpowers 
2252*4219Smcpowers 	obj_ndk.ndk_base_key.ck_format = CRYPTO_KEY_ATTR_LIST;
2253*4219Smcpowers 	obj_ndk.ndk_in_count = attr_count - 1;
2254*4219Smcpowers 	obj_ndk.ndk_out_count = 1;
2255*4219Smcpowers 
2256*4219Smcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_DERIVE_KEY,
2257*4219Smcpowers 	    &obj_ndk)) < 0) {
2258*4219Smcpowers 		if (errno != EINTR)
2259*4219Smcpowers 			break;
2260*4219Smcpowers 	}
2261*4219Smcpowers 	if (r < 0) {
2262*4219Smcpowers 		rv = CKR_FUNCTION_FAILED;
2263*4219Smcpowers 	} else {
2264*4219Smcpowers 		rv = crypto2pkcs11_error_number(obj_ndk.ndk_return_value);
2265*4219Smcpowers 	}
2266*4219Smcpowers 	free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
2267*4219Smcpowers 	free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
2268*4219Smcpowers 	    &obj_ndk.ndk_base_key.ck_count);
2269*4219Smcpowers 	if (rv != CKR_OK) {
2270*4219Smcpowers 		goto failed_exit;
2271*4219Smcpowers 	}
2272*4219Smcpowers 
2273*4219Smcpowers 	rv = get_object_attributes(&newTemplate[attr_count - 1],
2274*4219Smcpowers 	    1, obj_ndk.ndk_out_attributes);
2275*4219Smcpowers 	free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
2276*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
2277*4219Smcpowers 		goto failed_exit;
2278*4219Smcpowers 	}
2279*4219Smcpowers 
2280*4219Smcpowers 	removed = remove_one_attribute(newTemplate, CKA_VALUE_LEN,
2281*4219Smcpowers 	    attr_count, B_FALSE);
2282*4219Smcpowers 
2283*4219Smcpowers 	rv = kernel_build_object(newTemplate, removed ? attr_count - 1 :
2284*4219Smcpowers 	    attr_count, new_objp, session_p, KERNEL_GEN_KEY);
2285*4219Smcpowers 	if (rv != CRYPTO_SUCCESS) {
2286*4219Smcpowers 		goto failed_exit;
2287*4219Smcpowers 	}
2288*4219Smcpowers 
2289*4219Smcpowers 	free(key_buf);
2290*4219Smcpowers 	free(newTemplate);
2291*4219Smcpowers 	new_objp->is_lib_obj = B_TRUE;
2292*4219Smcpowers 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
2293*4219Smcpowers 	return (CKR_OK);
2294*4219Smcpowers 
2295*4219Smcpowers failed_exit:
2296*4219Smcpowers 	if (key_buf != NULL)
2297*4219Smcpowers 		free(key_buf);
2298*4219Smcpowers 	if (newTemplate != NULL)
2299*4219Smcpowers 		free(newTemplate);
2300*4219Smcpowers 	free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
2301*4219Smcpowers 	free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
2302*4219Smcpowers 	free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
2303*4219Smcpowers 	    &obj_ndk.ndk_base_key.ck_count);
2304*4219Smcpowers 	return (rv);
2305*4219Smcpowers }
23060Sstevel@tonic-gate 
23070Sstevel@tonic-gate CK_RV
23080Sstevel@tonic-gate C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
23090Sstevel@tonic-gate     CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
23100Sstevel@tonic-gate     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
23110Sstevel@tonic-gate {
23120Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
23130Sstevel@tonic-gate 	kernel_session_t	*session_p;
23140Sstevel@tonic-gate 	kernel_object_t		*basekey_p;
23150Sstevel@tonic-gate 	kernel_object_t		*new_objp;
23160Sstevel@tonic-gate 	kernel_slot_t		*pslot;
23170Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
23180Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj;
23190Sstevel@tonic-gate 	CK_BBOOL		is_token_obj = FALSE;
23200Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
23210Sstevel@tonic-gate 	int r;
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate 	if (!kernel_initialized)
23240Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
23250Sstevel@tonic-gate 
23260Sstevel@tonic-gate 	/* Obtain the session pointer. */
23270Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
23280Sstevel@tonic-gate 	if (rv != CKR_OK)
23290Sstevel@tonic-gate 		return (rv);
23300Sstevel@tonic-gate 
2331872Sizick 	if (pMechanism == NULL) {
2332214Smcpowers 		REFRELE(session_p, ses_lock_held);
2333214Smcpowers 		return (CKR_ARGUMENTS_BAD);
23340Sstevel@tonic-gate 	}
23350Sstevel@tonic-gate 
23360Sstevel@tonic-gate 	if ((pTemplate == NULL && ulAttributeCount != 0) ||
23370Sstevel@tonic-gate 	    (pTemplate != NULL && ulAttributeCount == 0)) {
2338214Smcpowers 		REFRELE(session_p, ses_lock_held);
2339214Smcpowers 		return (CKR_ARGUMENTS_BAD);
23400Sstevel@tonic-gate 	}
23410Sstevel@tonic-gate 
23420Sstevel@tonic-gate 	/* Obtain the base key object pointer. */
23430Sstevel@tonic-gate 	HANDLE2OBJECT(hBaseKey, basekey_p, rv);
23440Sstevel@tonic-gate 	if (rv != CKR_OK) {
2345214Smcpowers 		REFRELE(session_p, ses_lock_held);
2346214Smcpowers 		return (rv);
23470Sstevel@tonic-gate 	}
23480Sstevel@tonic-gate 
23490Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
23500Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
23510Sstevel@tonic-gate 	if (rv != CKR_OK) {
23520Sstevel@tonic-gate 		goto failed_exit;
23530Sstevel@tonic-gate 	}
23540Sstevel@tonic-gate 
23550Sstevel@tonic-gate 	/* Create an object wrapper in the library for the generated key. */
23560Sstevel@tonic-gate 	new_objp = calloc(1, sizeof (kernel_object_t));
23570Sstevel@tonic-gate 	if (new_objp == NULL) {
23580Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
23590Sstevel@tonic-gate 		goto failed_exit;
23600Sstevel@tonic-gate 	}
23610Sstevel@tonic-gate 
2362*4219Smcpowers 	/*
2363*4219Smcpowers 	 * Special Case: if token does not support object creation,
2364*4219Smcpowers 	 * but does support key derivation by value, then create a session
2365*4219Smcpowers 	 * object and initialize with values returned by token.
2366*4219Smcpowers 	 */
2367*4219Smcpowers 	pslot = slot_table[session_p->ses_slotid];
2368*4219Smcpowers 	if (!pslot->sl_func_list.fl_object_create) {
2369*4219Smcpowers 		rv = derive_key_by_value(pMechanism, pTemplate,
2370*4219Smcpowers 		    ulAttributeCount, session_p, k_mech_type, basekey_p,
2371*4219Smcpowers 		    new_objp);
2372*4219Smcpowers 		if (rv != CKR_OK)
2373*4219Smcpowers 			goto failed_exit;
2374*4219Smcpowers 	} else {
2375*4219Smcpowers 		crypto_derive_key_t obj_dk;
23760Sstevel@tonic-gate 
2377*4219Smcpowers 		rv = process_object_attributes(pTemplate, ulAttributeCount,
2378*4219Smcpowers 		    &obj_dk.dk_attributes, &is_token_obj);
2379*4219Smcpowers 		if (rv != CKR_OK) {
2380*4219Smcpowers 			goto failed_exit;
2381*4219Smcpowers 		}
2382*4219Smcpowers 
2383*4219Smcpowers 		/* Cannot create a token object with a READ-ONLY session. */
2384*4219Smcpowers 		if (is_token_obj && session_p->ses_RO) {
2385*4219Smcpowers 			free_object_attributes(obj_dk.dk_attributes,
2386*4219Smcpowers 			    ulAttributeCount);
2387*4219Smcpowers 			rv = CKR_SESSION_READ_ONLY;
2388*4219Smcpowers 			goto failed_exit;
2389*4219Smcpowers 		}
2390*4219Smcpowers 
2391*4219Smcpowers 		obj_dk.dk_session = session_p->k_session;
2392*4219Smcpowers 		obj_dk.dk_mechanism.cm_type = k_mech_type;
2393*4219Smcpowers 		obj_dk.dk_mechanism.cm_param = pMechanism->pParameter;
2394*4219Smcpowers 		obj_dk.dk_mechanism.cm_param_len = pMechanism->ulParameterLen;
2395*4219Smcpowers 		obj_dk.dk_base_key.ck_format = CRYPTO_KEY_REFERENCE;
2396*4219Smcpowers 		obj_dk.dk_base_key.ck_obj_id = basekey_p->k_handle;
2397*4219Smcpowers 		obj_dk.dk_count = ulAttributeCount;
23980Sstevel@tonic-gate 
2399*4219Smcpowers 		while ((r = ioctl(kernel_fd, CRYPTO_DERIVE_KEY, &obj_dk)) < 0) {
2400*4219Smcpowers 			if (errno != EINTR)
2401*4219Smcpowers 				break;
2402*4219Smcpowers 		}
2403*4219Smcpowers 		if (r < 0) {
2404*4219Smcpowers 			rv = CKR_FUNCTION_FAILED;
2405*4219Smcpowers 		} else {
2406*4219Smcpowers 			rv = crypto2pkcs11_error_number(obj_dk.dk_return_value);
2407*4219Smcpowers 		}
2408*4219Smcpowers 
2409*4219Smcpowers 		free_object_attributes(obj_dk.dk_attributes, ulAttributeCount);
2410*4219Smcpowers 		if (rv != CKR_OK) {
2411*4219Smcpowers 			goto failed_exit;
2412*4219Smcpowers 		}
24130Sstevel@tonic-gate 
2414*4219Smcpowers 		/* Get the CKA_PRIVATE value for the derived key. */
2415*4219Smcpowers 		rv = get_cka_private_value(session_p, obj_dk.dk_object_handle,
2416*4219Smcpowers 		    &is_pri_obj);
2417*4219Smcpowers 		if (rv != CKR_OK) {
2418*4219Smcpowers 			goto failed_exit;
2419*4219Smcpowers 		}
2420*4219Smcpowers 
2421*4219Smcpowers 		/*
2422*4219Smcpowers 		 * Store the kernel object handle into the new derived key
2423*4219Smcpowers 		 * object and finish the object initialization.
2424*4219Smcpowers 		 */
2425*4219Smcpowers 		new_objp->is_lib_obj = B_FALSE;
2426*4219Smcpowers 		new_objp->k_handle = obj_dk.dk_object_handle;
2427*4219Smcpowers 		new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
2428*4219Smcpowers 		new_objp->extra_attrlistp = NULL;
2429*4219Smcpowers 
2430*4219Smcpowers 		if (is_pri_obj)
2431*4219Smcpowers 			new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
2432*4219Smcpowers 		else
2433*4219Smcpowers 			new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
2434*4219Smcpowers 
2435*4219Smcpowers 		if (is_token_obj)
2436*4219Smcpowers 			new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
2437*4219Smcpowers 		else
2438*4219Smcpowers 			new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
24390Sstevel@tonic-gate 	}
24400Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
24410Sstevel@tonic-gate 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
24420Sstevel@tonic-gate 
24430Sstevel@tonic-gate 	/*
24440Sstevel@tonic-gate 	 * Add the new derived object to the slot's token list if it is a
24450Sstevel@tonic-gate 	 * token object. Otherwise, add it to the session's object list.
24460Sstevel@tonic-gate 	 */
24470Sstevel@tonic-gate 	if (is_token_obj) {
24480Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
24490Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_objp, pslot);
24500Sstevel@tonic-gate 	} else {
24510Sstevel@tonic-gate 		kernel_add_object_to_session(new_objp, session_p);
24520Sstevel@tonic-gate 	}
24530Sstevel@tonic-gate 
24540Sstevel@tonic-gate 	*phKey = (CK_OBJECT_HANDLE)new_objp;
2455214Smcpowers 	OBJ_REFRELE(basekey_p);
24560Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
24570Sstevel@tonic-gate 	return (rv);
24580Sstevel@tonic-gate 
24590Sstevel@tonic-gate failed_exit:
2460214Smcpowers 	OBJ_REFRELE(basekey_p);
24610Sstevel@tonic-gate 	if (new_objp != NULL) {
24620Sstevel@tonic-gate 		(void) free(new_objp);
24630Sstevel@tonic-gate 	}
24640Sstevel@tonic-gate 
24650Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
24660Sstevel@tonic-gate 	return (rv);
24670Sstevel@tonic-gate }
2468