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
5034448feSmcpowers  * Common Development and Distribution License (the "License").
6034448feSmcpowers  * 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 /*
2277e5e96bSMark Powers  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*a8793c76SJason King  * Copyright 2018, Joyent, Inc.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <strings.h>
287c478bd9Sstevel@tonic-gate #include <errno.h>
29f9fbec18Smcpowers #include <ecc_impl.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 
36034448feSmcpowers static boolean_t
attribute_in_template(CK_ATTRIBUTE_TYPE type,CK_ATTRIBUTE_PTR t,CK_ULONG cnt)37034448feSmcpowers attribute_in_template(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
38034448feSmcpowers {
39034448feSmcpowers 	int i;
40034448feSmcpowers 
41034448feSmcpowers 	for (i = 0; i < cnt; i++) {
42034448feSmcpowers 		if (t[i].type == type)
43034448feSmcpowers 			return (B_TRUE);
44034448feSmcpowers 	}
45034448feSmcpowers 	return (B_FALSE);
46034448feSmcpowers }
47034448feSmcpowers 
48034448feSmcpowers /*
49034448feSmcpowers  * This routine returns modulus bytes rounded up to the nearest 8 byte
50034448feSmcpowers  * chunk. This is so we don't have to pass in max sized buffers for
51034448feSmcpowers  * returned attributes. Every unnecessary byte that we pass in results
52034448feSmcpowers  * in a kernel allocation.
53034448feSmcpowers  */
54034448feSmcpowers static ulong_t
get_modulus_bytes(CK_ATTRIBUTE_PTR t,CK_ULONG cnt)55034448feSmcpowers get_modulus_bytes(CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
56034448feSmcpowers {
57034448feSmcpowers 	CK_ULONG modulus_len;
58034448feSmcpowers 	int i;
59034448feSmcpowers 
60034448feSmcpowers 	for (i = 0; i < cnt; i++) {
61034448feSmcpowers 		if (t[i].type == CKA_MODULUS_BITS) {
62034448feSmcpowers 			get_ulong_attr_from_template(&modulus_len, &t[i]);
63034448feSmcpowers 			/* convert from bit length to byte length */
64034448feSmcpowers 			modulus_len = (modulus_len - 1) / 64 + 1;
65034448feSmcpowers 			return (modulus_len * 8);
66034448feSmcpowers 		}
67034448feSmcpowers 	}
68034448feSmcpowers 	return (0);
69034448feSmcpowers }
70034448feSmcpowers 
71034448feSmcpowers /*
72034448feSmcpowers  * Remove specified attribute from array. Storage for the attribute's
73034448feSmcpowers  * value is freed if 'free_attr' is TRUE. Attributes are shifted so they are
74034448feSmcpowers  * contiguous within the array, i.e. the next attribute is shifted into
75034448feSmcpowers  * the position of the removed attribute. Returns TRUE if specified
76034448feSmcpowers  * attribute is removed.
77034448feSmcpowers  */
78034448feSmcpowers static boolean_t
remove_one_attribute(CK_ATTRIBUTE_PTR t,CK_ULONG type,uint_t count,boolean_t free_attr)79034448feSmcpowers remove_one_attribute(CK_ATTRIBUTE_PTR t, CK_ULONG type, uint_t count,
80034448feSmcpowers     boolean_t free_attr)
81034448feSmcpowers {
82034448feSmcpowers 	int i, j;
83034448feSmcpowers 
84034448feSmcpowers 	for (i = 0, j = 0; i < count; i++) {
85034448feSmcpowers 		if (t[i].type == type) {
86034448feSmcpowers 			if (free_attr) {
87034448feSmcpowers 				free(t[i].pValue);
88034448feSmcpowers 			}
89034448feSmcpowers 			continue;
90034448feSmcpowers 		}
91034448feSmcpowers 		if (i != j) {
92034448feSmcpowers 			t[j].type = t[i].type;
93034448feSmcpowers 			t[j].pValue = t[i].pValue;
94034448feSmcpowers 			t[j].ulValueLen = t[i].ulValueLen;
95034448feSmcpowers 		}
96034448feSmcpowers 		j++;
97034448feSmcpowers 	}
98034448feSmcpowers 	if (j == count)
99034448feSmcpowers 		return (B_FALSE);
100034448feSmcpowers 
101034448feSmcpowers 	/* safety */
102034448feSmcpowers 	t[j].pValue = NULL;
103034448feSmcpowers 	t[j].ulValueLen = 0;
104034448feSmcpowers 	return (B_TRUE);
105034448feSmcpowers }
106034448feSmcpowers 
1077c478bd9Sstevel@tonic-gate static boolean_t
is_secret_key_template(CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount)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 	}
117034448feSmcpowers 	return (B_FALSE);
118034448feSmcpowers }
119034448feSmcpowers 
120034448feSmcpowers /*
121034448feSmcpowers  * Allocate a template with space for new_count entries and copy the
122034448feSmcpowers  * specified template into the new template.
123034448feSmcpowers  */
124034448feSmcpowers static CK_ATTRIBUTE_PTR
grow_template(CK_ATTRIBUTE_PTR old_template,CK_ULONG old_count,CK_ULONG new_count)125034448feSmcpowers grow_template(CK_ATTRIBUTE_PTR old_template, CK_ULONG old_count,
126034448feSmcpowers     CK_ULONG new_count)
127034448feSmcpowers {
128034448feSmcpowers 	CK_ATTRIBUTE_PTR new_template;
129034448feSmcpowers 
130034448feSmcpowers 	new_template = malloc(new_count * sizeof (CK_ATTRIBUTE));
131034448feSmcpowers 	if (new_template != NULL)
132034448feSmcpowers 		bcopy(old_template, new_template,
133034448feSmcpowers 		    old_count * sizeof (CK_ATTRIBUTE));
134034448feSmcpowers 	return (new_template);
135034448feSmcpowers }
136034448feSmcpowers 
137034448feSmcpowers /*
138034448feSmcpowers  * For fixed length keys such as DES, return the length based on
139034448feSmcpowers  * the key type. For variable length keys such as AES, take the
140034448feSmcpowers  * length from the CKA_VALUE_LEN attribute.
141034448feSmcpowers  */
142034448feSmcpowers static int
get_key_len_from_template(CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,kernel_object_t * basekey_p,ulong_t * key_len)143034448feSmcpowers get_key_len_from_template(CK_MECHANISM_PTR pMechanism,
144034448feSmcpowers     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
145034448feSmcpowers     kernel_object_t *basekey_p,  ulong_t *key_len)
146034448feSmcpowers {
147034448feSmcpowers 	boolean_t fixed_len_key = B_FALSE;
148034448feSmcpowers 	ulong_t key_type;
149034448feSmcpowers 	int i;
150034448feSmcpowers 
151034448feSmcpowers 	for (i = 0; i < ulAttributeCount; i++) {
152034448feSmcpowers 		if (pTemplate[i].type == CKA_KEY_TYPE) {
153034448feSmcpowers 			get_ulong_attr_from_template(&key_type, &pTemplate[i]);
154034448feSmcpowers 			break;
155034448feSmcpowers 		}
156034448feSmcpowers 	}
157034448feSmcpowers 	/* CKA_KEY_TYPE must be present */
158034448feSmcpowers 	if (i == ulAttributeCount)
159034448feSmcpowers 		return (CKR_TEMPLATE_INCOMPLETE);
160034448feSmcpowers 
161034448feSmcpowers 	switch (key_type) {
162034448feSmcpowers 	case CKK_DES:
163034448feSmcpowers 		*key_len = 8;
164034448feSmcpowers 		fixed_len_key = B_TRUE;
165034448feSmcpowers 		break;
166034448feSmcpowers 	case CKK_DES3:
167034448feSmcpowers 		*key_len = 24;
168034448feSmcpowers 		fixed_len_key = B_TRUE;
169034448feSmcpowers 		break;
170034448feSmcpowers 	case CKK_AES:
171034448feSmcpowers 	case CKK_BLOWFISH:
172034448feSmcpowers 		for (i = 0; i < ulAttributeCount; i++) {
173034448feSmcpowers 			if (pTemplate[i].type == CKA_VALUE_LEN) {
174034448feSmcpowers 				get_ulong_attr_from_template(key_len,
175034448feSmcpowers 				    &pTemplate[i]);
176034448feSmcpowers 				break;
177034448feSmcpowers 			}
178034448feSmcpowers 		}
179034448feSmcpowers 		/* CKA_VALUE_LEN must be present */
180034448feSmcpowers 		if (i == ulAttributeCount)
181034448feSmcpowers 			return (CKR_TEMPLATE_INCOMPLETE);
182034448feSmcpowers 		break;
183034448feSmcpowers 	case CKK_GENERIC_SECRET:
184034448feSmcpowers 		/*
185034448feSmcpowers 		 * The key will not be truncated, so we need to
186034448feSmcpowers 		 * get the max length for the mechanism.
187034448feSmcpowers 		 */
188034448feSmcpowers 		if (pMechanism->mechanism == CKM_DH_PKCS_DERIVE) {
189034448feSmcpowers 			CK_ATTRIBUTE tmp;
190034448feSmcpowers 
191034448feSmcpowers 			tmp.type = CKA_PRIME;
192034448feSmcpowers 			tmp.pValue = NULL;
193034448feSmcpowers 
194034448feSmcpowers 			/* get size of attribute */
195034448feSmcpowers 			if (kernel_get_attribute(basekey_p, &tmp) != CKR_OK) {
196034448feSmcpowers 				return (CKR_ARGUMENTS_BAD);
197034448feSmcpowers 			}
198034448feSmcpowers 			*key_len = tmp.ulValueLen;
199ef39737bSmcpowers 		} else if (pMechanism->mechanism == CKM_ECDH1_DERIVE) {
200f9fbec18Smcpowers 			*key_len = EC_MAX_VALUE_LEN;
201034448feSmcpowers 		} else {
202034448feSmcpowers 			return (CKR_ARGUMENTS_BAD);
203034448feSmcpowers 		}
204034448feSmcpowers 		break;
205034448feSmcpowers 	default:
206034448feSmcpowers 		return (CKR_ATTRIBUTE_VALUE_INVALID);
207034448feSmcpowers 	}
208034448feSmcpowers 
209034448feSmcpowers 	if (fixed_len_key && attribute_in_template(CKA_VALUE_LEN,
210034448feSmcpowers 	    pTemplate, ulAttributeCount))
211034448feSmcpowers 		return (CKR_TEMPLATE_INCONSISTENT);
212034448feSmcpowers 
213034448feSmcpowers 	return (CKR_OK);
214034448feSmcpowers }
215034448feSmcpowers 
216034448feSmcpowers /* find specified attribute src template and copy to dest */
217034448feSmcpowers static int
copy_attribute(CK_ULONG type,CK_ATTRIBUTE_PTR src,CK_ULONG src_cnt,CK_ATTRIBUTE_PTR dst)218034448feSmcpowers copy_attribute(CK_ULONG type, CK_ATTRIBUTE_PTR src, CK_ULONG src_cnt,
219034448feSmcpowers     CK_ATTRIBUTE_PTR dst)
220034448feSmcpowers {
221034448feSmcpowers 	int rv, i;
222034448feSmcpowers 
223034448feSmcpowers 	for (i = 0; i < src_cnt; i++) {
224034448feSmcpowers 		if (src[i].type == type) {
225034448feSmcpowers 			rv = get_string_from_template(dst, &src[i]);
226034448feSmcpowers 			break;
227034448feSmcpowers 		}
228034448feSmcpowers 	}
229034448feSmcpowers 	/*
230034448feSmcpowers 	 * The public template didn't have attribute.
231034448feSmcpowers 	 */
232034448feSmcpowers 	if (i == src_cnt) {
233034448feSmcpowers 		rv = CKR_TEMPLATE_INCOMPLETE;
234034448feSmcpowers 	}
235034448feSmcpowers 	return (rv);
236034448feSmcpowers }
237034448feSmcpowers 
238034448feSmcpowers static void
free_attributes(caddr_t p,uint_t * countp)239034448feSmcpowers free_attributes(caddr_t p, uint_t *countp)
240034448feSmcpowers {
241034448feSmcpowers 	if (*countp > 0) {
242034448feSmcpowers 		free_object_attributes(p, *countp);
243034448feSmcpowers 		*countp = 0;
244034448feSmcpowers 	}
245034448feSmcpowers }
246034448feSmcpowers 
247034448feSmcpowers CK_RV
key_gen_by_value(CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,kernel_session_t * session_p,crypto_mech_type_t k_mech_type,kernel_object_t * new_objp)248034448feSmcpowers key_gen_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
249034448feSmcpowers     CK_ULONG ulCount, kernel_session_t *session_p,
250034448feSmcpowers     crypto_mech_type_t k_mech_type, kernel_object_t *new_objp)
251034448feSmcpowers {
252034448feSmcpowers 	crypto_nostore_generate_key_t obj_ngk;
253034448feSmcpowers 	char *key_buf = NULL;
254034448feSmcpowers 	CK_ATTRIBUTE_PTR newTemplate = NULL;
255034448feSmcpowers 	CK_BBOOL is_token_obj = FALSE;
256034448feSmcpowers 	CK_RV rv = CKR_OK;
257034448feSmcpowers 	ulong_t key_len = 0;
258034448feSmcpowers 	uint_t attr_count;
259034448feSmcpowers 	int r;
260034448feSmcpowers 
261034448feSmcpowers 	obj_ngk.ngk_in_count = 0;
262034448feSmcpowers 	obj_ngk.ngk_out_count = 0;
263034448feSmcpowers 
264034448feSmcpowers 	rv = get_key_len_from_template(pMechanism, pTemplate, ulCount,
265034448feSmcpowers 	    NULL, &key_len);
266034448feSmcpowers 	if (rv != CRYPTO_SUCCESS)
267034448feSmcpowers 		goto failed_exit;
268034448feSmcpowers 
269034448feSmcpowers 	if ((key_buf = malloc(key_len)) == NULL) {
270034448feSmcpowers 		rv = CKR_HOST_MEMORY;
271034448feSmcpowers 		goto failed_exit;
272034448feSmcpowers 	}
273034448feSmcpowers 
274034448feSmcpowers 	attr_count = ulCount + 1;
275034448feSmcpowers 	newTemplate = grow_template(pTemplate, ulCount, attr_count);
276034448feSmcpowers 	if (newTemplate == NULL) {
277034448feSmcpowers 		rv = CKR_HOST_MEMORY;
278034448feSmcpowers 		goto failed_exit;
279034448feSmcpowers 	}
280034448feSmcpowers 
281034448feSmcpowers 	/* Now add the CKA_VALUE attribute to template */
282034448feSmcpowers 	newTemplate[ulCount].type = CKA_VALUE;
283034448feSmcpowers 	newTemplate[ulCount].pValue = (caddr_t)key_buf;
284034448feSmcpowers 	newTemplate[ulCount].ulValueLen = key_len;
285034448feSmcpowers 
286034448feSmcpowers 	rv = process_object_attributes(newTemplate, attr_count - 1,
287034448feSmcpowers 	    &obj_ngk.ngk_in_attributes, &is_token_obj);
288034448feSmcpowers 	if (rv != CKR_OK) {
289034448feSmcpowers 		goto failed_exit;
290034448feSmcpowers 	}
291034448feSmcpowers 	rv = process_object_attributes(&newTemplate[ulCount],
292034448feSmcpowers 	    1, &obj_ngk.ngk_out_attributes, &is_token_obj);
293034448feSmcpowers 	if (rv != CKR_OK) {
294034448feSmcpowers 		goto failed_exit;
295034448feSmcpowers 	}
296034448feSmcpowers 
297034448feSmcpowers 	/* Cannot create a token object with a READ-ONLY session. */
298034448feSmcpowers 	if (is_token_obj && session_p->ses_RO) {
299034448feSmcpowers 		rv = CKR_SESSION_READ_ONLY;
300034448feSmcpowers 		goto failed_exit;
301034448feSmcpowers 	}
302034448feSmcpowers 
303034448feSmcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY ioctl */
304034448feSmcpowers 	obj_ngk.ngk_session = session_p->k_session;
305034448feSmcpowers 	obj_ngk.ngk_in_count = attr_count - 1;
306034448feSmcpowers 	obj_ngk.ngk_out_count = 1;
307034448feSmcpowers 	obj_ngk.ngk_mechanism.cm_type = k_mech_type;
308034448feSmcpowers 	obj_ngk.ngk_mechanism.cm_param = pMechanism->pParameter;
309034448feSmcpowers 	obj_ngk.ngk_mechanism.cm_param_len = pMechanism->ulParameterLen;
310034448feSmcpowers 
311034448feSmcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY,
312034448feSmcpowers 	    &obj_ngk)) < 0) {
313034448feSmcpowers 		if (errno != EINTR)
314034448feSmcpowers 			break;
315034448feSmcpowers 	}
316034448feSmcpowers 	if (r < 0) {
317034448feSmcpowers 		rv = CKR_FUNCTION_FAILED;
318034448feSmcpowers 	} else {
319034448feSmcpowers 		rv = crypto2pkcs11_error_number(obj_ngk.ngk_return_value);
320034448feSmcpowers 	}
321034448feSmcpowers 	free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
322034448feSmcpowers 	if (rv != CKR_OK) {
323034448feSmcpowers 		goto failed_exit;
324034448feSmcpowers 	}
325034448feSmcpowers 
326034448feSmcpowers 	rv = get_object_attributes(&newTemplate[ulCount], 1,
327034448feSmcpowers 	    obj_ngk.ngk_out_attributes);
328034448feSmcpowers 	free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
329034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
330034448feSmcpowers 		goto failed_exit;
331034448feSmcpowers 	}
332034448feSmcpowers 
333034448feSmcpowers 	/*
334034448feSmcpowers 	 * CKA_VALUE_LEN is not stored with the secret key object,
335034448feSmcpowers 	 * so we remove it by shifting attributes down one.
336034448feSmcpowers 	 */
337034448feSmcpowers 	(void) remove_one_attribute(newTemplate, CKA_VALUE_LEN,
338034448feSmcpowers 	    attr_count, B_FALSE);
339034448feSmcpowers 
340034448feSmcpowers 	rv = kernel_build_object(newTemplate, attr_count - 1,
341034448feSmcpowers 	    new_objp, session_p, KERNEL_GEN_KEY);
342034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
343034448feSmcpowers 		goto failed_exit;
344034448feSmcpowers 	}
345034448feSmcpowers 	new_objp->is_lib_obj = B_TRUE;
346034448feSmcpowers 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
347*a8793c76SJason King 	free(newTemplate);
348*a8793c76SJason King 	freezero(key_buf, key_len);
349034448feSmcpowers 	return (CKR_OK);
350034448feSmcpowers 
351034448feSmcpowers failed_exit:
352034448feSmcpowers 	free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
353034448feSmcpowers 	free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
354*a8793c76SJason King 	freezero(key_buf, key_len);
355*a8793c76SJason King 	free(newTemplate);
356034448feSmcpowers 	return (rv);
357034448feSmcpowers }
358034448feSmcpowers 
359034448feSmcpowers CK_RV
C_GenerateKey(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_OBJECT_HANDLE_PTR phKey)360034448feSmcpowers C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
361034448feSmcpowers     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
362034448feSmcpowers {
363034448feSmcpowers 	CK_RV			rv = CKR_OK;
364034448feSmcpowers 	kernel_session_t	*session_p;
365034448feSmcpowers 	kernel_object_t		*new_objp = NULL;
366034448feSmcpowers 	kernel_slot_t		*pslot;
367034448feSmcpowers 	boolean_t		ses_lock_held = B_FALSE;
368034448feSmcpowers 	CK_BBOOL		is_pri_obj;
369034448feSmcpowers 	CK_BBOOL		is_token_obj = FALSE;
370034448feSmcpowers 	crypto_mech_type_t	k_mech_type;
371034448feSmcpowers 	int r;
372034448feSmcpowers 
373034448feSmcpowers 	if (!kernel_initialized)
374034448feSmcpowers 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
375034448feSmcpowers 
376034448feSmcpowers 	/* Obtain the session pointer */
377034448feSmcpowers 	rv = handle2session(hSession, &session_p);
378034448feSmcpowers 	if (rv != CKR_OK)
379034448feSmcpowers 		return (rv);
380034448feSmcpowers 
381034448feSmcpowers 	if ((pMechanism == NULL) || (phKey == NULL)) {
382034448feSmcpowers 		rv = CKR_ARGUMENTS_BAD;
383034448feSmcpowers 		goto failed_exit;
384034448feSmcpowers 	}
385034448feSmcpowers 
386034448feSmcpowers 	if ((pTemplate == NULL) && (ulCount != 0)) {
387034448feSmcpowers 		rv = CKR_ARGUMENTS_BAD;
388034448feSmcpowers 		goto failed_exit;
389034448feSmcpowers 	}
390034448feSmcpowers 
391034448feSmcpowers 	/* Get the kernel's internal mechanism number. */
392034448feSmcpowers 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
393034448feSmcpowers 	if (rv != CKR_OK) {
394034448feSmcpowers 		goto failed_exit;
395034448feSmcpowers 	}
396034448feSmcpowers 
397034448feSmcpowers 	/* Create an object wrapper in the library first */
398034448feSmcpowers 	new_objp = calloc(1, sizeof (kernel_object_t));
399034448feSmcpowers 	if (new_objp == NULL) {
400034448feSmcpowers 		rv = CKR_HOST_MEMORY;
401034448feSmcpowers 		goto failed_exit;
402034448feSmcpowers 	}
403034448feSmcpowers 
404034448feSmcpowers 	/*
405034448feSmcpowers 	 * Special Case: if token does not support object creation,
406034448feSmcpowers 	 * but does support key generation by value, then create a session
407034448feSmcpowers 	 * object and initialize with value returned by token.
408034448feSmcpowers 	 */
409034448feSmcpowers 	pslot = slot_table[session_p->ses_slotid];
410034448feSmcpowers 	if (!pslot->sl_func_list.fl_object_create) {
411034448feSmcpowers 		rv = key_gen_by_value(pMechanism, pTemplate, ulCount, session_p,
412034448feSmcpowers 		    k_mech_type, new_objp);
413034448feSmcpowers 		if (rv != CKR_OK)
414034448feSmcpowers 			goto failed_exit;
415034448feSmcpowers 	} else {
416034448feSmcpowers 		crypto_object_generate_key_t obj_gk;
417034448feSmcpowers 
418034448feSmcpowers 		/* Process the attributes */
419034448feSmcpowers 		rv = process_object_attributes(pTemplate, ulCount,
420034448feSmcpowers 		    &obj_gk.gk_attributes, &is_token_obj);
421034448feSmcpowers 		if (rv != CKR_OK) {
422034448feSmcpowers 			goto failed_exit;
423034448feSmcpowers 		}
424034448feSmcpowers 		/* Cannot create a token object with a READ-ONLY session. */
425034448feSmcpowers 		if (is_token_obj && session_p->ses_RO) {
426034448feSmcpowers 			free_object_attributes(obj_gk.gk_attributes, ulCount);
427034448feSmcpowers 			rv = CKR_SESSION_READ_ONLY;
428034448feSmcpowers 			goto failed_exit;
429034448feSmcpowers 		}
430034448feSmcpowers 
431034448feSmcpowers 		/* Call the CRYPTO_GENERATE_KEY ioctl */
432034448feSmcpowers 		obj_gk.gk_session = session_p->k_session;
433034448feSmcpowers 		obj_gk.gk_count = ulCount;
434034448feSmcpowers 		obj_gk.gk_mechanism.cm_type = k_mech_type;
435034448feSmcpowers 		obj_gk.gk_mechanism.cm_param = pMechanism->pParameter;
436034448feSmcpowers 		obj_gk.gk_mechanism.cm_param_len = pMechanism->ulParameterLen;
437034448feSmcpowers 
438034448feSmcpowers 		while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY,
439034448feSmcpowers 		    &obj_gk)) < 0) {
440034448feSmcpowers 			if (errno != EINTR)
441034448feSmcpowers 				break;
442034448feSmcpowers 		}
443034448feSmcpowers 		if (r < 0) {
444034448feSmcpowers 			rv = CKR_FUNCTION_FAILED;
445034448feSmcpowers 		} else {
446034448feSmcpowers 			rv = crypto2pkcs11_error_number(obj_gk.gk_return_value);
447034448feSmcpowers 		}
448034448feSmcpowers 
449034448feSmcpowers 		free_object_attributes(obj_gk.gk_attributes, ulCount);
450034448feSmcpowers 
451034448feSmcpowers 		if (rv != CKR_OK) {
452034448feSmcpowers 			goto failed_exit;
453034448feSmcpowers 		}
454034448feSmcpowers 
455034448feSmcpowers 		/* Get the value of the CKA_PRIVATE attribute. */
456034448feSmcpowers 		rv = get_cka_private_value(session_p, obj_gk.gk_handle,
457034448feSmcpowers 		    &is_pri_obj);
458034448feSmcpowers 		if (rv != CKR_OK) {
459034448feSmcpowers 			goto failed_exit;
460034448feSmcpowers 		}
461034448feSmcpowers 
462034448feSmcpowers 		/*
463034448feSmcpowers 		 * Store the kernel object handle in the object wrapper and
464034448feSmcpowers 		 * initialize the library object.
465034448feSmcpowers 		 */
466034448feSmcpowers 		new_objp->k_handle = obj_gk.gk_handle;
467034448feSmcpowers 		new_objp->is_lib_obj = B_FALSE;
468034448feSmcpowers 		new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
469034448feSmcpowers 		new_objp->extra_attrlistp = NULL;
470034448feSmcpowers 
471034448feSmcpowers 		if (is_pri_obj)
472034448feSmcpowers 			new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
473034448feSmcpowers 		else
474034448feSmcpowers 			new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
475034448feSmcpowers 
476034448feSmcpowers 		if (is_token_obj)
477034448feSmcpowers 			new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
478034448feSmcpowers 		else
479034448feSmcpowers 			new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
480034448feSmcpowers 	}
481034448feSmcpowers 
482034448feSmcpowers 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
483034448feSmcpowers 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
484034448feSmcpowers 
485034448feSmcpowers 	/*
486034448feSmcpowers 	 * Add the new object to the slot's token object list if it is a
487034448feSmcpowers 	 * a token object. Otherwise, add it to the session's object list.
488034448feSmcpowers 	 */
489034448feSmcpowers 	if (is_token_obj) {
490034448feSmcpowers 		pslot = slot_table[session_p->ses_slotid];
491034448feSmcpowers 		kernel_add_token_object_to_slot(new_objp, pslot);
492034448feSmcpowers 	} else {
493034448feSmcpowers 		kernel_add_object_to_session(new_objp, session_p);
494034448feSmcpowers 	}
495034448feSmcpowers 
496034448feSmcpowers 	*phKey = (CK_OBJECT_HANDLE)new_objp;
497034448feSmcpowers 	REFRELE(session_p, ses_lock_held);
498034448feSmcpowers 	return (rv);
499034448feSmcpowers 
500034448feSmcpowers failed_exit:
501034448feSmcpowers 	if (new_objp != NULL) {
502034448feSmcpowers 		(void) free(new_objp);
503034448feSmcpowers 	}
504034448feSmcpowers 
505034448feSmcpowers 	REFRELE(session_p, ses_lock_held);
506034448feSmcpowers 	return (rv);
507034448feSmcpowers }
508034448feSmcpowers 
509034448feSmcpowers CK_RV
key_gen_rsa_by_value(CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pPublicKeyTemplate,CK_ULONG ulPublicKeyAttributeCount,CK_ATTRIBUTE_PTR pPrivateKeyTemplate,CK_ULONG ulPrivateKeyAttributeCount,kernel_session_t * session_p,crypto_mech_type_t k_mech_type,kernel_object_t * new_pub_objp,kernel_object_t * new_pri_objp)510034448feSmcpowers key_gen_rsa_by_value(CK_MECHANISM_PTR pMechanism,
511034448feSmcpowers     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
512034448feSmcpowers     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
513034448feSmcpowers     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
514034448feSmcpowers     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
515034448feSmcpowers {
516034448feSmcpowers 	crypto_nostore_generate_key_pair_t obj_nkp;
517034448feSmcpowers 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
518034448feSmcpowers 	CK_ATTRIBUTE_PTR priTemplate = NULL;
519034448feSmcpowers 	CK_RV rv = CKR_OK;
520034448feSmcpowers 	CK_BBOOL is_token_obj1 = FALSE;
521034448feSmcpowers 	CK_BBOOL is_token_obj2 = FALSE;
522034448feSmcpowers 	uint_t pub_attr_count, pri_attr_count;
523034448feSmcpowers 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
524034448feSmcpowers 	char public_modulus[512];
525034448feSmcpowers 	char public_exponent[8];
526034448feSmcpowers 	char private_exponent[512];
527034448feSmcpowers 	char private_modulus[512];
528034448feSmcpowers 	char prime_1[512];
529034448feSmcpowers 	char prime_2[512];
530034448feSmcpowers 	char exponent_1[512];
531034448feSmcpowers 	char exponent_2[512];
532034448feSmcpowers 	char coefficient[512];
533034448feSmcpowers 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
534034448feSmcpowers 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
535034448feSmcpowers 	CK_ULONG key_type;
536034448feSmcpowers 	CK_ULONG modulus_bytes;
537034448feSmcpowers 	boolean_t has_class, has_key_type, has_pub_exponent;
538034448feSmcpowers 	int n, r;
539034448feSmcpowers 
540034448feSmcpowers 	obj_nkp.nkp_in_public_count = 0;
541034448feSmcpowers 	obj_nkp.nkp_out_public_count = 0;
542034448feSmcpowers 	obj_nkp.nkp_in_private_count = 0;
543034448feSmcpowers 	obj_nkp.nkp_out_private_count = 0;
544034448feSmcpowers 
545034448feSmcpowers 	/* modulus bits must be present when generating a RSA key pair */
546034448feSmcpowers 	if (!attribute_in_template(CKA_MODULUS_BITS, pPublicKeyTemplate,
547034448feSmcpowers 	    ulPublicKeyAttributeCount)) {
548034448feSmcpowers 		rv = CKR_TEMPLATE_INCOMPLETE;
549034448feSmcpowers 		goto failed_exit;
550034448feSmcpowers 	}
551034448feSmcpowers 
552034448feSmcpowers 	modulus_bytes = get_modulus_bytes(pPublicKeyTemplate,
553034448feSmcpowers 	    ulPublicKeyAttributeCount);
554034448feSmcpowers 
555034448feSmcpowers 	/*
556034448feSmcpowers 	 * Add CKA_MODULUS to the public template.
557034448feSmcpowers 	 * This attribute must not be in the template.
558034448feSmcpowers 	 */
559034448feSmcpowers 	if (attribute_in_template(CKA_MODULUS, pPublicKeyTemplate,
560034448feSmcpowers 	    ulPublicKeyAttributeCount)) {
561034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
562034448feSmcpowers 		goto failed_exit;
563034448feSmcpowers 	}
564034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
565034448feSmcpowers 	    ulPublicKeyAttributeCount);
566034448feSmcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
567034448feSmcpowers 	    ulPublicKeyAttributeCount);
568034448feSmcpowers 	has_pub_exponent = attribute_in_template(CKA_PUBLIC_EXPONENT,
569034448feSmcpowers 	    pPublicKeyTemplate, ulPublicKeyAttributeCount);
570034448feSmcpowers 
571034448feSmcpowers 	pub_attr_count = ulPublicKeyAttributeCount + 1;
572034448feSmcpowers 	if (!has_class)
573034448feSmcpowers 		pub_attr_count++;
574034448feSmcpowers 	if (!has_key_type)
575034448feSmcpowers 		pub_attr_count++;
576034448feSmcpowers 	if (!has_pub_exponent)
577034448feSmcpowers 		pub_attr_count++;
578034448feSmcpowers 	pubTemplate = grow_template(pPublicKeyTemplate,
579034448feSmcpowers 	    ulPublicKeyAttributeCount, pub_attr_count);
580034448feSmcpowers 	if (pubTemplate == NULL) {
581034448feSmcpowers 		rv = CKR_HOST_MEMORY;
582034448feSmcpowers 		goto failed_exit;
583034448feSmcpowers 	}
584034448feSmcpowers 
585034448feSmcpowers 	n = ulPublicKeyAttributeCount;
586034448feSmcpowers 	if (!has_class) {
587034448feSmcpowers 		pubTemplate[n].type = CKA_CLASS;
588034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)&pub_class;
589034448feSmcpowers 		pubTemplate[n].ulValueLen = sizeof (pub_class);
590034448feSmcpowers 		n++;
591034448feSmcpowers 	}
592034448feSmcpowers 	if (!has_key_type) {
593034448feSmcpowers 		pubTemplate[n].type = CKA_KEY_TYPE;
594034448feSmcpowers 		key_type = CKK_RSA;
595034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)&key_type;
596034448feSmcpowers 		pubTemplate[n].ulValueLen = sizeof (key_type);
597034448feSmcpowers 		n++;
598034448feSmcpowers 	}
599034448feSmcpowers 	if (!has_pub_exponent) {
600034448feSmcpowers 		pubTemplate[n].type = CKA_PUBLIC_EXPONENT;
601034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)public_exponent;
602034448feSmcpowers 		pubTemplate[n].ulValueLen = modulus_bytes;
603034448feSmcpowers 		n++;
604034448feSmcpowers 		pub_out_attr_count++;
605034448feSmcpowers 	}
606034448feSmcpowers 	pubTemplate[n].type = CKA_MODULUS;
607034448feSmcpowers 	pubTemplate[n].pValue = (caddr_t)public_modulus;
608034448feSmcpowers 	pubTemplate[n].ulValueLen = modulus_bytes;
609034448feSmcpowers 	pub_out_attr_count++;
610034448feSmcpowers 
611034448feSmcpowers 	rv = process_object_attributes(pubTemplate,
612034448feSmcpowers 	    pub_attr_count - pub_out_attr_count,
613034448feSmcpowers 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
614034448feSmcpowers 	if (rv != CKR_OK) {
615034448feSmcpowers 		goto failed_exit;
616034448feSmcpowers 	}
617034448feSmcpowers 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
618034448feSmcpowers 
619034448feSmcpowers 	rv = process_object_attributes(
620034448feSmcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
621034448feSmcpowers 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
622034448feSmcpowers 	    &is_token_obj1);
623034448feSmcpowers 	if (rv != CKR_OK) {
624034448feSmcpowers 		goto failed_exit;
625034448feSmcpowers 	}
626034448feSmcpowers 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
627034448feSmcpowers 
628034448feSmcpowers 	/*
629034448feSmcpowers 	 * Cannot create a token object with a READ-ONLY
630034448feSmcpowers 	 * session.
631034448feSmcpowers 	 */
632034448feSmcpowers 	if (is_token_obj1 && session_p->ses_RO) {
633034448feSmcpowers 		rv = CKR_SESSION_READ_ONLY;
634034448feSmcpowers 		goto failed_exit;
635034448feSmcpowers 	}
636034448feSmcpowers 
637034448feSmcpowers 	/*
638034448feSmcpowers 	 * Add CKA_MODULUS and CKA_PRIVATE_EXPONENT
639034448feSmcpowers 	 * to the private template. These attributes
640034448feSmcpowers 	 * must not be in the template.
641034448feSmcpowers 	 */
642034448feSmcpowers 	if (attribute_in_template(CKA_PRIVATE_EXPONENT,
643034448feSmcpowers 	    pPrivateKeyTemplate, ulPrivateKeyAttributeCount) ||
644034448feSmcpowers 	    attribute_in_template(CKA_MODULUS,
645034448feSmcpowers 	    pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) {
646034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
647034448feSmcpowers 		goto failed_exit;
648034448feSmcpowers 	}
649034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
650034448feSmcpowers 	    ulPrivateKeyAttributeCount);
651034448feSmcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
652034448feSmcpowers 	    ulPrivateKeyAttributeCount);
653034448feSmcpowers 
654034448feSmcpowers 	pri_attr_count = ulPrivateKeyAttributeCount + 7;
655034448feSmcpowers 	if (!has_class)
656034448feSmcpowers 		pri_attr_count++;
657034448feSmcpowers 	if (!has_key_type)
658034448feSmcpowers 		pri_attr_count++;
659034448feSmcpowers 
660034448feSmcpowers 	/* allocate space for CKA_PUBLIC_EXPONENT */
661034448feSmcpowers 	priTemplate = grow_template(pPrivateKeyTemplate,
662034448feSmcpowers 	    ulPrivateKeyAttributeCount, pri_attr_count + 1);
663034448feSmcpowers 	if (priTemplate == NULL) {
664034448feSmcpowers 		rv = CKR_HOST_MEMORY;
665034448feSmcpowers 		goto failed_exit;
666034448feSmcpowers 	}
667034448feSmcpowers 	n = ulPrivateKeyAttributeCount;
668034448feSmcpowers 	if (!has_class) {
669034448feSmcpowers 		priTemplate[n].type = CKA_CLASS;
670034448feSmcpowers 		priTemplate[n].pValue = (caddr_t)&pri_class;
671034448feSmcpowers 		priTemplate[n].ulValueLen = sizeof (pri_class);
672034448feSmcpowers 		n++;
673034448feSmcpowers 	}
674034448feSmcpowers 	if (!has_key_type) {
675034448feSmcpowers 		priTemplate[n].type = CKA_KEY_TYPE;
676034448feSmcpowers 		key_type = CKK_RSA;
677034448feSmcpowers 		priTemplate[n].pValue = (caddr_t)&key_type;
678034448feSmcpowers 		priTemplate[n].ulValueLen = sizeof (key_type);
679034448feSmcpowers 		n++;
680034448feSmcpowers 	}
681034448feSmcpowers 	priTemplate[n].type = CKA_MODULUS;
682034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)private_modulus;
683034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes;
684034448feSmcpowers 	pri_out_attr_count++;
685034448feSmcpowers 
686034448feSmcpowers 	n++;
687034448feSmcpowers 	priTemplate[n].type = CKA_PRIVATE_EXPONENT;
688034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)private_exponent;
689034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes;
690034448feSmcpowers 	pri_out_attr_count++;
691034448feSmcpowers 
692034448feSmcpowers 	n++;
693034448feSmcpowers 	priTemplate[n].type = CKA_PRIME_1;
694034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)prime_1;
695034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
696034448feSmcpowers 	pri_out_attr_count++;
697034448feSmcpowers 
698034448feSmcpowers 	n++;
699034448feSmcpowers 	priTemplate[n].type = CKA_PRIME_2;
700034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)prime_2;
701034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
702034448feSmcpowers 	pri_out_attr_count++;
703034448feSmcpowers 
704034448feSmcpowers 	n++;
705034448feSmcpowers 	priTemplate[n].type = CKA_EXPONENT_1;
706034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)exponent_1;
707034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
708034448feSmcpowers 	pri_out_attr_count++;
709034448feSmcpowers 
710034448feSmcpowers 	n++;
711034448feSmcpowers 	priTemplate[n].type = CKA_EXPONENT_2;
712034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)exponent_2;
713034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
714034448feSmcpowers 	pri_out_attr_count++;
715034448feSmcpowers 
716034448feSmcpowers 	n++;
717034448feSmcpowers 	priTemplate[n].type = CKA_COEFFICIENT;
718034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)coefficient;
719034448feSmcpowers 	priTemplate[n].ulValueLen = modulus_bytes/2;
720034448feSmcpowers 	pri_out_attr_count++;
721034448feSmcpowers 
722034448feSmcpowers 	rv = process_object_attributes(priTemplate,
723034448feSmcpowers 	    pri_attr_count - pri_out_attr_count,
724034448feSmcpowers 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
725034448feSmcpowers 	if (rv != CKR_OK) {
726034448feSmcpowers 		goto failed_exit;
727034448feSmcpowers 	}
728034448feSmcpowers 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
729034448feSmcpowers 
730034448feSmcpowers 	rv = process_object_attributes(
731034448feSmcpowers 	    &priTemplate[pri_attr_count - pri_out_attr_count],
732034448feSmcpowers 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
733034448feSmcpowers 	    &is_token_obj2);
734034448feSmcpowers 	if (rv != CKR_OK) {
735034448feSmcpowers 		goto failed_exit;
736034448feSmcpowers 	}
737034448feSmcpowers 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
738034448feSmcpowers 
739034448feSmcpowers 	/*
740034448feSmcpowers 	 * The public key and the private key need to contain the same
741034448feSmcpowers 	 * attribute values for CKA_TOKEN.
742034448feSmcpowers 	 */
743034448feSmcpowers 	if (is_token_obj1 != is_token_obj2) {
744034448feSmcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
745034448feSmcpowers 		goto failed_exit;
746034448feSmcpowers 	}
747034448feSmcpowers 
748034448feSmcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
749034448feSmcpowers 	obj_nkp.nkp_session = session_p-> k_session;
750034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
751034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
752034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
753034448feSmcpowers 
754034448feSmcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
755034448feSmcpowers 	    &obj_nkp)) < 0) {
756034448feSmcpowers 		if (errno != EINTR)
757034448feSmcpowers 			break;
758034448feSmcpowers 	}
759034448feSmcpowers 	if (r < 0) {
760034448feSmcpowers 		rv = CKR_FUNCTION_FAILED;
761034448feSmcpowers 	} else {
762034448feSmcpowers 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
763034448feSmcpowers 	}
764034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
765034448feSmcpowers 	    &obj_nkp.nkp_in_public_count);
766034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
767034448feSmcpowers 	    &obj_nkp.nkp_in_private_count);
768034448feSmcpowers 
769034448feSmcpowers 	if (rv != CKR_OK) {
770034448feSmcpowers 		goto failed_exit;
771034448feSmcpowers 	}
772034448feSmcpowers 
773034448feSmcpowers 	rv = get_object_attributes(
774034448feSmcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
775034448feSmcpowers 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
776034448feSmcpowers 	if (rv == CRYPTO_SUCCESS) {
777034448feSmcpowers 		rv = get_object_attributes(
778034448feSmcpowers 		    &priTemplate[pri_attr_count - pri_out_attr_count],
779034448feSmcpowers 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
780034448feSmcpowers 	}
781034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
782034448feSmcpowers 	    &obj_nkp.nkp_out_public_count);
783034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
784034448feSmcpowers 	    &obj_nkp.nkp_out_private_count);
785034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
786034448feSmcpowers 		goto failed_exit;
787034448feSmcpowers 	}
788034448feSmcpowers 
789034448feSmcpowers 	/* store generated modulus and public exponent */
790034448feSmcpowers 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
791034448feSmcpowers 	    session_p, KERNEL_GEN_KEY);
792034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
793034448feSmcpowers 		goto failed_exit;
794034448feSmcpowers 	}
795034448feSmcpowers 
796034448feSmcpowers 	/*
797034448feSmcpowers 	 * Copy CKA_PUBLIC_EXPONENT from the public template
798034448feSmcpowers 	 * to the private template.
799034448feSmcpowers 	 */
800034448feSmcpowers 	rv = copy_attribute(CKA_PUBLIC_EXPONENT, pubTemplate,
801034448feSmcpowers 	    pub_attr_count, &priTemplate[pri_attr_count]);
802034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
803034448feSmcpowers 		goto failed_exit;
804034448feSmcpowers 	}
805034448feSmcpowers 
806034448feSmcpowers 	rv = kernel_build_object(priTemplate, pri_attr_count + 1, new_pri_objp,
807034448feSmcpowers 	    session_p, KERNEL_GEN_KEY);
808034448feSmcpowers 	(void) free(priTemplate[pri_attr_count].pValue);
809034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
810034448feSmcpowers 		goto failed_exit;
811034448feSmcpowers 	}
812034448feSmcpowers 	(void) free(pubTemplate);
813034448feSmcpowers 	(void) free(priTemplate);
814034448feSmcpowers 
815034448feSmcpowers 	new_pub_objp->is_lib_obj = B_TRUE;
816034448feSmcpowers 	new_pri_objp->is_lib_obj = B_TRUE;
817034448feSmcpowers 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
818034448feSmcpowers 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
819034448feSmcpowers 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
820034448feSmcpowers 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
821034448feSmcpowers 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
822034448feSmcpowers 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
823034448feSmcpowers 	return (CKR_OK);
8247c478bd9Sstevel@tonic-gate 
825034448feSmcpowers failed_exit:
826034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
827034448feSmcpowers 	    &obj_nkp.nkp_in_public_count);
828034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
829034448feSmcpowers 	    &obj_nkp.nkp_out_public_count);
830034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
831034448feSmcpowers 	    &obj_nkp.nkp_in_private_count);
832034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
833034448feSmcpowers 	    &obj_nkp.nkp_out_private_count);
834034448feSmcpowers 	if (pubTemplate != NULL) {
835034448feSmcpowers 		(void) free(pubTemplate);
836034448feSmcpowers 	}
837034448feSmcpowers 	if (priTemplate != NULL) {
838034448feSmcpowers 		(void) free(priTemplate);
839034448feSmcpowers 	}
840034448feSmcpowers 	return (rv);
841034448feSmcpowers }
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate CK_RV
key_gen_dh_by_value(CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pPublicKeyTemplate,CK_ULONG ulPublicKeyAttributeCount,CK_ATTRIBUTE_PTR pPrivateKeyTemplate,CK_ULONG ulPrivateKeyAttributeCount,kernel_session_t * session_p,crypto_mech_type_t k_mech_type,kernel_object_t * new_pub_objp,kernel_object_t * new_pri_objp)844034448feSmcpowers key_gen_dh_by_value(CK_MECHANISM_PTR pMechanism,
845034448feSmcpowers     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
846034448feSmcpowers     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
847034448feSmcpowers     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
848034448feSmcpowers     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
8497c478bd9Sstevel@tonic-gate {
850034448feSmcpowers 	crypto_nostore_generate_key_pair_t obj_nkp;
851034448feSmcpowers 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
852034448feSmcpowers 	CK_ATTRIBUTE_PTR priTemplate = NULL;
853034448feSmcpowers 	CK_RV rv = CKR_OK;
854034448feSmcpowers 	CK_BBOOL is_token_obj1 = FALSE;
855034448feSmcpowers 	CK_BBOOL is_token_obj2 = FALSE;
856034448feSmcpowers 	uint_t pub_attr_count, pri_attr_count;
857034448feSmcpowers 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
858034448feSmcpowers 	char public_value[256];
859034448feSmcpowers 	char private_value[256];
860034448feSmcpowers 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
861034448feSmcpowers 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
862034448feSmcpowers 	CK_ULONG key_type;
863034448feSmcpowers 	boolean_t has_class, has_key_type;
864034448feSmcpowers 	int n, r;
865034448feSmcpowers 
866034448feSmcpowers 	obj_nkp.nkp_in_public_count = 0;
867034448feSmcpowers 	obj_nkp.nkp_out_public_count = 0;
868034448feSmcpowers 	obj_nkp.nkp_in_private_count = 0;
869034448feSmcpowers 	obj_nkp.nkp_out_private_count = 0;
8707c478bd9Sstevel@tonic-gate 
871034448feSmcpowers 	/*
872034448feSmcpowers 	 * Add CKA_VALUE to the public template.
873034448feSmcpowers 	 * This attribute must not be in the template.
874034448feSmcpowers 	 */
875034448feSmcpowers 	if (attribute_in_template(CKA_VALUE, pPublicKeyTemplate,
876034448feSmcpowers 	    ulPublicKeyAttributeCount)) {
877034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
878034448feSmcpowers 		goto failed_exit;
879034448feSmcpowers 	}
880034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
881034448feSmcpowers 	    ulPublicKeyAttributeCount);
882034448feSmcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
883034448feSmcpowers 	    ulPublicKeyAttributeCount);
8847c478bd9Sstevel@tonic-gate 
885034448feSmcpowers 	pub_attr_count = ulPublicKeyAttributeCount + 1;
886034448feSmcpowers 	if (!has_class)
887034448feSmcpowers 		pub_attr_count++;
888034448feSmcpowers 	if (!has_key_type)
889034448feSmcpowers 		pub_attr_count++;
890034448feSmcpowers 	pubTemplate = grow_template(pPublicKeyTemplate,
891034448feSmcpowers 	    ulPublicKeyAttributeCount, pub_attr_count);
892034448feSmcpowers 	if (pubTemplate == NULL) {
893034448feSmcpowers 		rv = CKR_HOST_MEMORY;
8947c478bd9Sstevel@tonic-gate 		goto failed_exit;
8957c478bd9Sstevel@tonic-gate 	}
8967c478bd9Sstevel@tonic-gate 
897034448feSmcpowers 	n = ulPublicKeyAttributeCount;
898034448feSmcpowers 	if (!has_class) {
899034448feSmcpowers 		pubTemplate[n].type = CKA_CLASS;
900034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)&pub_class;
901034448feSmcpowers 		pubTemplate[n].ulValueLen = sizeof (pub_class);
902034448feSmcpowers 		n++;
903034448feSmcpowers 	}
904034448feSmcpowers 	if (!has_key_type) {
905034448feSmcpowers 		pubTemplate[n].type = CKA_KEY_TYPE;
906034448feSmcpowers 		key_type = CKK_DH;
907034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)&key_type;
908034448feSmcpowers 		pubTemplate[n].ulValueLen = sizeof (key_type);
909034448feSmcpowers 		n++;
910034448feSmcpowers 	}
911034448feSmcpowers 	pubTemplate[n].type = CKA_VALUE;
912034448feSmcpowers 	pubTemplate[n].pValue = (caddr_t)public_value;
913034448feSmcpowers 	pubTemplate[n].ulValueLen = sizeof (public_value);
914034448feSmcpowers 	pub_out_attr_count++;
915034448feSmcpowers 
916034448feSmcpowers 	rv = process_object_attributes(pubTemplate,
917034448feSmcpowers 	    pub_attr_count - pub_out_attr_count,
918034448feSmcpowers 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
919034448feSmcpowers 	if (rv != CKR_OK) {
9207c478bd9Sstevel@tonic-gate 		goto failed_exit;
9217c478bd9Sstevel@tonic-gate 	}
922034448feSmcpowers 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
9237c478bd9Sstevel@tonic-gate 
924034448feSmcpowers 	rv = process_object_attributes(
925034448feSmcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
926034448feSmcpowers 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
927034448feSmcpowers 	    &is_token_obj1);
9287c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
9297c478bd9Sstevel@tonic-gate 		goto failed_exit;
9307c478bd9Sstevel@tonic-gate 	}
931034448feSmcpowers 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
9327c478bd9Sstevel@tonic-gate 
933034448feSmcpowers 	/*
934034448feSmcpowers 	 * Cannot create a token object with a READ-ONLY
935034448feSmcpowers 	 * session.
936034448feSmcpowers 	 */
937034448feSmcpowers 	if (is_token_obj1 && session_p->ses_RO) {
938034448feSmcpowers 		rv = CKR_SESSION_READ_ONLY;
939034448feSmcpowers 		goto failed_exit;
940034448feSmcpowers 	}
941034448feSmcpowers 
942034448feSmcpowers 	/*
943034448feSmcpowers 	 * CKA_BASE, CKA_PRIME, and CKA_VALUE must not appear
944034448feSmcpowers 	 * in private template.
945034448feSmcpowers 	 */
946034448feSmcpowers 	if (attribute_in_template(CKA_BASE, pPrivateKeyTemplate,
947034448feSmcpowers 	    ulPrivateKeyAttributeCount) ||
948034448feSmcpowers 	    attribute_in_template(CKA_PRIME, pPrivateKeyTemplate,
949034448feSmcpowers 	    ulPrivateKeyAttributeCount) ||
950034448feSmcpowers 	    attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
951034448feSmcpowers 	    ulPrivateKeyAttributeCount)) {
952034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
953034448feSmcpowers 		goto failed_exit;
954034448feSmcpowers 	}
955034448feSmcpowers 
956034448feSmcpowers 	if (attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
957034448feSmcpowers 	    ulPrivateKeyAttributeCount)) {
958034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
959034448feSmcpowers 		goto failed_exit;
960034448feSmcpowers 	}
961034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
962034448feSmcpowers 	    ulPrivateKeyAttributeCount);
963034448feSmcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
964034448feSmcpowers 	    ulPrivateKeyAttributeCount);
965034448feSmcpowers 
966034448feSmcpowers 	pri_attr_count = ulPrivateKeyAttributeCount + 1;
967034448feSmcpowers 	if (!has_class)
968034448feSmcpowers 		pri_attr_count++;
969034448feSmcpowers 	if (!has_key_type)
970034448feSmcpowers 		pri_attr_count++;
971034448feSmcpowers 
972034448feSmcpowers 	/* allocate space for CKA_BASE and CKA_PRIME */
973034448feSmcpowers 	priTemplate = grow_template(pPrivateKeyTemplate,
974034448feSmcpowers 	    ulPrivateKeyAttributeCount, pri_attr_count + 2);
975034448feSmcpowers 	if (priTemplate == NULL) {
9767c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
9777c478bd9Sstevel@tonic-gate 		goto failed_exit;
9787c478bd9Sstevel@tonic-gate 	}
979034448feSmcpowers 	n = ulPrivateKeyAttributeCount;
980034448feSmcpowers 	if (!has_class) {
981034448feSmcpowers 		priTemplate[n].type = CKA_CLASS;
982034448feSmcpowers 		priTemplate[n].pValue = (caddr_t)&pri_class;
983034448feSmcpowers 		priTemplate[n].ulValueLen = sizeof (pri_class);
984034448feSmcpowers 		n++;
985034448feSmcpowers 	}
986034448feSmcpowers 	if (!has_key_type) {
987034448feSmcpowers 		priTemplate[n].type = CKA_KEY_TYPE;
988034448feSmcpowers 		key_type = CKK_DH;
989034448feSmcpowers 		priTemplate[n].pValue = (caddr_t)&key_type;
990034448feSmcpowers 		priTemplate[n].ulValueLen = sizeof (key_type);
991034448feSmcpowers 		n++;
992034448feSmcpowers 	}
993034448feSmcpowers 	priTemplate[n].type = CKA_VALUE;
994034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)private_value;
995034448feSmcpowers 	priTemplate[n].ulValueLen = sizeof (private_value);
996034448feSmcpowers 	pri_out_attr_count++;
997034448feSmcpowers 
998034448feSmcpowers 	rv = process_object_attributes(priTemplate,
999034448feSmcpowers 	    pri_attr_count - pri_out_attr_count,
1000034448feSmcpowers 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
1001034448feSmcpowers 	if (rv != CKR_OK) {
1002034448feSmcpowers 		goto failed_exit;
1003034448feSmcpowers 	}
1004034448feSmcpowers 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
10057c478bd9Sstevel@tonic-gate 
1006034448feSmcpowers 	rv = process_object_attributes(
1007034448feSmcpowers 	    &priTemplate[pri_attr_count - pri_out_attr_count],
1008034448feSmcpowers 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
1009034448feSmcpowers 	    &is_token_obj2);
10107c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
10117c478bd9Sstevel@tonic-gate 		goto failed_exit;
10127c478bd9Sstevel@tonic-gate 	}
1013034448feSmcpowers 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
10147c478bd9Sstevel@tonic-gate 
1015034448feSmcpowers 	/*
1016034448feSmcpowers 	 * The public key and the private key need to contain the same
1017034448feSmcpowers 	 * attribute values for CKA_TOKEN.
1018034448feSmcpowers 	 */
1019034448feSmcpowers 	if (is_token_obj1 != is_token_obj2) {
1020034448feSmcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
10217c478bd9Sstevel@tonic-gate 		goto failed_exit;
10227c478bd9Sstevel@tonic-gate 	}
10237c478bd9Sstevel@tonic-gate 
1024034448feSmcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
1025034448feSmcpowers 	obj_nkp.nkp_session = session_p-> k_session;
1026034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
1027034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
1028034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
10297c478bd9Sstevel@tonic-gate 
1030034448feSmcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
1031034448feSmcpowers 	    &obj_nkp)) < 0) {
10327c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
10337c478bd9Sstevel@tonic-gate 			break;
10347c478bd9Sstevel@tonic-gate 	}
10357c478bd9Sstevel@tonic-gate 	if (r < 0) {
10367c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
10377c478bd9Sstevel@tonic-gate 	} else {
1038034448feSmcpowers 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
1039034448feSmcpowers 	}
1040034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
1041034448feSmcpowers 	    &obj_nkp.nkp_in_public_count);
1042034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
1043034448feSmcpowers 	    &obj_nkp.nkp_in_private_count);
1044034448feSmcpowers 
1045034448feSmcpowers 	if (rv != CKR_OK) {
1046034448feSmcpowers 		goto failed_exit;
1047034448feSmcpowers 	}
1048034448feSmcpowers 
1049034448feSmcpowers 	rv = get_object_attributes(
1050034448feSmcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
1051034448feSmcpowers 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
1052034448feSmcpowers 	if (rv == CRYPTO_SUCCESS) {
1053034448feSmcpowers 		rv = get_object_attributes(
1054034448feSmcpowers 		    &priTemplate[pri_attr_count - pri_out_attr_count],
1055034448feSmcpowers 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
1056034448feSmcpowers 	}
1057034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
1058034448feSmcpowers 	    &obj_nkp.nkp_out_public_count);
1059034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
1060034448feSmcpowers 	    &obj_nkp.nkp_out_private_count);
1061034448feSmcpowers 
1062034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1063034448feSmcpowers 		goto failed_exit;
1064034448feSmcpowers 	}
1065034448feSmcpowers 
1066034448feSmcpowers 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
1067034448feSmcpowers 	    session_p, KERNEL_GEN_KEY);
1068034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1069034448feSmcpowers 		goto failed_exit;
1070034448feSmcpowers 	}
1071034448feSmcpowers 
1072034448feSmcpowers 	/*
1073034448feSmcpowers 	 * Copy CKA_BASE and CKA_PRIME from the public template
1074034448feSmcpowers 	 * to the private template.
1075034448feSmcpowers 	 */
1076034448feSmcpowers 	rv = copy_attribute(CKA_BASE, pubTemplate, pub_attr_count,
1077034448feSmcpowers 	    &priTemplate[pri_attr_count]);
1078034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1079034448feSmcpowers 		goto failed_exit;
1080034448feSmcpowers 	}
1081034448feSmcpowers 	rv = copy_attribute(CKA_PRIME, pubTemplate, pub_attr_count,
1082034448feSmcpowers 	    &priTemplate[pri_attr_count + 1]);
1083034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1084034448feSmcpowers 		(void) free(priTemplate[pri_attr_count].pValue);
1085034448feSmcpowers 		goto failed_exit;
1086034448feSmcpowers 	}
1087034448feSmcpowers 
1088034448feSmcpowers 	/* +2 to account for CKA_BASE and CKA_PRIME */
1089034448feSmcpowers 	rv = kernel_build_object(priTemplate, pri_attr_count + 2,
1090034448feSmcpowers 	    new_pri_objp, session_p, KERNEL_GEN_KEY);
1091034448feSmcpowers 	(void) free(priTemplate[pri_attr_count].pValue);
1092034448feSmcpowers 	(void) free(priTemplate[pri_attr_count + 1].pValue);
1093034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1094034448feSmcpowers 		goto failed_exit;
1095034448feSmcpowers 	}
1096034448feSmcpowers 	(void) free(pubTemplate);
1097034448feSmcpowers 	(void) free(priTemplate);
1098034448feSmcpowers 
1099034448feSmcpowers 	new_pub_objp->is_lib_obj = B_TRUE;
1100034448feSmcpowers 	new_pri_objp->is_lib_obj = B_TRUE;
1101034448feSmcpowers 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1102034448feSmcpowers 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1103034448feSmcpowers 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1104034448feSmcpowers 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1105034448feSmcpowers 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1106034448feSmcpowers 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1107034448feSmcpowers 	return (CKR_OK);
1108034448feSmcpowers 
1109034448feSmcpowers failed_exit:
1110034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
1111034448feSmcpowers 	    &obj_nkp.nkp_in_public_count);
1112034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
1113034448feSmcpowers 	    &obj_nkp.nkp_out_public_count);
1114034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
1115034448feSmcpowers 	    &obj_nkp.nkp_in_private_count);
1116034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
1117034448feSmcpowers 	    &obj_nkp.nkp_out_private_count);
1118034448feSmcpowers 	if (pubTemplate != NULL) {
1119034448feSmcpowers 		(void) free(pubTemplate);
1120034448feSmcpowers 	}
1121034448feSmcpowers 	if (priTemplate != NULL) {
1122034448feSmcpowers 		(void) free(priTemplate);
1123034448feSmcpowers 	}
1124034448feSmcpowers 	return (rv);
1125034448feSmcpowers }
1126034448feSmcpowers 
1127034448feSmcpowers CK_RV
key_gen_ec_by_value(CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pPublicKeyTemplate,CK_ULONG ulPublicKeyAttributeCount,CK_ATTRIBUTE_PTR pPrivateKeyTemplate,CK_ULONG ulPrivateKeyAttributeCount,kernel_session_t * session_p,crypto_mech_type_t k_mech_type,kernel_object_t * new_pub_objp,kernel_object_t * new_pri_objp)1128034448feSmcpowers key_gen_ec_by_value(CK_MECHANISM_PTR pMechanism,
1129034448feSmcpowers     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
1130034448feSmcpowers     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
1131034448feSmcpowers     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
1132034448feSmcpowers     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
1133034448feSmcpowers {
1134034448feSmcpowers 	crypto_nostore_generate_key_pair_t obj_nkp;
1135034448feSmcpowers 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
1136034448feSmcpowers 	CK_ATTRIBUTE_PTR priTemplate = NULL;
1137034448feSmcpowers 	CK_RV rv = CKR_OK;
1138034448feSmcpowers 	CK_BBOOL is_token_obj1 = FALSE;
1139034448feSmcpowers 	CK_BBOOL is_token_obj2 = FALSE;
1140034448feSmcpowers 	uint_t pub_attr_count, pri_attr_count;
1141034448feSmcpowers 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
1142f9fbec18Smcpowers 	char value[EC_MAX_VALUE_LEN];
1143f9fbec18Smcpowers 	char point[EC_MAX_POINT_LEN];
1144034448feSmcpowers 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
1145034448feSmcpowers 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
1146034448feSmcpowers 	CK_ULONG key_type;
1147034448feSmcpowers 	boolean_t has_class, has_key_type;
1148034448feSmcpowers 	int n, r;
1149034448feSmcpowers 
1150034448feSmcpowers 	obj_nkp.nkp_in_public_count = 0;
1151034448feSmcpowers 	obj_nkp.nkp_out_public_count = 0;
1152034448feSmcpowers 	obj_nkp.nkp_in_private_count = 0;
1153034448feSmcpowers 	obj_nkp.nkp_out_private_count = 0;
1154034448feSmcpowers 
1155034448feSmcpowers 	/*
1156034448feSmcpowers 	 * Add CKA_EC_POINT to the public template.
1157034448feSmcpowers 	 * This is the generated value Q. This attribute
1158034448feSmcpowers 	 * must not be in the template.
1159034448feSmcpowers 	 */
1160034448feSmcpowers 	if (attribute_in_template(CKA_EC_POINT, pPublicKeyTemplate,
1161034448feSmcpowers 	    ulPublicKeyAttributeCount)) {
1162034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
1163034448feSmcpowers 		goto failed_exit;
1164034448feSmcpowers 	}
1165034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
1166034448feSmcpowers 	    ulPublicKeyAttributeCount);
1167034448feSmcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
1168034448feSmcpowers 	    ulPublicKeyAttributeCount);
1169034448feSmcpowers 
1170034448feSmcpowers 	pub_attr_count = ulPublicKeyAttributeCount + 1;
1171034448feSmcpowers 	if (!has_class)
1172034448feSmcpowers 		pub_attr_count++;
1173034448feSmcpowers 	if (!has_key_type)
1174034448feSmcpowers 		pub_attr_count++;
1175034448feSmcpowers 	pubTemplate = grow_template(pPublicKeyTemplate,
1176034448feSmcpowers 	    ulPublicKeyAttributeCount, pub_attr_count);
1177034448feSmcpowers 	if (pubTemplate == NULL) {
1178034448feSmcpowers 		rv = CKR_HOST_MEMORY;
1179034448feSmcpowers 		goto failed_exit;
11807c478bd9Sstevel@tonic-gate 	}
11817c478bd9Sstevel@tonic-gate 
1182034448feSmcpowers 	n = ulPublicKeyAttributeCount;
1183034448feSmcpowers 	if (!has_class) {
1184034448feSmcpowers 		pubTemplate[n].type = CKA_CLASS;
1185034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)&pub_class;
1186034448feSmcpowers 		pubTemplate[n].ulValueLen = sizeof (pub_class);
1187034448feSmcpowers 		n++;
1188034448feSmcpowers 	}
1189034448feSmcpowers 	if (!has_key_type) {
1190034448feSmcpowers 		pubTemplate[n].type = CKA_KEY_TYPE;
1191034448feSmcpowers 		key_type = CKK_EC;
1192034448feSmcpowers 		pubTemplate[n].pValue = (caddr_t)&key_type;
1193034448feSmcpowers 		pubTemplate[n].ulValueLen = sizeof (key_type);
1194034448feSmcpowers 		n++;
1195034448feSmcpowers 	}
1196034448feSmcpowers 	pubTemplate[n].type = CKA_EC_POINT;
1197034448feSmcpowers 	pubTemplate[n].pValue = (caddr_t)point;
1198034448feSmcpowers 	pubTemplate[n].ulValueLen = sizeof (point);
1199034448feSmcpowers 	pub_out_attr_count++;
1200034448feSmcpowers 
1201034448feSmcpowers 	rv = process_object_attributes(pubTemplate,
1202034448feSmcpowers 	    pub_attr_count - pub_out_attr_count,
1203034448feSmcpowers 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
12047c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
12057c478bd9Sstevel@tonic-gate 		goto failed_exit;
12067c478bd9Sstevel@tonic-gate 	}
1207034448feSmcpowers 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
12087c478bd9Sstevel@tonic-gate 
1209034448feSmcpowers 	rv = process_object_attributes(
1210034448feSmcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
1211034448feSmcpowers 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
1212034448feSmcpowers 	    &is_token_obj1);
12137c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
12147c478bd9Sstevel@tonic-gate 		goto failed_exit;
12157c478bd9Sstevel@tonic-gate 	}
1216034448feSmcpowers 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	/*
1219034448feSmcpowers 	 * Cannot create a token object with a READ-ONLY
1220034448feSmcpowers 	 * session.
12217c478bd9Sstevel@tonic-gate 	 */
1222034448feSmcpowers 	if (is_token_obj1 && session_p->ses_RO) {
1223034448feSmcpowers 		rv = CKR_SESSION_READ_ONLY;
1224034448feSmcpowers 		goto failed_exit;
1225034448feSmcpowers 	}
12267c478bd9Sstevel@tonic-gate 
1227034448feSmcpowers 	/*
1228034448feSmcpowers 	 * CKA_EC_PARAMS and CKA_VALUE must not appear in
1229034448feSmcpowers 	 * private template.
1230034448feSmcpowers 	 */
1231034448feSmcpowers 	if (attribute_in_template(CKA_EC_PARAMS, pPrivateKeyTemplate,
1232034448feSmcpowers 	    ulPrivateKeyAttributeCount) ||
1233034448feSmcpowers 	    attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
1234034448feSmcpowers 	    ulPrivateKeyAttributeCount)) {
1235034448feSmcpowers 		rv = CKR_TEMPLATE_INCONSISTENT;
1236034448feSmcpowers 		goto failed_exit;
1237034448feSmcpowers 	}
1238034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
1239034448feSmcpowers 	    ulPrivateKeyAttributeCount);
1240034448feSmcpowers 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
1241034448feSmcpowers 	    ulPrivateKeyAttributeCount);
12427c478bd9Sstevel@tonic-gate 
1243034448feSmcpowers 	pri_attr_count = ulPrivateKeyAttributeCount + 1;
1244034448feSmcpowers 	if (!has_class)
1245034448feSmcpowers 		pri_attr_count++;
1246034448feSmcpowers 	if (!has_key_type)
1247034448feSmcpowers 		pri_attr_count++;
12487c478bd9Sstevel@tonic-gate 
1249034448feSmcpowers 	/* allocate space for CKA_EC_PARAMS */
1250034448feSmcpowers 	priTemplate = grow_template(pPrivateKeyTemplate,
1251034448feSmcpowers 	    ulPrivateKeyAttributeCount, pri_attr_count + 1);
1252034448feSmcpowers 	if (priTemplate == NULL) {
1253034448feSmcpowers 		rv = CKR_HOST_MEMORY;
1254034448feSmcpowers 		goto failed_exit;
1255034448feSmcpowers 	}
1256034448feSmcpowers 	n = ulPrivateKeyAttributeCount;
1257034448feSmcpowers 	if (!has_class) {
1258034448feSmcpowers 		priTemplate[n].type = CKA_CLASS;
1259034448feSmcpowers 		priTemplate[n].pValue = (caddr_t)&pri_class;
1260034448feSmcpowers 		priTemplate[n].ulValueLen = sizeof (pri_class);
1261034448feSmcpowers 		n++;
1262034448feSmcpowers 	}
1263034448feSmcpowers 	if (!has_key_type) {
1264034448feSmcpowers 		priTemplate[n].type = CKA_KEY_TYPE;
1265034448feSmcpowers 		key_type = CKK_EC;
1266034448feSmcpowers 		priTemplate[n].pValue = (caddr_t)&key_type;
1267034448feSmcpowers 		priTemplate[n].ulValueLen = sizeof (key_type);
1268034448feSmcpowers 		n++;
1269034448feSmcpowers 	}
1270034448feSmcpowers 	priTemplate[n].type = CKA_VALUE;
1271034448feSmcpowers 	priTemplate[n].pValue = (caddr_t)value;
1272034448feSmcpowers 	priTemplate[n].ulValueLen = sizeof (value);
1273034448feSmcpowers 	pri_out_attr_count++;
1274034448feSmcpowers 
1275034448feSmcpowers 	rv = process_object_attributes(priTemplate,
1276034448feSmcpowers 	    pri_attr_count - pri_out_attr_count,
1277034448feSmcpowers 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
1278034448feSmcpowers 	if (rv != CKR_OK) {
1279034448feSmcpowers 		goto failed_exit;
1280034448feSmcpowers 	}
1281034448feSmcpowers 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
1282034448feSmcpowers 
1283034448feSmcpowers 	rv = process_object_attributes(
1284034448feSmcpowers 	    &priTemplate[pri_attr_count - pri_out_attr_count],
1285034448feSmcpowers 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
1286034448feSmcpowers 	    &is_token_obj2);
1287034448feSmcpowers 	if (rv != CKR_OK) {
1288034448feSmcpowers 		goto failed_exit;
1289034448feSmcpowers 	}
1290034448feSmcpowers 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 	/*
1293034448feSmcpowers 	 * The public key and the private key need to contain the same
1294034448feSmcpowers 	 * attribute values for CKA_TOKEN.
12957c478bd9Sstevel@tonic-gate 	 */
1296034448feSmcpowers 	if (is_token_obj1 != is_token_obj2) {
1297034448feSmcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
1298034448feSmcpowers 		goto failed_exit;
1299034448feSmcpowers 	}
1300034448feSmcpowers 
1301034448feSmcpowers 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
1302034448feSmcpowers 	obj_nkp.nkp_session = session_p-> k_session;
1303034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
1304034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
1305034448feSmcpowers 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1306034448feSmcpowers 
1307034448feSmcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
1308034448feSmcpowers 	    &obj_nkp)) < 0) {
1309034448feSmcpowers 		if (errno != EINTR)
1310034448feSmcpowers 			break;
1311034448feSmcpowers 	}
1312034448feSmcpowers 	if (r < 0) {
1313034448feSmcpowers 		rv = CKR_FUNCTION_FAILED;
13147c478bd9Sstevel@tonic-gate 	} else {
1315034448feSmcpowers 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
13167c478bd9Sstevel@tonic-gate 	}
1317034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
1318034448feSmcpowers 	    &obj_nkp.nkp_in_public_count);
1319034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
1320034448feSmcpowers 	    &obj_nkp.nkp_in_private_count);
13217c478bd9Sstevel@tonic-gate 
1322034448feSmcpowers 	if (rv != CKR_OK) {
1323034448feSmcpowers 		goto failed_exit;
1324034448feSmcpowers 	}
13257c478bd9Sstevel@tonic-gate 
1326034448feSmcpowers 	rv = get_object_attributes(
1327034448feSmcpowers 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
1328034448feSmcpowers 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
1329034448feSmcpowers 	if (rv == CRYPTO_SUCCESS) {
1330034448feSmcpowers 		rv = get_object_attributes(
1331034448feSmcpowers 		    &priTemplate[pri_attr_count - pri_out_attr_count],
1332034448feSmcpowers 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
1333034448feSmcpowers 	}
1334034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
1335034448feSmcpowers 	    &obj_nkp.nkp_out_public_count);
1336034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
1337034448feSmcpowers 	    &obj_nkp.nkp_out_private_count);
1338034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1339034448feSmcpowers 		goto failed_exit;
13407c478bd9Sstevel@tonic-gate 	}
13417c478bd9Sstevel@tonic-gate 
1342034448feSmcpowers 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
1343034448feSmcpowers 	    session_p, KERNEL_GEN_KEY);
1344034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1345034448feSmcpowers 		goto failed_exit;
1346034448feSmcpowers 	}
1347034448feSmcpowers 
1348034448feSmcpowers 	/*
1349034448feSmcpowers 	 * Copy CKA_EC_PARAMS from the public template to the
1350034448feSmcpowers 	 * private template.
1351034448feSmcpowers 	 */
1352034448feSmcpowers 	rv = copy_attribute(CKA_EC_PARAMS, pubTemplate, pub_attr_count,
1353034448feSmcpowers 	    &priTemplate[pri_attr_count]);
1354034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1355034448feSmcpowers 		goto failed_exit;
1356034448feSmcpowers 	}
1357034448feSmcpowers 
1358034448feSmcpowers 	/* +1 to account for CKA_EC_PARAMS */
1359034448feSmcpowers 	rv = kernel_build_object(priTemplate, pri_attr_count + 1,
1360034448feSmcpowers 	    new_pri_objp, session_p, KERNEL_GEN_KEY);
1361034448feSmcpowers 	(void) free(priTemplate[pri_attr_count].pValue);
1362034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
1363034448feSmcpowers 		goto failed_exit;
1364034448feSmcpowers 	}
1365034448feSmcpowers 	(void) free(pubTemplate);
1366034448feSmcpowers 	(void) free(priTemplate);
1367034448feSmcpowers 
1368034448feSmcpowers 	new_pub_objp->is_lib_obj = B_TRUE;
1369034448feSmcpowers 	new_pri_objp->is_lib_obj = B_TRUE;
1370034448feSmcpowers 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1371034448feSmcpowers 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1372034448feSmcpowers 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1373034448feSmcpowers 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1374034448feSmcpowers 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1375034448feSmcpowers 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1376034448feSmcpowers 	return (CKR_OK);
1377034448feSmcpowers 
1378034448feSmcpowers failed_exit:
1379034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_public_attributes,
1380034448feSmcpowers 	    &obj_nkp.nkp_in_public_count);
1381034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_public_attributes,
1382034448feSmcpowers 	    &obj_nkp.nkp_out_public_count);
1383034448feSmcpowers 	free_attributes(obj_nkp.nkp_in_private_attributes,
1384034448feSmcpowers 	    &obj_nkp.nkp_in_private_count);
1385034448feSmcpowers 	free_attributes(obj_nkp.nkp_out_private_attributes,
1386034448feSmcpowers 	    &obj_nkp.nkp_out_private_count);
1387034448feSmcpowers 	if (pubTemplate != NULL) {
1388034448feSmcpowers 		(void) free(pubTemplate);
1389034448feSmcpowers 	}
1390034448feSmcpowers 	if (priTemplate != NULL) {
1391034448feSmcpowers 		(void) free(priTemplate);
1392034448feSmcpowers 	}
13937c478bd9Sstevel@tonic-gate 	return (rv);
13947c478bd9Sstevel@tonic-gate }
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate CK_RV
C_GenerateKeyPair(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pPublicKeyTemplate,CK_ULONG ulPublicKeyAttributeCount,CK_ATTRIBUTE_PTR pPrivateKeyTemplate,CK_ULONG ulPrivateKeyAttributeCount,CK_OBJECT_HANDLE_PTR phPublicKey,CK_OBJECT_HANDLE_PTR phPrivateKey)13977c478bd9Sstevel@tonic-gate C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
13987c478bd9Sstevel@tonic-gate     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
13997c478bd9Sstevel@tonic-gate     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
14007c478bd9Sstevel@tonic-gate     CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
14017c478bd9Sstevel@tonic-gate {
14027c478bd9Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
14037c478bd9Sstevel@tonic-gate 	kernel_session_t	*session_p;
14047c478bd9Sstevel@tonic-gate 	kernel_object_t		*new_pub_objp = NULL;
14057c478bd9Sstevel@tonic-gate 	kernel_object_t		*new_pri_objp = NULL;
14067c478bd9Sstevel@tonic-gate 	kernel_slot_t		*pslot;
14077c478bd9Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
14087c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj1;
14097c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj2;
14107c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_token_obj1 = FALSE;
14117c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_token_obj2 = FALSE;
14127c478bd9Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
14137c478bd9Sstevel@tonic-gate 	int r;
1414034448feSmcpowers 	CK_RV (*func)(CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG,
1415034448feSmcpowers 	    CK_ATTRIBUTE_PTR, CK_ULONG, kernel_session_t *, crypto_mech_type_t,
1416034448feSmcpowers 	    kernel_object_t *, kernel_object_t *);
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
14197c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 	/* Obtain the session pointer. */
14227c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
14237c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
14247c478bd9Sstevel@tonic-gate 		return (rv);
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate 	if ((pMechanism == NULL) || (phPublicKey == NULL) ||
14277c478bd9Sstevel@tonic-gate 	    (phPrivateKey == NULL)) {
14287c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
14297c478bd9Sstevel@tonic-gate 		goto failed_exit;
14307c478bd9Sstevel@tonic-gate 	}
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate 	if ((pPublicKeyTemplate == NULL) && (ulPublicKeyAttributeCount != 0)) {
14337c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
14347c478bd9Sstevel@tonic-gate 		goto failed_exit;
14357c478bd9Sstevel@tonic-gate 	}
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 	if ((pPrivateKeyTemplate == NULL) &&
14387c478bd9Sstevel@tonic-gate 	    (ulPrivateKeyAttributeCount != 0)) {
14397c478bd9Sstevel@tonic-gate 		rv = CKR_ARGUMENTS_BAD;
14407c478bd9Sstevel@tonic-gate 		goto failed_exit;
14417c478bd9Sstevel@tonic-gate 	}
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
14447c478bd9Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
14457c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
14467c478bd9Sstevel@tonic-gate 		goto failed_exit;
14477c478bd9Sstevel@tonic-gate 	}
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 	/* Create an object wrapper for the public key */
14507c478bd9Sstevel@tonic-gate 	new_pub_objp = calloc(1, sizeof (kernel_object_t));
14517c478bd9Sstevel@tonic-gate 	if (new_pub_objp == NULL) {
14527c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
14537c478bd9Sstevel@tonic-gate 		goto failed_exit;
14547c478bd9Sstevel@tonic-gate 	}
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	/* Create an object wrapper for the private key. */
14577c478bd9Sstevel@tonic-gate 	new_pri_objp = calloc(1, sizeof (kernel_object_t));
14587c478bd9Sstevel@tonic-gate 	if (new_pri_objp == NULL) {
14597c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
14607c478bd9Sstevel@tonic-gate 		goto failed_exit;
14617c478bd9Sstevel@tonic-gate 	}
14627c478bd9Sstevel@tonic-gate 
1463034448feSmcpowers 	/*
1464034448feSmcpowers 	 * Special Case: if token does not support object creation,
1465034448feSmcpowers 	 * but does support key generation by value, then create a session
1466034448feSmcpowers 	 * object and initialize with values returned by token.
1467034448feSmcpowers 	 */
1468034448feSmcpowers 	pslot = slot_table[session_p->ses_slotid];
1469034448feSmcpowers 	if (!pslot->sl_func_list.fl_object_create) {
1470034448feSmcpowers 		switch (pMechanism->mechanism) {
1471034448feSmcpowers 		case CKM_RSA_PKCS_KEY_PAIR_GEN:
1472034448feSmcpowers 			func = key_gen_rsa_by_value;
1473034448feSmcpowers 			break;
14747c478bd9Sstevel@tonic-gate 
1475034448feSmcpowers 		case CKM_DH_PKCS_KEY_PAIR_GEN:
1476034448feSmcpowers 			func = key_gen_dh_by_value;
1477034448feSmcpowers 			break;
1478034448feSmcpowers 
1479034448feSmcpowers 		case CKM_EC_KEY_PAIR_GEN:
1480034448feSmcpowers 			func = key_gen_ec_by_value;
1481034448feSmcpowers 			break;
1482034448feSmcpowers 
1483034448feSmcpowers 		default:
1484034448feSmcpowers 			rv = CKR_MECHANISM_INVALID;
1485034448feSmcpowers 			goto failed_exit;
1486034448feSmcpowers 		}
1487034448feSmcpowers 		rv = (*func)(pMechanism, pPublicKeyTemplate,
1488034448feSmcpowers 		    ulPublicKeyAttributeCount, pPrivateKeyTemplate,
1489034448feSmcpowers 		    ulPrivateKeyAttributeCount, session_p, k_mech_type,
1490034448feSmcpowers 		    new_pub_objp, new_pri_objp);
1491034448feSmcpowers 		if (rv != CKR_OK)
1492034448feSmcpowers 			goto failed_exit;
1493034448feSmcpowers 	} else {
1494034448feSmcpowers 		crypto_object_generate_key_pair_t obj_kp;
1495034448feSmcpowers 
1496034448feSmcpowers 		/* Process the public key attributes. */
1497034448feSmcpowers 		rv = process_object_attributes(pPublicKeyTemplate,
1498034448feSmcpowers 		    ulPublicKeyAttributeCount, &obj_kp.kp_public_attributes,
1499034448feSmcpowers 		    &is_token_obj1);
1500034448feSmcpowers 		if (rv != CKR_OK) {
1501034448feSmcpowers 			goto failed_exit;
1502034448feSmcpowers 		}
1503034448feSmcpowers 
1504034448feSmcpowers 		/* Cannot create a token object with a READ-ONLY session. */
1505034448feSmcpowers 		if (is_token_obj1 && session_p->ses_RO) {
1506034448feSmcpowers 			free_object_attributes(obj_kp.kp_public_attributes,
1507034448feSmcpowers 			    ulPublicKeyAttributeCount);
1508034448feSmcpowers 			rv = CKR_SESSION_READ_ONLY;
1509034448feSmcpowers 			goto failed_exit;
1510034448feSmcpowers 		}
1511034448feSmcpowers 
1512034448feSmcpowers 		/* Process the private key attributes. */
1513034448feSmcpowers 		rv = process_object_attributes(pPrivateKeyTemplate,
1514034448feSmcpowers 		    ulPrivateKeyAttributeCount, &obj_kp.kp_private_attributes,
1515034448feSmcpowers 		    &is_token_obj2);
1516034448feSmcpowers 		if (rv != CKR_OK) {
1517034448feSmcpowers 			free_object_attributes(obj_kp.kp_public_attributes,
1518034448feSmcpowers 			    ulPublicKeyAttributeCount);
1519034448feSmcpowers 			goto failed_exit;
1520034448feSmcpowers 		}
15217c478bd9Sstevel@tonic-gate 
1522034448feSmcpowers 		/*
1523034448feSmcpowers 		 * The public key and the private key need to contain the same
1524034448feSmcpowers 		 * attribute values for CKA_TOKEN.
1525034448feSmcpowers 		 */
1526034448feSmcpowers 		if (is_token_obj1 != is_token_obj2) {
1527034448feSmcpowers 			free_object_attributes(obj_kp.kp_public_attributes,
1528034448feSmcpowers 			    ulPublicKeyAttributeCount);
1529034448feSmcpowers 			free_object_attributes(obj_kp.kp_private_attributes,
1530034448feSmcpowers 			    ulPrivateKeyAttributeCount);
1531034448feSmcpowers 			rv = CKR_ATTRIBUTE_VALUE_INVALID;
1532034448feSmcpowers 			goto failed_exit;
1533034448feSmcpowers 		}
15347c478bd9Sstevel@tonic-gate 
1535034448feSmcpowers 		/* Call the CRYPTO_GENERATE_KEY_PAIR ioctl. */
1536034448feSmcpowers 		obj_kp.kp_session = session_p-> k_session;
1537034448feSmcpowers 		obj_kp.kp_mechanism.cm_type = k_mech_type;
1538034448feSmcpowers 		obj_kp.kp_mechanism.cm_param = pMechanism->pParameter;
1539034448feSmcpowers 		obj_kp.kp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1540034448feSmcpowers 		obj_kp.kp_public_count = ulPublicKeyAttributeCount;
1541034448feSmcpowers 		obj_kp.kp_private_count = ulPrivateKeyAttributeCount;
1542034448feSmcpowers 
1543034448feSmcpowers 		while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY_PAIR,
1544034448feSmcpowers 		    &obj_kp)) < 0) {
1545034448feSmcpowers 			if (errno != EINTR)
1546034448feSmcpowers 				break;
1547034448feSmcpowers 		}
1548034448feSmcpowers 		if (r < 0) {
1549034448feSmcpowers 			rv = CKR_FUNCTION_FAILED;
1550034448feSmcpowers 		} else {
1551034448feSmcpowers 			rv = crypto2pkcs11_error_number(obj_kp.kp_return_value);
1552034448feSmcpowers 		}
15537c478bd9Sstevel@tonic-gate 		free_object_attributes(obj_kp.kp_public_attributes,
15547c478bd9Sstevel@tonic-gate 		    ulPublicKeyAttributeCount);
15557c478bd9Sstevel@tonic-gate 		free_object_attributes(obj_kp.kp_private_attributes,
15567c478bd9Sstevel@tonic-gate 		    ulPrivateKeyAttributeCount);
15577c478bd9Sstevel@tonic-gate 
1558034448feSmcpowers 		if (rv != CKR_OK)
1559034448feSmcpowers 			goto failed_exit;
15607c478bd9Sstevel@tonic-gate 
1561034448feSmcpowers 		/* Get the CKA_PRIVATE value for the key pair. */
1562034448feSmcpowers 		rv = get_cka_private_value(session_p, obj_kp.kp_public_handle,
1563034448feSmcpowers 		    &is_pri_obj1);
1564034448feSmcpowers 		if (rv != CKR_OK) {
1565034448feSmcpowers 			goto failed_exit;
1566034448feSmcpowers 		}
15677c478bd9Sstevel@tonic-gate 
1568034448feSmcpowers 		rv = get_cka_private_value(session_p, obj_kp.kp_private_handle,
1569034448feSmcpowers 		    &is_pri_obj2);
1570034448feSmcpowers 		if (rv != CKR_OK) {
1571034448feSmcpowers 			goto failed_exit;
1572034448feSmcpowers 		}
15737c478bd9Sstevel@tonic-gate 
1574034448feSmcpowers 		/*
1575034448feSmcpowers 		 * Store the kernel public key handle into the public key
1576034448feSmcpowers 		 * object and finish the public key object initialization.
1577034448feSmcpowers 		 */
1578034448feSmcpowers 		new_pub_objp->is_lib_obj = B_FALSE;
1579034448feSmcpowers 		new_pub_objp->k_handle = obj_kp.kp_public_handle;
1580034448feSmcpowers 		new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1581034448feSmcpowers 		new_pub_objp->extra_attrlistp = NULL;
15827c478bd9Sstevel@tonic-gate 
1583034448feSmcpowers 		if (is_pri_obj1)
1584034448feSmcpowers 			new_pub_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
1585034448feSmcpowers 		else
1586034448feSmcpowers 			new_pub_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
15877c478bd9Sstevel@tonic-gate 
1588034448feSmcpowers 		if (is_token_obj1)
1589034448feSmcpowers 			new_pub_objp->bool_attr_mask |= TOKEN_BOOL_ON;
1590034448feSmcpowers 		else
1591034448feSmcpowers 			new_pub_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
15927c478bd9Sstevel@tonic-gate 
1593034448feSmcpowers 		(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1594034448feSmcpowers 		new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
15957c478bd9Sstevel@tonic-gate 
1596034448feSmcpowers 		/*
1597034448feSmcpowers 		 * Store the kernel private key handle into the private key
1598034448feSmcpowers 		 * object and finish the private key object initialization.
1599034448feSmcpowers 		 */
1600034448feSmcpowers 		new_pri_objp->is_lib_obj = B_FALSE;
1601034448feSmcpowers 		new_pri_objp->k_handle = obj_kp.kp_private_handle;
1602034448feSmcpowers 		new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1603034448feSmcpowers 		new_pri_objp->extra_attrlistp = NULL;
16047c478bd9Sstevel@tonic-gate 
1605034448feSmcpowers 		if (is_pri_obj2)
1606034448feSmcpowers 			new_pri_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
1607034448feSmcpowers 		else
1608034448feSmcpowers 			new_pri_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
16097c478bd9Sstevel@tonic-gate 
1610034448feSmcpowers 		if (is_token_obj2)
1611034448feSmcpowers 			new_pri_objp->bool_attr_mask |= TOKEN_BOOL_ON;
1612034448feSmcpowers 		else
1613034448feSmcpowers 			new_pri_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
16147c478bd9Sstevel@tonic-gate 
1615034448feSmcpowers 	}
16167c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
16177c478bd9Sstevel@tonic-gate 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 	/*
16207c478bd9Sstevel@tonic-gate 	 * Add the new pub/pri objects to the slot's token list if they are
16217c478bd9Sstevel@tonic-gate 	 * token objects. Otherwise, add them to the session's object list.
16227c478bd9Sstevel@tonic-gate 	 */
16237c478bd9Sstevel@tonic-gate 	if (is_token_obj1) { /* is_token_obj1 == is_token_obj2 */
16247c478bd9Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
16257c478bd9Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_pub_objp, pslot);
16267c478bd9Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_pri_objp, pslot);
16277c478bd9Sstevel@tonic-gate 	} else {
16287c478bd9Sstevel@tonic-gate 		kernel_add_object_to_session(new_pub_objp, session_p);
16297c478bd9Sstevel@tonic-gate 		kernel_add_object_to_session(new_pri_objp, session_p);
16307c478bd9Sstevel@tonic-gate 	}
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 	*phPublicKey = (CK_OBJECT_HANDLE)new_pub_objp;
16337c478bd9Sstevel@tonic-gate 	*phPrivateKey = (CK_OBJECT_HANDLE)new_pri_objp;
16347c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
16357c478bd9Sstevel@tonic-gate 	return (rv);
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate failed_exit:
16387c478bd9Sstevel@tonic-gate 	if (new_pub_objp != NULL) {
16397c478bd9Sstevel@tonic-gate 		(void) free(new_pub_objp);
16407c478bd9Sstevel@tonic-gate 	}
16417c478bd9Sstevel@tonic-gate 	if (new_pri_objp != NULL) {
16427c478bd9Sstevel@tonic-gate 		(void) free(new_pri_objp);
16437c478bd9Sstevel@tonic-gate 	}
16447c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
16457c478bd9Sstevel@tonic-gate 	return (rv);
16467c478bd9Sstevel@tonic-gate }
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate CK_RV
C_WrapKey(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hWrappingKey,CK_OBJECT_HANDLE hKey,CK_BYTE_PTR pWrappedKey,CK_ULONG_PTR pulWrappedKeyLen)16507c478bd9Sstevel@tonic-gate C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
16517c478bd9Sstevel@tonic-gate     CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
16527c478bd9Sstevel@tonic-gate     CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen)
16537c478bd9Sstevel@tonic-gate {
16547c478bd9Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
16557c478bd9Sstevel@tonic-gate 	kernel_session_t	*session_p;
16567c478bd9Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
16577c478bd9Sstevel@tonic-gate 	kernel_object_t		*wrappingkey_p;
16587c478bd9Sstevel@tonic-gate 	kernel_object_t		*key_p;
16597c478bd9Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
16607c478bd9Sstevel@tonic-gate 	crypto_object_wrap_key_t obj_wrapkey;
16617c478bd9Sstevel@tonic-gate 	int r;
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
16647c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
16657c478bd9Sstevel@tonic-gate 
16667c478bd9Sstevel@tonic-gate 	if (pulWrappedKeyLen == NULL || pMechanism == NULL) {
16677c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
16687c478bd9Sstevel@tonic-gate 	}
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	/*
16717c478bd9Sstevel@tonic-gate 	 * Obtain the session pointer.  Also, increment the session
16727c478bd9Sstevel@tonic-gate 	 * reference count.
16737c478bd9Sstevel@tonic-gate 	 */
16747c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
16757c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
16767c478bd9Sstevel@tonic-gate 		return (rv);
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
16797c478bd9Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
16807c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
16817c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
16827c478bd9Sstevel@tonic-gate 		return (rv);
16837c478bd9Sstevel@tonic-gate 	}
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 	/* Obtain the wrapping key object pointer. */
16867c478bd9Sstevel@tonic-gate 	HANDLE2OBJECT(hWrappingKey, wrappingkey_p, rv);
16877c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
16887c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
16897c478bd9Sstevel@tonic-gate 		return (rv);
16907c478bd9Sstevel@tonic-gate 	}
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate 	/* Obtain the to_be_wrapped key object pointer. */
16937c478bd9Sstevel@tonic-gate 	HANDLE2OBJECT(hKey, key_p, rv);
16947c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
169501223cbaSmcpowers 		OBJ_REFRELE(wrappingkey_p);
16967c478bd9Sstevel@tonic-gate 		REFRELE(session_p, ses_lock_held);
16977c478bd9Sstevel@tonic-gate 		return (rv);
16987c478bd9Sstevel@tonic-gate 	}
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 	/* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */
17017c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_session = session_p->k_session;
17027c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_mechanism.cm_type = k_mech_type;
17037c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_mechanism.cm_param = pMechanism->pParameter;
17047c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_mechanism.cm_param_len = pMechanism->ulParameterLen;
17057c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_wrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
17067c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_wrapping_key.ck_obj_id = wrappingkey_p->k_handle;
17077c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_object_handle = key_p->k_handle;
17087c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_wrapped_key_len = *pulWrappedKeyLen;
17097c478bd9Sstevel@tonic-gate 	obj_wrapkey.wk_wrapped_key = (char *)pWrappedKey;
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_WRAP_KEY, &obj_wrapkey)) < 0) {
17127c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
17137c478bd9Sstevel@tonic-gate 			break;
17147c478bd9Sstevel@tonic-gate 	}
17157c478bd9Sstevel@tonic-gate 	if (r < 0) {
17167c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
17177c478bd9Sstevel@tonic-gate 	} else {
17187c478bd9Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(obj_wrapkey.wk_return_value);
17197c478bd9Sstevel@tonic-gate 	}
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	/*
17227c478bd9Sstevel@tonic-gate 	 * Besides rv == CKR_OK, we will set the value of pulWrappedKeyLen
17237c478bd9Sstevel@tonic-gate 	 * when the applciation-supplied wrapped key buffer is too small.
17247c478bd9Sstevel@tonic-gate 	 * The situation that the application only asks for the length of
17257c478bd9Sstevel@tonic-gate 	 * the wrapped key is covered in rv == CKR_OK.
17267c478bd9Sstevel@tonic-gate 	 */
17277c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
17287c478bd9Sstevel@tonic-gate 		*pulWrappedKeyLen = obj_wrapkey.wk_wrapped_key_len;
17297c478bd9Sstevel@tonic-gate 	}
17307c478bd9Sstevel@tonic-gate 
173101223cbaSmcpowers 	OBJ_REFRELE(key_p);
173201223cbaSmcpowers 	OBJ_REFRELE(wrappingkey_p);
17337c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
17347c478bd9Sstevel@tonic-gate 	return (rv);
17357c478bd9Sstevel@tonic-gate }
17367c478bd9Sstevel@tonic-gate 
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate CK_RV
C_UnwrapKey(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hUnwrappingKey,CK_BYTE_PTR pWrappedKey,CK_ULONG ulWrappedKeyLen,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,CK_OBJECT_HANDLE_PTR phKey)17397c478bd9Sstevel@tonic-gate C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
17407c478bd9Sstevel@tonic-gate     CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey,
17417c478bd9Sstevel@tonic-gate     CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
17427c478bd9Sstevel@tonic-gate     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
17437c478bd9Sstevel@tonic-gate {
17447c478bd9Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
17457c478bd9Sstevel@tonic-gate 	kernel_session_t	*session_p;
17467c478bd9Sstevel@tonic-gate 	kernel_object_t		*unwrappingkey_p;
17477c478bd9Sstevel@tonic-gate 	kernel_object_t		*new_objp = NULL;
17487c478bd9Sstevel@tonic-gate 	kernel_slot_t		*pslot;
17497c478bd9Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
17507c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj;
17517c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_token_obj = FALSE;
17527c478bd9Sstevel@tonic-gate 	CK_MECHANISM_INFO	info;
17537c478bd9Sstevel@tonic-gate 	uint32_t		k_mi_flags;
17547c478bd9Sstevel@tonic-gate 	CK_BYTE			*clear_key_val = NULL;
1755*a8793c76SJason King 	CK_ULONG		ulDataLen;
17567c478bd9Sstevel@tonic-gate 	CK_ATTRIBUTE_PTR	newTemplate = NULL;
17577c478bd9Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
17587c478bd9Sstevel@tonic-gate 	crypto_object_unwrap_key_t obj_unwrapkey;
17597c478bd9Sstevel@tonic-gate 	int r;
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
17627c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) {
17657c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
17667c478bd9Sstevel@tonic-gate 	}
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate 	if ((pTemplate == NULL) && (ulAttributeCount != 0)) {
17697c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
17707c478bd9Sstevel@tonic-gate 	}
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 	/* Obtain the session pointer. */
17737c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
17747c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
17757c478bd9Sstevel@tonic-gate 		return (rv);
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 	/* Obtain the wrapping key object pointer. */
17787c478bd9Sstevel@tonic-gate 	HANDLE2OBJECT(hUnwrappingKey, unwrappingkey_p, rv);
17797c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
178001223cbaSmcpowers 		REFRELE(session_p, ses_lock_held);
178101223cbaSmcpowers 		return (rv);
17827c478bd9Sstevel@tonic-gate 	}
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 	/*
17857c478bd9Sstevel@tonic-gate 	 * If the HW provider doesn't support C_UnwrapKey, we will try
17867c478bd9Sstevel@tonic-gate 	 * to emulate it in the library.
17877c478bd9Sstevel@tonic-gate 	 */
17887c478bd9Sstevel@tonic-gate 	pslot = slot_table[session_p->ses_slotid];
1789034448feSmcpowers 	if ((!pslot->sl_func_list.fl_object_create) &&
1790034448feSmcpowers 	    (!pslot->sl_func_list.fl_key_unwrap)) {
17917c478bd9Sstevel@tonic-gate 		rv = get_mechanism_info(pslot, pMechanism->mechanism, &info,
17927c478bd9Sstevel@tonic-gate 		    &k_mi_flags);
17937c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
17947c478bd9Sstevel@tonic-gate 			goto failed_exit;
17957c478bd9Sstevel@tonic-gate 		}
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 		/*
17987c478bd9Sstevel@tonic-gate 		 * If the mechanism flag doesn't have CKF_UNWRAP, and it's
17997c478bd9Sstevel@tonic-gate 		 * an unwrapping of a secret key object, then help this
18007c478bd9Sstevel@tonic-gate 		 * out with a decryption followed by an object creation.
18017c478bd9Sstevel@tonic-gate 		 */
18027c478bd9Sstevel@tonic-gate 		if (!(k_mi_flags & CRYPTO_FG_UNWRAP) &&
18037c478bd9Sstevel@tonic-gate 		    (k_mi_flags & CRYPTO_FG_DECRYPT) &&
18047c478bd9Sstevel@tonic-gate 		    (is_secret_key_template(pTemplate, ulAttributeCount))) {
18057c478bd9Sstevel@tonic-gate 
18067c478bd9Sstevel@tonic-gate 			/* First allocate space for the recovered key value */
18077c478bd9Sstevel@tonic-gate 			clear_key_val = malloc(ulWrappedKeyLen);
18087c478bd9Sstevel@tonic-gate 			if (clear_key_val == NULL) {
18097c478bd9Sstevel@tonic-gate 				rv = CKR_HOST_MEMORY;
18107c478bd9Sstevel@tonic-gate 				goto failed_exit;
18117c478bd9Sstevel@tonic-gate 			}
18127c478bd9Sstevel@tonic-gate 
18137c478bd9Sstevel@tonic-gate 			rv = kernel_decrypt_init(session_p, unwrappingkey_p,
18147c478bd9Sstevel@tonic-gate 			    pMechanism);
18157c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
18167c478bd9Sstevel@tonic-gate 				goto failed_exit;
18177c478bd9Sstevel@tonic-gate 			}
18187c478bd9Sstevel@tonic-gate 
18197c478bd9Sstevel@tonic-gate 			ulDataLen = ulWrappedKeyLen;
18207c478bd9Sstevel@tonic-gate 			rv = kernel_decrypt(session_p, pWrappedKey,
18217c478bd9Sstevel@tonic-gate 			    ulWrappedKeyLen, clear_key_val, &ulDataLen);
18227c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
18237c478bd9Sstevel@tonic-gate 				goto failed_exit;
18247c478bd9Sstevel@tonic-gate 			}
18257c478bd9Sstevel@tonic-gate 
1826034448feSmcpowers 			newTemplate = grow_template(pTemplate, ulAttributeCount,
1827034448feSmcpowers 			    ulAttributeCount + 1);
18287c478bd9Sstevel@tonic-gate 			if (newTemplate == NULL) {
18297c478bd9Sstevel@tonic-gate 				rv = CKR_HOST_MEMORY;
18307c478bd9Sstevel@tonic-gate 				goto failed_exit;
18317c478bd9Sstevel@tonic-gate 			}
1832034448feSmcpowers 			/* Now add the CKA_VALUE attribute to template */
18337c478bd9Sstevel@tonic-gate 			newTemplate[ulAttributeCount].type = CKA_VALUE;
18347c478bd9Sstevel@tonic-gate 			newTemplate[ulAttributeCount].pValue = clear_key_val;
18357c478bd9Sstevel@tonic-gate 			newTemplate[ulAttributeCount].ulValueLen = ulDataLen;
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 			/* Finally create the key, based on the new template */
18387c478bd9Sstevel@tonic-gate 			rv = kernel_add_object(newTemplate,
18397c478bd9Sstevel@tonic-gate 			    ulAttributeCount + 1, phKey, session_p);
18407c478bd9Sstevel@tonic-gate 			(void) free(clear_key_val);
18417c478bd9Sstevel@tonic-gate 			(void) free(newTemplate);
184201223cbaSmcpowers 			OBJ_REFRELE(unwrappingkey_p);
18437c478bd9Sstevel@tonic-gate 			REFRELE(session_p, ses_lock_held);
18447c478bd9Sstevel@tonic-gate 			return (rv);
18457c478bd9Sstevel@tonic-gate 		} else {
18467c478bd9Sstevel@tonic-gate 			rv = CKR_FUNCTION_FAILED;
18477c478bd9Sstevel@tonic-gate 			goto failed_exit;
18487c478bd9Sstevel@tonic-gate 		}
18497c478bd9Sstevel@tonic-gate 	}
18507c478bd9Sstevel@tonic-gate 
18517c478bd9Sstevel@tonic-gate 	/*
18527c478bd9Sstevel@tonic-gate 	 * If we come here, the HW provider must have registered the unwrapkey
18537c478bd9Sstevel@tonic-gate 	 * entry.  Therefore, the unwrap key will be performed in the HW
18547c478bd9Sstevel@tonic-gate 	 * provider.
18557c478bd9Sstevel@tonic-gate 	 */
18567c478bd9Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
18577c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
18587c478bd9Sstevel@tonic-gate 		goto failed_exit;
18597c478bd9Sstevel@tonic-gate 	}
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	/* Create an object wrapper for the new key in the library first */
18627c478bd9Sstevel@tonic-gate 	new_objp = calloc(1, sizeof (kernel_object_t));
18637c478bd9Sstevel@tonic-gate 	if (new_objp == NULL) {
18647c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
18657c478bd9Sstevel@tonic-gate 		goto failed_exit;
18667c478bd9Sstevel@tonic-gate 	}
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 	/* Process the attributes */
18697c478bd9Sstevel@tonic-gate 	rv = process_object_attributes(pTemplate, ulAttributeCount,
18707c478bd9Sstevel@tonic-gate 	    &obj_unwrapkey.uk_attributes, &is_token_obj);
18717c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
18727c478bd9Sstevel@tonic-gate 		goto failed_exit;
18737c478bd9Sstevel@tonic-gate 	}
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 	/* Cannot create a token object with a READ-ONLY session. */
18767c478bd9Sstevel@tonic-gate 	if (is_token_obj && session_p->ses_RO) {
18777c478bd9Sstevel@tonic-gate 		free_object_attributes(obj_unwrapkey.uk_attributes,
18787c478bd9Sstevel@tonic-gate 		    ulAttributeCount);
18797c478bd9Sstevel@tonic-gate 		rv = CKR_SESSION_READ_ONLY;
18807c478bd9Sstevel@tonic-gate 		goto failed_exit;
18817c478bd9Sstevel@tonic-gate 	}
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate 	/* Make the CRYPTO_UNWRAP_KEY ioctl call. */
18847c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_session = session_p->k_session;
18857c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_mechanism.cm_type = k_mech_type;
18867c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_mechanism.cm_param = pMechanism->pParameter;
18877c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_mechanism.cm_param_len = pMechanism->ulParameterLen;
18887c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_unwrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
18897c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_unwrapping_key.ck_obj_id = unwrappingkey_p->k_handle;
18907c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_wrapped_key = (char *)pWrappedKey;
18917c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_wrapped_key_len = ulWrappedKeyLen;
18927c478bd9Sstevel@tonic-gate 	obj_unwrapkey.uk_count = ulAttributeCount;
18937c478bd9Sstevel@tonic-gate 
18947c478bd9Sstevel@tonic-gate 	while ((r = ioctl(kernel_fd, CRYPTO_UNWRAP_KEY, &obj_unwrapkey)) < 0) {
18957c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
18967c478bd9Sstevel@tonic-gate 			break;
18977c478bd9Sstevel@tonic-gate 	}
18987c478bd9Sstevel@tonic-gate 	if (r < 0) {
18997c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
19007c478bd9Sstevel@tonic-gate 	} else {
19017c478bd9Sstevel@tonic-gate 		rv = crypto2pkcs11_error_number(obj_unwrapkey.uk_return_value);
19027c478bd9Sstevel@tonic-gate 	}
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 	free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount);
19057c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
19067c478bd9Sstevel@tonic-gate 		goto failed_exit;
19077c478bd9Sstevel@tonic-gate 	}
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	/* Get the CKA_PRIVATE value for the unwrapped key. */
19107c478bd9Sstevel@tonic-gate 	rv = get_cka_private_value(session_p, obj_unwrapkey.uk_object_handle,
19117c478bd9Sstevel@tonic-gate 	    &is_pri_obj);
19127c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
19137c478bd9Sstevel@tonic-gate 		goto failed_exit;
19147c478bd9Sstevel@tonic-gate 	}
19157c478bd9Sstevel@tonic-gate 
19167c478bd9Sstevel@tonic-gate 	/*
19177c478bd9Sstevel@tonic-gate 	 * Store the kernel object handle in the new key object wrapper and
19187c478bd9Sstevel@tonic-gate 	 * initialize it.
19197c478bd9Sstevel@tonic-gate 	 */
19207c478bd9Sstevel@tonic-gate 	new_objp->k_handle = obj_unwrapkey.uk_object_handle;
19217c478bd9Sstevel@tonic-gate 	new_objp->is_lib_obj = B_FALSE;
19227c478bd9Sstevel@tonic-gate 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
19237c478bd9Sstevel@tonic-gate 	new_objp->extra_attrlistp = NULL;
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate 	if (is_pri_obj)
19267c478bd9Sstevel@tonic-gate 		new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
19277c478bd9Sstevel@tonic-gate 	else
19287c478bd9Sstevel@tonic-gate 		new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 	if (is_token_obj)
19317c478bd9Sstevel@tonic-gate 		new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
19327c478bd9Sstevel@tonic-gate 	else
19337c478bd9Sstevel@tonic-gate 		new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
19347c478bd9Sstevel@tonic-gate 
19357c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
19367c478bd9Sstevel@tonic-gate 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate 	/*
19397c478bd9Sstevel@tonic-gate 	 * Add the new object to the slot's token object list if it is a
19407c478bd9Sstevel@tonic-gate 	 * a token object. Otherwise, add it to the session's object list.
19417c478bd9Sstevel@tonic-gate 	 */
19427c478bd9Sstevel@tonic-gate 	if (is_token_obj) {
19437c478bd9Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
19447c478bd9Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_objp, pslot);
19457c478bd9Sstevel@tonic-gate 	} else {
19467c478bd9Sstevel@tonic-gate 		kernel_add_object_to_session(new_objp, session_p);
19477c478bd9Sstevel@tonic-gate 	}
19487c478bd9Sstevel@tonic-gate 
19497c478bd9Sstevel@tonic-gate 	*phKey = (CK_OBJECT_HANDLE)new_objp;
195001223cbaSmcpowers 	OBJ_REFRELE(unwrappingkey_p);
19517c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
19527c478bd9Sstevel@tonic-gate 	return (rv);
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate failed_exit:
195501223cbaSmcpowers 	OBJ_REFRELE(unwrappingkey_p);
19567c478bd9Sstevel@tonic-gate 	if (new_objp != NULL)
19577c478bd9Sstevel@tonic-gate 		(void) free(new_objp);
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 	if (clear_key_val != NULL)
19607c478bd9Sstevel@tonic-gate 		(void) free(clear_key_val);
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 	if (newTemplate != NULL)
19637c478bd9Sstevel@tonic-gate 		(void) free(newTemplate);
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
19667c478bd9Sstevel@tonic-gate 	return (rv);
19677c478bd9Sstevel@tonic-gate }
19687c478bd9Sstevel@tonic-gate 
1969034448feSmcpowers /*
1970034448feSmcpowers  * Get sufficient attributes from a base key to pass by value in a
1971034448feSmcpowers  * crypto_key structure. Storage for attributes is allocated.
1972034448feSmcpowers  * For EC public keys, it is CKA_EC_PARAMS and CKA_EC_POINT.
1973034448feSmcpowers  * For EC private keys, it is CKA_EC_PARAMS and CKA_VALUE.
1974034448feSmcpowers  */
1975034448feSmcpowers static int
get_base_key_attributes(kernel_object_t * base_key,crypto_key_t * key_by_value)1976034448feSmcpowers get_base_key_attributes(kernel_object_t *base_key, crypto_key_t *key_by_value)
1977034448feSmcpowers {
1978034448feSmcpowers 	CK_ATTRIBUTE tmp;
197977e5e96bSMark Powers 	crypto_object_attribute_t *attrs = NULL;
1980034448feSmcpowers 	biginteger_t *big;
198177e5e96bSMark Powers 	int i, count = 0, rv;
1982034448feSmcpowers 
1983034448feSmcpowers 	switch (base_key->key_type) {
1984034448feSmcpowers 	case CKK_EC:
198577e5e96bSMark Powers 		count = 2;
198677e5e96bSMark Powers 		attrs = malloc(count * sizeof (crypto_object_attribute_t));
1987034448feSmcpowers 		if (attrs == NULL) {
1988034448feSmcpowers 			rv = CKR_HOST_MEMORY;
1989034448feSmcpowers 			goto out;
1990034448feSmcpowers 		}
199177e5e96bSMark Powers 		bzero(attrs, count * sizeof (crypto_object_attribute_t));
1992034448feSmcpowers 
1993034448feSmcpowers 		(void) pthread_mutex_lock(&base_key->object_mutex);
1994034448feSmcpowers 
1995034448feSmcpowers 		if (!base_key->is_lib_obj) {
1996034448feSmcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
1997034448feSmcpowers 			goto out;
1998034448feSmcpowers 		}
1999034448feSmcpowers 
2000034448feSmcpowers 		if (base_key->class != CKO_PUBLIC_KEY &&
2001034448feSmcpowers 		    base_key->class != CKO_PRIVATE_KEY) {
2002034448feSmcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
2003034448feSmcpowers 			goto out;
2004034448feSmcpowers 		}
2005034448feSmcpowers 
2006034448feSmcpowers 		/*
2007034448feSmcpowers 		 * Both public and private EC keys should have
2008034448feSmcpowers 		 * a CKA_EC_PARAMS attribute.
2009034448feSmcpowers 		 */
2010034448feSmcpowers 		tmp.type = CKA_EC_PARAMS;
2011034448feSmcpowers 		tmp.pValue = NULL;
2012034448feSmcpowers 
2013034448feSmcpowers 		/* get size of attribute */
2014034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2015034448feSmcpowers 		if (rv != CKR_OK) {
2016034448feSmcpowers 			goto out;
2017034448feSmcpowers 		}
2018034448feSmcpowers 
2019034448feSmcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2020034448feSmcpowers 		if (tmp.pValue == NULL) {
2021034448feSmcpowers 			rv = CKR_HOST_MEMORY;
2022034448feSmcpowers 			goto out;
2023034448feSmcpowers 		}
2024034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2025034448feSmcpowers 		if (rv != CKR_OK) {
202677e5e96bSMark Powers 			free(tmp.pValue);
2027034448feSmcpowers 			goto out;
2028034448feSmcpowers 		}
2029034448feSmcpowers 		attrs[0].oa_type = tmp.type;
2030034448feSmcpowers 		attrs[0].oa_value = tmp.pValue;
2031034448feSmcpowers 		attrs[0].oa_value_len = tmp.ulValueLen;
2032034448feSmcpowers 
2033034448feSmcpowers 		switch (base_key->class) {
2034034448feSmcpowers 		case CKO_PUBLIC_KEY:
2035034448feSmcpowers 			big = OBJ_PUB_EC_POINT(base_key);
2036034448feSmcpowers 			tmp.type = CKA_EC_POINT;
2037034448feSmcpowers 			break;
2038034448feSmcpowers 
2039034448feSmcpowers 		case CKO_PRIVATE_KEY:
2040034448feSmcpowers 			big = OBJ_PRI_EC_VALUE(base_key);
2041034448feSmcpowers 			tmp.type = CKA_VALUE;
2042034448feSmcpowers 			break;
2043034448feSmcpowers 
2044034448feSmcpowers 		default:
2045034448feSmcpowers 			rv = CKR_ATTRIBUTE_TYPE_INVALID;
2046034448feSmcpowers 			goto out;
2047034448feSmcpowers 		}
2048034448feSmcpowers 		tmp.ulValueLen = big->big_value_len;
2049034448feSmcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2050034448feSmcpowers 		if (tmp.pValue == NULL) {
2051034448feSmcpowers 			rv = CKR_HOST_MEMORY;
2052034448feSmcpowers 			goto out;
2053034448feSmcpowers 		}
2054034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2055034448feSmcpowers 		if (rv != CKR_OK) {
205677e5e96bSMark Powers 			free(tmp.pValue);
2057034448feSmcpowers 			goto out;
2058034448feSmcpowers 		}
2059034448feSmcpowers 		attrs[1].oa_type = tmp.type;
2060034448feSmcpowers 		attrs[1].oa_value = tmp.pValue;
2061034448feSmcpowers 		attrs[1].oa_value_len = tmp.ulValueLen;
2062034448feSmcpowers 		key_by_value->ck_attrs = attrs;
2063034448feSmcpowers 		key_by_value->ck_count = 2;
2064034448feSmcpowers 		break;
2065034448feSmcpowers 
2066034448feSmcpowers 	case CKK_DH:
206777e5e96bSMark Powers 		count = 3;
206877e5e96bSMark Powers 		attrs = malloc(count * sizeof (crypto_object_attribute_t));
2069034448feSmcpowers 		if (attrs == NULL) {
2070034448feSmcpowers 			rv = CKR_HOST_MEMORY;
2071034448feSmcpowers 			goto out;
2072034448feSmcpowers 		}
207377e5e96bSMark Powers 		bzero(attrs, count * sizeof (crypto_object_attribute_t));
2074034448feSmcpowers 
2075034448feSmcpowers 		(void) pthread_mutex_lock(&base_key->object_mutex);
2076034448feSmcpowers 
2077034448feSmcpowers 		if (!base_key->is_lib_obj) {
2078034448feSmcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
2079034448feSmcpowers 			goto out;
2080034448feSmcpowers 		}
2081034448feSmcpowers 
2082034448feSmcpowers 		if (base_key->class != CKO_PRIVATE_KEY) {
2083034448feSmcpowers 			rv = CRYPTO_ARGUMENTS_BAD;
2084034448feSmcpowers 			goto out;
2085034448feSmcpowers 		}
2086034448feSmcpowers 		tmp.type = CKA_BASE;
2087034448feSmcpowers 		tmp.pValue = NULL;
2088034448feSmcpowers 
2089034448feSmcpowers 		/* get size of attribute */
2090034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2091034448feSmcpowers 		if (rv != CKR_OK) {
2092034448feSmcpowers 			goto out;
2093034448feSmcpowers 		}
2094034448feSmcpowers 
2095034448feSmcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2096034448feSmcpowers 		if (tmp.pValue == NULL) {
2097034448feSmcpowers 			rv = CKR_HOST_MEMORY;
2098034448feSmcpowers 			goto out;
2099034448feSmcpowers 		}
2100034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2101034448feSmcpowers 		if (rv != CKR_OK) {
210277e5e96bSMark Powers 			free(tmp.pValue);
2103034448feSmcpowers 			goto out;
2104034448feSmcpowers 		}
2105034448feSmcpowers 		attrs[0].oa_type = tmp.type;
2106034448feSmcpowers 		attrs[0].oa_value = tmp.pValue;
2107034448feSmcpowers 		attrs[0].oa_value_len = tmp.ulValueLen;
2108034448feSmcpowers 
2109034448feSmcpowers 		tmp.type = CKA_PRIME;
2110034448feSmcpowers 		tmp.pValue = NULL;
2111034448feSmcpowers 
2112034448feSmcpowers 		/* get size of attribute */
2113034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2114034448feSmcpowers 		if (rv != CKR_OK) {
2115034448feSmcpowers 			goto out;
2116034448feSmcpowers 		}
2117034448feSmcpowers 
2118034448feSmcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2119034448feSmcpowers 		if (tmp.pValue == NULL) {
2120034448feSmcpowers 			rv = CKR_HOST_MEMORY;
2121034448feSmcpowers 			goto out;
2122034448feSmcpowers 		}
2123034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2124034448feSmcpowers 		if (rv != CKR_OK) {
212577e5e96bSMark Powers 			free(tmp.pValue);
2126034448feSmcpowers 			goto out;
2127034448feSmcpowers 		}
2128034448feSmcpowers 		attrs[1].oa_type = tmp.type;
2129034448feSmcpowers 		attrs[1].oa_value = tmp.pValue;
2130034448feSmcpowers 		attrs[1].oa_value_len = tmp.ulValueLen;
2131034448feSmcpowers 
213277e5e96bSMark Powers 		big = OBJ_PRI_DH_VALUE(base_key);
2133034448feSmcpowers 		tmp.type = CKA_VALUE;
2134034448feSmcpowers 
2135034448feSmcpowers 		tmp.ulValueLen = big->big_value_len;
2136034448feSmcpowers 		tmp.pValue = malloc(tmp.ulValueLen);
2137034448feSmcpowers 		if (tmp.pValue == NULL) {
2138034448feSmcpowers 			rv = CKR_HOST_MEMORY;
2139034448feSmcpowers 			goto out;
2140034448feSmcpowers 		}
2141034448feSmcpowers 		rv = kernel_get_attribute(base_key, &tmp);
2142034448feSmcpowers 		if (rv != CKR_OK) {
214377e5e96bSMark Powers 			free(tmp.pValue);
2144034448feSmcpowers 			goto out;
2145034448feSmcpowers 		}
2146034448feSmcpowers 		attrs[2].oa_type = tmp.type;
2147034448feSmcpowers 		attrs[2].oa_value = tmp.pValue;
2148034448feSmcpowers 		attrs[2].oa_value_len = tmp.ulValueLen;
2149034448feSmcpowers 		key_by_value->ck_attrs = attrs;
2150034448feSmcpowers 		key_by_value->ck_count = 3;
2151034448feSmcpowers 		break;
2152034448feSmcpowers 
2153034448feSmcpowers 	default:
2154034448feSmcpowers 		rv = CKR_ATTRIBUTE_TYPE_INVALID;
2155034448feSmcpowers 		goto out;
2156034448feSmcpowers 	}
2157034448feSmcpowers 	(void) pthread_mutex_unlock(&base_key->object_mutex);
2158034448feSmcpowers 	return (CKR_OK);
2159034448feSmcpowers 
2160034448feSmcpowers out:
2161034448feSmcpowers 	(void) pthread_mutex_unlock(&base_key->object_mutex);
216277e5e96bSMark Powers 	if (attrs != NULL) {
216377e5e96bSMark Powers 		for (i = 0; i < count; i++) {
216477e5e96bSMark Powers 			if (attrs[i].oa_value != NULL)
216577e5e96bSMark Powers 				free(attrs[i].oa_value);
216677e5e96bSMark Powers 		}
216777e5e96bSMark Powers 		free(attrs);
216877e5e96bSMark Powers 	}
2169034448feSmcpowers 	return (rv);
2170034448feSmcpowers }
2171034448feSmcpowers 
2172034448feSmcpowers CK_RV
derive_key_by_value(CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,kernel_session_t * session_p,crypto_mech_type_t k_mech_type,kernel_object_t * basekey_p,kernel_object_t * new_objp)2173034448feSmcpowers derive_key_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
2174034448feSmcpowers     CK_ULONG ulAttributeCount, kernel_session_t *session_p,
2175034448feSmcpowers     crypto_mech_type_t k_mech_type, kernel_object_t *basekey_p,
2176034448feSmcpowers     kernel_object_t *new_objp)
2177034448feSmcpowers {
2178034448feSmcpowers 	crypto_nostore_derive_key_t obj_ndk;
2179034448feSmcpowers 	char *key_buf = NULL;
2180034448feSmcpowers 	CK_ATTRIBUTE_PTR newTemplate = NULL;
2181034448feSmcpowers 	CK_BBOOL is_token_obj = FALSE;
2182034448feSmcpowers 	CK_RV rv = CKR_OK;
2183034448feSmcpowers 	CK_ULONG secret_class = CKO_SECRET_KEY;
2184034448feSmcpowers 	ulong_t key_len = 0;
2185034448feSmcpowers 	uint_t attr_count = 0;
2186034448feSmcpowers 	boolean_t removed;
2187034448feSmcpowers 	boolean_t has_class;
2188034448feSmcpowers 	int r, n;
2189034448feSmcpowers 
2190034448feSmcpowers 	obj_ndk.ndk_in_count = 0;
2191034448feSmcpowers 	obj_ndk.ndk_out_count = 0;
2192034448feSmcpowers 	obj_ndk.ndk_base_key.ck_count = 0;
2193034448feSmcpowers 
2194034448feSmcpowers 	rv = get_key_len_from_template(pMechanism, pTemplate, ulAttributeCount,
2195034448feSmcpowers 	    basekey_p, &key_len);
2196034448feSmcpowers 	if (rv != CKR_OK) {
2197034448feSmcpowers 		goto failed_exit;
2198034448feSmcpowers 	}
2199034448feSmcpowers 
2200034448feSmcpowers 	if ((key_buf = malloc(key_len)) == NULL) {
2201034448feSmcpowers 		rv = CKR_HOST_MEMORY;
2202034448feSmcpowers 		goto failed_exit;
2203034448feSmcpowers 	}
2204034448feSmcpowers 
2205034448feSmcpowers 	has_class = attribute_in_template(CKA_CLASS, pTemplate,
2206034448feSmcpowers 	    ulAttributeCount);
2207034448feSmcpowers 
2208034448feSmcpowers 	attr_count = ulAttributeCount + 1;
2209034448feSmcpowers 	if (!has_class)
2210034448feSmcpowers 		attr_count++;
2211034448feSmcpowers 
2212034448feSmcpowers 	newTemplate = grow_template(pTemplate, ulAttributeCount, attr_count);
2213034448feSmcpowers 	if (newTemplate == NULL) {
2214034448feSmcpowers 		rv = CKR_HOST_MEMORY;
2215034448feSmcpowers 		goto failed_exit;
2216034448feSmcpowers 	}
2217034448feSmcpowers 
2218034448feSmcpowers 	n = ulAttributeCount;
2219034448feSmcpowers 	if (!has_class) {
2220034448feSmcpowers 		newTemplate[n].type = CKA_CLASS;
2221034448feSmcpowers 		newTemplate[n].pValue = (caddr_t)&secret_class;
2222034448feSmcpowers 		newTemplate[n].ulValueLen = sizeof (secret_class);
2223034448feSmcpowers 		n++;
2224034448feSmcpowers 	}
2225034448feSmcpowers 
2226034448feSmcpowers 	/* Add CKA_VALUE to the template */
2227034448feSmcpowers 	newTemplate[n].type = CKA_VALUE;
2228034448feSmcpowers 	newTemplate[n].pValue = (caddr_t)key_buf;
2229034448feSmcpowers 	newTemplate[n].ulValueLen = key_len;
2230034448feSmcpowers 
2231034448feSmcpowers 	rv = process_object_attributes(newTemplate, attr_count - 1,
2232034448feSmcpowers 	    &obj_ndk.ndk_in_attributes, &is_token_obj);
2233034448feSmcpowers 	if (rv != CKR_OK) {
2234034448feSmcpowers 		goto failed_exit;
2235034448feSmcpowers 	}
223677e5e96bSMark Powers 	obj_ndk.ndk_in_count = attr_count - 1;
2237034448feSmcpowers 
2238034448feSmcpowers 	rv = process_object_attributes(&newTemplate[attr_count - 1],
2239034448feSmcpowers 	    1, &obj_ndk.ndk_out_attributes, &is_token_obj);
2240034448feSmcpowers 	if (rv != CKR_OK) {
2241034448feSmcpowers 		goto failed_exit;
2242034448feSmcpowers 	}
224377e5e96bSMark Powers 	obj_ndk.ndk_out_count = 1;
2244034448feSmcpowers 
2245034448feSmcpowers 	/* Cannot create a token object with a READ-ONLY session. */
2246034448feSmcpowers 	if (is_token_obj && session_p->ses_RO) {
2247034448feSmcpowers 		rv = CKR_SESSION_READ_ONLY;
2248034448feSmcpowers 		goto failed_exit;
2249034448feSmcpowers 	}
2250034448feSmcpowers 
2251034448feSmcpowers 	obj_ndk.ndk_session = session_p->k_session;
2252034448feSmcpowers 	obj_ndk.ndk_mechanism.cm_type = k_mech_type;
2253034448feSmcpowers 	obj_ndk.ndk_mechanism.cm_param = pMechanism->pParameter;
2254034448feSmcpowers 	obj_ndk.ndk_mechanism.cm_param_len = pMechanism->ulParameterLen;
2255034448feSmcpowers 
2256034448feSmcpowers 	/*
2257034448feSmcpowers 	 * Obtain the attributes of base key and pass them by value.
2258034448feSmcpowers 	 */
2259034448feSmcpowers 	rv = get_base_key_attributes(basekey_p, &obj_ndk.ndk_base_key);
2260034448feSmcpowers 	if (rv != CKR_OK) {
2261034448feSmcpowers 		goto failed_exit;
2262034448feSmcpowers 	}
2263034448feSmcpowers 
2264034448feSmcpowers 	obj_ndk.ndk_base_key.ck_format = CRYPTO_KEY_ATTR_LIST;
2265034448feSmcpowers 
2266034448feSmcpowers 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_DERIVE_KEY,
2267034448feSmcpowers 	    &obj_ndk)) < 0) {
2268034448feSmcpowers 		if (errno != EINTR)
2269034448feSmcpowers 			break;
2270034448feSmcpowers 	}
2271034448feSmcpowers 	if (r < 0) {
2272034448feSmcpowers 		rv = CKR_FUNCTION_FAILED;
2273034448feSmcpowers 	} else {
2274034448feSmcpowers 		rv = crypto2pkcs11_error_number(obj_ndk.ndk_return_value);
2275034448feSmcpowers 	}
2276034448feSmcpowers 	free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
2277034448feSmcpowers 	free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
2278034448feSmcpowers 	    &obj_ndk.ndk_base_key.ck_count);
2279034448feSmcpowers 	if (rv != CKR_OK) {
2280034448feSmcpowers 		goto failed_exit;
2281034448feSmcpowers 	}
2282034448feSmcpowers 
2283034448feSmcpowers 	rv = get_object_attributes(&newTemplate[attr_count - 1],
2284034448feSmcpowers 	    1, obj_ndk.ndk_out_attributes);
2285034448feSmcpowers 	free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
2286034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
2287034448feSmcpowers 		goto failed_exit;
2288034448feSmcpowers 	}
2289034448feSmcpowers 
2290034448feSmcpowers 	removed = remove_one_attribute(newTemplate, CKA_VALUE_LEN,
2291034448feSmcpowers 	    attr_count, B_FALSE);
2292034448feSmcpowers 
2293034448feSmcpowers 	rv = kernel_build_object(newTemplate, removed ? attr_count - 1 :
2294034448feSmcpowers 	    attr_count, new_objp, session_p, KERNEL_GEN_KEY);
2295034448feSmcpowers 	if (rv != CRYPTO_SUCCESS) {
2296034448feSmcpowers 		goto failed_exit;
2297034448feSmcpowers 	}
2298034448feSmcpowers 
2299034448feSmcpowers 	free(key_buf);
2300034448feSmcpowers 	free(newTemplate);
2301034448feSmcpowers 	new_objp->is_lib_obj = B_TRUE;
2302034448feSmcpowers 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
2303034448feSmcpowers 	return (CKR_OK);
2304034448feSmcpowers 
2305034448feSmcpowers failed_exit:
2306034448feSmcpowers 	if (key_buf != NULL)
2307034448feSmcpowers 		free(key_buf);
2308034448feSmcpowers 	if (newTemplate != NULL)
2309034448feSmcpowers 		free(newTemplate);
2310034448feSmcpowers 	free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
2311034448feSmcpowers 	free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
2312034448feSmcpowers 	free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
2313034448feSmcpowers 	    &obj_ndk.ndk_base_key.ck_count);
2314034448feSmcpowers 	return (rv);
2315034448feSmcpowers }
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate CK_RV
C_DeriveKey(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hBaseKey,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,CK_OBJECT_HANDLE_PTR phKey)23187c478bd9Sstevel@tonic-gate C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
23197c478bd9Sstevel@tonic-gate     CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
23207c478bd9Sstevel@tonic-gate     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
23217c478bd9Sstevel@tonic-gate {
23227c478bd9Sstevel@tonic-gate 	CK_RV			rv = CKR_OK;
23237c478bd9Sstevel@tonic-gate 	kernel_session_t	*session_p;
23247c478bd9Sstevel@tonic-gate 	kernel_object_t		*basekey_p;
23257c478bd9Sstevel@tonic-gate 	kernel_object_t		*new_objp;
23267c478bd9Sstevel@tonic-gate 	kernel_slot_t		*pslot;
23277c478bd9Sstevel@tonic-gate 	boolean_t		ses_lock_held = B_FALSE;
23287c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_pri_obj;
23297c478bd9Sstevel@tonic-gate 	CK_BBOOL		is_token_obj = FALSE;
23307c478bd9Sstevel@tonic-gate 	crypto_mech_type_t	k_mech_type;
23317c478bd9Sstevel@tonic-gate 	int r;
23327c478bd9Sstevel@tonic-gate 
23337c478bd9Sstevel@tonic-gate 	if (!kernel_initialized)
23347c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate 	/* Obtain the session pointer. */
23377c478bd9Sstevel@tonic-gate 	rv = handle2session(hSession, &session_p);
23387c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
23397c478bd9Sstevel@tonic-gate 		return (rv);
23407c478bd9Sstevel@tonic-gate 
234160722cc8Sizick 	if (pMechanism == NULL) {
234201223cbaSmcpowers 		REFRELE(session_p, ses_lock_held);
234301223cbaSmcpowers 		return (CKR_ARGUMENTS_BAD);
23447c478bd9Sstevel@tonic-gate 	}
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate 	if ((pTemplate == NULL && ulAttributeCount != 0) ||
23477c478bd9Sstevel@tonic-gate 	    (pTemplate != NULL && ulAttributeCount == 0)) {
234801223cbaSmcpowers 		REFRELE(session_p, ses_lock_held);
234901223cbaSmcpowers 		return (CKR_ARGUMENTS_BAD);
23507c478bd9Sstevel@tonic-gate 	}
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 	/* Obtain the base key object pointer. */
23537c478bd9Sstevel@tonic-gate 	HANDLE2OBJECT(hBaseKey, basekey_p, rv);
23547c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
235501223cbaSmcpowers 		REFRELE(session_p, ses_lock_held);
235601223cbaSmcpowers 		return (rv);
23577c478bd9Sstevel@tonic-gate 	}
23587c478bd9Sstevel@tonic-gate 
23597c478bd9Sstevel@tonic-gate 	/* Get the kernel's internal mechanism number. */
23607c478bd9Sstevel@tonic-gate 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
23617c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
23627c478bd9Sstevel@tonic-gate 		goto failed_exit;
23637c478bd9Sstevel@tonic-gate 	}
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate 	/* Create an object wrapper in the library for the generated key. */
23667c478bd9Sstevel@tonic-gate 	new_objp = calloc(1, sizeof (kernel_object_t));
23677c478bd9Sstevel@tonic-gate 	if (new_objp == NULL) {
23687c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
23697c478bd9Sstevel@tonic-gate 		goto failed_exit;
23707c478bd9Sstevel@tonic-gate 	}
23717c478bd9Sstevel@tonic-gate 
2372034448feSmcpowers 	/*
2373034448feSmcpowers 	 * Special Case: if token does not support object creation,
2374034448feSmcpowers 	 * but does support key derivation by value, then create a session
2375034448feSmcpowers 	 * object and initialize with values returned by token.
2376034448feSmcpowers 	 */
2377034448feSmcpowers 	pslot = slot_table[session_p->ses_slotid];
2378034448feSmcpowers 	if (!pslot->sl_func_list.fl_object_create) {
2379034448feSmcpowers 		rv = derive_key_by_value(pMechanism, pTemplate,
2380034448feSmcpowers 		    ulAttributeCount, session_p, k_mech_type, basekey_p,
2381034448feSmcpowers 		    new_objp);
2382034448feSmcpowers 		if (rv != CKR_OK)
2383034448feSmcpowers 			goto failed_exit;
2384034448feSmcpowers 	} else {
2385034448feSmcpowers 		crypto_derive_key_t obj_dk;
23867c478bd9Sstevel@tonic-gate 
2387034448feSmcpowers 		rv = process_object_attributes(pTemplate, ulAttributeCount,
2388034448feSmcpowers 		    &obj_dk.dk_attributes, &is_token_obj);
2389034448feSmcpowers 		if (rv != CKR_OK) {
2390034448feSmcpowers 			goto failed_exit;
2391034448feSmcpowers 		}
23927c478bd9Sstevel@tonic-gate 
2393034448feSmcpowers 		/* Cannot create a token object with a READ-ONLY session. */
2394034448feSmcpowers 		if (is_token_obj && session_p->ses_RO) {
2395034448feSmcpowers 			free_object_attributes(obj_dk.dk_attributes,
2396034448feSmcpowers 			    ulAttributeCount);
2397034448feSmcpowers 			rv = CKR_SESSION_READ_ONLY;
2398034448feSmcpowers 			goto failed_exit;
2399034448feSmcpowers 		}
24007c478bd9Sstevel@tonic-gate 
2401034448feSmcpowers 		obj_dk.dk_session = session_p->k_session;
2402034448feSmcpowers 		obj_dk.dk_mechanism.cm_type = k_mech_type;
2403034448feSmcpowers 		obj_dk.dk_mechanism.cm_param = pMechanism->pParameter;
2404034448feSmcpowers 		obj_dk.dk_mechanism.cm_param_len = pMechanism->ulParameterLen;
2405034448feSmcpowers 		obj_dk.dk_base_key.ck_format = CRYPTO_KEY_REFERENCE;
2406034448feSmcpowers 		obj_dk.dk_base_key.ck_obj_id = basekey_p->k_handle;
2407034448feSmcpowers 		obj_dk.dk_count = ulAttributeCount;
2408034448feSmcpowers 
2409034448feSmcpowers 		while ((r = ioctl(kernel_fd, CRYPTO_DERIVE_KEY, &obj_dk)) < 0) {
2410034448feSmcpowers 			if (errno != EINTR)
2411034448feSmcpowers 				break;
2412034448feSmcpowers 		}
2413034448feSmcpowers 		if (r < 0) {
2414034448feSmcpowers 			rv = CKR_FUNCTION_FAILED;
2415034448feSmcpowers 		} else {
2416034448feSmcpowers 			rv = crypto2pkcs11_error_number(obj_dk.dk_return_value);
2417034448feSmcpowers 		}
24187c478bd9Sstevel@tonic-gate 
2419034448feSmcpowers 		free_object_attributes(obj_dk.dk_attributes, ulAttributeCount);
2420034448feSmcpowers 		if (rv != CKR_OK) {
2421034448feSmcpowers 			goto failed_exit;
2422034448feSmcpowers 		}
24237c478bd9Sstevel@tonic-gate 
2424034448feSmcpowers 		/* Get the CKA_PRIVATE value for the derived key. */
2425034448feSmcpowers 		rv = get_cka_private_value(session_p, obj_dk.dk_object_handle,
2426034448feSmcpowers 		    &is_pri_obj);
2427034448feSmcpowers 		if (rv != CKR_OK) {
2428034448feSmcpowers 			goto failed_exit;
2429034448feSmcpowers 		}
24307c478bd9Sstevel@tonic-gate 
2431034448feSmcpowers 		/*
2432034448feSmcpowers 		 * Store the kernel object handle into the new derived key
2433034448feSmcpowers 		 * object and finish the object initialization.
2434034448feSmcpowers 		 */
2435034448feSmcpowers 		new_objp->is_lib_obj = B_FALSE;
2436034448feSmcpowers 		new_objp->k_handle = obj_dk.dk_object_handle;
2437034448feSmcpowers 		new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
2438034448feSmcpowers 		new_objp->extra_attrlistp = NULL;
24397c478bd9Sstevel@tonic-gate 
2440034448feSmcpowers 		if (is_pri_obj)
2441034448feSmcpowers 			new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
2442034448feSmcpowers 		else
2443034448feSmcpowers 			new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
24447c478bd9Sstevel@tonic-gate 
2445034448feSmcpowers 		if (is_token_obj)
2446034448feSmcpowers 			new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
2447034448feSmcpowers 		else
2448034448feSmcpowers 			new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
2449034448feSmcpowers 	}
24507c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
24517c478bd9Sstevel@tonic-gate 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
24527c478bd9Sstevel@tonic-gate 
24537c478bd9Sstevel@tonic-gate 	/*
24547c478bd9Sstevel@tonic-gate 	 * Add the new derived object to the slot's token list if it is a
24557c478bd9Sstevel@tonic-gate 	 * token object. Otherwise, add it to the session's object list.
24567c478bd9Sstevel@tonic-gate 	 */
24577c478bd9Sstevel@tonic-gate 	if (is_token_obj) {
24587c478bd9Sstevel@tonic-gate 		pslot = slot_table[session_p->ses_slotid];
24597c478bd9Sstevel@tonic-gate 		kernel_add_token_object_to_slot(new_objp, pslot);
24607c478bd9Sstevel@tonic-gate 	} else {
24617c478bd9Sstevel@tonic-gate 		kernel_add_object_to_session(new_objp, session_p);
24627c478bd9Sstevel@tonic-gate 	}
24637c478bd9Sstevel@tonic-gate 
24647c478bd9Sstevel@tonic-gate 	*phKey = (CK_OBJECT_HANDLE)new_objp;
246501223cbaSmcpowers 	OBJ_REFRELE(basekey_p);
24667c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
24677c478bd9Sstevel@tonic-gate 	return (rv);
24687c478bd9Sstevel@tonic-gate 
24697c478bd9Sstevel@tonic-gate failed_exit:
247001223cbaSmcpowers 	OBJ_REFRELE(basekey_p);
24717c478bd9Sstevel@tonic-gate 	if (new_objp != NULL) {
24727c478bd9Sstevel@tonic-gate 		(void) free(new_objp);
24737c478bd9Sstevel@tonic-gate 	}
24747c478bd9Sstevel@tonic-gate 
24757c478bd9Sstevel@tonic-gate 	REFRELE(session_p, ses_lock_held);
24767c478bd9Sstevel@tonic-gate 	return (rv);
24777c478bd9Sstevel@tonic-gate }
2478