17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*034448feSmcpowers  * Common Development and Distribution License (the "License").
6*034448feSmcpowers  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*034448feSmcpowers  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <strings.h>
297c478bd9Sstevel@tonic-gate #include <errno.h>
307c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
317c478bd9Sstevel@tonic-gate #include <sys/crypto/ioctl.h>
327c478bd9Sstevel@tonic-gate #include "kernelGlobal.h"
337c478bd9Sstevel@tonic-gate #include "kernelSession.h"
347c478bd9Sstevel@tonic-gate #include "kernelObject.h"
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate static boolean_t
37*034448feSmcpowers attribute_in_template(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
38*034448feSmcpowers {
39*034448feSmcpowers 	int i;
40*034448feSmcpowers 
41*034448feSmcpowers 	for (i = 0; i < cnt; i++) {
42*034448feSmcpowers 		if (t[i].type == type)
43*034448feSmcpowers 			return (B_TRUE);
44*034448feSmcpowers 	}
45*034448feSmcpowers 	return (B_FALSE);
46*034448feSmcpowers }
47*034448feSmcpowers 
48*034448feSmcpowers /*
49*034448feSmcpowers  * This routine returns modulus bytes rounded up to the nearest 8 byte
50*034448feSmcpowers  * chunk. This is so we don't have to pass in max sized buffers for
51*034448feSmcpowers  * returned attributes. Every unnecessary byte that we pass in results
52*034448feSmcpowers  * in a kernel allocation.
53*034448feSmcpowers  */
54*034448feSmcpowers static ulong_t
55*034448feSmcpowers get_modulus_bytes(CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
56*034448feSmcpowers {
57*034448feSmcpowers 	CK_ULONG modulus_len;
58*034448feSmcpowers 	int i;
59*034448feSmcpowers 
60*034448feSmcpowers 	for (i = 0; i < cnt; i++) {
61*034448feSmcpowers 		if (t[i].type == CKA_MODULUS_BITS) {
62*034448feSmcpowers 			get_ulong_attr_from_template(&modulus_len, &t[i]);
63*034448feSmcpowers 			/* convert from bit length to byte length */
64*034448feSmcpowers 			modulus_len = (modulus_len - 1) / 64 + 1;
65*034448feSmcpowers 			return (modulus_len * 8);
66*034448feSmcpowers 		}
67*034448feSmcpowers 	}
68*034448feSmcpowers 	return (0);
69*034448feSmcpowers }
70*034448feSmcpowers 
71*034448feSmcpowers /*
72*034448feSmcpowers  * Remove specified attribute from array. Storage for the attribute's
73*034448feSmcpowers  * value is freed if 'free_attr' is TRUE. Attributes are shifted so they are
74*034448feSmcpowers  * contiguous within the array, i.e. the next attribute is shifted into
75*034448feSmcpowers  * the position of the removed attribute. Returns TRUE if specified
76*034448feSmcpowers  * attribute is removed.
77*034448feSmcpowers  */
78*034448feSmcpowers static boolean_t
79*034448feSmcpowers remove_one_attribute(CK_ATTRIBUTE_PTR t, CK_ULONG type, uint_t count,
80*034448feSmcpowers     boolean_t free_attr)
81*034448feSmcpowers {
82*034448feSmcpowers 	int i, j;
83*034448feSmcpowers 
84*034448feSmcpowers 	for (i = 0, j = 0; i < count; i++) {
85*034448feSmcpowers 		if (t[i].type == type) {
86*034448feSmcpowers 			if (free_attr) {
87*034448feSmcpowers 				free(t[i].pValue);
88*034448feSmcpowers 			}
89*034448feSmcpowers 			continue;
90*034448feSmcpowers 		}
91*034448feSmcpowers 		if (i != j) {
92*034448feSmcpowers 			t[j].type = t[i].type;
93*034448feSmcpowers 			t[j].pValue = t[i].pValue;
94*034448feSmcpowers 			t[j].ulValueLen = t[i].ulValueLen;
95*034448feSmcpowers 		}
96*034448feSmcpowers 		j++;
97*034448feSmcpowers 	}
98*034448feSmcpowers 	if (j == count)
99*034448feSmcpowers 		return (B_FALSE);
100*034448feSmcpowers 
101*034448feSmcpowers 	/* safety */
102*034448feSmcpowers 	t[j].pValue = NULL;
103*034448feSmcpowers 	t[j].ulValueLen = 0;
104*034448feSmcpowers 	return (B_TRUE);
105*034448feSmcpowers }
106*034448feSmcpowers 
107*034448feSmcpowers static boolean_t
1087c478bd9Sstevel@tonic-gate is_secret_key_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate 	int i;
1117c478bd9Sstevel@tonic-gate 	for (i = 0; i < ulAttributeCount; i++) {
1127c478bd9Sstevel@tonic-gate 		if (pTemplate[i].type == CKA_CLASS &&
1137c478bd9Sstevel@tonic-gate 		    *(CK_OBJECT_CLASS *)(pTemplate[i].pValue) ==
1147c478bd9Sstevel@tonic-gate 		    CKO_SECRET_KEY)
1157c478bd9Sstevel@tonic-gate 			return (B_TRUE);
1167c478bd9Sstevel@tonic-gate 	}
1177c478bd9Sstevel@tonic-gate 	return (B_FALSE);
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
120*034448feSmcpowers /*
121*034448feSmcpowers  * Allocate a template with space for new_count entries and copy the
122*034448feSmcpowers  * specified template into the new template.
123*034448feSmcpowers  */
124*034448feSmcpowers static CK_ATTRIBUTE_PTR
125*034448feSmcpowers grow_template(CK_ATTRIBUTE_PTR old_template, CK_ULONG old_count,
126*034448feSmcpowers     CK_ULONG new_count)
127*034448feSmcpowers {
128*034448feSmcpowers 	CK_ATTRIBUTE_PTR new_template;
129*034448feSmcpowers 
130*034448feSmcpowers 	new_template = malloc(new_count * sizeof (CK_ATTRIBUTE));
131*034448feSmcpowers 	if (new_template != NULL)
132*034448feSmcpowers 		bcopy(old_template, new_template,
133*034448feSmcpowers 		    old_count * sizeof (CK_ATTRIBUTE));
134*034448feSmcpowers 	return (new_template);
135*034448feSmcpowers }
136*034448feSmcpowers 
137*034448feSmcpowers /*
138*034448feSmcpowers  * For fixed length keys such as DES, return the length based on
139*034448feSmcpowers  * the key type. For variable length keys such as AES, take the
140*034448feSmcpowers  * length from the CKA_VALUE_LEN attribute.
141*034448feSmcpowers  */
142*034448feSmcpowers static int
143*034448feSmcpowers get_key_len_from_template(CK_MECHANISM_PTR pMechanism,
144*034448feSmcpowers     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
145*034448feSmcpowers     kernel_object_t *basekey_p,  ulong_t *key_len)
146*034448feSmcpowers {
147*034448feSmcpowers 	boolean_t fixed_len_key = B_FALSE;
148*034448feSmcpowers 	ulong_t key_type;
149*034448feSmcpowers 	int i;
150*034448feSmcpowers 
151*034448feSmcpowers 	for (i = 0; i < ulAttributeCount; i++) {
152*034448feSmcpowers 		if (pTemplate[i].type == CKA_KEY_TYPE) {
153*034448feSmcpowers 			get_ulong_attr_from_template(&key_type, &pTemplate[i]);
154*034448feSmcpowers 			break;
155*034448feSmcpowers 		}
156*034448feSmcpowers 	}
157*034448feSmcpowers 	/* CKA_KEY_TYPE must be present */
158*034448feSmcpowers 	if (i == ulAttributeCount)
159*034448feSmcpowers 		return (CKR_TEMPLATE_INCOMPLETE);
160*034448feSmcpowers 
161*034448feSmcpowers 	switch (key_type) {
162*034448feSmcpowers 	case CKK_DES:
163*034448feSmcpowers 		*key_len = 8;
164*034448feSmcpowers 		fixed_len_key = B_TRUE;
165*034448feSmcpowers 		break;
166*034448feSmcpowers 	case CKK_DES3:
167*034448feSmcpowers 		*key_len = 24;
168*034448feSmcpowers 		fixed_len_key = B_TRUE;
169*034448feSmcpowers 		break;
170*034448feSmcpowers 	case CKK_AES:
171*034448feSmcpowers 	case CKK_BLOWFISH:
172*034448feSmcpowers 		for (i = 0; i < ulAttributeCount; i++) {
173*034448feSmcpowers 			if (pTemplate[i].type == CKA_VALUE_LEN) {
174*034448feSmcpowers 				get_ulong_attr_from_template(key_len,
175*034448feSmcpowers 				    &pTemplate[i]);
176*034448feSmcpowers 				break;
177*034448feSmcpowers 			}
178*034448feSmcpowers 		}
179*034448feSmcpowers 		/* CKA_VALUE_LEN must be present */
180*034448feSmcpowers 		if (i == ulAttributeCount)
181*034448feSmcpowers 			return (CKR_TEMPLATE_INCOMPLETE);
182*034448feSmcpowers 		break;
183*034448feSmcpowers 	case CKK_GENERIC_SECRET:
184*034448feSmcpowers 		/*
185*034448feSmcpowers 		 * The key will not be truncated, so we need to
186*034448feSmcpowers 		 * get the max length for the mechanism.
187*034448feSmcpowers 		 */
188*034448feSmcpowers 		if (pMechanism->mechanism == CKM_DH_PKCS_DERIVE) {
189*034448feSmcpowers 			CK_ATTRIBUTE tmp;
190*034448feSmcpowers 
191*034448feSmcpowers 			tmp.type = CKA_PRIME;
192*034448feSmcpowers 			tmp.pValue = NULL;
193*034448feSmcpowers 
194*034448feSmcpowers 			/* get size of attribute */
195*034448feSmcpowers 			if (kernel_get_attribute(basekey_p, &tmp) != CKR_OK) {
196*034448feSmcpowers 				return (CKR_ARGUMENTS_BAD);
197*034448feSmcpowers 			}
198*034448feSmcpowers 			*key_len = tmp.ulValueLen;
199*034448feSmcpowers 		} else {
200*034448feSmcpowers 			return (CKR_ARGUMENTS_BAD);
201*034448feSmcpowers 		}
202*034448feSmcpowers 		break;
203*034448feSmcpowers 	default:
204*034448feSmcpowers 		return (CKR_ATTRIBUTE_VALUE_INVALID);
205*034448feSmcpowers 	}
206*034448feSmcpowers 
207*034448feSmcpowers 	if (fixed_len_key && attribute_in_template(CKA_VALUE_LEN,
208*034448feSmcpowers 	    pTemplate, ulAttributeCount))
209*034448feSmcpowers 		return (CKR_TEMPLATE_INCONSISTENT);
210*034448feSmcpowers 
211*034448feSmcpowers 	return (CKR_OK);
212*034448feSmcpowers }
213*034448feSmcpowers 
214*034448feSmcpowers /* find specified attribute src template and copy to dest */
215*034448feSmcpowers static int
216*034448feSmcpowers copy_attribute(CK_ULONG type, CK_ATTRIBUTE_PTR src, CK_ULONG src_cnt,
217*034448feSmcpowers     CK_ATTRIBUTE_PTR dst)
218*034448feSmcpowers {
219*034448feSmcpowers 	int rv, i;
220*034448feSmcpowers 
221*034448feSmcpowers 	for (i = 0; i < src_cnt; i++) {
222*034448feSmcpowers 		if (src[i].type == type) {
223*034448feSmcpowers 			rv = get_string_from_template(dst, &src[i]);
224*034448feSmcpowers 			break;
225*034448feSmcpowers 		}
226*034448feSmcpowers 	}
227*034448feSmcpowers 	/*
228*034448feSmcpowers 	 * The public template didn't have attribute.
229*034448feSmcpowers 	 */
230*034448feSmcpowers 	if (i == src_cnt) {
231*034448feSmcpowers 		rv = CKR_TEMPLATE_INCOMPLETE;
232*034448feSmcpowers 	}
233*034448feSmcpowers 	return (rv);
234*034448feSmcpowers }
235*034448feSmcpowers 
236*034448feSmcpowers static void
237*034448feSmcpowers free_attributes(caddr_t p, uint_t *countp)
238*034448feSmcpowers {
239*034448feSmcpowers 	if (*countp > 0) {
240*034448feSmcpowers 		free_object_attributes(p, *countp);
241*034448feSmcpowers 		*countp = 0;
242*034448feSmcpowers 	}
243*034448feSmcpowers }
244*034448feSmcpowers 
245*034448feSmcpowers CK_RV
246*034448feSmcpowers key_gen_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
247*034448feSmcpowers     CK_ULONG ulCount, kernel_session_t *session_p,
248*034448feSmcpowers     crypto_mech_type_t k_mech_type, kernel_object_t *new_objp)
249*034448feSmcpowers {
250*034448feSmcpowers 	crypto_nostore_generate_key_t obj_ngk;
251*034448feSmcpowers 	char *key_buf = NULL;
252*034448feSmcpowers 	CK_ATTRIBUTE_PTR newTemplate = NULL;
253*034448feSmcpowers 	CK_BBOOL is_token_obj = FALSE;
254*034448feSmcpowers 	CK_RV rv = CKR_OK;
255*034448feSmcpowers 	ulong_t key_len = 0;
256*034448feSmcpowers 	uint_t attr_count;
257*034448feSmcpowers 	int r;
258*034448feSmcpowers 
259*034448feSmcpowers 	obj_ngk.ngk_in_count = 0;
260*034448feSmcpowers 	obj_ngk.ngk_out_count = 0;
261*034448feSmcpowers 
262*034448feSmcpowers 	rv = get_key_len_from_template(pMechanism, pTemplate, ulCount,
263*034448feSmcpowers 	    NULL, &key_len);
264*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS)
265*034448feSmcpowers 		goto failed_exit;
266*034448feSmcpowers 
267*034448feSmcpowers 	if ((key_buf = malloc(key_len)) == NULL) {
268*034448feSmcpowers 		rv = CKR_HOST_MEMORY;
269*034448feSmcpowers 		goto failed_exit;
270*034448feSmcpowers 	}
271*034448feSmcpowers 
272*034448feSmcpowers 	attr_count = ulCount + 1;
273*034448feSmcpowers 	newTemplate = grow_template(pTemplate, ulCount, attr_count);
274*034448feSmcpowers 	if (newTemplate == NULL) {
275*034448feSmcpowers 		rv = CKR_HOST_MEMORY;
276*034448feSmcpowers 		goto failed_exit;
277*034448feSmcpowers 	}
278*034448feSmcpowers 
279*034448feSmcpowers 	/* Now add the CKA_VALUE attribute to template */
280*034448feSmcpowers 	newTemplate[ulCount].type = CKA_VALUE;
281*034448feSmcpowers 	newTemplate[ulCount].pValue = (caddr_t)key_buf;
282*034448feSmcpowers 	newTemplate[ulCount].ulValueLen = key_len;
283*034448feSmcpowers 
284*034448feSmcpowers 	rv = process_object_attributes(newTemplate, attr_count - 1,
285*034448feSmcpowers 	    &obj_ngk.ngk_in_attributes, &is_token_obj);
286*034448feSmcpowers 	if (rv != CKR_OK) {
287*034448feSmcpowers 		goto failed_exit;
288*034448feSmcpowers 	}
289*034448feSmcpowers 	rv = process_object_attributes(&newTemplate[ulCount],
290*034448feSmcpowers 	    1, &obj_ngk.ngk_out_attributes, &is_token_obj);
291*034448feSmcpowers 	if (rv != CKR_OK) {
292*034448feSmcpowers 		goto failed_exit;
293*034448feSmcpowers 	}
294*034448feSmcpowers 
295*034448feSmcpowers 	/* Cannot create a token object with a READ-ONLY session. */
296*034448feSmcpowers 	if (is_token_obj && session_p->ses_RO) {
297*034448feSmcpowers 		rv = CKR_SESSION_READ_ONLY;
298*034448feSmcpowers 		goto failed_exit;
299*034448feSmcpowers 	}
300*034448feSmcpowers 
301*034448feSmcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY ioctl */
302*034448feSmcpowers 	obj_ngk.ngk_session = session_p->k_session;
303*034448feSmcpowers 	obj_ngk.ngk_in_count = attr_count - 1;
304*034448feSmcpowers 	obj_ngk.ngk_out_count = 1;
305*034448feSmcpowers 	obj_ngk.ngk_mechanism.cm_type = k_mech_type;
306*034448feSmcpowers 	obj_ngk.ngk_mechanism.cm_param = pMechanism->pParameter;
307*034448feSmcpowers 	obj_ngk.ngk_mechanism.cm_param_len = pMechanism->ulParameterLen;
308*034448feSmcpowers 
309*034448feSmcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY,
310*034448feSmcpowers 	    &obj_ngk)) < 0) {
311*034448feSmcpowers 		if (errno != EINTR)
312*034448feSmcpowers 			break;
313*034448feSmcpowers 	}
314*034448feSmcpowers 	if (r < 0) {
315*034448feSmcpowers 		rv = CKR_FUNCTION_FAILED;
316*034448feSmcpowers 	} else {
317*034448feSmcpowers 		rv = crypto2pkcs11_error_number(obj_ngk.ngk_return_value);
318*034448feSmcpowers 	}
319*034448feSmcpowers 	free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
320*034448feSmcpowers 	if (rv != CKR_OK) {
321*034448feSmcpowers 		goto failed_exit;
322*034448feSmcpowers 	}
323*034448feSmcpowers 
324*034448feSmcpowers 	rv = get_object_attributes(&newTemplate[ulCount], 1,
325*034448feSmcpowers 	    obj_ngk.ngk_out_attributes);
326*034448feSmcpowers 	free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
327*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
328*034448feSmcpowers 		goto failed_exit;
329*034448feSmcpowers 	}
330*034448feSmcpowers 
331*034448feSmcpowers 	/*
332*034448feSmcpowers 	 * CKA_VALUE_LEN is not stored with the secret key object,
333*034448feSmcpowers 	 * so we remove it by shifting attributes down one.
334*034448feSmcpowers 	 */
335*034448feSmcpowers 	(void) remove_one_attribute(newTemplate, CKA_VALUE_LEN,
336*034448feSmcpowers 	    attr_count, B_FALSE);
337*034448feSmcpowers 
338*034448feSmcpowers 	rv = kernel_build_object(newTemplate, attr_count - 1,
339*034448feSmcpowers 	    new_objp, session_p, KERNEL_GEN_KEY);
340*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
341*034448feSmcpowers 		goto failed_exit;
342*034448feSmcpowers 	}
343*034448feSmcpowers 	new_objp->is_lib_obj = B_TRUE;
344*034448feSmcpowers 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
345*034448feSmcpowers 	(void) free(newTemplate);
346*034448feSmcpowers 	bzero(key_buf, key_len);
347*034448feSmcpowers 	(void) free(key_buf);
348*034448feSmcpowers 	return (CKR_OK);
349*034448feSmcpowers 
350*034448feSmcpowers failed_exit:
351*034448feSmcpowers 	free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
352*034448feSmcpowers 	free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
353*034448feSmcpowers 	if (key_buf != NULL) {
354*034448feSmcpowers 		bzero(key_buf, key_len);
355*034448feSmcpowers 		(void) free(key_buf);
356*034448feSmcpowers 	}
357*034448feSmcpowers 	if (newTemplate != NULL) {
358*034448feSmcpowers 		(void) free(newTemplate);
359*034448feSmcpowers 	}
360*034448feSmcpowers 	return (rv);
361*034448feSmcpowers }
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate CK_RV
3647c478bd9Sstevel@tonic-gate C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
3657c478bd9Sstevel@tonic-gate     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
3687c478bd9Sstevel@tonic-gate 	kernel_session_t	*session_p;
3697c478bd9Sstevel@tonic-gate 	kernel_object_t		*new_objp = NULL;
3707c478bd9Sstevel@tonic-gate 	kernel_slot_t		*pslot;
3717c478bd9Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
3727c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj;
3737c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_token_obj = FALSE;
3747c478bd9Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
3757c478bd9Sstevel@tonic-gate 	int r;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
3787c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	/* Obtain the session pointer */
3817c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
3827c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
3837c478bd9Sstevel@tonic-gate 		return (rv);
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	if ((pMechanism == NULL) || (phKey == NULL)) {
3867c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
3877c478bd9Sstevel@tonic-gate 		goto failed_exit;
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	if ((pTemplate == NULL) && (ulCount != 0)) {
3917c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
3927c478bd9Sstevel@tonic-gate 		goto failed_exit;
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
3967c478bd9Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
3977c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
3987c478bd9Sstevel@tonic-gate 		goto failed_exit;
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	/* Create an object wrapper in the library first */
4027c478bd9Sstevel@tonic-gate 	new_objp = calloc(1, sizeof (kernel_object_t));
4037c478bd9Sstevel@tonic-gate 	if (new_objp == NULL) {
4047c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
4057c478bd9Sstevel@tonic-gate 		goto failed_exit;
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 
408*034448feSmcpowers 	/*
409*034448feSmcpowers 	 * Special Case: if token does not support object creation,
410*034448feSmcpowers 	 * but does support key generation by value, then create a session
411*034448feSmcpowers 	 * object and initialize with value returned by token.
412*034448feSmcpowers 	 */
413*034448feSmcpowers 	pslot = slot_table[session_p->ses_slotid];
414*034448feSmcpowers 	if (!pslot->sl_func_list.fl_object_create) {
415*034448feSmcpowers 		rv = key_gen_by_value(pMechanism, pTemplate, ulCount, session_p,
416*034448feSmcpowers 		    k_mech_type, new_objp);
417*034448feSmcpowers 		if (rv != CKR_OK)
418*034448feSmcpowers 			goto failed_exit;
419*034448feSmcpowers 	} else {
420*034448feSmcpowers 		crypto_object_generate_key_t obj_gk;
421*034448feSmcpowers 
4227c478bd9Sstevel@tonic-gate 		/* Process the attributes */
4237c478bd9Sstevel@tonic-gate 		rv = process_object_attributes(pTemplate, ulCount,
4247c478bd9Sstevel@tonic-gate 		    &obj_gk.gk_attributes, &is_token_obj);
4257c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
4267c478bd9Sstevel@tonic-gate 			goto failed_exit;
4277c478bd9Sstevel@tonic-gate 		}
4287c478bd9Sstevel@tonic-gate 		/* Cannot create a token object with a READ-ONLY session. */
4297c478bd9Sstevel@tonic-gate 		if (is_token_obj && session_p->ses_RO) {
4307c478bd9Sstevel@tonic-gate 			free_object_attributes(obj_gk.gk_attributes, ulCount);
4317c478bd9Sstevel@tonic-gate 			rv = CKR_SESSION_READ_ONLY;
4327c478bd9Sstevel@tonic-gate 			goto failed_exit;
4337c478bd9Sstevel@tonic-gate 		}
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 		/* Call the CRYPTO_GENERATE_KEY ioctl */
4367c478bd9Sstevel@tonic-gate 		obj_gk.gk_session = session_p->k_session;
4377c478bd9Sstevel@tonic-gate 		obj_gk.gk_count = ulCount;
4387c478bd9Sstevel@tonic-gate 		obj_gk.gk_mechanism.cm_type = k_mech_type;
4397c478bd9Sstevel@tonic-gate 		obj_gk.gk_mechanism.cm_param = pMechanism->pParameter;
4407c478bd9Sstevel@tonic-gate 		obj_gk.gk_mechanism.cm_param_len = pMechanism->ulParameterLen;
4417c478bd9Sstevel@tonic-gate 
442*034448feSmcpowers 		while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY,
443*034448feSmcpowers 		    &obj_gk)) < 0) {
4447c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
4457c478bd9Sstevel@tonic-gate 				break;
4467c478bd9Sstevel@tonic-gate 		}
4477c478bd9Sstevel@tonic-gate 		if (r < 0) {
4487c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
4497c478bd9Sstevel@tonic-gate 		} else {
4507c478bd9Sstevel@tonic-gate 			rv = crypto2pkcs11_error_number(obj_gk.gk_return_value);
4517c478bd9Sstevel@tonic-gate 		}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 		free_object_attributes(obj_gk.gk_attributes, ulCount);
454*034448feSmcpowers 
4557c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
4567c478bd9Sstevel@tonic-gate 			goto failed_exit;
4577c478bd9Sstevel@tonic-gate 		}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 		/* Get the value of the CKA_PRIVATE attribute. */
460*034448feSmcpowers 		rv = get_cka_private_value(session_p, obj_gk.gk_handle,
461*034448feSmcpowers 		    &is_pri_obj);
4627c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
4637c478bd9Sstevel@tonic-gate 			goto failed_exit;
4647c478bd9Sstevel@tonic-gate 		}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		/*
4677c478bd9Sstevel@tonic-gate 		 * Store the kernel object handle in the object wrapper and
4687c478bd9Sstevel@tonic-gate 		 * initialize the library object.
4697c478bd9Sstevel@tonic-gate 		 */
4707c478bd9Sstevel@tonic-gate 		new_objp->k_handle = obj_gk.gk_handle;
4717c478bd9Sstevel@tonic-gate 		new_objp->is_lib_obj = B_FALSE;
4727c478bd9Sstevel@tonic-gate 		new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
4737c478bd9Sstevel@tonic-gate 		new_objp->extra_attrlistp = NULL;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 		if (is_pri_obj)
4767c478bd9Sstevel@tonic-gate 			new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
4777c478bd9Sstevel@tonic-gate 		else
4787c478bd9Sstevel@tonic-gate 			new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 		if (is_token_obj)
4817c478bd9Sstevel@tonic-gate 			new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
4827c478bd9Sstevel@tonic-gate 		else
4837c478bd9Sstevel@tonic-gate 			new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
484*034448feSmcpowers 	}
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
4877c478bd9Sstevel@tonic-gate 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	/*
4907c478bd9Sstevel@tonic-gate 	 * Add the new object to the slot's token object list if it is a
4917c478bd9Sstevel@tonic-gate 	 * a token object. Otherwise, add it to the session's object list.
4927c478bd9Sstevel@tonic-gate 	 */
4937c478bd9Sstevel@tonic-gate 	if (is_token_obj) {
4947c478bd9Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
4957c478bd9Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_objp, pslot);
4967c478bd9Sstevel@tonic-gate 	} else {
4977c478bd9Sstevel@tonic-gate 		kernel_add_object_to_session(new_objp, session_p);
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	*phKey = (CK_OBJECT_HANDLE)new_objp;
5017c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
5027c478bd9Sstevel@tonic-gate 	return (rv);
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate failed_exit:
5057c478bd9Sstevel@tonic-gate 	if (new_objp != NULL) {
5067c478bd9Sstevel@tonic-gate 		(void) free(new_objp);
5077c478bd9Sstevel@tonic-gate 	}
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
5107c478bd9Sstevel@tonic-gate 	return (rv);
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate 
513*034448feSmcpowers CK_RV
514*034448feSmcpowers key_gen_rsa_by_value(CK_MECHANISM_PTR pMechanism,
515*034448feSmcpowers     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
516*034448feSmcpowers     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
517*034448feSmcpowers     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
518*034448feSmcpowers     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
519*034448feSmcpowers {
520*034448feSmcpowers 	crypto_nostore_generate_key_pair_t obj_nkp;
521*034448feSmcpowers 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
522*034448feSmcpowers 	CK_ATTRIBUTE_PTR priTemplate = NULL;
523*034448feSmcpowers 	CK_RV rv = CKR_OK;
524*034448feSmcpowers 	CK_BBOOL is_token_obj1 = FALSE;
525*034448feSmcpowers 	CK_BBOOL is_token_obj2 = FALSE;
526*034448feSmcpowers 	uint_t pub_attr_count, pri_attr_count;
527*034448feSmcpowers 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
528*034448feSmcpowers 	char public_modulus[512];
529*034448feSmcpowers 	char public_exponent[8];
530*034448feSmcpowers 	char private_exponent[512];
531*034448feSmcpowers 	char private_modulus[512];
532*034448feSmcpowers 	char prime_1[512];
533*034448feSmcpowers 	char prime_2[512];
534*034448feSmcpowers 	char exponent_1[512];
535*034448feSmcpowers 	char exponent_2[512];
536*034448feSmcpowers 	char coefficient[512];
537*034448feSmcpowers 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
538*034448feSmcpowers 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
539*034448feSmcpowers 	CK_ULONG key_type;
540*034448feSmcpowers 	CK_ULONG modulus_bytes;
541*034448feSmcpowers 	boolean_t has_class, has_key_type, has_pub_exponent;
542*034448feSmcpowers 	int n, r;
543*034448feSmcpowers 
544*034448feSmcpowers 	obj_nkp.nkp_in_public_count = 0;
545*034448feSmcpowers 	obj_nkp.nkp_out_public_count = 0;
546*034448feSmcpowers 	obj_nkp.nkp_in_private_count = 0;
547*034448feSmcpowers 	obj_nkp.nkp_out_private_count = 0;
548*034448feSmcpowers 
549*034448feSmcpowers 	/* modulus bits must be present when generating a RSA key pair */
550*034448feSmcpowers 	if (!attribute_in_template(CKA_MODULUS_BITS, pPublicKeyTemplate,
551*034448feSmcpowers 	    ulPublicKeyAttributeCount)) {
552*034448feSmcpowers 		rv = CKR_TEMPLATE_INCOMPLETE;
553*034448feSmcpowers 		goto failed_exit;
554*034448feSmcpowers 	}
555*034448feSmcpowers 
556*034448feSmcpowers 	modulus_bytes = get_modulus_bytes(pPublicKeyTemplate,
557*034448feSmcpowers 	    ulPublicKeyAttributeCount);
558*034448feSmcpowers 
559*034448feSmcpowers 	/*
560*034448feSmcpowers 	 * Add CKA_MODULUS to the public template.
561*034448feSmcpowers 	 * This attribute must not be in the template.
562*034448feSmcpowers 	 */
563*034448feSmcpowers 	if (attribute_in_template(CKA_MODULUS, pPublicKeyTemplate,
564*034448feSmcpowers 	    ulPublicKeyAttributeCount)) {
565*034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
566*034448feSmcpowers 		goto failed_exit;
567*034448feSmcpowers 	}
568*034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
569*034448feSmcpowers 	    ulPublicKeyAttributeCount);
570*034448feSmcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
571*034448feSmcpowers 	    ulPublicKeyAttributeCount);
572*034448feSmcpowers 	has_pub_exponent = attribute_in_template(CKA_PUBLIC_EXPONENT,
573*034448feSmcpowers 	    pPublicKeyTemplate, ulPublicKeyAttributeCount);
574*034448feSmcpowers 
575*034448feSmcpowers 	pub_attr_count = ulPublicKeyAttributeCount + 1;
576*034448feSmcpowers 	if (!has_class)
577*034448feSmcpowers 		pub_attr_count++;
578*034448feSmcpowers 	if (!has_key_type)
579*034448feSmcpowers 		pub_attr_count++;
580*034448feSmcpowers 	if (!has_pub_exponent)
581*034448feSmcpowers 		pub_attr_count++;
582*034448feSmcpowers 	pubTemplate = grow_template(pPublicKeyTemplate,
583*034448feSmcpowers 	    ulPublicKeyAttributeCount, pub_attr_count);
584*034448feSmcpowers 	if (pubTemplate == NULL) {
585*034448feSmcpowers 		rv = CKR_HOST_MEMORY;
586*034448feSmcpowers 		goto failed_exit;
587*034448feSmcpowers 	}
588*034448feSmcpowers 
589*034448feSmcpowers 	n = ulPublicKeyAttributeCount;
590*034448feSmcpowers 	if (!has_class) {
591*034448feSmcpowers 		pubTemplate[n].type = CKA_CLASS;
592*034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)&pub_class;
593*034448feSmcpowers 		pubTemplate[n].ulValueLen = sizeof (pub_class);
594*034448feSmcpowers 		n++;
595*034448feSmcpowers 	}
596*034448feSmcpowers 	if (!has_key_type) {
597*034448feSmcpowers 		pubTemplate[n].type = CKA_KEY_TYPE;
598*034448feSmcpowers 		key_type = CKK_RSA;
599*034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)&key_type;
600*034448feSmcpowers 		pubTemplate[n].ulValueLen = sizeof (key_type);
601*034448feSmcpowers 		n++;
602*034448feSmcpowers 	}
603*034448feSmcpowers 	if (!has_pub_exponent) {
604*034448feSmcpowers 		pubTemplate[n].type = CKA_PUBLIC_EXPONENT;
605*034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)public_exponent;
606*034448feSmcpowers 		pubTemplate[n].ulValueLen = modulus_bytes;
607*034448feSmcpowers 		n++;
608*034448feSmcpowers 		pub_out_attr_count++;
609*034448feSmcpowers 	}
610*034448feSmcpowers 	pubTemplate[n].type = CKA_MODULUS;
611*034448feSmcpowers 	pubTemplate[n].pValue = (caddr_t)public_modulus;
612*034448feSmcpowers 	pubTemplate[n].ulValueLen = modulus_bytes;
613*034448feSmcpowers 	pub_out_attr_count++;
614*034448feSmcpowers 
615*034448feSmcpowers 	rv = process_object_attributes(pubTemplate,
616*034448feSmcpowers 	    pub_attr_count - pub_out_attr_count,
617*034448feSmcpowers 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
618*034448feSmcpowers 	if (rv != CKR_OK) {
619*034448feSmcpowers 		goto failed_exit;
620*034448feSmcpowers 	}
621*034448feSmcpowers 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
622*034448feSmcpowers 
623*034448feSmcpowers 	rv = process_object_attributes(
624*034448feSmcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
625*034448feSmcpowers 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
626*034448feSmcpowers 	    &is_token_obj1);
627*034448feSmcpowers 	if (rv != CKR_OK) {
628*034448feSmcpowers 		goto failed_exit;
629*034448feSmcpowers 	}
630*034448feSmcpowers 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
631*034448feSmcpowers 
632*034448feSmcpowers 	/*
633*034448feSmcpowers 	 * Cannot create a token object with a READ-ONLY
634*034448feSmcpowers 	 * session.
635*034448feSmcpowers 	 */
636*034448feSmcpowers 	if (is_token_obj1 && session_p->ses_RO) {
637*034448feSmcpowers 		rv = CKR_SESSION_READ_ONLY;
638*034448feSmcpowers 		goto failed_exit;
639*034448feSmcpowers 	}
640*034448feSmcpowers 
641*034448feSmcpowers 	/*
642*034448feSmcpowers 	 * Add CKA_MODULUS and CKA_PRIVATE_EXPONENT
643*034448feSmcpowers 	 * to the private template. These attributes
644*034448feSmcpowers 	 * must not be in the template.
645*034448feSmcpowers 	 */
646*034448feSmcpowers 	if (attribute_in_template(CKA_PRIVATE_EXPONENT,
647*034448feSmcpowers 	    pPrivateKeyTemplate, ulPrivateKeyAttributeCount) ||
648*034448feSmcpowers 	    attribute_in_template(CKA_MODULUS,
649*034448feSmcpowers 	    pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) {
650*034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
651*034448feSmcpowers 		goto failed_exit;
652*034448feSmcpowers 	}
653*034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
654*034448feSmcpowers 	    ulPrivateKeyAttributeCount);
655*034448feSmcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
656*034448feSmcpowers 	    ulPrivateKeyAttributeCount);
657*034448feSmcpowers 
658*034448feSmcpowers 	pri_attr_count = ulPrivateKeyAttributeCount + 7;
659*034448feSmcpowers 	if (!has_class)
660*034448feSmcpowers 		pri_attr_count++;
661*034448feSmcpowers 	if (!has_key_type)
662*034448feSmcpowers 		pri_attr_count++;
663*034448feSmcpowers 
664*034448feSmcpowers 	/* allocate space for CKA_PUBLIC_EXPONENT */
665*034448feSmcpowers 	priTemplate = grow_template(pPrivateKeyTemplate,
666*034448feSmcpowers 	    ulPrivateKeyAttributeCount, pri_attr_count + 1);
667*034448feSmcpowers 	if (priTemplate == NULL) {
668*034448feSmcpowers 		rv = CKR_HOST_MEMORY;
669*034448feSmcpowers 		goto failed_exit;
670*034448feSmcpowers 	}
671*034448feSmcpowers 	n = ulPrivateKeyAttributeCount;
672*034448feSmcpowers 	if (!has_class) {
673*034448feSmcpowers 		priTemplate[n].type = CKA_CLASS;
674*034448feSmcpowers 		priTemplate[n].pValue = (caddr_t)&pri_class;
675*034448feSmcpowers 		priTemplate[n].ulValueLen = sizeof (pri_class);
676*034448feSmcpowers 		n++;
677*034448feSmcpowers 	}
678*034448feSmcpowers 	if (!has_key_type) {
679*034448feSmcpowers 		priTemplate[n].type = CKA_KEY_TYPE;
680*034448feSmcpowers 		key_type = CKK_RSA;
681*034448feSmcpowers 		priTemplate[n].pValue = (caddr_t)&key_type;
682*034448feSmcpowers 		priTemplate[n].ulValueLen = sizeof (key_type);
683*034448feSmcpowers 		n++;
684*034448feSmcpowers 	}
685*034448feSmcpowers 	priTemplate[n].type = CKA_MODULUS;
686*034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)private_modulus;
687*034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes;
688*034448feSmcpowers 	pri_out_attr_count++;
689*034448feSmcpowers 
690*034448feSmcpowers 	n++;
691*034448feSmcpowers 	priTemplate[n].type = CKA_PRIVATE_EXPONENT;
692*034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)private_exponent;
693*034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes;
694*034448feSmcpowers 	pri_out_attr_count++;
695*034448feSmcpowers 
696*034448feSmcpowers 	n++;
697*034448feSmcpowers 	priTemplate[n].type = CKA_PRIME_1;
698*034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)prime_1;
699*034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
700*034448feSmcpowers 	pri_out_attr_count++;
701*034448feSmcpowers 
702*034448feSmcpowers 	n++;
703*034448feSmcpowers 	priTemplate[n].type = CKA_PRIME_2;
704*034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)prime_2;
705*034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
706*034448feSmcpowers 	pri_out_attr_count++;
707*034448feSmcpowers 
708*034448feSmcpowers 	n++;
709*034448feSmcpowers 	priTemplate[n].type = CKA_EXPONENT_1;
710*034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)exponent_1;
711*034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
712*034448feSmcpowers 	pri_out_attr_count++;
713*034448feSmcpowers 
714*034448feSmcpowers 	n++;
715*034448feSmcpowers 	priTemplate[n].type = CKA_EXPONENT_2;
716*034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)exponent_2;
717*034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
718*034448feSmcpowers 	pri_out_attr_count++;
719*034448feSmcpowers 
720*034448feSmcpowers 	n++;
721*034448feSmcpowers 	priTemplate[n].type = CKA_COEFFICIENT;
722*034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)coefficient;
723*034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
724*034448feSmcpowers 	pri_out_attr_count++;
725*034448feSmcpowers 
726*034448feSmcpowers 	rv = process_object_attributes(priTemplate,
727*034448feSmcpowers 	    pri_attr_count - pri_out_attr_count,
728*034448feSmcpowers 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
729*034448feSmcpowers 	if (rv != CKR_OK) {
730*034448feSmcpowers 		goto failed_exit;
731*034448feSmcpowers 	}
732*034448feSmcpowers 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
733*034448feSmcpowers 
734*034448feSmcpowers 	rv = process_object_attributes(
735*034448feSmcpowers 	    &priTemplate[pri_attr_count - pri_out_attr_count],
736*034448feSmcpowers 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
737*034448feSmcpowers 	    &is_token_obj2);
738*034448feSmcpowers 	if (rv != CKR_OK) {
739*034448feSmcpowers 		goto failed_exit;
740*034448feSmcpowers 	}
741*034448feSmcpowers 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
742*034448feSmcpowers 
743*034448feSmcpowers 	/*
744*034448feSmcpowers 	 * The public key and the private key need to contain the same
745*034448feSmcpowers 	 * attribute values for CKA_TOKEN.
746*034448feSmcpowers 	 */
747*034448feSmcpowers 	if (is_token_obj1 != is_token_obj2) {
748*034448feSmcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
749*034448feSmcpowers 		goto failed_exit;
750*034448feSmcpowers 	}
751*034448feSmcpowers 
752*034448feSmcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
753*034448feSmcpowers 	obj_nkp.nkp_session = session_p-> k_session;
754*034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
755*034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
756*034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
757*034448feSmcpowers 
758*034448feSmcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
759*034448feSmcpowers 	    &obj_nkp)) < 0) {
760*034448feSmcpowers 		if (errno != EINTR)
761*034448feSmcpowers 			break;
762*034448feSmcpowers 	}
763*034448feSmcpowers 	if (r < 0) {
764*034448feSmcpowers 		rv = CKR_FUNCTION_FAILED;
765*034448feSmcpowers 	} else {
766*034448feSmcpowers 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
767*034448feSmcpowers 	}
768*034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
769*034448feSmcpowers 	    &obj_nkp.nkp_in_public_count);
770*034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
771*034448feSmcpowers 	    &obj_nkp.nkp_in_private_count);
772*034448feSmcpowers 
773*034448feSmcpowers 	if (rv != CKR_OK) {
774*034448feSmcpowers 		goto failed_exit;
775*034448feSmcpowers 	}
776*034448feSmcpowers 
777*034448feSmcpowers 	rv = get_object_attributes(
778*034448feSmcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
779*034448feSmcpowers 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
780*034448feSmcpowers 	if (rv == CRYPTO_SUCCESS) {
781*034448feSmcpowers 		rv = get_object_attributes(
782*034448feSmcpowers 		    &priTemplate[pri_attr_count - pri_out_attr_count],
783*034448feSmcpowers 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
784*034448feSmcpowers 	}
785*034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
786*034448feSmcpowers 	    &obj_nkp.nkp_out_public_count);
787*034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
788*034448feSmcpowers 	    &obj_nkp.nkp_out_private_count);
789*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
790*034448feSmcpowers 		goto failed_exit;
791*034448feSmcpowers 	}
792*034448feSmcpowers 
793*034448feSmcpowers 	/* store generated modulus and public exponent */
794*034448feSmcpowers 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
795*034448feSmcpowers 	    session_p, KERNEL_GEN_KEY);
796*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
797*034448feSmcpowers 		goto failed_exit;
798*034448feSmcpowers 	}
799*034448feSmcpowers 
800*034448feSmcpowers 	/*
801*034448feSmcpowers 	 * Copy CKA_PUBLIC_EXPONENT from the public template
802*034448feSmcpowers 	 * to the private template.
803*034448feSmcpowers 	 */
804*034448feSmcpowers 	rv = copy_attribute(CKA_PUBLIC_EXPONENT, pubTemplate,
805*034448feSmcpowers 	    pub_attr_count, &priTemplate[pri_attr_count]);
806*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
807*034448feSmcpowers 		goto failed_exit;
808*034448feSmcpowers 	}
809*034448feSmcpowers 
810*034448feSmcpowers 	rv = kernel_build_object(priTemplate, pri_attr_count + 1, new_pri_objp,
811*034448feSmcpowers 	    session_p, KERNEL_GEN_KEY);
812*034448feSmcpowers 	(void) free(priTemplate[pri_attr_count].pValue);
813*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
814*034448feSmcpowers 		goto failed_exit;
815*034448feSmcpowers 	}
816*034448feSmcpowers 	(void) free(pubTemplate);
817*034448feSmcpowers 	(void) free(priTemplate);
818*034448feSmcpowers 
819*034448feSmcpowers 	new_pub_objp->is_lib_obj = B_TRUE;
820*034448feSmcpowers 	new_pri_objp->is_lib_obj = B_TRUE;
821*034448feSmcpowers 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
822*034448feSmcpowers 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
823*034448feSmcpowers 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
824*034448feSmcpowers 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
825*034448feSmcpowers 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
826*034448feSmcpowers 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
827*034448feSmcpowers 	return (CKR_OK);
828*034448feSmcpowers 
829*034448feSmcpowers failed_exit:
830*034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
831*034448feSmcpowers 	    &obj_nkp.nkp_in_public_count);
832*034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
833*034448feSmcpowers 	    &obj_nkp.nkp_out_public_count);
834*034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
835*034448feSmcpowers 	    &obj_nkp.nkp_in_private_count);
836*034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
837*034448feSmcpowers 	    &obj_nkp.nkp_out_private_count);
838*034448feSmcpowers 	if (pubTemplate != NULL) {
839*034448feSmcpowers 		(void) free(pubTemplate);
840*034448feSmcpowers 	}
841*034448feSmcpowers 	if (priTemplate != NULL) {
842*034448feSmcpowers 		(void) free(priTemplate);
843*034448feSmcpowers 	}
844*034448feSmcpowers 	return (rv);
845*034448feSmcpowers }
846*034448feSmcpowers 
847*034448feSmcpowers CK_RV
848*034448feSmcpowers key_gen_dh_by_value(CK_MECHANISM_PTR pMechanism,
849*034448feSmcpowers     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
850*034448feSmcpowers     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
851*034448feSmcpowers     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
852*034448feSmcpowers     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
853*034448feSmcpowers {
854*034448feSmcpowers 	crypto_nostore_generate_key_pair_t obj_nkp;
855*034448feSmcpowers 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
856*034448feSmcpowers 	CK_ATTRIBUTE_PTR priTemplate = NULL;
857*034448feSmcpowers 	CK_RV rv = CKR_OK;
858*034448feSmcpowers 	CK_BBOOL is_token_obj1 = FALSE;
859*034448feSmcpowers 	CK_BBOOL is_token_obj2 = FALSE;
860*034448feSmcpowers 	uint_t pub_attr_count, pri_attr_count;
861*034448feSmcpowers 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
862*034448feSmcpowers 	char public_value[256];
863*034448feSmcpowers 	char private_value[256];
864*034448feSmcpowers 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
865*034448feSmcpowers 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
866*034448feSmcpowers 	CK_ULONG key_type;
867*034448feSmcpowers 	boolean_t has_class, has_key_type;
868*034448feSmcpowers 	int n, r;
869*034448feSmcpowers 
870*034448feSmcpowers 	obj_nkp.nkp_in_public_count = 0;
871*034448feSmcpowers 	obj_nkp.nkp_out_public_count = 0;
872*034448feSmcpowers 	obj_nkp.nkp_in_private_count = 0;
873*034448feSmcpowers 	obj_nkp.nkp_out_private_count = 0;
874*034448feSmcpowers 
875*034448feSmcpowers 	/*
876*034448feSmcpowers 	 * Add CKA_VALUE to the public template.
877*034448feSmcpowers 	 * This attribute must not be in the template.
878*034448feSmcpowers 	 */
879*034448feSmcpowers 	if (attribute_in_template(CKA_VALUE, pPublicKeyTemplate,
880*034448feSmcpowers 	    ulPublicKeyAttributeCount)) {
881*034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
882*034448feSmcpowers 		goto failed_exit;
883*034448feSmcpowers 	}
884*034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
885*034448feSmcpowers 	    ulPublicKeyAttributeCount);
886*034448feSmcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
887*034448feSmcpowers 	    ulPublicKeyAttributeCount);
888*034448feSmcpowers 
889*034448feSmcpowers 	pub_attr_count = ulPublicKeyAttributeCount + 1;
890*034448feSmcpowers 	if (!has_class)
891*034448feSmcpowers 		pub_attr_count++;
892*034448feSmcpowers 	if (!has_key_type)
893*034448feSmcpowers 		pub_attr_count++;
894*034448feSmcpowers 	pubTemplate = grow_template(pPublicKeyTemplate,
895*034448feSmcpowers 	    ulPublicKeyAttributeCount, pub_attr_count);
896*034448feSmcpowers 	if (pubTemplate == NULL) {
897*034448feSmcpowers 		rv = CKR_HOST_MEMORY;
898*034448feSmcpowers 		goto failed_exit;
899*034448feSmcpowers 	}
900*034448feSmcpowers 
901*034448feSmcpowers 	n = ulPublicKeyAttributeCount;
902*034448feSmcpowers 	if (!has_class) {
903*034448feSmcpowers 		pubTemplate[n].type = CKA_CLASS;
904*034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)&pub_class;
905*034448feSmcpowers 		pubTemplate[n].ulValueLen = sizeof (pub_class);
906*034448feSmcpowers 		n++;
907*034448feSmcpowers 	}
908*034448feSmcpowers 	if (!has_key_type) {
909*034448feSmcpowers 		pubTemplate[n].type = CKA_KEY_TYPE;
910*034448feSmcpowers 		key_type = CKK_DH;
911*034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)&key_type;
912*034448feSmcpowers 		pubTemplate[n].ulValueLen = sizeof (key_type);
913*034448feSmcpowers 		n++;
914*034448feSmcpowers 	}
915*034448feSmcpowers 	pubTemplate[n].type = CKA_VALUE;
916*034448feSmcpowers 	pubTemplate[n].pValue = (caddr_t)public_value;
917*034448feSmcpowers 	pubTemplate[n].ulValueLen = sizeof (public_value);
918*034448feSmcpowers 	pub_out_attr_count++;
919*034448feSmcpowers 
920*034448feSmcpowers 	rv = process_object_attributes(pubTemplate,
921*034448feSmcpowers 	    pub_attr_count - pub_out_attr_count,
922*034448feSmcpowers 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
923*034448feSmcpowers 	if (rv != CKR_OK) {
924*034448feSmcpowers 		goto failed_exit;
925*034448feSmcpowers 	}
926*034448feSmcpowers 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
927*034448feSmcpowers 
928*034448feSmcpowers 	rv = process_object_attributes(
929*034448feSmcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
930*034448feSmcpowers 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
931*034448feSmcpowers 	    &is_token_obj1);
932*034448feSmcpowers 	if (rv != CKR_OK) {
933*034448feSmcpowers 		goto failed_exit;
934*034448feSmcpowers 	}
935*034448feSmcpowers 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
936*034448feSmcpowers 
937*034448feSmcpowers 	/*
938*034448feSmcpowers 	 * Cannot create a token object with a READ-ONLY
939*034448feSmcpowers 	 * session.
940*034448feSmcpowers 	 */
941*034448feSmcpowers 	if (is_token_obj1 && session_p->ses_RO) {
942*034448feSmcpowers 		rv = CKR_SESSION_READ_ONLY;
943*034448feSmcpowers 		goto failed_exit;
944*034448feSmcpowers 	}
945*034448feSmcpowers 
946*034448feSmcpowers 	/*
947*034448feSmcpowers 	 * CKA_BASE, CKA_PRIME, and CKA_VALUE must not appear
948*034448feSmcpowers 	 * in private template.
949*034448feSmcpowers 	 */
950*034448feSmcpowers 	if (attribute_in_template(CKA_BASE, pPrivateKeyTemplate,
951*034448feSmcpowers 	    ulPrivateKeyAttributeCount) ||
952*034448feSmcpowers 	    attribute_in_template(CKA_PRIME, pPrivateKeyTemplate,
953*034448feSmcpowers 	    ulPrivateKeyAttributeCount) ||
954*034448feSmcpowers 	    attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
955*034448feSmcpowers 	    ulPrivateKeyAttributeCount)) {
956*034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
957*034448feSmcpowers 		goto failed_exit;
958*034448feSmcpowers 	}
959*034448feSmcpowers 
960*034448feSmcpowers 	if (attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
961*034448feSmcpowers 	    ulPrivateKeyAttributeCount)) {
962*034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
963*034448feSmcpowers 		goto failed_exit;
964*034448feSmcpowers 	}
965*034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
966*034448feSmcpowers 	    ulPrivateKeyAttributeCount);
967*034448feSmcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
968*034448feSmcpowers 	    ulPrivateKeyAttributeCount);
969*034448feSmcpowers 
970*034448feSmcpowers 	pri_attr_count = ulPrivateKeyAttributeCount + 1;
971*034448feSmcpowers 	if (!has_class)
972*034448feSmcpowers 		pri_attr_count++;
973*034448feSmcpowers 	if (!has_key_type)
974*034448feSmcpowers 		pri_attr_count++;
975*034448feSmcpowers 
976*034448feSmcpowers 	/* allocate space for CKA_BASE and CKA_PRIME */
977*034448feSmcpowers 	priTemplate = grow_template(pPrivateKeyTemplate,
978*034448feSmcpowers 	    ulPrivateKeyAttributeCount, pri_attr_count + 2);
979*034448feSmcpowers 	if (priTemplate == NULL) {
980*034448feSmcpowers 		rv = CKR_HOST_MEMORY;
981*034448feSmcpowers 		goto failed_exit;
982*034448feSmcpowers 	}
983*034448feSmcpowers 	n = ulPrivateKeyAttributeCount;
984*034448feSmcpowers 	if (!has_class) {
985*034448feSmcpowers 		priTemplate[n].type = CKA_CLASS;
986*034448feSmcpowers 		priTemplate[n].pValue = (caddr_t)&pri_class;
987*034448feSmcpowers 		priTemplate[n].ulValueLen = sizeof (pri_class);
988*034448feSmcpowers 		n++;
989*034448feSmcpowers 	}
990*034448feSmcpowers 	if (!has_key_type) {
991*034448feSmcpowers 		priTemplate[n].type = CKA_KEY_TYPE;
992*034448feSmcpowers 		key_type = CKK_DH;
993*034448feSmcpowers 		priTemplate[n].pValue = (caddr_t)&key_type;
994*034448feSmcpowers 		priTemplate[n].ulValueLen = sizeof (key_type);
995*034448feSmcpowers 		n++;
996*034448feSmcpowers 	}
997*034448feSmcpowers 	priTemplate[n].type = CKA_VALUE;
998*034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)private_value;
999*034448feSmcpowers 	priTemplate[n].ulValueLen = sizeof (private_value);
1000*034448feSmcpowers 	pri_out_attr_count++;
1001*034448feSmcpowers 
1002*034448feSmcpowers 	rv = process_object_attributes(priTemplate,
1003*034448feSmcpowers 	    pri_attr_count - pri_out_attr_count,
1004*034448feSmcpowers 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
1005*034448feSmcpowers 	if (rv != CKR_OK) {
1006*034448feSmcpowers 		goto failed_exit;
1007*034448feSmcpowers 	}
1008*034448feSmcpowers 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
1009*034448feSmcpowers 
1010*034448feSmcpowers 	rv = process_object_attributes(
1011*034448feSmcpowers 	    &priTemplate[pri_attr_count - pri_out_attr_count],
1012*034448feSmcpowers 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
1013*034448feSmcpowers 	    &is_token_obj2);
1014*034448feSmcpowers 	if (rv != CKR_OK) {
1015*034448feSmcpowers 		goto failed_exit;
1016*034448feSmcpowers 	}
1017*034448feSmcpowers 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
1018*034448feSmcpowers 
1019*034448feSmcpowers 	/*
1020*034448feSmcpowers 	 * The public key and the private key need to contain the same
1021*034448feSmcpowers 	 * attribute values for CKA_TOKEN.
1022*034448feSmcpowers 	 */
1023*034448feSmcpowers 	if (is_token_obj1 != is_token_obj2) {
1024*034448feSmcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
1025*034448feSmcpowers 		goto failed_exit;
1026*034448feSmcpowers 	}
1027*034448feSmcpowers 
1028*034448feSmcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
1029*034448feSmcpowers 	obj_nkp.nkp_session = session_p-> k_session;
1030*034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
1031*034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
1032*034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1033*034448feSmcpowers 
1034*034448feSmcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
1035*034448feSmcpowers 	    &obj_nkp)) < 0) {
1036*034448feSmcpowers 		if (errno != EINTR)
1037*034448feSmcpowers 			break;
1038*034448feSmcpowers 	}
1039*034448feSmcpowers 	if (r < 0) {
1040*034448feSmcpowers 		rv = CKR_FUNCTION_FAILED;
1041*034448feSmcpowers 	} else {
1042*034448feSmcpowers 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
1043*034448feSmcpowers 	}
1044*034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
1045*034448feSmcpowers 	    &obj_nkp.nkp_in_public_count);
1046*034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
1047*034448feSmcpowers 	    &obj_nkp.nkp_in_private_count);
1048*034448feSmcpowers 
1049*034448feSmcpowers 	if (rv != CKR_OK) {
1050*034448feSmcpowers 		goto failed_exit;
1051*034448feSmcpowers 	}
1052*034448feSmcpowers 
1053*034448feSmcpowers 	rv = get_object_attributes(
1054*034448feSmcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
1055*034448feSmcpowers 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
1056*034448feSmcpowers 	if (rv == CRYPTO_SUCCESS) {
1057*034448feSmcpowers 		rv = get_object_attributes(
1058*034448feSmcpowers 		    &priTemplate[pri_attr_count - pri_out_attr_count],
1059*034448feSmcpowers 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
1060*034448feSmcpowers 	}
1061*034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
1062*034448feSmcpowers 	    &obj_nkp.nkp_out_public_count);
1063*034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
1064*034448feSmcpowers 	    &obj_nkp.nkp_out_private_count);
1065*034448feSmcpowers 
1066*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1067*034448feSmcpowers 		goto failed_exit;
1068*034448feSmcpowers 	}
1069*034448feSmcpowers 
1070*034448feSmcpowers 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
1071*034448feSmcpowers 	    session_p, KERNEL_GEN_KEY);
1072*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1073*034448feSmcpowers 		goto failed_exit;
1074*034448feSmcpowers 	}
1075*034448feSmcpowers 
1076*034448feSmcpowers 	/*
1077*034448feSmcpowers 	 * Copy CKA_BASE and CKA_PRIME from the public template
1078*034448feSmcpowers 	 * to the private template.
1079*034448feSmcpowers 	 */
1080*034448feSmcpowers 	rv = copy_attribute(CKA_BASE, pubTemplate, pub_attr_count,
1081*034448feSmcpowers 	    &priTemplate[pri_attr_count]);
1082*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1083*034448feSmcpowers 		goto failed_exit;
1084*034448feSmcpowers 	}
1085*034448feSmcpowers 	rv = copy_attribute(CKA_PRIME, pubTemplate, pub_attr_count,
1086*034448feSmcpowers 	    &priTemplate[pri_attr_count + 1]);
1087*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1088*034448feSmcpowers 		(void) free(priTemplate[pri_attr_count].pValue);
1089*034448feSmcpowers 		goto failed_exit;
1090*034448feSmcpowers 	}
1091*034448feSmcpowers 
1092*034448feSmcpowers 	/* +2 to account for CKA_BASE and CKA_PRIME */
1093*034448feSmcpowers 	rv = kernel_build_object(priTemplate, pri_attr_count + 2,
1094*034448feSmcpowers 	    new_pri_objp, session_p, KERNEL_GEN_KEY);
1095*034448feSmcpowers 	(void) free(priTemplate[pri_attr_count].pValue);
1096*034448feSmcpowers 	(void) free(priTemplate[pri_attr_count + 1].pValue);
1097*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1098*034448feSmcpowers 		goto failed_exit;
1099*034448feSmcpowers 	}
1100*034448feSmcpowers 	(void) free(pubTemplate);
1101*034448feSmcpowers 	(void) free(priTemplate);
1102*034448feSmcpowers 
1103*034448feSmcpowers 	new_pub_objp->is_lib_obj = B_TRUE;
1104*034448feSmcpowers 	new_pri_objp->is_lib_obj = B_TRUE;
1105*034448feSmcpowers 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1106*034448feSmcpowers 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1107*034448feSmcpowers 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1108*034448feSmcpowers 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1109*034448feSmcpowers 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1110*034448feSmcpowers 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1111*034448feSmcpowers 	return (CKR_OK);
1112*034448feSmcpowers 
1113*034448feSmcpowers failed_exit:
1114*034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
1115*034448feSmcpowers 	    &obj_nkp.nkp_in_public_count);
1116*034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
1117*034448feSmcpowers 	    &obj_nkp.nkp_out_public_count);
1118*034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
1119*034448feSmcpowers 	    &obj_nkp.nkp_in_private_count);
1120*034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
1121*034448feSmcpowers 	    &obj_nkp.nkp_out_private_count);
1122*034448feSmcpowers 	if (pubTemplate != NULL) {
1123*034448feSmcpowers 		(void) free(pubTemplate);
1124*034448feSmcpowers 	}
1125*034448feSmcpowers 	if (priTemplate != NULL) {
1126*034448feSmcpowers 		(void) free(priTemplate);
1127*034448feSmcpowers 	}
1128*034448feSmcpowers 	return (rv);
1129*034448feSmcpowers }
1130*034448feSmcpowers 
1131*034448feSmcpowers CK_RV
1132*034448feSmcpowers key_gen_ec_by_value(CK_MECHANISM_PTR pMechanism,
1133*034448feSmcpowers     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
1134*034448feSmcpowers     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
1135*034448feSmcpowers     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
1136*034448feSmcpowers     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
1137*034448feSmcpowers {
1138*034448feSmcpowers 	crypto_nostore_generate_key_pair_t obj_nkp;
1139*034448feSmcpowers 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
1140*034448feSmcpowers 	CK_ATTRIBUTE_PTR priTemplate = NULL;
1141*034448feSmcpowers 	CK_RV rv = CKR_OK;
1142*034448feSmcpowers 	CK_BBOOL is_token_obj1 = FALSE;
1143*034448feSmcpowers 	CK_BBOOL is_token_obj2 = FALSE;
1144*034448feSmcpowers 	uint_t pub_attr_count, pri_attr_count;
1145*034448feSmcpowers 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
1146*034448feSmcpowers 	char value[32];
1147*034448feSmcpowers 	char point[128];
1148*034448feSmcpowers 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
1149*034448feSmcpowers 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
1150*034448feSmcpowers 	CK_ULONG key_type;
1151*034448feSmcpowers 	boolean_t has_class, has_key_type;
1152*034448feSmcpowers 	int n, r;
1153*034448feSmcpowers 
1154*034448feSmcpowers 	obj_nkp.nkp_in_public_count = 0;
1155*034448feSmcpowers 	obj_nkp.nkp_out_public_count = 0;
1156*034448feSmcpowers 	obj_nkp.nkp_in_private_count = 0;
1157*034448feSmcpowers 	obj_nkp.nkp_out_private_count = 0;
1158*034448feSmcpowers 
1159*034448feSmcpowers 	/*
1160*034448feSmcpowers 	 * Add CKA_EC_POINT to the public template.
1161*034448feSmcpowers 	 * This is the generated value Q. This attribute
1162*034448feSmcpowers 	 * must not be in the template.
1163*034448feSmcpowers 	 */
1164*034448feSmcpowers 	if (attribute_in_template(CKA_EC_POINT, pPublicKeyTemplate,
1165*034448feSmcpowers 	    ulPublicKeyAttributeCount)) {
1166*034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
1167*034448feSmcpowers 		goto failed_exit;
1168*034448feSmcpowers 	}
1169*034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
1170*034448feSmcpowers 	    ulPublicKeyAttributeCount);
1171*034448feSmcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
1172*034448feSmcpowers 	    ulPublicKeyAttributeCount);
1173*034448feSmcpowers 
1174*034448feSmcpowers 	pub_attr_count = ulPublicKeyAttributeCount + 1;
1175*034448feSmcpowers 	if (!has_class)
1176*034448feSmcpowers 		pub_attr_count++;
1177*034448feSmcpowers 	if (!has_key_type)
1178*034448feSmcpowers 		pub_attr_count++;
1179*034448feSmcpowers 	pubTemplate = grow_template(pPublicKeyTemplate,
1180*034448feSmcpowers 	    ulPublicKeyAttributeCount, pub_attr_count);
1181*034448feSmcpowers 	if (pubTemplate == NULL) {
1182*034448feSmcpowers 		rv = CKR_HOST_MEMORY;
1183*034448feSmcpowers 		goto failed_exit;
1184*034448feSmcpowers 	}
1185*034448feSmcpowers 
1186*034448feSmcpowers 	n = ulPublicKeyAttributeCount;
1187*034448feSmcpowers 	if (!has_class) {
1188*034448feSmcpowers 		pubTemplate[n].type = CKA_CLASS;
1189*034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)&pub_class;
1190*034448feSmcpowers 		pubTemplate[n].ulValueLen = sizeof (pub_class);
1191*034448feSmcpowers 		n++;
1192*034448feSmcpowers 	}
1193*034448feSmcpowers 	if (!has_key_type) {
1194*034448feSmcpowers 		pubTemplate[n].type = CKA_KEY_TYPE;
1195*034448feSmcpowers 		key_type = CKK_EC;
1196*034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)&key_type;
1197*034448feSmcpowers 		pubTemplate[n].ulValueLen = sizeof (key_type);
1198*034448feSmcpowers 		n++;
1199*034448feSmcpowers 	}
1200*034448feSmcpowers 	pubTemplate[n].type = CKA_EC_POINT;
1201*034448feSmcpowers 	pubTemplate[n].pValue = (caddr_t)point;
1202*034448feSmcpowers 	pubTemplate[n].ulValueLen = sizeof (point);
1203*034448feSmcpowers 	pub_out_attr_count++;
1204*034448feSmcpowers 
1205*034448feSmcpowers 	rv = process_object_attributes(pubTemplate,
1206*034448feSmcpowers 	    pub_attr_count - pub_out_attr_count,
1207*034448feSmcpowers 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
1208*034448feSmcpowers 	if (rv != CKR_OK) {
1209*034448feSmcpowers 		goto failed_exit;
1210*034448feSmcpowers 	}
1211*034448feSmcpowers 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
1212*034448feSmcpowers 
1213*034448feSmcpowers 	rv = process_object_attributes(
1214*034448feSmcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
1215*034448feSmcpowers 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
1216*034448feSmcpowers 	    &is_token_obj1);
1217*034448feSmcpowers 	if (rv != CKR_OK) {
1218*034448feSmcpowers 		goto failed_exit;
1219*034448feSmcpowers 	}
1220*034448feSmcpowers 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
1221*034448feSmcpowers 
1222*034448feSmcpowers 	/*
1223*034448feSmcpowers 	 * Cannot create a token object with a READ-ONLY
1224*034448feSmcpowers 	 * session.
1225*034448feSmcpowers 	 */
1226*034448feSmcpowers 	if (is_token_obj1 && session_p->ses_RO) {
1227*034448feSmcpowers 		rv = CKR_SESSION_READ_ONLY;
1228*034448feSmcpowers 		goto failed_exit;
1229*034448feSmcpowers 	}
1230*034448feSmcpowers 
1231*034448feSmcpowers 	/*
1232*034448feSmcpowers 	 * CKA_EC_PARAMS and CKA_VALUE must not appear in
1233*034448feSmcpowers 	 * private template.
1234*034448feSmcpowers 	 */
1235*034448feSmcpowers 	if (attribute_in_template(CKA_EC_PARAMS, pPrivateKeyTemplate,
1236*034448feSmcpowers 	    ulPrivateKeyAttributeCount) ||
1237*034448feSmcpowers 	    attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
1238*034448feSmcpowers 	    ulPrivateKeyAttributeCount)) {
1239*034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
1240*034448feSmcpowers 		goto failed_exit;
1241*034448feSmcpowers 	}
1242*034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
1243*034448feSmcpowers 	    ulPrivateKeyAttributeCount);
1244*034448feSmcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
1245*034448feSmcpowers 	    ulPrivateKeyAttributeCount);
1246*034448feSmcpowers 
1247*034448feSmcpowers 	pri_attr_count = ulPrivateKeyAttributeCount + 1;
1248*034448feSmcpowers 	if (!has_class)
1249*034448feSmcpowers 		pri_attr_count++;
1250*034448feSmcpowers 	if (!has_key_type)
1251*034448feSmcpowers 		pri_attr_count++;
1252*034448feSmcpowers 
1253*034448feSmcpowers 	/* allocate space for CKA_EC_PARAMS */
1254*034448feSmcpowers 	priTemplate = grow_template(pPrivateKeyTemplate,
1255*034448feSmcpowers 	    ulPrivateKeyAttributeCount, pri_attr_count + 1);
1256*034448feSmcpowers 	if (priTemplate == NULL) {
1257*034448feSmcpowers 		rv = CKR_HOST_MEMORY;
1258*034448feSmcpowers 		goto failed_exit;
1259*034448feSmcpowers 	}
1260*034448feSmcpowers 	n = ulPrivateKeyAttributeCount;
1261*034448feSmcpowers 	if (!has_class) {
1262*034448feSmcpowers 		priTemplate[n].type = CKA_CLASS;
1263*034448feSmcpowers 		priTemplate[n].pValue = (caddr_t)&pri_class;
1264*034448feSmcpowers 		priTemplate[n].ulValueLen = sizeof (pri_class);
1265*034448feSmcpowers 		n++;
1266*034448feSmcpowers 	}
1267*034448feSmcpowers 	if (!has_key_type) {
1268*034448feSmcpowers 		priTemplate[n].type = CKA_KEY_TYPE;
1269*034448feSmcpowers 		key_type = CKK_EC;
1270*034448feSmcpowers 		priTemplate[n].pValue = (caddr_t)&key_type;
1271*034448feSmcpowers 		priTemplate[n].ulValueLen = sizeof (key_type);
1272*034448feSmcpowers 		n++;
1273*034448feSmcpowers 	}
1274*034448feSmcpowers 	priTemplate[n].type = CKA_VALUE;
1275*034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)value;
1276*034448feSmcpowers 	priTemplate[n].ulValueLen = sizeof (value);
1277*034448feSmcpowers 	pri_out_attr_count++;
1278*034448feSmcpowers 
1279*034448feSmcpowers 	rv = process_object_attributes(priTemplate,
1280*034448feSmcpowers 	    pri_attr_count - pri_out_attr_count,
1281*034448feSmcpowers 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
1282*034448feSmcpowers 	if (rv != CKR_OK) {
1283*034448feSmcpowers 		goto failed_exit;
1284*034448feSmcpowers 	}
1285*034448feSmcpowers 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
1286*034448feSmcpowers 
1287*034448feSmcpowers 	rv = process_object_attributes(
1288*034448feSmcpowers 	    &priTemplate[pri_attr_count - pri_out_attr_count],
1289*034448feSmcpowers 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
1290*034448feSmcpowers 	    &is_token_obj2);
1291*034448feSmcpowers 	if (rv != CKR_OK) {
1292*034448feSmcpowers 		goto failed_exit;
1293*034448feSmcpowers 	}
1294*034448feSmcpowers 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
1295*034448feSmcpowers 
1296*034448feSmcpowers 	/*
1297*034448feSmcpowers 	 * The public key and the private key need to contain the same
1298*034448feSmcpowers 	 * attribute values for CKA_TOKEN.
1299*034448feSmcpowers 	 */
1300*034448feSmcpowers 	if (is_token_obj1 != is_token_obj2) {
1301*034448feSmcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
1302*034448feSmcpowers 		goto failed_exit;
1303*034448feSmcpowers 	}
1304*034448feSmcpowers 
1305*034448feSmcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
1306*034448feSmcpowers 	obj_nkp.nkp_session = session_p-> k_session;
1307*034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
1308*034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
1309*034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1310*034448feSmcpowers 
1311*034448feSmcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
1312*034448feSmcpowers 	    &obj_nkp)) < 0) {
1313*034448feSmcpowers 		if (errno != EINTR)
1314*034448feSmcpowers 			break;
1315*034448feSmcpowers 	}
1316*034448feSmcpowers 	if (r < 0) {
1317*034448feSmcpowers 		rv = CKR_FUNCTION_FAILED;
1318*034448feSmcpowers 	} else {
1319*034448feSmcpowers 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
1320*034448feSmcpowers 	}
1321*034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
1322*034448feSmcpowers 	    &obj_nkp.nkp_in_public_count);
1323*034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
1324*034448feSmcpowers 	    &obj_nkp.nkp_in_private_count);
1325*034448feSmcpowers 
1326*034448feSmcpowers 	if (rv != CKR_OK) {
1327*034448feSmcpowers 		goto failed_exit;
1328*034448feSmcpowers 	}
1329*034448feSmcpowers 
1330*034448feSmcpowers 	rv = get_object_attributes(
1331*034448feSmcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
1332*034448feSmcpowers 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
1333*034448feSmcpowers 	if (rv == CRYPTO_SUCCESS) {
1334*034448feSmcpowers 		rv = get_object_attributes(
1335*034448feSmcpowers 		    &priTemplate[pri_attr_count - pri_out_attr_count],
1336*034448feSmcpowers 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
1337*034448feSmcpowers 	}
1338*034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
1339*034448feSmcpowers 	    &obj_nkp.nkp_out_public_count);
1340*034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
1341*034448feSmcpowers 	    &obj_nkp.nkp_out_private_count);
1342*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1343*034448feSmcpowers 		goto failed_exit;
1344*034448feSmcpowers 	}
1345*034448feSmcpowers 
1346*034448feSmcpowers 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
1347*034448feSmcpowers 	    session_p, KERNEL_GEN_KEY);
1348*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1349*034448feSmcpowers 		goto failed_exit;
1350*034448feSmcpowers 	}
1351*034448feSmcpowers 
1352*034448feSmcpowers 	/*
1353*034448feSmcpowers 	 * Copy CKA_EC_PARAMS from the public template to the
1354*034448feSmcpowers 	 * private template.
1355*034448feSmcpowers 	 */
1356*034448feSmcpowers 	rv = copy_attribute(CKA_EC_PARAMS, pubTemplate, pub_attr_count,
1357*034448feSmcpowers 	    &priTemplate[pri_attr_count]);
1358*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1359*034448feSmcpowers 		goto failed_exit;
1360*034448feSmcpowers 	}
1361*034448feSmcpowers 
1362*034448feSmcpowers 	/* +1 to account for CKA_EC_PARAMS */
1363*034448feSmcpowers 	rv = kernel_build_object(priTemplate, pri_attr_count + 1,
1364*034448feSmcpowers 	    new_pri_objp, session_p, KERNEL_GEN_KEY);
1365*034448feSmcpowers 	(void) free(priTemplate[pri_attr_count].pValue);
1366*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1367*034448feSmcpowers 		goto failed_exit;
1368*034448feSmcpowers 	}
1369*034448feSmcpowers 	(void) free(pubTemplate);
1370*034448feSmcpowers 	(void) free(priTemplate);
1371*034448feSmcpowers 
1372*034448feSmcpowers 	new_pub_objp->is_lib_obj = B_TRUE;
1373*034448feSmcpowers 	new_pri_objp->is_lib_obj = B_TRUE;
1374*034448feSmcpowers 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1375*034448feSmcpowers 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1376*034448feSmcpowers 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1377*034448feSmcpowers 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1378*034448feSmcpowers 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1379*034448feSmcpowers 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1380*034448feSmcpowers 	return (CKR_OK);
1381*034448feSmcpowers 
1382*034448feSmcpowers failed_exit:
1383*034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
1384*034448feSmcpowers 	    &obj_nkp.nkp_in_public_count);
1385*034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
1386*034448feSmcpowers 	    &obj_nkp.nkp_out_public_count);
1387*034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
1388*034448feSmcpowers 	    &obj_nkp.nkp_in_private_count);
1389*034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
1390*034448feSmcpowers 	    &obj_nkp.nkp_out_private_count);
1391*034448feSmcpowers 	if (pubTemplate != NULL) {
1392*034448feSmcpowers 		(void) free(pubTemplate);
1393*034448feSmcpowers 	}
1394*034448feSmcpowers 	if (priTemplate != NULL) {
1395*034448feSmcpowers 		(void) free(priTemplate);
1396*034448feSmcpowers 	}
1397*034448feSmcpowers 	return (rv);
1398*034448feSmcpowers }
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate CK_RV
14017c478bd9Sstevel@tonic-gate C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
14027c478bd9Sstevel@tonic-gate     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
14037c478bd9Sstevel@tonic-gate     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
14047c478bd9Sstevel@tonic-gate     CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
14057c478bd9Sstevel@tonic-gate {
14067c478bd9Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
14077c478bd9Sstevel@tonic-gate 	kernel_session_t	*session_p;
14087c478bd9Sstevel@tonic-gate 	kernel_object_t		*new_pub_objp = NULL;
14097c478bd9Sstevel@tonic-gate 	kernel_object_t		*new_pri_objp = NULL;
14107c478bd9Sstevel@tonic-gate 	kernel_slot_t		*pslot;
14117c478bd9Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
14127c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj1;
14137c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj2;
14147c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_token_obj1 = FALSE;
14157c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_token_obj2 = FALSE;
14167c478bd9Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
14177c478bd9Sstevel@tonic-gate 	int r;
1418*034448feSmcpowers 	CK_RV (*func)(CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG,
1419*034448feSmcpowers 	    CK_ATTRIBUTE_PTR, CK_ULONG, kernel_session_t *, crypto_mech_type_t,
1420*034448feSmcpowers 	    kernel_object_t *, kernel_object_t *);
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
14237c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	/* Obtain the session pointer. */
14267c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
14277c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
14287c478bd9Sstevel@tonic-gate 		return (rv);
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 	if ((pMechanism == NULL) || (phPublicKey == NULL) ||
14317c478bd9Sstevel@tonic-gate 	    (phPrivateKey == NULL)) {
14327c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
14337c478bd9Sstevel@tonic-gate 		goto failed_exit;
14347c478bd9Sstevel@tonic-gate 	}
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 	if ((pPublicKeyTemplate == NULL) && (ulPublicKeyAttributeCount != 0)) {
14377c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
14387c478bd9Sstevel@tonic-gate 		goto failed_exit;
14397c478bd9Sstevel@tonic-gate 	}
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	if ((pPrivateKeyTemplate == NULL) &&
14427c478bd9Sstevel@tonic-gate 	    (ulPrivateKeyAttributeCount != 0)) {
14437c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
14447c478bd9Sstevel@tonic-gate 		goto failed_exit;
14457c478bd9Sstevel@tonic-gate 	}
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
14487c478bd9Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
14497c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
14507c478bd9Sstevel@tonic-gate 		goto failed_exit;
14517c478bd9Sstevel@tonic-gate 	}
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	/* Create an object wrapper for the public key */
14547c478bd9Sstevel@tonic-gate 	new_pub_objp = calloc(1, sizeof (kernel_object_t));
14557c478bd9Sstevel@tonic-gate 	if (new_pub_objp == NULL) {
14567c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
14577c478bd9Sstevel@tonic-gate 		goto failed_exit;
14587c478bd9Sstevel@tonic-gate 	}
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	/* Create an object wrapper for the private key. */
14617c478bd9Sstevel@tonic-gate 	new_pri_objp = calloc(1, sizeof (kernel_object_t));
14627c478bd9Sstevel@tonic-gate 	if (new_pri_objp == NULL) {
14637c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
14647c478bd9Sstevel@tonic-gate 		goto failed_exit;
14657c478bd9Sstevel@tonic-gate 	}
14667c478bd9Sstevel@tonic-gate 
1467*034448feSmcpowers 	/*
1468*034448feSmcpowers 	 * Special Case: if token does not support object creation,
1469*034448feSmcpowers 	 * but does support key generation by value, then create a session
1470*034448feSmcpowers 	 * object and initialize with values returned by token.
1471*034448feSmcpowers 	 */
1472*034448feSmcpowers 	pslot = slot_table[session_p->ses_slotid];
1473*034448feSmcpowers 	if (!pslot->sl_func_list.fl_object_create) {
1474*034448feSmcpowers 		switch (pMechanism->mechanism) {
1475*034448feSmcpowers 		case CKM_RSA_PKCS_KEY_PAIR_GEN:
1476*034448feSmcpowers 			func = key_gen_rsa_by_value;
1477*034448feSmcpowers 			break;
1478*034448feSmcpowers 
1479*034448feSmcpowers 		case CKM_DH_PKCS_KEY_PAIR_GEN:
1480*034448feSmcpowers 			func = key_gen_dh_by_value;
1481*034448feSmcpowers 			break;
1482*034448feSmcpowers 
1483*034448feSmcpowers 		case CKM_EC_KEY_PAIR_GEN:
1484*034448feSmcpowers 			func = key_gen_ec_by_value;
1485*034448feSmcpowers 			break;
1486*034448feSmcpowers 
1487*034448feSmcpowers 		default:
1488*034448feSmcpowers 			rv = CKR_MECHANISM_INVALID;
1489*034448feSmcpowers 			goto failed_exit;
1490*034448feSmcpowers 		}
1491*034448feSmcpowers 		rv = (*func)(pMechanism, pPublicKeyTemplate,
1492*034448feSmcpowers 		    ulPublicKeyAttributeCount, pPrivateKeyTemplate,
1493*034448feSmcpowers 		    ulPrivateKeyAttributeCount, session_p, k_mech_type,
1494*034448feSmcpowers 		    new_pub_objp, new_pri_objp);
1495*034448feSmcpowers 		if (rv != CKR_OK)
1496*034448feSmcpowers 			goto failed_exit;
1497*034448feSmcpowers 	} else {
1498*034448feSmcpowers 		crypto_object_generate_key_pair_t obj_kp;
1499*034448feSmcpowers 
15007c478bd9Sstevel@tonic-gate 		/* Process the public key attributes. */
15017c478bd9Sstevel@tonic-gate 		rv = process_object_attributes(pPublicKeyTemplate,
15027c478bd9Sstevel@tonic-gate 		    ulPublicKeyAttributeCount, &obj_kp.kp_public_attributes,
15037c478bd9Sstevel@tonic-gate 		    &is_token_obj1);
15047c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
15057c478bd9Sstevel@tonic-gate 			goto failed_exit;
15067c478bd9Sstevel@tonic-gate 		}
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 		/* Cannot create a token object with a READ-ONLY session. */
15097c478bd9Sstevel@tonic-gate 		if (is_token_obj1 && session_p->ses_RO) {
15107c478bd9Sstevel@tonic-gate 			free_object_attributes(obj_kp.kp_public_attributes,
15117c478bd9Sstevel@tonic-gate 			    ulPublicKeyAttributeCount);
15127c478bd9Sstevel@tonic-gate 			rv = CKR_SESSION_READ_ONLY;
15137c478bd9Sstevel@tonic-gate 			goto failed_exit;
15147c478bd9Sstevel@tonic-gate 		}
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 		/* Process the private key attributes. */
15177c478bd9Sstevel@tonic-gate 		rv = process_object_attributes(pPrivateKeyTemplate,
15187c478bd9Sstevel@tonic-gate 		    ulPrivateKeyAttributeCount, &obj_kp.kp_private_attributes,
15197c478bd9Sstevel@tonic-gate 		    &is_token_obj2);
15207c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
15217c478bd9Sstevel@tonic-gate 			free_object_attributes(obj_kp.kp_public_attributes,
15227c478bd9Sstevel@tonic-gate 			    ulPublicKeyAttributeCount);
15237c478bd9Sstevel@tonic-gate 			goto failed_exit;
15247c478bd9Sstevel@tonic-gate 		}
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 		/*
15277c478bd9Sstevel@tonic-gate 		 * The public key and the private key need to contain the same
15287c478bd9Sstevel@tonic-gate 		 * attribute values for CKA_TOKEN.
15297c478bd9Sstevel@tonic-gate 		 */
15307c478bd9Sstevel@tonic-gate 		if (is_token_obj1 != is_token_obj2) {
15317c478bd9Sstevel@tonic-gate 			free_object_attributes(obj_kp.kp_public_attributes,
15327c478bd9Sstevel@tonic-gate 			    ulPublicKeyAttributeCount);
15337c478bd9Sstevel@tonic-gate 			free_object_attributes(obj_kp.kp_private_attributes,
15347c478bd9Sstevel@tonic-gate 			    ulPrivateKeyAttributeCount);
15357c478bd9Sstevel@tonic-gate 			rv = CKR_ATTRIBUTE_VALUE_INVALID;
15367c478bd9Sstevel@tonic-gate 			goto failed_exit;
15377c478bd9Sstevel@tonic-gate 		}
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 		/* Call the CRYPTO_GENERATE_KEY_PAIR ioctl. */
15407c478bd9Sstevel@tonic-gate 		obj_kp.kp_session = session_p-> k_session;
15417c478bd9Sstevel@tonic-gate 		obj_kp.kp_mechanism.cm_type = k_mech_type;
15427c478bd9Sstevel@tonic-gate 		obj_kp.kp_mechanism.cm_param = pMechanism->pParameter;
15437c478bd9Sstevel@tonic-gate 		obj_kp.kp_mechanism.cm_param_len = pMechanism->ulParameterLen;
15447c478bd9Sstevel@tonic-gate 		obj_kp.kp_public_count = ulPublicKeyAttributeCount;
15457c478bd9Sstevel@tonic-gate 		obj_kp.kp_private_count = ulPrivateKeyAttributeCount;
15467c478bd9Sstevel@tonic-gate 
1547*034448feSmcpowers 		while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY_PAIR,
1548*034448feSmcpowers 		    &obj_kp)) < 0) {
15497c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
15507c478bd9Sstevel@tonic-gate 				break;
15517c478bd9Sstevel@tonic-gate 		}
15527c478bd9Sstevel@tonic-gate 		if (r < 0) {
15537c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
15547c478bd9Sstevel@tonic-gate 		} else {
15557c478bd9Sstevel@tonic-gate 			rv = crypto2pkcs11_error_number(obj_kp.kp_return_value);
15567c478bd9Sstevel@tonic-gate 		}
15577c478bd9Sstevel@tonic-gate 		free_object_attributes(obj_kp.kp_public_attributes,
15587c478bd9Sstevel@tonic-gate 		    ulPublicKeyAttributeCount);
15597c478bd9Sstevel@tonic-gate 		free_object_attributes(obj_kp.kp_private_attributes,
15607c478bd9Sstevel@tonic-gate 		    ulPrivateKeyAttributeCount);
15617c478bd9Sstevel@tonic-gate 
1562*034448feSmcpowers 		if (rv != CKR_OK)
15637c478bd9Sstevel@tonic-gate 			goto failed_exit;
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 		/* Get the CKA_PRIVATE value for the key pair. */
15667c478bd9Sstevel@tonic-gate 		rv = get_cka_private_value(session_p, obj_kp.kp_public_handle,
15677c478bd9Sstevel@tonic-gate 		    &is_pri_obj1);
15687c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
15697c478bd9Sstevel@tonic-gate 			goto failed_exit;
15707c478bd9Sstevel@tonic-gate 		}
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 		rv = get_cka_private_value(session_p, obj_kp.kp_private_handle,
15737c478bd9Sstevel@tonic-gate 		    &is_pri_obj2);
15747c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
15757c478bd9Sstevel@tonic-gate 			goto failed_exit;
15767c478bd9Sstevel@tonic-gate 		}
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 		/*
1579*034448feSmcpowers 		 * Store the kernel public key handle into the public key
1580*034448feSmcpowers 		 * object and finish the public key object initialization.
15817c478bd9Sstevel@tonic-gate 		 */
15827c478bd9Sstevel@tonic-gate 		new_pub_objp->is_lib_obj = B_FALSE;
15837c478bd9Sstevel@tonic-gate 		new_pub_objp->k_handle = obj_kp.kp_public_handle;
15847c478bd9Sstevel@tonic-gate 		new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
15857c478bd9Sstevel@tonic-gate 		new_pub_objp->extra_attrlistp = NULL;
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate 		if (is_pri_obj1)
15887c478bd9Sstevel@tonic-gate 			new_pub_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
15897c478bd9Sstevel@tonic-gate 		else
15907c478bd9Sstevel@tonic-gate 			new_pub_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 		if (is_token_obj1)
15937c478bd9Sstevel@tonic-gate 			new_pub_objp->bool_attr_mask |= TOKEN_BOOL_ON;
15947c478bd9Sstevel@tonic-gate 		else
15957c478bd9Sstevel@tonic-gate 			new_pub_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
15987c478bd9Sstevel@tonic-gate 		new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 		/*
1601*034448feSmcpowers 		 * Store the kernel private key handle into the private key
1602*034448feSmcpowers 		 * object and finish the private key object initialization.
16037c478bd9Sstevel@tonic-gate 		 */
16047c478bd9Sstevel@tonic-gate 		new_pri_objp->is_lib_obj = B_FALSE;
16057c478bd9Sstevel@tonic-gate 		new_pri_objp->k_handle = obj_kp.kp_private_handle;
16067c478bd9Sstevel@tonic-gate 		new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
16077c478bd9Sstevel@tonic-gate 		new_pri_objp->extra_attrlistp = NULL;
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 		if (is_pri_obj2)
16107c478bd9Sstevel@tonic-gate 			new_pri_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
16117c478bd9Sstevel@tonic-gate 		else
16127c478bd9Sstevel@tonic-gate 			new_pri_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 		if (is_token_obj2)
16157c478bd9Sstevel@tonic-gate 			new_pri_objp->bool_attr_mask |= TOKEN_BOOL_ON;
16167c478bd9Sstevel@tonic-gate 		else
16177c478bd9Sstevel@tonic-gate 			new_pri_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
16187c478bd9Sstevel@tonic-gate 
1619*034448feSmcpowers 	}
16207c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
16217c478bd9Sstevel@tonic-gate 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 	/*
16247c478bd9Sstevel@tonic-gate 	 * Add the new pub/pri objects to the slot's token list if they are
16257c478bd9Sstevel@tonic-gate 	 * token objects. Otherwise, add them to the session's object list.
16267c478bd9Sstevel@tonic-gate 	 */
16277c478bd9Sstevel@tonic-gate 	if (is_token_obj1) { /* is_token_obj1 == is_token_obj2 */
16287c478bd9Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
16297c478bd9Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_pub_objp, pslot);
16307c478bd9Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_pri_objp, pslot);
16317c478bd9Sstevel@tonic-gate 	} else {
16327c478bd9Sstevel@tonic-gate 		kernel_add_object_to_session(new_pub_objp, session_p);
16337c478bd9Sstevel@tonic-gate 		kernel_add_object_to_session(new_pri_objp, session_p);
16347c478bd9Sstevel@tonic-gate 	}
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 	*phPublicKey = (CK_OBJECT_HANDLE)new_pub_objp;
16377c478bd9Sstevel@tonic-gate 	*phPrivateKey = (CK_OBJECT_HANDLE)new_pri_objp;
16387c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
16397c478bd9Sstevel@tonic-gate 	return (rv);
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate failed_exit:
16427c478bd9Sstevel@tonic-gate 	if (new_pub_objp != NULL) {
16437c478bd9Sstevel@tonic-gate 		(void) free(new_pub_objp);
16447c478bd9Sstevel@tonic-gate 	}
16457c478bd9Sstevel@tonic-gate 	if (new_pri_objp != NULL) {
16467c478bd9Sstevel@tonic-gate 		(void) free(new_pri_objp);
16477c478bd9Sstevel@tonic-gate 	}
16487c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
16497c478bd9Sstevel@tonic-gate 	return (rv);
16507c478bd9Sstevel@tonic-gate }
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate CK_RV
16547c478bd9Sstevel@tonic-gate C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
16557c478bd9Sstevel@tonic-gate     CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
16567c478bd9Sstevel@tonic-gate     CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen)
16577c478bd9Sstevel@tonic-gate {
16587c478bd9Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
16597c478bd9Sstevel@tonic-gate 	kernel_session_t	*session_p;
16607c478bd9Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
16617c478bd9Sstevel@tonic-gate 	kernel_object_t		*wrappingkey_p;
16627c478bd9Sstevel@tonic-gate 	kernel_object_t		*key_p;
16637c478bd9Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
16647c478bd9Sstevel@tonic-gate 	crypto_object_wrap_key_t obj_wrapkey;
16657c478bd9Sstevel@tonic-gate 	int r;
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
16687c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	if (pulWrappedKeyLen == NULL || pMechanism == NULL) {
16717c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
16727c478bd9Sstevel@tonic-gate 	}
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	/*
16757c478bd9Sstevel@tonic-gate 	 * Obtain the session pointer.  Also, increment the session
16767c478bd9Sstevel@tonic-gate 	 * reference count.
16777c478bd9Sstevel@tonic-gate 	 */
16787c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
16797c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
16807c478bd9Sstevel@tonic-gate 		return (rv);
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
16837c478bd9Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
16847c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
16857c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
16867c478bd9Sstevel@tonic-gate 		return (rv);
16877c478bd9Sstevel@tonic-gate 	}
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate 	/* Obtain the wrapping key object pointer. */
16907c478bd9Sstevel@tonic-gate 	HANDLE2OBJECT(hWrappingKey, wrappingkey_p, rv);
16917c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
16927c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
16937c478bd9Sstevel@tonic-gate 		return (rv);
16947c478bd9Sstevel@tonic-gate 	}
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate 	/* Obtain the to_be_wrapped key object pointer. */
16977c478bd9Sstevel@tonic-gate 	HANDLE2OBJECT(hKey, key_p, rv);
16987c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
169901223cbaSmcpowers 		OBJ_REFRELE(wrappingkey_p);
17007c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
17017c478bd9Sstevel@tonic-gate 		return (rv);
17027c478bd9Sstevel@tonic-gate 	}
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	/* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */
17057c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_session = session_p->k_session;
17067c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_mechanism.cm_type = k_mech_type;
17077c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_mechanism.cm_param = pMechanism->pParameter;
17087c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_mechanism.cm_param_len = pMechanism->ulParameterLen;
17097c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_wrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
17107c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_wrapping_key.ck_obj_id = wrappingkey_p->k_handle;
17117c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_object_handle = key_p->k_handle;
17127c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_wrapped_key_len = *pulWrappedKeyLen;
17137c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_wrapped_key = (char *)pWrappedKey;
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_WRAP_KEY, &obj_wrapkey)) < 0) {
17167c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
17177c478bd9Sstevel@tonic-gate 			break;
17187c478bd9Sstevel@tonic-gate 	}
17197c478bd9Sstevel@tonic-gate 	if (r < 0) {
17207c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
17217c478bd9Sstevel@tonic-gate 	} else {
17227c478bd9Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(obj_wrapkey.wk_return_value);
17237c478bd9Sstevel@tonic-gate 	}
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 	/*
17267c478bd9Sstevel@tonic-gate 	 * Besides rv == CKR_OK, we will set the value of pulWrappedKeyLen
17277c478bd9Sstevel@tonic-gate 	 * when the applciation-supplied wrapped key buffer is too small.
17287c478bd9Sstevel@tonic-gate 	 * The situation that the application only asks for the length of
17297c478bd9Sstevel@tonic-gate 	 * the wrapped key is covered in rv == CKR_OK.
17307c478bd9Sstevel@tonic-gate 	 */
17317c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
17327c478bd9Sstevel@tonic-gate 		*pulWrappedKeyLen = obj_wrapkey.wk_wrapped_key_len;
17337c478bd9Sstevel@tonic-gate 	}
17347c478bd9Sstevel@tonic-gate 
173501223cbaSmcpowers 	OBJ_REFRELE(key_p);
173601223cbaSmcpowers 	OBJ_REFRELE(wrappingkey_p);
17377c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
17387c478bd9Sstevel@tonic-gate 	return (rv);
17397c478bd9Sstevel@tonic-gate }
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate CK_RV
17437c478bd9Sstevel@tonic-gate C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
17447c478bd9Sstevel@tonic-gate     CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey,
17457c478bd9Sstevel@tonic-gate     CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
17467c478bd9Sstevel@tonic-gate     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
17477c478bd9Sstevel@tonic-gate {
17487c478bd9Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
17497c478bd9Sstevel@tonic-gate 	kernel_session_t	*session_p;
17507c478bd9Sstevel@tonic-gate 	kernel_object_t		*unwrappingkey_p;
17517c478bd9Sstevel@tonic-gate 	kernel_object_t		*new_objp = NULL;
17527c478bd9Sstevel@tonic-gate 	kernel_slot_t		*pslot;
17537c478bd9Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
17547c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj;
17557c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_token_obj = FALSE;
17567c478bd9Sstevel@tonic-gate 	CK_MECHANISM_INFO	info;
17577c478bd9Sstevel@tonic-gate 	uint32_t		k_mi_flags;
17587c478bd9Sstevel@tonic-gate 	CK_BYTE			*clear_key_val = NULL;
17597c478bd9Sstevel@tonic-gate 	CK_ULONG 		ulDataLen;
17607c478bd9Sstevel@tonic-gate 	CK_ATTRIBUTE_PTR	newTemplate = NULL;
17617c478bd9Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
17627c478bd9Sstevel@tonic-gate 	crypto_object_unwrap_key_t obj_unwrapkey;
17637c478bd9Sstevel@tonic-gate 	int r;
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
17667c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate 	if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) {
17697c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
17707c478bd9Sstevel@tonic-gate 	}
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 	if ((pTemplate == NULL) && (ulAttributeCount != 0)) {
17737c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
17747c478bd9Sstevel@tonic-gate 	}
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 	/* Obtain the session pointer. */
17777c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
17787c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
17797c478bd9Sstevel@tonic-gate 		return (rv);
17807c478bd9Sstevel@tonic-gate 
17817c478bd9Sstevel@tonic-gate 	/* Obtain the wrapping key object pointer. */
17827c478bd9Sstevel@tonic-gate 	HANDLE2OBJECT(hUnwrappingKey, unwrappingkey_p, rv);
17837c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
178401223cbaSmcpowers 		REFRELE(session_p, ses_lock_held);
178501223cbaSmcpowers 		return (rv);
17867c478bd9Sstevel@tonic-gate 	}
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate 	/*
17897c478bd9Sstevel@tonic-gate 	 * If the HW provider doesn't support C_UnwrapKey, we will try
17907c478bd9Sstevel@tonic-gate 	 * to emulate it in the library.
17917c478bd9Sstevel@tonic-gate 	 */
17927c478bd9Sstevel@tonic-gate 	pslot = slot_table[session_p->ses_slotid];
1793*034448feSmcpowers 	if ((!pslot->sl_func_list.fl_object_create) &&
1794*034448feSmcpowers 	    (!pslot->sl_func_list.fl_key_unwrap)) {
17957c478bd9Sstevel@tonic-gate 		rv = get_mechanism_info(pslot, pMechanism->mechanism, &info,
17967c478bd9Sstevel@tonic-gate 		    &k_mi_flags);
17977c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
17987c478bd9Sstevel@tonic-gate 			goto failed_exit;
17997c478bd9Sstevel@tonic-gate 		}
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate 		/*
18027c478bd9Sstevel@tonic-gate 		 * If the mechanism flag doesn't have CKF_UNWRAP, and it's
18037c478bd9Sstevel@tonic-gate 		 * an unwrapping of a secret key object, then help this
18047c478bd9Sstevel@tonic-gate 		 * out with a decryption followed by an object creation.
18057c478bd9Sstevel@tonic-gate 		 */
18067c478bd9Sstevel@tonic-gate 		if (!(k_mi_flags & CRYPTO_FG_UNWRAP) &&
18077c478bd9Sstevel@tonic-gate 		    (k_mi_flags & CRYPTO_FG_DECRYPT) &&
18087c478bd9Sstevel@tonic-gate 		    (is_secret_key_template(pTemplate, ulAttributeCount))) {
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 			/* First allocate space for the recovered key value */
18117c478bd9Sstevel@tonic-gate 			clear_key_val = malloc(ulWrappedKeyLen);
18127c478bd9Sstevel@tonic-gate 			if (clear_key_val == NULL) {
18137c478bd9Sstevel@tonic-gate 				rv = CKR_HOST_MEMORY;
18147c478bd9Sstevel@tonic-gate 				goto failed_exit;
18157c478bd9Sstevel@tonic-gate 			}
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 			rv = kernel_decrypt_init(session_p, unwrappingkey_p,
18187c478bd9Sstevel@tonic-gate 			    pMechanism);
18197c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
18207c478bd9Sstevel@tonic-gate 				goto failed_exit;
18217c478bd9Sstevel@tonic-gate 			}
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate 			ulDataLen = ulWrappedKeyLen;
18247c478bd9Sstevel@tonic-gate 			rv = kernel_decrypt(session_p, pWrappedKey,
18257c478bd9Sstevel@tonic-gate 			    ulWrappedKeyLen, clear_key_val, &ulDataLen);
18267c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
18277c478bd9Sstevel@tonic-gate 				goto failed_exit;
18287c478bd9Sstevel@tonic-gate 			}
18297c478bd9Sstevel@tonic-gate 
1830*034448feSmcpowers 			newTemplate = grow_template(pTemplate, ulAttributeCount,
1831*034448feSmcpowers 			    ulAttributeCount + 1);
18327c478bd9Sstevel@tonic-gate 			if (newTemplate == NULL) {
18337c478bd9Sstevel@tonic-gate 				rv = CKR_HOST_MEMORY;
18347c478bd9Sstevel@tonic-gate 				goto failed_exit;
18357c478bd9Sstevel@tonic-gate 			}
1836*034448feSmcpowers 			/* Now add the CKA_VALUE attribute to template */
18377c478bd9Sstevel@tonic-gate 			newTemplate[ulAttributeCount].type = CKA_VALUE;
18387c478bd9Sstevel@tonic-gate 			newTemplate[ulAttributeCount].pValue = clear_key_val;
18397c478bd9Sstevel@tonic-gate 			newTemplate[ulAttributeCount].ulValueLen = ulDataLen;
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 			/* Finally create the key, based on the new template */
18427c478bd9Sstevel@tonic-gate 			rv = kernel_add_object(newTemplate,
18437c478bd9Sstevel@tonic-gate 			    ulAttributeCount + 1, phKey, session_p);
18447c478bd9Sstevel@tonic-gate 			(void) free(clear_key_val);
18457c478bd9Sstevel@tonic-gate 			(void) free(newTemplate);
184601223cbaSmcpowers 			OBJ_REFRELE(unwrappingkey_p);
18477c478bd9Sstevel@tonic-gate 			REFRELE(session_p, ses_lock_held);
18487c478bd9Sstevel@tonic-gate 			return (rv);
18497c478bd9Sstevel@tonic-gate 		} else {
18507c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
18517c478bd9Sstevel@tonic-gate 			goto failed_exit;
18527c478bd9Sstevel@tonic-gate 		}
18537c478bd9Sstevel@tonic-gate 	}
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 	/*
18567c478bd9Sstevel@tonic-gate 	 * If we come here, the HW provider must have registered the unwrapkey
18577c478bd9Sstevel@tonic-gate 	 * entry.  Therefore, the unwrap key will be performed in the HW
18587c478bd9Sstevel@tonic-gate 	 * provider.
18597c478bd9Sstevel@tonic-gate 	 */
18607c478bd9Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
18617c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
18627c478bd9Sstevel@tonic-gate 		goto failed_exit;
18637c478bd9Sstevel@tonic-gate 	}
18647c478bd9Sstevel@tonic-gate 
18657c478bd9Sstevel@tonic-gate 	/* Create an object wrapper for the new key in the library first */
18667c478bd9Sstevel@tonic-gate 	new_objp = calloc(1, sizeof (kernel_object_t));
18677c478bd9Sstevel@tonic-gate 	if (new_objp == NULL) {
18687c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
18697c478bd9Sstevel@tonic-gate 		goto failed_exit;
18707c478bd9Sstevel@tonic-gate 	}
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 	/* Process the attributes */
18737c478bd9Sstevel@tonic-gate 	rv = process_object_attributes(pTemplate, ulAttributeCount,
18747c478bd9Sstevel@tonic-gate 	    &obj_unwrapkey.uk_attributes, &is_token_obj);
18757c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
18767c478bd9Sstevel@tonic-gate 		goto failed_exit;
18777c478bd9Sstevel@tonic-gate 	}
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 	/* Cannot create a token object with a READ-ONLY session. */
18807c478bd9Sstevel@tonic-gate 	if (is_token_obj && session_p->ses_RO) {
18817c478bd9Sstevel@tonic-gate 		free_object_attributes(obj_unwrapkey.uk_attributes,
18827c478bd9Sstevel@tonic-gate 		    ulAttributeCount);
18837c478bd9Sstevel@tonic-gate 		rv = CKR_SESSION_READ_ONLY;
18847c478bd9Sstevel@tonic-gate 		goto failed_exit;
18857c478bd9Sstevel@tonic-gate 	}
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 	/* Make the CRYPTO_UNWRAP_KEY ioctl call. */
18887c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_session = session_p->k_session;
18897c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_mechanism.cm_type = k_mech_type;
18907c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_mechanism.cm_param = pMechanism->pParameter;
18917c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_mechanism.cm_param_len = pMechanism->ulParameterLen;
18927c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_unwrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
18937c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_unwrapping_key.ck_obj_id = unwrappingkey_p->k_handle;
18947c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_wrapped_key = (char *)pWrappedKey;
18957c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_wrapped_key_len = ulWrappedKeyLen;
18967c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_count = ulAttributeCount;
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_UNWRAP_KEY, &obj_unwrapkey)) < 0) {
18997c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
19007c478bd9Sstevel@tonic-gate 			break;
19017c478bd9Sstevel@tonic-gate 	}
19027c478bd9Sstevel@tonic-gate 	if (r < 0) {
19037c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
19047c478bd9Sstevel@tonic-gate 	} else {
19057c478bd9Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(obj_unwrapkey.uk_return_value);
19067c478bd9Sstevel@tonic-gate 	}
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount);
19097c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
19107c478bd9Sstevel@tonic-gate 		goto failed_exit;
19117c478bd9Sstevel@tonic-gate 	}
19127c478bd9Sstevel@tonic-gate 
19137c478bd9Sstevel@tonic-gate 	/* Get the CKA_PRIVATE value for the unwrapped key. */
19147c478bd9Sstevel@tonic-gate 	rv = get_cka_private_value(session_p, obj_unwrapkey.uk_object_handle,
19157c478bd9Sstevel@tonic-gate 	    &is_pri_obj);
19167c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
19177c478bd9Sstevel@tonic-gate 		goto failed_exit;
19187c478bd9Sstevel@tonic-gate 	}
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 	/*
19217c478bd9Sstevel@tonic-gate 	 * Store the kernel object handle in the new key object wrapper and
19227c478bd9Sstevel@tonic-gate 	 * initialize it.
19237c478bd9Sstevel@tonic-gate 	 */
19247c478bd9Sstevel@tonic-gate 	new_objp->k_handle = obj_unwrapkey.uk_object_handle;
19257c478bd9Sstevel@tonic-gate 	new_objp->is_lib_obj = B_FALSE;
19267c478bd9Sstevel@tonic-gate 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
19277c478bd9Sstevel@tonic-gate 	new_objp->extra_attrlistp = NULL;
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate 	if (is_pri_obj)
19307c478bd9Sstevel@tonic-gate 		new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
19317c478bd9Sstevel@tonic-gate 	else
19327c478bd9Sstevel@tonic-gate 		new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 	if (is_token_obj)
19357c478bd9Sstevel@tonic-gate 		new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
19367c478bd9Sstevel@tonic-gate 	else
19377c478bd9Sstevel@tonic-gate 		new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
19407c478bd9Sstevel@tonic-gate 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 	/*
19437c478bd9Sstevel@tonic-gate 	 * Add the new object to the slot's token object list if it is a
19447c478bd9Sstevel@tonic-gate 	 * a token object. Otherwise, add it to the session's object list.
19457c478bd9Sstevel@tonic-gate 	 */
19467c478bd9Sstevel@tonic-gate 	if (is_token_obj) {
19477c478bd9Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
19487c478bd9Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_objp, pslot);
19497c478bd9Sstevel@tonic-gate 	} else {
19507c478bd9Sstevel@tonic-gate 		kernel_add_object_to_session(new_objp, session_p);
19517c478bd9Sstevel@tonic-gate 	}
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	*phKey = (CK_OBJECT_HANDLE)new_objp;
195401223cbaSmcpowers 	OBJ_REFRELE(unwrappingkey_p);
19557c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
19567c478bd9Sstevel@tonic-gate 	return (rv);
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate failed_exit:
195901223cbaSmcpowers 	OBJ_REFRELE(unwrappingkey_p);
19607c478bd9Sstevel@tonic-gate 	if (new_objp != NULL)
19617c478bd9Sstevel@tonic-gate 		(void) free(new_objp);
19627c478bd9Sstevel@tonic-gate 
19637c478bd9Sstevel@tonic-gate 	if (clear_key_val != NULL)
19647c478bd9Sstevel@tonic-gate 		(void) free(clear_key_val);
19657c478bd9Sstevel@tonic-gate 
19667c478bd9Sstevel@tonic-gate 	if (newTemplate != NULL)
19677c478bd9Sstevel@tonic-gate 		(void) free(newTemplate);
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
19707c478bd9Sstevel@tonic-gate 	return (rv);
19717c478bd9Sstevel@tonic-gate }
19727c478bd9Sstevel@tonic-gate 
1973*034448feSmcpowers /*
1974*034448feSmcpowers  * Get sufficient attributes from a base key to pass by value in a
1975*034448feSmcpowers  * crypto_key structure. Storage for attributes is allocated.
1976*034448feSmcpowers  * For EC public keys, it is CKA_EC_PARAMS and CKA_EC_POINT.
1977*034448feSmcpowers  * For EC private keys, it is CKA_EC_PARAMS and CKA_VALUE.
1978*034448feSmcpowers  */
1979*034448feSmcpowers static int
1980*034448feSmcpowers get_base_key_attributes(kernel_object_t *base_key, crypto_key_t *key_by_value)
1981*034448feSmcpowers {
1982*034448feSmcpowers 	CK_ATTRIBUTE tmp;
1983*034448feSmcpowers 	crypto_object_attribute_t *attrs;
1984*034448feSmcpowers 	biginteger_t *big;
1985*034448feSmcpowers 	int rv;
1986*034448feSmcpowers 
1987*034448feSmcpowers 	switch (base_key->key_type) {
1988*034448feSmcpowers 	case CKK_EC:
1989*034448feSmcpowers 		attrs = malloc(2 * sizeof (crypto_object_attribute_t));
1990*034448feSmcpowers 		if (attrs == NULL) {
1991*034448feSmcpowers 			rv = CKR_HOST_MEMORY;
1992*034448feSmcpowers 			goto out;
1993*034448feSmcpowers 		}
1994*034448feSmcpowers 		bzero(attrs, 2 * sizeof (crypto_object_attribute_t));
1995*034448feSmcpowers 
1996*034448feSmcpowers 		(void) pthread_mutex_lock(&base_key->object_mutex);
1997*034448feSmcpowers 
1998*034448feSmcpowers 		if (!base_key->is_lib_obj) {
1999*034448feSmcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
2000*034448feSmcpowers 			goto out;
2001*034448feSmcpowers 		}
2002*034448feSmcpowers 
2003*034448feSmcpowers 		if (base_key->class != CKO_PUBLIC_KEY &&
2004*034448feSmcpowers 		    base_key->class != CKO_PRIVATE_KEY) {
2005*034448feSmcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
2006*034448feSmcpowers 			goto out;
2007*034448feSmcpowers 		}
2008*034448feSmcpowers 
2009*034448feSmcpowers 		/*
2010*034448feSmcpowers 		 * Both public and private EC keys should have
2011*034448feSmcpowers 		 * a CKA_EC_PARAMS attribute.
2012*034448feSmcpowers 		 */
2013*034448feSmcpowers 		tmp.type = CKA_EC_PARAMS;
2014*034448feSmcpowers 		tmp.pValue = NULL;
2015*034448feSmcpowers 
2016*034448feSmcpowers 		/* get size of attribute */
2017*034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2018*034448feSmcpowers 		if (rv != CKR_OK) {
2019*034448feSmcpowers 			goto out;
2020*034448feSmcpowers 		}
2021*034448feSmcpowers 
2022*034448feSmcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2023*034448feSmcpowers 		if (tmp.pValue == NULL) {
2024*034448feSmcpowers 			rv = CKR_HOST_MEMORY;
2025*034448feSmcpowers 			goto out;
2026*034448feSmcpowers 		}
2027*034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2028*034448feSmcpowers 		if (rv != CKR_OK) {
2029*034448feSmcpowers 			goto out;
2030*034448feSmcpowers 		}
2031*034448feSmcpowers 		attrs[0].oa_type = tmp.type;
2032*034448feSmcpowers 		attrs[0].oa_value = tmp.pValue;
2033*034448feSmcpowers 		attrs[0].oa_value_len = tmp.ulValueLen;
2034*034448feSmcpowers 
2035*034448feSmcpowers 		switch (base_key->class) {
2036*034448feSmcpowers 		case CKO_PUBLIC_KEY:
2037*034448feSmcpowers 			big = OBJ_PUB_EC_POINT(base_key);
2038*034448feSmcpowers 			tmp.type = CKA_EC_POINT;
2039*034448feSmcpowers 			break;
2040*034448feSmcpowers 
2041*034448feSmcpowers 		case CKO_PRIVATE_KEY:
2042*034448feSmcpowers 			big = OBJ_PRI_EC_VALUE(base_key);
2043*034448feSmcpowers 			tmp.type = CKA_VALUE;
2044*034448feSmcpowers 			break;
2045*034448feSmcpowers 
2046*034448feSmcpowers 		default:
2047*034448feSmcpowers 			rv = CKR_ATTRIBUTE_TYPE_INVALID;
2048*034448feSmcpowers 			goto out;
2049*034448feSmcpowers 		}
2050*034448feSmcpowers 		tmp.ulValueLen = big->big_value_len;
2051*034448feSmcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2052*034448feSmcpowers 		if (tmp.pValue == NULL) {
2053*034448feSmcpowers 			rv = CKR_HOST_MEMORY;
2054*034448feSmcpowers 			goto out;
2055*034448feSmcpowers 		}
2056*034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2057*034448feSmcpowers 		if (rv != CKR_OK) {
2058*034448feSmcpowers 			goto out;
2059*034448feSmcpowers 		}
2060*034448feSmcpowers 		attrs[1].oa_type = tmp.type;
2061*034448feSmcpowers 		attrs[1].oa_value = tmp.pValue;
2062*034448feSmcpowers 		attrs[1].oa_value_len = tmp.ulValueLen;
2063*034448feSmcpowers 		key_by_value->ck_attrs = attrs;
2064*034448feSmcpowers 		key_by_value->ck_count = 2;
2065*034448feSmcpowers 		break;
2066*034448feSmcpowers 
2067*034448feSmcpowers 	case CKK_DH:
2068*034448feSmcpowers 		attrs = malloc(3 * sizeof (crypto_object_attribute_t));
2069*034448feSmcpowers 		if (attrs == NULL) {
2070*034448feSmcpowers 			rv = CKR_HOST_MEMORY;
2071*034448feSmcpowers 			goto out;
2072*034448feSmcpowers 		}
2073*034448feSmcpowers 		bzero(attrs, 3 * sizeof (crypto_object_attribute_t));
2074*034448feSmcpowers 
2075*034448feSmcpowers 		(void) pthread_mutex_lock(&base_key->object_mutex);
2076*034448feSmcpowers 
2077*034448feSmcpowers 		if (!base_key->is_lib_obj) {
2078*034448feSmcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
2079*034448feSmcpowers 			goto out;
2080*034448feSmcpowers 		}
2081*034448feSmcpowers 
2082*034448feSmcpowers 		if (base_key->class != CKO_PRIVATE_KEY) {
2083*034448feSmcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
2084*034448feSmcpowers 			goto out;
2085*034448feSmcpowers 		}
2086*034448feSmcpowers 		tmp.type = CKA_BASE;
2087*034448feSmcpowers 		tmp.pValue = NULL;
2088*034448feSmcpowers 
2089*034448feSmcpowers 		/* get size of attribute */
2090*034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2091*034448feSmcpowers 		if (rv != CKR_OK) {
2092*034448feSmcpowers 			goto out;
2093*034448feSmcpowers 		}
2094*034448feSmcpowers 
2095*034448feSmcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2096*034448feSmcpowers 		if (tmp.pValue == NULL) {
2097*034448feSmcpowers 			rv = CKR_HOST_MEMORY;
2098*034448feSmcpowers 			goto out;
2099*034448feSmcpowers 		}
2100*034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2101*034448feSmcpowers 		if (rv != CKR_OK) {
2102*034448feSmcpowers 			goto out;
2103*034448feSmcpowers 		}
2104*034448feSmcpowers 		attrs[0].oa_type = tmp.type;
2105*034448feSmcpowers 		attrs[0].oa_value = tmp.pValue;
2106*034448feSmcpowers 		attrs[0].oa_value_len = tmp.ulValueLen;
2107*034448feSmcpowers 
2108*034448feSmcpowers 		tmp.type = CKA_PRIME;
2109*034448feSmcpowers 		tmp.pValue = NULL;
2110*034448feSmcpowers 
2111*034448feSmcpowers 		/* get size of attribute */
2112*034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2113*034448feSmcpowers 		if (rv != CKR_OK) {
2114*034448feSmcpowers 			goto out;
2115*034448feSmcpowers 		}
2116*034448feSmcpowers 
2117*034448feSmcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2118*034448feSmcpowers 		if (tmp.pValue == NULL) {
2119*034448feSmcpowers 			rv = CKR_HOST_MEMORY;
2120*034448feSmcpowers 			goto out;
2121*034448feSmcpowers 		}
2122*034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2123*034448feSmcpowers 		if (rv != CKR_OK) {
2124*034448feSmcpowers 			goto out;
2125*034448feSmcpowers 		}
2126*034448feSmcpowers 		attrs[1].oa_type = tmp.type;
2127*034448feSmcpowers 		attrs[1].oa_value = tmp.pValue;
2128*034448feSmcpowers 		attrs[1].oa_value_len = tmp.ulValueLen;
2129*034448feSmcpowers 
2130*034448feSmcpowers 		big = OBJ_PRI_EC_VALUE(base_key);
2131*034448feSmcpowers 		tmp.type = CKA_VALUE;
2132*034448feSmcpowers 
2133*034448feSmcpowers 		tmp.ulValueLen = big->big_value_len;
2134*034448feSmcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2135*034448feSmcpowers 		if (tmp.pValue == NULL) {
2136*034448feSmcpowers 			rv = CKR_HOST_MEMORY;
2137*034448feSmcpowers 			goto out;
2138*034448feSmcpowers 		}
2139*034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2140*034448feSmcpowers 		if (rv != CKR_OK) {
2141*034448feSmcpowers 			goto out;
2142*034448feSmcpowers 		}
2143*034448feSmcpowers 		attrs[2].oa_type = tmp.type;
2144*034448feSmcpowers 		attrs[2].oa_value = tmp.pValue;
2145*034448feSmcpowers 		attrs[2].oa_value_len = tmp.ulValueLen;
2146*034448feSmcpowers 		key_by_value->ck_attrs = attrs;
2147*034448feSmcpowers 		key_by_value->ck_count = 3;
2148*034448feSmcpowers 		break;
2149*034448feSmcpowers 
2150*034448feSmcpowers 	default:
2151*034448feSmcpowers 		rv = CKR_ATTRIBUTE_TYPE_INVALID;
2152*034448feSmcpowers 		goto out;
2153*034448feSmcpowers 	}
2154*034448feSmcpowers 	(void) pthread_mutex_unlock(&base_key->object_mutex);
2155*034448feSmcpowers 	return (CKR_OK);
2156*034448feSmcpowers 
2157*034448feSmcpowers out:
2158*034448feSmcpowers 	(void) pthread_mutex_unlock(&base_key->object_mutex);
2159*034448feSmcpowers 	return (rv);
2160*034448feSmcpowers }
2161*034448feSmcpowers 
2162*034448feSmcpowers CK_RV
2163*034448feSmcpowers derive_key_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
2164*034448feSmcpowers     CK_ULONG ulAttributeCount, kernel_session_t *session_p,
2165*034448feSmcpowers     crypto_mech_type_t k_mech_type, kernel_object_t *basekey_p,
2166*034448feSmcpowers     kernel_object_t *new_objp)
2167*034448feSmcpowers {
2168*034448feSmcpowers 	crypto_nostore_derive_key_t obj_ndk;
2169*034448feSmcpowers 	char *key_buf = NULL;
2170*034448feSmcpowers 	CK_ATTRIBUTE_PTR newTemplate = NULL;
2171*034448feSmcpowers 	CK_BBOOL is_token_obj = FALSE;
2172*034448feSmcpowers 	CK_RV rv = CKR_OK;
2173*034448feSmcpowers 	CK_ULONG secret_class = CKO_SECRET_KEY;
2174*034448feSmcpowers 	ulong_t key_len = 0;
2175*034448feSmcpowers 	uint_t attr_count = 0;
2176*034448feSmcpowers 	boolean_t removed;
2177*034448feSmcpowers 	boolean_t has_class;
2178*034448feSmcpowers 	int r, n;
2179*034448feSmcpowers 
2180*034448feSmcpowers 	obj_ndk.ndk_in_count = 0;
2181*034448feSmcpowers 	obj_ndk.ndk_out_count = 0;
2182*034448feSmcpowers 	obj_ndk.ndk_base_key.ck_count = 0;
2183*034448feSmcpowers 
2184*034448feSmcpowers 	rv = get_key_len_from_template(pMechanism, pTemplate, ulAttributeCount,
2185*034448feSmcpowers 	    basekey_p, &key_len);
2186*034448feSmcpowers 	if (rv != CKR_OK) {
2187*034448feSmcpowers 		goto failed_exit;
2188*034448feSmcpowers 	}
2189*034448feSmcpowers 
2190*034448feSmcpowers 	if ((key_buf = malloc(key_len)) == NULL) {
2191*034448feSmcpowers 		rv = CKR_HOST_MEMORY;
2192*034448feSmcpowers 		goto failed_exit;
2193*034448feSmcpowers 	}
2194*034448feSmcpowers 
2195*034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pTemplate,
2196*034448feSmcpowers 	    ulAttributeCount);
2197*034448feSmcpowers 
2198*034448feSmcpowers 	attr_count = ulAttributeCount + 1;
2199*034448feSmcpowers 	if (!has_class)
2200*034448feSmcpowers 		attr_count++;
2201*034448feSmcpowers 
2202*034448feSmcpowers 	newTemplate = grow_template(pTemplate, ulAttributeCount, attr_count);
2203*034448feSmcpowers 	if (newTemplate == NULL) {
2204*034448feSmcpowers 		rv = CKR_HOST_MEMORY;
2205*034448feSmcpowers 		goto failed_exit;
2206*034448feSmcpowers 	}
2207*034448feSmcpowers 
2208*034448feSmcpowers 	n = ulAttributeCount;
2209*034448feSmcpowers 	if (!has_class) {
2210*034448feSmcpowers 		newTemplate[n].type = CKA_CLASS;
2211*034448feSmcpowers 		newTemplate[n].pValue = (caddr_t)&secret_class;
2212*034448feSmcpowers 		newTemplate[n].ulValueLen = sizeof (secret_class);
2213*034448feSmcpowers 		n++;
2214*034448feSmcpowers 	}
2215*034448feSmcpowers 
2216*034448feSmcpowers 	/* Add CKA_VALUE to the template */
2217*034448feSmcpowers 	newTemplate[n].type = CKA_VALUE;
2218*034448feSmcpowers 	newTemplate[n].pValue = (caddr_t)key_buf;
2219*034448feSmcpowers 	newTemplate[n].ulValueLen = key_len;
2220*034448feSmcpowers 
2221*034448feSmcpowers 	rv = process_object_attributes(newTemplate, attr_count - 1,
2222*034448feSmcpowers 	    &obj_ndk.ndk_in_attributes, &is_token_obj);
2223*034448feSmcpowers 	if (rv != CKR_OK) {
2224*034448feSmcpowers 		goto failed_exit;
2225*034448feSmcpowers 	}
2226*034448feSmcpowers 
2227*034448feSmcpowers 	rv = process_object_attributes(&newTemplate[attr_count - 1],
2228*034448feSmcpowers 	    1, &obj_ndk.ndk_out_attributes, &is_token_obj);
2229*034448feSmcpowers 	if (rv != CKR_OK) {
2230*034448feSmcpowers 		goto failed_exit;
2231*034448feSmcpowers 	}
2232*034448feSmcpowers 
2233*034448feSmcpowers 	/* Cannot create a token object with a READ-ONLY session. */
2234*034448feSmcpowers 	if (is_token_obj && session_p->ses_RO) {
2235*034448feSmcpowers 		rv = CKR_SESSION_READ_ONLY;
2236*034448feSmcpowers 		goto failed_exit;
2237*034448feSmcpowers 	}
2238*034448feSmcpowers 
2239*034448feSmcpowers 	obj_ndk.ndk_session = session_p->k_session;
2240*034448feSmcpowers 	obj_ndk.ndk_mechanism.cm_type = k_mech_type;
2241*034448feSmcpowers 	obj_ndk.ndk_mechanism.cm_param = pMechanism->pParameter;
2242*034448feSmcpowers 	obj_ndk.ndk_mechanism.cm_param_len = pMechanism->ulParameterLen;
2243*034448feSmcpowers 
2244*034448feSmcpowers 	/*
2245*034448feSmcpowers 	 * Obtain the attributes of base key and pass them by value.
2246*034448feSmcpowers 	 */
2247*034448feSmcpowers 	rv = get_base_key_attributes(basekey_p, &obj_ndk.ndk_base_key);
2248*034448feSmcpowers 	if (rv != CKR_OK) {
2249*034448feSmcpowers 		goto failed_exit;
2250*034448feSmcpowers 	}
2251*034448feSmcpowers 
2252*034448feSmcpowers 	obj_ndk.ndk_base_key.ck_format = CRYPTO_KEY_ATTR_LIST;
2253*034448feSmcpowers 	obj_ndk.ndk_in_count = attr_count - 1;
2254*034448feSmcpowers 	obj_ndk.ndk_out_count = 1;
2255*034448feSmcpowers 
2256*034448feSmcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_DERIVE_KEY,
2257*034448feSmcpowers 	    &obj_ndk)) < 0) {
2258*034448feSmcpowers 		if (errno != EINTR)
2259*034448feSmcpowers 			break;
2260*034448feSmcpowers 	}
2261*034448feSmcpowers 	if (r < 0) {
2262*034448feSmcpowers 		rv = CKR_FUNCTION_FAILED;
2263*034448feSmcpowers 	} else {
2264*034448feSmcpowers 		rv = crypto2pkcs11_error_number(obj_ndk.ndk_return_value);
2265*034448feSmcpowers 	}
2266*034448feSmcpowers 	free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
2267*034448feSmcpowers 	free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
2268*034448feSmcpowers 	    &obj_ndk.ndk_base_key.ck_count);
2269*034448feSmcpowers 	if (rv != CKR_OK) {
2270*034448feSmcpowers 		goto failed_exit;
2271*034448feSmcpowers 	}
2272*034448feSmcpowers 
2273*034448feSmcpowers 	rv = get_object_attributes(&newTemplate[attr_count - 1],
2274*034448feSmcpowers 	    1, obj_ndk.ndk_out_attributes);
2275*034448feSmcpowers 	free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
2276*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
2277*034448feSmcpowers 		goto failed_exit;
2278*034448feSmcpowers 	}
2279*034448feSmcpowers 
2280*034448feSmcpowers 	removed = remove_one_attribute(newTemplate, CKA_VALUE_LEN,
2281*034448feSmcpowers 	    attr_count, B_FALSE);
2282*034448feSmcpowers 
2283*034448feSmcpowers 	rv = kernel_build_object(newTemplate, removed ? attr_count - 1 :
2284*034448feSmcpowers 	    attr_count, new_objp, session_p, KERNEL_GEN_KEY);
2285*034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
2286*034448feSmcpowers 		goto failed_exit;
2287*034448feSmcpowers 	}
2288*034448feSmcpowers 
2289*034448feSmcpowers 	free(key_buf);
2290*034448feSmcpowers 	free(newTemplate);
2291*034448feSmcpowers 	new_objp->is_lib_obj = B_TRUE;
2292*034448feSmcpowers 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
2293*034448feSmcpowers 	return (CKR_OK);
2294*034448feSmcpowers 
2295*034448feSmcpowers failed_exit:
2296*034448feSmcpowers 	if (key_buf != NULL)
2297*034448feSmcpowers 		free(key_buf);
2298*034448feSmcpowers 	if (newTemplate != NULL)
2299*034448feSmcpowers 		free(newTemplate);
2300*034448feSmcpowers 	free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
2301*034448feSmcpowers 	free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
2302*034448feSmcpowers 	free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
2303*034448feSmcpowers 	    &obj_ndk.ndk_base_key.ck_count);
2304*034448feSmcpowers 	return (rv);
2305*034448feSmcpowers }
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate CK_RV
23087c478bd9Sstevel@tonic-gate C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
23097c478bd9Sstevel@tonic-gate     CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
23107c478bd9Sstevel@tonic-gate     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
23117c478bd9Sstevel@tonic-gate {
23127c478bd9Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
23137c478bd9Sstevel@tonic-gate 	kernel_session_t	*session_p;
23147c478bd9Sstevel@tonic-gate 	kernel_object_t		*basekey_p;
23157c478bd9Sstevel@tonic-gate 	kernel_object_t		*new_objp;
23167c478bd9Sstevel@tonic-gate 	kernel_slot_t		*pslot;
23177c478bd9Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
23187c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj;
23197c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_token_obj = FALSE;
23207c478bd9Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
23217c478bd9Sstevel@tonic-gate 	int r;
23227c478bd9Sstevel@tonic-gate 
23237c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
23247c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate 	/* Obtain the session pointer. */
23277c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
23287c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
23297c478bd9Sstevel@tonic-gate 		return (rv);
23307c478bd9Sstevel@tonic-gate 
233160722cc8Sizick 	if (pMechanism == NULL) {
233201223cbaSmcpowers 		REFRELE(session_p, ses_lock_held);
233301223cbaSmcpowers 		return (CKR_ARGUMENTS_BAD);
23347c478bd9Sstevel@tonic-gate 	}
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate 	if ((pTemplate == NULL && ulAttributeCount != 0) ||
23377c478bd9Sstevel@tonic-gate 	    (pTemplate != NULL && ulAttributeCount == 0)) {
233801223cbaSmcpowers 		REFRELE(session_p, ses_lock_held);
233901223cbaSmcpowers 		return (CKR_ARGUMENTS_BAD);
23407c478bd9Sstevel@tonic-gate 	}
23417c478bd9Sstevel@tonic-gate 
23427c478bd9Sstevel@tonic-gate 	/* Obtain the base key object pointer. */
23437c478bd9Sstevel@tonic-gate 	HANDLE2OBJECT(hBaseKey, basekey_p, rv);
23447c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
234501223cbaSmcpowers 		REFRELE(session_p, ses_lock_held);
234601223cbaSmcpowers 		return (rv);
23477c478bd9Sstevel@tonic-gate 	}
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
23507c478bd9Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
23517c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
23527c478bd9Sstevel@tonic-gate 		goto failed_exit;
23537c478bd9Sstevel@tonic-gate 	}
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 	/* Create an object wrapper in the library for the generated key. */
23567c478bd9Sstevel@tonic-gate 	new_objp = calloc(1, sizeof (kernel_object_t));
23577c478bd9Sstevel@tonic-gate 	if (new_objp == NULL) {
23587c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
23597c478bd9Sstevel@tonic-gate 		goto failed_exit;
23607c478bd9Sstevel@tonic-gate 	}
23617c478bd9Sstevel@tonic-gate 
2362*034448feSmcpowers 	/*
2363*034448feSmcpowers 	 * Special Case: if token does not support object creation,
2364*034448feSmcpowers 	 * but does support key derivation by value, then create a session
2365*034448feSmcpowers 	 * object and initialize with values returned by token.
2366*034448feSmcpowers 	 */
2367*034448feSmcpowers 	pslot = slot_table[session_p->ses_slotid];
2368*034448feSmcpowers 	if (!pslot->sl_func_list.fl_object_create) {
2369*034448feSmcpowers 		rv = derive_key_by_value(pMechanism, pTemplate,
2370*034448feSmcpowers 		    ulAttributeCount, session_p, k_mech_type, basekey_p,
2371*034448feSmcpowers 		    new_objp);
2372*034448feSmcpowers 		if (rv != CKR_OK)
2373*034448feSmcpowers 			goto failed_exit;
2374*034448feSmcpowers 	} else {
2375*034448feSmcpowers 		crypto_derive_key_t obj_dk;
2376*034448feSmcpowers 
23777c478bd9Sstevel@tonic-gate 		rv = process_object_attributes(pTemplate, ulAttributeCount,
23787c478bd9Sstevel@tonic-gate 		    &obj_dk.dk_attributes, &is_token_obj);
23797c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
23807c478bd9Sstevel@tonic-gate 			goto failed_exit;
23817c478bd9Sstevel@tonic-gate 		}
23827c478bd9Sstevel@tonic-gate 
23837c478bd9Sstevel@tonic-gate 		/* Cannot create a token object with a READ-ONLY session. */
23847c478bd9Sstevel@tonic-gate 		if (is_token_obj && session_p->ses_RO) {
2385*034448feSmcpowers 			free_object_attributes(obj_dk.dk_attributes,
2386*034448feSmcpowers 			    ulAttributeCount);
23877c478bd9Sstevel@tonic-gate 			rv = CKR_SESSION_READ_ONLY;
23887c478bd9Sstevel@tonic-gate 			goto failed_exit;
23897c478bd9Sstevel@tonic-gate 		}
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate 		obj_dk.dk_session = session_p->k_session;
23927c478bd9Sstevel@tonic-gate 		obj_dk.dk_mechanism.cm_type = k_mech_type;
23937c478bd9Sstevel@tonic-gate 		obj_dk.dk_mechanism.cm_param = pMechanism->pParameter;
23947c478bd9Sstevel@tonic-gate 		obj_dk.dk_mechanism.cm_param_len = pMechanism->ulParameterLen;
23957c478bd9Sstevel@tonic-gate 		obj_dk.dk_base_key.ck_format = CRYPTO_KEY_REFERENCE;
23967c478bd9Sstevel@tonic-gate 		obj_dk.dk_base_key.ck_obj_id = basekey_p->k_handle;
23977c478bd9Sstevel@tonic-gate 		obj_dk.dk_count = ulAttributeCount;
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate 		while ((r = ioctl(kernel_fd, CRYPTO_DERIVE_KEY, &obj_dk)) < 0) {
24007c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
24017c478bd9Sstevel@tonic-gate 				break;
24027c478bd9Sstevel@tonic-gate 		}
24037c478bd9Sstevel@tonic-gate 		if (r < 0) {
24047c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
24057c478bd9Sstevel@tonic-gate 		} else {
24067c478bd9Sstevel@tonic-gate 			rv = crypto2pkcs11_error_number(obj_dk.dk_return_value);
24077c478bd9Sstevel@tonic-gate 		}
24087c478bd9Sstevel@tonic-gate 
24097c478bd9Sstevel@tonic-gate 		free_object_attributes(obj_dk.dk_attributes, ulAttributeCount);
24107c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
24117c478bd9Sstevel@tonic-gate 			goto failed_exit;
24127c478bd9Sstevel@tonic-gate 		}
24137c478bd9Sstevel@tonic-gate 
24147c478bd9Sstevel@tonic-gate 		/* Get the CKA_PRIVATE value for the derived key. */
24157c478bd9Sstevel@tonic-gate 		rv = get_cka_private_value(session_p, obj_dk.dk_object_handle,
24167c478bd9Sstevel@tonic-gate 		    &is_pri_obj);
24177c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
24187c478bd9Sstevel@tonic-gate 			goto failed_exit;
24197c478bd9Sstevel@tonic-gate 		}
24207c478bd9Sstevel@tonic-gate 
24217c478bd9Sstevel@tonic-gate 		/*
2422*034448feSmcpowers 		 * Store the kernel object handle into the new derived key
2423*034448feSmcpowers 		 * object and finish the object initialization.
24247c478bd9Sstevel@tonic-gate 		 */
24257c478bd9Sstevel@tonic-gate 		new_objp->is_lib_obj = B_FALSE;
24267c478bd9Sstevel@tonic-gate 		new_objp->k_handle = obj_dk.dk_object_handle;
24277c478bd9Sstevel@tonic-gate 		new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
24287c478bd9Sstevel@tonic-gate 		new_objp->extra_attrlistp = NULL;
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate 		if (is_pri_obj)
24317c478bd9Sstevel@tonic-gate 			new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
24327c478bd9Sstevel@tonic-gate 		else
24337c478bd9Sstevel@tonic-gate 			new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
24347c478bd9Sstevel@tonic-gate 
24357c478bd9Sstevel@tonic-gate 		if (is_token_obj)
24367c478bd9Sstevel@tonic-gate 			new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
24377c478bd9Sstevel@tonic-gate 		else
24387c478bd9Sstevel@tonic-gate 			new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
2439*034448feSmcpowers 	}
24407c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
24417c478bd9Sstevel@tonic-gate 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 	/*
24447c478bd9Sstevel@tonic-gate 	 * Add the new derived object to the slot's token list if it is a
24457c478bd9Sstevel@tonic-gate 	 * token object. Otherwise, add it to the session's object list.
24467c478bd9Sstevel@tonic-gate 	 */
24477c478bd9Sstevel@tonic-gate 	if (is_token_obj) {
24487c478bd9Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
24497c478bd9Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_objp, pslot);
24507c478bd9Sstevel@tonic-gate 	} else {
24517c478bd9Sstevel@tonic-gate 		kernel_add_object_to_session(new_objp, session_p);
24527c478bd9Sstevel@tonic-gate 	}
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 	*phKey = (CK_OBJECT_HANDLE)new_objp;
245501223cbaSmcpowers 	OBJ_REFRELE(basekey_p);
24567c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
24577c478bd9Sstevel@tonic-gate 	return (rv);
24587c478bd9Sstevel@tonic-gate 
24597c478bd9Sstevel@tonic-gate failed_exit:
246001223cbaSmcpowers 	OBJ_REFRELE(basekey_p);
24617c478bd9Sstevel@tonic-gate 	if (new_objp != NULL) {
24627c478bd9Sstevel@tonic-gate 		(void) free(new_objp);
24637c478bd9Sstevel@tonic-gate 	}
24647c478bd9Sstevel@tonic-gate 
24657c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
24667c478bd9Sstevel@tonic-gate 	return (rv);
24677c478bd9Sstevel@tonic-gate }
2468