xref: /titanic_51/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelKeys.c (revision 5d1dd9a99f22e7799cd7c62987a566ed51713c5a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <strings.h>
29 #include <errno.h>
30 #include <security/cryptoki.h>
31 #include <sys/crypto/ioctl.h>
32 #include "kernelGlobal.h"
33 #include "kernelSession.h"
34 #include "kernelObject.h"
35 
36 static boolean_t
37 attribute_in_template(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
38 {
39 	int i;
40 
41 	for (i = 0; i < cnt; i++) {
42 		if (t[i].type == type)
43 			return (B_TRUE);
44 	}
45 	return (B_FALSE);
46 }
47 
48 /*
49  * This routine returns modulus bytes rounded up to the nearest 8 byte
50  * chunk. This is so we don't have to pass in max sized buffers for
51  * returned attributes. Every unnecessary byte that we pass in results
52  * in a kernel allocation.
53  */
54 static ulong_t
55 get_modulus_bytes(CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
56 {
57 	CK_ULONG modulus_len;
58 	int i;
59 
60 	for (i = 0; i < cnt; i++) {
61 		if (t[i].type == CKA_MODULUS_BITS) {
62 			get_ulong_attr_from_template(&modulus_len, &t[i]);
63 			/* convert from bit length to byte length */
64 			modulus_len = (modulus_len - 1) / 64 + 1;
65 			return (modulus_len * 8);
66 		}
67 	}
68 	return (0);
69 }
70 
71 /*
72  * Remove specified attribute from array. Storage for the attribute's
73  * value is freed if 'free_attr' is TRUE. Attributes are shifted so they are
74  * contiguous within the array, i.e. the next attribute is shifted into
75  * the position of the removed attribute. Returns TRUE if specified
76  * attribute is removed.
77  */
78 static boolean_t
79 remove_one_attribute(CK_ATTRIBUTE_PTR t, CK_ULONG type, uint_t count,
80     boolean_t free_attr)
81 {
82 	int i, j;
83 
84 	for (i = 0, j = 0; i < count; i++) {
85 		if (t[i].type == type) {
86 			if (free_attr) {
87 				free(t[i].pValue);
88 			}
89 			continue;
90 		}
91 		if (i != j) {
92 			t[j].type = t[i].type;
93 			t[j].pValue = t[i].pValue;
94 			t[j].ulValueLen = t[i].ulValueLen;
95 		}
96 		j++;
97 	}
98 	if (j == count)
99 		return (B_FALSE);
100 
101 	/* safety */
102 	t[j].pValue = NULL;
103 	t[j].ulValueLen = 0;
104 	return (B_TRUE);
105 }
106 
107 static boolean_t
108 is_secret_key_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
109 {
110 	int i;
111 	for (i = 0; i < ulAttributeCount; i++) {
112 		if (pTemplate[i].type == CKA_CLASS &&
113 		    *(CK_OBJECT_CLASS *)(pTemplate[i].pValue) ==
114 		    CKO_SECRET_KEY)
115 			return (B_TRUE);
116 	}
117 	return (B_FALSE);
118 }
119 
120 /*
121  * Allocate a template with space for new_count entries and copy the
122  * specified template into the new template.
123  */
124 static CK_ATTRIBUTE_PTR
125 grow_template(CK_ATTRIBUTE_PTR old_template, CK_ULONG old_count,
126     CK_ULONG new_count)
127 {
128 	CK_ATTRIBUTE_PTR new_template;
129 
130 	new_template = malloc(new_count * sizeof (CK_ATTRIBUTE));
131 	if (new_template != NULL)
132 		bcopy(old_template, new_template,
133 		    old_count * sizeof (CK_ATTRIBUTE));
134 	return (new_template);
135 }
136 
137 /*
138  * For fixed length keys such as DES, return the length based on
139  * the key type. For variable length keys such as AES, take the
140  * length from the CKA_VALUE_LEN attribute.
141  */
142 static int
143 get_key_len_from_template(CK_MECHANISM_PTR pMechanism,
144     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
145     kernel_object_t *basekey_p,  ulong_t *key_len)
146 {
147 	boolean_t fixed_len_key = B_FALSE;
148 	ulong_t key_type;
149 	int i;
150 
151 	for (i = 0; i < ulAttributeCount; i++) {
152 		if (pTemplate[i].type == CKA_KEY_TYPE) {
153 			get_ulong_attr_from_template(&key_type, &pTemplate[i]);
154 			break;
155 		}
156 	}
157 	/* CKA_KEY_TYPE must be present */
158 	if (i == ulAttributeCount)
159 		return (CKR_TEMPLATE_INCOMPLETE);
160 
161 	switch (key_type) {
162 	case CKK_DES:
163 		*key_len = 8;
164 		fixed_len_key = B_TRUE;
165 		break;
166 	case CKK_DES3:
167 		*key_len = 24;
168 		fixed_len_key = B_TRUE;
169 		break;
170 	case CKK_AES:
171 	case CKK_BLOWFISH:
172 		for (i = 0; i < ulAttributeCount; i++) {
173 			if (pTemplate[i].type == CKA_VALUE_LEN) {
174 				get_ulong_attr_from_template(key_len,
175 				    &pTemplate[i]);
176 				break;
177 			}
178 		}
179 		/* CKA_VALUE_LEN must be present */
180 		if (i == ulAttributeCount)
181 			return (CKR_TEMPLATE_INCOMPLETE);
182 		break;
183 	case CKK_GENERIC_SECRET:
184 		/*
185 		 * The key will not be truncated, so we need to
186 		 * get the max length for the mechanism.
187 		 */
188 		if (pMechanism->mechanism == CKM_DH_PKCS_DERIVE) {
189 			CK_ATTRIBUTE tmp;
190 
191 			tmp.type = CKA_PRIME;
192 			tmp.pValue = NULL;
193 
194 			/* get size of attribute */
195 			if (kernel_get_attribute(basekey_p, &tmp) != CKR_OK) {
196 				return (CKR_ARGUMENTS_BAD);
197 			}
198 			*key_len = tmp.ulValueLen;
199 		} else if (pMechanism->mechanism == CKM_ECDH1_DERIVE) {
200 			*key_len = 72;
201 		} else {
202 			return (CKR_ARGUMENTS_BAD);
203 		}
204 		break;
205 	default:
206 		return (CKR_ATTRIBUTE_VALUE_INVALID);
207 	}
208 
209 	if (fixed_len_key && attribute_in_template(CKA_VALUE_LEN,
210 	    pTemplate, ulAttributeCount))
211 		return (CKR_TEMPLATE_INCONSISTENT);
212 
213 	return (CKR_OK);
214 }
215 
216 /* find specified attribute src template and copy to dest */
217 static int
218 copy_attribute(CK_ULONG type, CK_ATTRIBUTE_PTR src, CK_ULONG src_cnt,
219     CK_ATTRIBUTE_PTR dst)
220 {
221 	int rv, i;
222 
223 	for (i = 0; i < src_cnt; i++) {
224 		if (src[i].type == type) {
225 			rv = get_string_from_template(dst, &src[i]);
226 			break;
227 		}
228 	}
229 	/*
230 	 * The public template didn't have attribute.
231 	 */
232 	if (i == src_cnt) {
233 		rv = CKR_TEMPLATE_INCOMPLETE;
234 	}
235 	return (rv);
236 }
237 
238 static void
239 free_attributes(caddr_t p, uint_t *countp)
240 {
241 	if (*countp > 0) {
242 		free_object_attributes(p, *countp);
243 		*countp = 0;
244 	}
245 }
246 
247 CK_RV
248 key_gen_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
249     CK_ULONG ulCount, kernel_session_t *session_p,
250     crypto_mech_type_t k_mech_type, kernel_object_t *new_objp)
251 {
252 	crypto_nostore_generate_key_t obj_ngk;
253 	char *key_buf = NULL;
254 	CK_ATTRIBUTE_PTR newTemplate = NULL;
255 	CK_BBOOL is_token_obj = FALSE;
256 	CK_RV rv = CKR_OK;
257 	ulong_t key_len = 0;
258 	uint_t attr_count;
259 	int r;
260 
261 	obj_ngk.ngk_in_count = 0;
262 	obj_ngk.ngk_out_count = 0;
263 
264 	rv = get_key_len_from_template(pMechanism, pTemplate, ulCount,
265 	    NULL, &key_len);
266 	if (rv != CRYPTO_SUCCESS)
267 		goto failed_exit;
268 
269 	if ((key_buf = malloc(key_len)) == NULL) {
270 		rv = CKR_HOST_MEMORY;
271 		goto failed_exit;
272 	}
273 
274 	attr_count = ulCount + 1;
275 	newTemplate = grow_template(pTemplate, ulCount, attr_count);
276 	if (newTemplate == NULL) {
277 		rv = CKR_HOST_MEMORY;
278 		goto failed_exit;
279 	}
280 
281 	/* Now add the CKA_VALUE attribute to template */
282 	newTemplate[ulCount].type = CKA_VALUE;
283 	newTemplate[ulCount].pValue = (caddr_t)key_buf;
284 	newTemplate[ulCount].ulValueLen = key_len;
285 
286 	rv = process_object_attributes(newTemplate, attr_count - 1,
287 	    &obj_ngk.ngk_in_attributes, &is_token_obj);
288 	if (rv != CKR_OK) {
289 		goto failed_exit;
290 	}
291 	rv = process_object_attributes(&newTemplate[ulCount],
292 	    1, &obj_ngk.ngk_out_attributes, &is_token_obj);
293 	if (rv != CKR_OK) {
294 		goto failed_exit;
295 	}
296 
297 	/* Cannot create a token object with a READ-ONLY session. */
298 	if (is_token_obj && session_p->ses_RO) {
299 		rv = CKR_SESSION_READ_ONLY;
300 		goto failed_exit;
301 	}
302 
303 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY ioctl */
304 	obj_ngk.ngk_session = session_p->k_session;
305 	obj_ngk.ngk_in_count = attr_count - 1;
306 	obj_ngk.ngk_out_count = 1;
307 	obj_ngk.ngk_mechanism.cm_type = k_mech_type;
308 	obj_ngk.ngk_mechanism.cm_param = pMechanism->pParameter;
309 	obj_ngk.ngk_mechanism.cm_param_len = pMechanism->ulParameterLen;
310 
311 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY,
312 	    &obj_ngk)) < 0) {
313 		if (errno != EINTR)
314 			break;
315 	}
316 	if (r < 0) {
317 		rv = CKR_FUNCTION_FAILED;
318 	} else {
319 		rv = crypto2pkcs11_error_number(obj_ngk.ngk_return_value);
320 	}
321 	free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
322 	if (rv != CKR_OK) {
323 		goto failed_exit;
324 	}
325 
326 	rv = get_object_attributes(&newTemplate[ulCount], 1,
327 	    obj_ngk.ngk_out_attributes);
328 	free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
329 	if (rv != CRYPTO_SUCCESS) {
330 		goto failed_exit;
331 	}
332 
333 	/*
334 	 * CKA_VALUE_LEN is not stored with the secret key object,
335 	 * so we remove it by shifting attributes down one.
336 	 */
337 	(void) remove_one_attribute(newTemplate, CKA_VALUE_LEN,
338 	    attr_count, B_FALSE);
339 
340 	rv = kernel_build_object(newTemplate, attr_count - 1,
341 	    new_objp, session_p, KERNEL_GEN_KEY);
342 	if (rv != CRYPTO_SUCCESS) {
343 		goto failed_exit;
344 	}
345 	new_objp->is_lib_obj = B_TRUE;
346 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
347 	(void) free(newTemplate);
348 	bzero(key_buf, key_len);
349 	(void) free(key_buf);
350 	return (CKR_OK);
351 
352 failed_exit:
353 	free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
354 	free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
355 	if (key_buf != NULL) {
356 		bzero(key_buf, key_len);
357 		(void) free(key_buf);
358 	}
359 	if (newTemplate != NULL) {
360 		(void) free(newTemplate);
361 	}
362 	return (rv);
363 }
364 
365 CK_RV
366 C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
367     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
368 {
369 	CK_RV			rv = CKR_OK;
370 	kernel_session_t	*session_p;
371 	kernel_object_t		*new_objp = NULL;
372 	kernel_slot_t		*pslot;
373 	boolean_t		ses_lock_held = B_FALSE;
374 	CK_BBOOL		is_pri_obj;
375 	CK_BBOOL		is_token_obj = FALSE;
376 	crypto_mech_type_t	k_mech_type;
377 	int r;
378 
379 	if (!kernel_initialized)
380 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
381 
382 	/* Obtain the session pointer */
383 	rv = handle2session(hSession, &session_p);
384 	if (rv != CKR_OK)
385 		return (rv);
386 
387 	if ((pMechanism == NULL) || (phKey == NULL)) {
388 		rv = CKR_ARGUMENTS_BAD;
389 		goto failed_exit;
390 	}
391 
392 	if ((pTemplate == NULL) && (ulCount != 0)) {
393 		rv = CKR_ARGUMENTS_BAD;
394 		goto failed_exit;
395 	}
396 
397 	/* Get the kernel's internal mechanism number. */
398 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
399 	if (rv != CKR_OK) {
400 		goto failed_exit;
401 	}
402 
403 	/* Create an object wrapper in the library first */
404 	new_objp = calloc(1, sizeof (kernel_object_t));
405 	if (new_objp == NULL) {
406 		rv = CKR_HOST_MEMORY;
407 		goto failed_exit;
408 	}
409 
410 	/*
411 	 * Special Case: if token does not support object creation,
412 	 * but does support key generation by value, then create a session
413 	 * object and initialize with value returned by token.
414 	 */
415 	pslot = slot_table[session_p->ses_slotid];
416 	if (!pslot->sl_func_list.fl_object_create) {
417 		rv = key_gen_by_value(pMechanism, pTemplate, ulCount, session_p,
418 		    k_mech_type, new_objp);
419 		if (rv != CKR_OK)
420 			goto failed_exit;
421 	} else {
422 		crypto_object_generate_key_t obj_gk;
423 
424 		/* Process the attributes */
425 		rv = process_object_attributes(pTemplate, ulCount,
426 		    &obj_gk.gk_attributes, &is_token_obj);
427 		if (rv != CKR_OK) {
428 			goto failed_exit;
429 		}
430 		/* Cannot create a token object with a READ-ONLY session. */
431 		if (is_token_obj && session_p->ses_RO) {
432 			free_object_attributes(obj_gk.gk_attributes, ulCount);
433 			rv = CKR_SESSION_READ_ONLY;
434 			goto failed_exit;
435 		}
436 
437 		/* Call the CRYPTO_GENERATE_KEY ioctl */
438 		obj_gk.gk_session = session_p->k_session;
439 		obj_gk.gk_count = ulCount;
440 		obj_gk.gk_mechanism.cm_type = k_mech_type;
441 		obj_gk.gk_mechanism.cm_param = pMechanism->pParameter;
442 		obj_gk.gk_mechanism.cm_param_len = pMechanism->ulParameterLen;
443 
444 		while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY,
445 		    &obj_gk)) < 0) {
446 			if (errno != EINTR)
447 				break;
448 		}
449 		if (r < 0) {
450 			rv = CKR_FUNCTION_FAILED;
451 		} else {
452 			rv = crypto2pkcs11_error_number(obj_gk.gk_return_value);
453 		}
454 
455 		free_object_attributes(obj_gk.gk_attributes, ulCount);
456 
457 		if (rv != CKR_OK) {
458 			goto failed_exit;
459 		}
460 
461 		/* Get the value of the CKA_PRIVATE attribute. */
462 		rv = get_cka_private_value(session_p, obj_gk.gk_handle,
463 		    &is_pri_obj);
464 		if (rv != CKR_OK) {
465 			goto failed_exit;
466 		}
467 
468 		/*
469 		 * Store the kernel object handle in the object wrapper and
470 		 * initialize the library object.
471 		 */
472 		new_objp->k_handle = obj_gk.gk_handle;
473 		new_objp->is_lib_obj = B_FALSE;
474 		new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
475 		new_objp->extra_attrlistp = NULL;
476 
477 		if (is_pri_obj)
478 			new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
479 		else
480 			new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
481 
482 		if (is_token_obj)
483 			new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
484 		else
485 			new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
486 	}
487 
488 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
489 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
490 
491 	/*
492 	 * Add the new object to the slot's token object list if it is a
493 	 * a token object. Otherwise, add it to the session's object list.
494 	 */
495 	if (is_token_obj) {
496 		pslot = slot_table[session_p->ses_slotid];
497 		kernel_add_token_object_to_slot(new_objp, pslot);
498 	} else {
499 		kernel_add_object_to_session(new_objp, session_p);
500 	}
501 
502 	*phKey = (CK_OBJECT_HANDLE)new_objp;
503 	REFRELE(session_p, ses_lock_held);
504 	return (rv);
505 
506 failed_exit:
507 	if (new_objp != NULL) {
508 		(void) free(new_objp);
509 	}
510 
511 	REFRELE(session_p, ses_lock_held);
512 	return (rv);
513 }
514 
515 CK_RV
516 key_gen_rsa_by_value(CK_MECHANISM_PTR pMechanism,
517     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
518     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
519     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
520     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
521 {
522 	crypto_nostore_generate_key_pair_t obj_nkp;
523 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
524 	CK_ATTRIBUTE_PTR priTemplate = NULL;
525 	CK_RV rv = CKR_OK;
526 	CK_BBOOL is_token_obj1 = FALSE;
527 	CK_BBOOL is_token_obj2 = FALSE;
528 	uint_t pub_attr_count, pri_attr_count;
529 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
530 	char public_modulus[512];
531 	char public_exponent[8];
532 	char private_exponent[512];
533 	char private_modulus[512];
534 	char prime_1[512];
535 	char prime_2[512];
536 	char exponent_1[512];
537 	char exponent_2[512];
538 	char coefficient[512];
539 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
540 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
541 	CK_ULONG key_type;
542 	CK_ULONG modulus_bytes;
543 	boolean_t has_class, has_key_type, has_pub_exponent;
544 	int n, r;
545 
546 	obj_nkp.nkp_in_public_count = 0;
547 	obj_nkp.nkp_out_public_count = 0;
548 	obj_nkp.nkp_in_private_count = 0;
549 	obj_nkp.nkp_out_private_count = 0;
550 
551 	/* modulus bits must be present when generating a RSA key pair */
552 	if (!attribute_in_template(CKA_MODULUS_BITS, pPublicKeyTemplate,
553 	    ulPublicKeyAttributeCount)) {
554 		rv = CKR_TEMPLATE_INCOMPLETE;
555 		goto failed_exit;
556 	}
557 
558 	modulus_bytes = get_modulus_bytes(pPublicKeyTemplate,
559 	    ulPublicKeyAttributeCount);
560 
561 	/*
562 	 * Add CKA_MODULUS to the public template.
563 	 * This attribute must not be in the template.
564 	 */
565 	if (attribute_in_template(CKA_MODULUS, pPublicKeyTemplate,
566 	    ulPublicKeyAttributeCount)) {
567 		rv = CKR_TEMPLATE_INCONSISTENT;
568 		goto failed_exit;
569 	}
570 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
571 	    ulPublicKeyAttributeCount);
572 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
573 	    ulPublicKeyAttributeCount);
574 	has_pub_exponent = attribute_in_template(CKA_PUBLIC_EXPONENT,
575 	    pPublicKeyTemplate, ulPublicKeyAttributeCount);
576 
577 	pub_attr_count = ulPublicKeyAttributeCount + 1;
578 	if (!has_class)
579 		pub_attr_count++;
580 	if (!has_key_type)
581 		pub_attr_count++;
582 	if (!has_pub_exponent)
583 		pub_attr_count++;
584 	pubTemplate = grow_template(pPublicKeyTemplate,
585 	    ulPublicKeyAttributeCount, pub_attr_count);
586 	if (pubTemplate == NULL) {
587 		rv = CKR_HOST_MEMORY;
588 		goto failed_exit;
589 	}
590 
591 	n = ulPublicKeyAttributeCount;
592 	if (!has_class) {
593 		pubTemplate[n].type = CKA_CLASS;
594 		pubTemplate[n].pValue = (caddr_t)&pub_class;
595 		pubTemplate[n].ulValueLen = sizeof (pub_class);
596 		n++;
597 	}
598 	if (!has_key_type) {
599 		pubTemplate[n].type = CKA_KEY_TYPE;
600 		key_type = CKK_RSA;
601 		pubTemplate[n].pValue = (caddr_t)&key_type;
602 		pubTemplate[n].ulValueLen = sizeof (key_type);
603 		n++;
604 	}
605 	if (!has_pub_exponent) {
606 		pubTemplate[n].type = CKA_PUBLIC_EXPONENT;
607 		pubTemplate[n].pValue = (caddr_t)public_exponent;
608 		pubTemplate[n].ulValueLen = modulus_bytes;
609 		n++;
610 		pub_out_attr_count++;
611 	}
612 	pubTemplate[n].type = CKA_MODULUS;
613 	pubTemplate[n].pValue = (caddr_t)public_modulus;
614 	pubTemplate[n].ulValueLen = modulus_bytes;
615 	pub_out_attr_count++;
616 
617 	rv = process_object_attributes(pubTemplate,
618 	    pub_attr_count - pub_out_attr_count,
619 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
620 	if (rv != CKR_OK) {
621 		goto failed_exit;
622 	}
623 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
624 
625 	rv = process_object_attributes(
626 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
627 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
628 	    &is_token_obj1);
629 	if (rv != CKR_OK) {
630 		goto failed_exit;
631 	}
632 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
633 
634 	/*
635 	 * Cannot create a token object with a READ-ONLY
636 	 * session.
637 	 */
638 	if (is_token_obj1 && session_p->ses_RO) {
639 		rv = CKR_SESSION_READ_ONLY;
640 		goto failed_exit;
641 	}
642 
643 	/*
644 	 * Add CKA_MODULUS and CKA_PRIVATE_EXPONENT
645 	 * to the private template. These attributes
646 	 * must not be in the template.
647 	 */
648 	if (attribute_in_template(CKA_PRIVATE_EXPONENT,
649 	    pPrivateKeyTemplate, ulPrivateKeyAttributeCount) ||
650 	    attribute_in_template(CKA_MODULUS,
651 	    pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) {
652 		rv = CKR_TEMPLATE_INCONSISTENT;
653 		goto failed_exit;
654 	}
655 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
656 	    ulPrivateKeyAttributeCount);
657 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
658 	    ulPrivateKeyAttributeCount);
659 
660 	pri_attr_count = ulPrivateKeyAttributeCount + 7;
661 	if (!has_class)
662 		pri_attr_count++;
663 	if (!has_key_type)
664 		pri_attr_count++;
665 
666 	/* allocate space for CKA_PUBLIC_EXPONENT */
667 	priTemplate = grow_template(pPrivateKeyTemplate,
668 	    ulPrivateKeyAttributeCount, pri_attr_count + 1);
669 	if (priTemplate == NULL) {
670 		rv = CKR_HOST_MEMORY;
671 		goto failed_exit;
672 	}
673 	n = ulPrivateKeyAttributeCount;
674 	if (!has_class) {
675 		priTemplate[n].type = CKA_CLASS;
676 		priTemplate[n].pValue = (caddr_t)&pri_class;
677 		priTemplate[n].ulValueLen = sizeof (pri_class);
678 		n++;
679 	}
680 	if (!has_key_type) {
681 		priTemplate[n].type = CKA_KEY_TYPE;
682 		key_type = CKK_RSA;
683 		priTemplate[n].pValue = (caddr_t)&key_type;
684 		priTemplate[n].ulValueLen = sizeof (key_type);
685 		n++;
686 	}
687 	priTemplate[n].type = CKA_MODULUS;
688 	priTemplate[n].pValue = (caddr_t)private_modulus;
689 	priTemplate[n].ulValueLen = modulus_bytes;
690 	pri_out_attr_count++;
691 
692 	n++;
693 	priTemplate[n].type = CKA_PRIVATE_EXPONENT;
694 	priTemplate[n].pValue = (caddr_t)private_exponent;
695 	priTemplate[n].ulValueLen = modulus_bytes;
696 	pri_out_attr_count++;
697 
698 	n++;
699 	priTemplate[n].type = CKA_PRIME_1;
700 	priTemplate[n].pValue = (caddr_t)prime_1;
701 	priTemplate[n].ulValueLen = modulus_bytes/2;
702 	pri_out_attr_count++;
703 
704 	n++;
705 	priTemplate[n].type = CKA_PRIME_2;
706 	priTemplate[n].pValue = (caddr_t)prime_2;
707 	priTemplate[n].ulValueLen = modulus_bytes/2;
708 	pri_out_attr_count++;
709 
710 	n++;
711 	priTemplate[n].type = CKA_EXPONENT_1;
712 	priTemplate[n].pValue = (caddr_t)exponent_1;
713 	priTemplate[n].ulValueLen = modulus_bytes/2;
714 	pri_out_attr_count++;
715 
716 	n++;
717 	priTemplate[n].type = CKA_EXPONENT_2;
718 	priTemplate[n].pValue = (caddr_t)exponent_2;
719 	priTemplate[n].ulValueLen = modulus_bytes/2;
720 	pri_out_attr_count++;
721 
722 	n++;
723 	priTemplate[n].type = CKA_COEFFICIENT;
724 	priTemplate[n].pValue = (caddr_t)coefficient;
725 	priTemplate[n].ulValueLen = modulus_bytes/2;
726 	pri_out_attr_count++;
727 
728 	rv = process_object_attributes(priTemplate,
729 	    pri_attr_count - pri_out_attr_count,
730 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
731 	if (rv != CKR_OK) {
732 		goto failed_exit;
733 	}
734 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
735 
736 	rv = process_object_attributes(
737 	    &priTemplate[pri_attr_count - pri_out_attr_count],
738 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
739 	    &is_token_obj2);
740 	if (rv != CKR_OK) {
741 		goto failed_exit;
742 	}
743 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
744 
745 	/*
746 	 * The public key and the private key need to contain the same
747 	 * attribute values for CKA_TOKEN.
748 	 */
749 	if (is_token_obj1 != is_token_obj2) {
750 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
751 		goto failed_exit;
752 	}
753 
754 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
755 	obj_nkp.nkp_session = session_p-> k_session;
756 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
757 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
758 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
759 
760 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
761 	    &obj_nkp)) < 0) {
762 		if (errno != EINTR)
763 			break;
764 	}
765 	if (r < 0) {
766 		rv = CKR_FUNCTION_FAILED;
767 	} else {
768 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
769 	}
770 	free_attributes(obj_nkp.nkp_in_public_attributes,
771 	    &obj_nkp.nkp_in_public_count);
772 	free_attributes(obj_nkp.nkp_in_private_attributes,
773 	    &obj_nkp.nkp_in_private_count);
774 
775 	if (rv != CKR_OK) {
776 		goto failed_exit;
777 	}
778 
779 	rv = get_object_attributes(
780 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
781 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
782 	if (rv == CRYPTO_SUCCESS) {
783 		rv = get_object_attributes(
784 		    &priTemplate[pri_attr_count - pri_out_attr_count],
785 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
786 	}
787 	free_attributes(obj_nkp.nkp_out_public_attributes,
788 	    &obj_nkp.nkp_out_public_count);
789 	free_attributes(obj_nkp.nkp_out_private_attributes,
790 	    &obj_nkp.nkp_out_private_count);
791 	if (rv != CRYPTO_SUCCESS) {
792 		goto failed_exit;
793 	}
794 
795 	/* store generated modulus and public exponent */
796 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
797 	    session_p, KERNEL_GEN_KEY);
798 	if (rv != CRYPTO_SUCCESS) {
799 		goto failed_exit;
800 	}
801 
802 	/*
803 	 * Copy CKA_PUBLIC_EXPONENT from the public template
804 	 * to the private template.
805 	 */
806 	rv = copy_attribute(CKA_PUBLIC_EXPONENT, pubTemplate,
807 	    pub_attr_count, &priTemplate[pri_attr_count]);
808 	if (rv != CRYPTO_SUCCESS) {
809 		goto failed_exit;
810 	}
811 
812 	rv = kernel_build_object(priTemplate, pri_attr_count + 1, new_pri_objp,
813 	    session_p, KERNEL_GEN_KEY);
814 	(void) free(priTemplate[pri_attr_count].pValue);
815 	if (rv != CRYPTO_SUCCESS) {
816 		goto failed_exit;
817 	}
818 	(void) free(pubTemplate);
819 	(void) free(priTemplate);
820 
821 	new_pub_objp->is_lib_obj = B_TRUE;
822 	new_pri_objp->is_lib_obj = B_TRUE;
823 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
824 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
825 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
826 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
827 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
828 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
829 	return (CKR_OK);
830 
831 failed_exit:
832 	free_attributes(obj_nkp.nkp_in_public_attributes,
833 	    &obj_nkp.nkp_in_public_count);
834 	free_attributes(obj_nkp.nkp_out_public_attributes,
835 	    &obj_nkp.nkp_out_public_count);
836 	free_attributes(obj_nkp.nkp_in_private_attributes,
837 	    &obj_nkp.nkp_in_private_count);
838 	free_attributes(obj_nkp.nkp_out_private_attributes,
839 	    &obj_nkp.nkp_out_private_count);
840 	if (pubTemplate != NULL) {
841 		(void) free(pubTemplate);
842 	}
843 	if (priTemplate != NULL) {
844 		(void) free(priTemplate);
845 	}
846 	return (rv);
847 }
848 
849 CK_RV
850 key_gen_dh_by_value(CK_MECHANISM_PTR pMechanism,
851     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
852     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
853     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
854     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
855 {
856 	crypto_nostore_generate_key_pair_t obj_nkp;
857 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
858 	CK_ATTRIBUTE_PTR priTemplate = NULL;
859 	CK_RV rv = CKR_OK;
860 	CK_BBOOL is_token_obj1 = FALSE;
861 	CK_BBOOL is_token_obj2 = FALSE;
862 	uint_t pub_attr_count, pri_attr_count;
863 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
864 	char public_value[256];
865 	char private_value[256];
866 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
867 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
868 	CK_ULONG key_type;
869 	boolean_t has_class, has_key_type;
870 	int n, r;
871 
872 	obj_nkp.nkp_in_public_count = 0;
873 	obj_nkp.nkp_out_public_count = 0;
874 	obj_nkp.nkp_in_private_count = 0;
875 	obj_nkp.nkp_out_private_count = 0;
876 
877 	/*
878 	 * Add CKA_VALUE to the public template.
879 	 * This attribute must not be in the template.
880 	 */
881 	if (attribute_in_template(CKA_VALUE, pPublicKeyTemplate,
882 	    ulPublicKeyAttributeCount)) {
883 		rv = CKR_TEMPLATE_INCONSISTENT;
884 		goto failed_exit;
885 	}
886 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
887 	    ulPublicKeyAttributeCount);
888 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
889 	    ulPublicKeyAttributeCount);
890 
891 	pub_attr_count = ulPublicKeyAttributeCount + 1;
892 	if (!has_class)
893 		pub_attr_count++;
894 	if (!has_key_type)
895 		pub_attr_count++;
896 	pubTemplate = grow_template(pPublicKeyTemplate,
897 	    ulPublicKeyAttributeCount, pub_attr_count);
898 	if (pubTemplate == NULL) {
899 		rv = CKR_HOST_MEMORY;
900 		goto failed_exit;
901 	}
902 
903 	n = ulPublicKeyAttributeCount;
904 	if (!has_class) {
905 		pubTemplate[n].type = CKA_CLASS;
906 		pubTemplate[n].pValue = (caddr_t)&pub_class;
907 		pubTemplate[n].ulValueLen = sizeof (pub_class);
908 		n++;
909 	}
910 	if (!has_key_type) {
911 		pubTemplate[n].type = CKA_KEY_TYPE;
912 		key_type = CKK_DH;
913 		pubTemplate[n].pValue = (caddr_t)&key_type;
914 		pubTemplate[n].ulValueLen = sizeof (key_type);
915 		n++;
916 	}
917 	pubTemplate[n].type = CKA_VALUE;
918 	pubTemplate[n].pValue = (caddr_t)public_value;
919 	pubTemplate[n].ulValueLen = sizeof (public_value);
920 	pub_out_attr_count++;
921 
922 	rv = process_object_attributes(pubTemplate,
923 	    pub_attr_count - pub_out_attr_count,
924 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
925 	if (rv != CKR_OK) {
926 		goto failed_exit;
927 	}
928 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
929 
930 	rv = process_object_attributes(
931 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
932 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
933 	    &is_token_obj1);
934 	if (rv != CKR_OK) {
935 		goto failed_exit;
936 	}
937 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
938 
939 	/*
940 	 * Cannot create a token object with a READ-ONLY
941 	 * session.
942 	 */
943 	if (is_token_obj1 && session_p->ses_RO) {
944 		rv = CKR_SESSION_READ_ONLY;
945 		goto failed_exit;
946 	}
947 
948 	/*
949 	 * CKA_BASE, CKA_PRIME, and CKA_VALUE must not appear
950 	 * in private template.
951 	 */
952 	if (attribute_in_template(CKA_BASE, pPrivateKeyTemplate,
953 	    ulPrivateKeyAttributeCount) ||
954 	    attribute_in_template(CKA_PRIME, pPrivateKeyTemplate,
955 	    ulPrivateKeyAttributeCount) ||
956 	    attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
957 	    ulPrivateKeyAttributeCount)) {
958 		rv = CKR_TEMPLATE_INCONSISTENT;
959 		goto failed_exit;
960 	}
961 
962 	if (attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
963 	    ulPrivateKeyAttributeCount)) {
964 		rv = CKR_TEMPLATE_INCONSISTENT;
965 		goto failed_exit;
966 	}
967 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
968 	    ulPrivateKeyAttributeCount);
969 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
970 	    ulPrivateKeyAttributeCount);
971 
972 	pri_attr_count = ulPrivateKeyAttributeCount + 1;
973 	if (!has_class)
974 		pri_attr_count++;
975 	if (!has_key_type)
976 		pri_attr_count++;
977 
978 	/* allocate space for CKA_BASE and CKA_PRIME */
979 	priTemplate = grow_template(pPrivateKeyTemplate,
980 	    ulPrivateKeyAttributeCount, pri_attr_count + 2);
981 	if (priTemplate == NULL) {
982 		rv = CKR_HOST_MEMORY;
983 		goto failed_exit;
984 	}
985 	n = ulPrivateKeyAttributeCount;
986 	if (!has_class) {
987 		priTemplate[n].type = CKA_CLASS;
988 		priTemplate[n].pValue = (caddr_t)&pri_class;
989 		priTemplate[n].ulValueLen = sizeof (pri_class);
990 		n++;
991 	}
992 	if (!has_key_type) {
993 		priTemplate[n].type = CKA_KEY_TYPE;
994 		key_type = CKK_DH;
995 		priTemplate[n].pValue = (caddr_t)&key_type;
996 		priTemplate[n].ulValueLen = sizeof (key_type);
997 		n++;
998 	}
999 	priTemplate[n].type = CKA_VALUE;
1000 	priTemplate[n].pValue = (caddr_t)private_value;
1001 	priTemplate[n].ulValueLen = sizeof (private_value);
1002 	pri_out_attr_count++;
1003 
1004 	rv = process_object_attributes(priTemplate,
1005 	    pri_attr_count - pri_out_attr_count,
1006 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
1007 	if (rv != CKR_OK) {
1008 		goto failed_exit;
1009 	}
1010 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
1011 
1012 	rv = process_object_attributes(
1013 	    &priTemplate[pri_attr_count - pri_out_attr_count],
1014 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
1015 	    &is_token_obj2);
1016 	if (rv != CKR_OK) {
1017 		goto failed_exit;
1018 	}
1019 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
1020 
1021 	/*
1022 	 * The public key and the private key need to contain the same
1023 	 * attribute values for CKA_TOKEN.
1024 	 */
1025 	if (is_token_obj1 != is_token_obj2) {
1026 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
1027 		goto failed_exit;
1028 	}
1029 
1030 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
1031 	obj_nkp.nkp_session = session_p-> k_session;
1032 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
1033 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
1034 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1035 
1036 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
1037 	    &obj_nkp)) < 0) {
1038 		if (errno != EINTR)
1039 			break;
1040 	}
1041 	if (r < 0) {
1042 		rv = CKR_FUNCTION_FAILED;
1043 	} else {
1044 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
1045 	}
1046 	free_attributes(obj_nkp.nkp_in_public_attributes,
1047 	    &obj_nkp.nkp_in_public_count);
1048 	free_attributes(obj_nkp.nkp_in_private_attributes,
1049 	    &obj_nkp.nkp_in_private_count);
1050 
1051 	if (rv != CKR_OK) {
1052 		goto failed_exit;
1053 	}
1054 
1055 	rv = get_object_attributes(
1056 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
1057 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
1058 	if (rv == CRYPTO_SUCCESS) {
1059 		rv = get_object_attributes(
1060 		    &priTemplate[pri_attr_count - pri_out_attr_count],
1061 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
1062 	}
1063 	free_attributes(obj_nkp.nkp_out_public_attributes,
1064 	    &obj_nkp.nkp_out_public_count);
1065 	free_attributes(obj_nkp.nkp_out_private_attributes,
1066 	    &obj_nkp.nkp_out_private_count);
1067 
1068 	if (rv != CRYPTO_SUCCESS) {
1069 		goto failed_exit;
1070 	}
1071 
1072 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
1073 	    session_p, KERNEL_GEN_KEY);
1074 	if (rv != CRYPTO_SUCCESS) {
1075 		goto failed_exit;
1076 	}
1077 
1078 	/*
1079 	 * Copy CKA_BASE and CKA_PRIME from the public template
1080 	 * to the private template.
1081 	 */
1082 	rv = copy_attribute(CKA_BASE, pubTemplate, pub_attr_count,
1083 	    &priTemplate[pri_attr_count]);
1084 	if (rv != CRYPTO_SUCCESS) {
1085 		goto failed_exit;
1086 	}
1087 	rv = copy_attribute(CKA_PRIME, pubTemplate, pub_attr_count,
1088 	    &priTemplate[pri_attr_count + 1]);
1089 	if (rv != CRYPTO_SUCCESS) {
1090 		(void) free(priTemplate[pri_attr_count].pValue);
1091 		goto failed_exit;
1092 	}
1093 
1094 	/* +2 to account for CKA_BASE and CKA_PRIME */
1095 	rv = kernel_build_object(priTemplate, pri_attr_count + 2,
1096 	    new_pri_objp, session_p, KERNEL_GEN_KEY);
1097 	(void) free(priTemplate[pri_attr_count].pValue);
1098 	(void) free(priTemplate[pri_attr_count + 1].pValue);
1099 	if (rv != CRYPTO_SUCCESS) {
1100 		goto failed_exit;
1101 	}
1102 	(void) free(pubTemplate);
1103 	(void) free(priTemplate);
1104 
1105 	new_pub_objp->is_lib_obj = B_TRUE;
1106 	new_pri_objp->is_lib_obj = B_TRUE;
1107 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1108 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1109 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1110 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1111 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1112 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1113 	return (CKR_OK);
1114 
1115 failed_exit:
1116 	free_attributes(obj_nkp.nkp_in_public_attributes,
1117 	    &obj_nkp.nkp_in_public_count);
1118 	free_attributes(obj_nkp.nkp_out_public_attributes,
1119 	    &obj_nkp.nkp_out_public_count);
1120 	free_attributes(obj_nkp.nkp_in_private_attributes,
1121 	    &obj_nkp.nkp_in_private_count);
1122 	free_attributes(obj_nkp.nkp_out_private_attributes,
1123 	    &obj_nkp.nkp_out_private_count);
1124 	if (pubTemplate != NULL) {
1125 		(void) free(pubTemplate);
1126 	}
1127 	if (priTemplate != NULL) {
1128 		(void) free(priTemplate);
1129 	}
1130 	return (rv);
1131 }
1132 
1133 CK_RV
1134 key_gen_ec_by_value(CK_MECHANISM_PTR pMechanism,
1135     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
1136     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
1137     kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
1138     kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
1139 {
1140 	crypto_nostore_generate_key_pair_t obj_nkp;
1141 	CK_ATTRIBUTE_PTR pubTemplate = NULL;
1142 	CK_ATTRIBUTE_PTR priTemplate = NULL;
1143 	CK_RV rv = CKR_OK;
1144 	CK_BBOOL is_token_obj1 = FALSE;
1145 	CK_BBOOL is_token_obj2 = FALSE;
1146 	uint_t pub_attr_count, pri_attr_count;
1147 	uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
1148 	char value[72];
1149 	char point[145];
1150 	CK_ULONG pub_class = CKO_PUBLIC_KEY;
1151 	CK_ULONG pri_class = CKO_PRIVATE_KEY;
1152 	CK_ULONG key_type;
1153 	boolean_t has_class, has_key_type;
1154 	int n, r;
1155 
1156 	obj_nkp.nkp_in_public_count = 0;
1157 	obj_nkp.nkp_out_public_count = 0;
1158 	obj_nkp.nkp_in_private_count = 0;
1159 	obj_nkp.nkp_out_private_count = 0;
1160 
1161 	/*
1162 	 * Add CKA_EC_POINT to the public template.
1163 	 * This is the generated value Q. This attribute
1164 	 * must not be in the template.
1165 	 */
1166 	if (attribute_in_template(CKA_EC_POINT, pPublicKeyTemplate,
1167 	    ulPublicKeyAttributeCount)) {
1168 		rv = CKR_TEMPLATE_INCONSISTENT;
1169 		goto failed_exit;
1170 	}
1171 	has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
1172 	    ulPublicKeyAttributeCount);
1173 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
1174 	    ulPublicKeyAttributeCount);
1175 
1176 	pub_attr_count = ulPublicKeyAttributeCount + 1;
1177 	if (!has_class)
1178 		pub_attr_count++;
1179 	if (!has_key_type)
1180 		pub_attr_count++;
1181 	pubTemplate = grow_template(pPublicKeyTemplate,
1182 	    ulPublicKeyAttributeCount, pub_attr_count);
1183 	if (pubTemplate == NULL) {
1184 		rv = CKR_HOST_MEMORY;
1185 		goto failed_exit;
1186 	}
1187 
1188 	n = ulPublicKeyAttributeCount;
1189 	if (!has_class) {
1190 		pubTemplate[n].type = CKA_CLASS;
1191 		pubTemplate[n].pValue = (caddr_t)&pub_class;
1192 		pubTemplate[n].ulValueLen = sizeof (pub_class);
1193 		n++;
1194 	}
1195 	if (!has_key_type) {
1196 		pubTemplate[n].type = CKA_KEY_TYPE;
1197 		key_type = CKK_EC;
1198 		pubTemplate[n].pValue = (caddr_t)&key_type;
1199 		pubTemplate[n].ulValueLen = sizeof (key_type);
1200 		n++;
1201 	}
1202 	pubTemplate[n].type = CKA_EC_POINT;
1203 	pubTemplate[n].pValue = (caddr_t)point;
1204 	pubTemplate[n].ulValueLen = sizeof (point);
1205 	pub_out_attr_count++;
1206 
1207 	rv = process_object_attributes(pubTemplate,
1208 	    pub_attr_count - pub_out_attr_count,
1209 	    &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
1210 	if (rv != CKR_OK) {
1211 		goto failed_exit;
1212 	}
1213 	obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
1214 
1215 	rv = process_object_attributes(
1216 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
1217 	    pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
1218 	    &is_token_obj1);
1219 	if (rv != CKR_OK) {
1220 		goto failed_exit;
1221 	}
1222 	obj_nkp.nkp_out_public_count = pub_out_attr_count;
1223 
1224 	/*
1225 	 * Cannot create a token object with a READ-ONLY
1226 	 * session.
1227 	 */
1228 	if (is_token_obj1 && session_p->ses_RO) {
1229 		rv = CKR_SESSION_READ_ONLY;
1230 		goto failed_exit;
1231 	}
1232 
1233 	/*
1234 	 * CKA_EC_PARAMS and CKA_VALUE must not appear in
1235 	 * private template.
1236 	 */
1237 	if (attribute_in_template(CKA_EC_PARAMS, pPrivateKeyTemplate,
1238 	    ulPrivateKeyAttributeCount) ||
1239 	    attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
1240 	    ulPrivateKeyAttributeCount)) {
1241 		rv = CKR_TEMPLATE_INCONSISTENT;
1242 		goto failed_exit;
1243 	}
1244 	has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
1245 	    ulPrivateKeyAttributeCount);
1246 	has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
1247 	    ulPrivateKeyAttributeCount);
1248 
1249 	pri_attr_count = ulPrivateKeyAttributeCount + 1;
1250 	if (!has_class)
1251 		pri_attr_count++;
1252 	if (!has_key_type)
1253 		pri_attr_count++;
1254 
1255 	/* allocate space for CKA_EC_PARAMS */
1256 	priTemplate = grow_template(pPrivateKeyTemplate,
1257 	    ulPrivateKeyAttributeCount, pri_attr_count + 1);
1258 	if (priTemplate == NULL) {
1259 		rv = CKR_HOST_MEMORY;
1260 		goto failed_exit;
1261 	}
1262 	n = ulPrivateKeyAttributeCount;
1263 	if (!has_class) {
1264 		priTemplate[n].type = CKA_CLASS;
1265 		priTemplate[n].pValue = (caddr_t)&pri_class;
1266 		priTemplate[n].ulValueLen = sizeof (pri_class);
1267 		n++;
1268 	}
1269 	if (!has_key_type) {
1270 		priTemplate[n].type = CKA_KEY_TYPE;
1271 		key_type = CKK_EC;
1272 		priTemplate[n].pValue = (caddr_t)&key_type;
1273 		priTemplate[n].ulValueLen = sizeof (key_type);
1274 		n++;
1275 	}
1276 	priTemplate[n].type = CKA_VALUE;
1277 	priTemplate[n].pValue = (caddr_t)value;
1278 	priTemplate[n].ulValueLen = sizeof (value);
1279 	pri_out_attr_count++;
1280 
1281 	rv = process_object_attributes(priTemplate,
1282 	    pri_attr_count - pri_out_attr_count,
1283 	    &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
1284 	if (rv != CKR_OK) {
1285 		goto failed_exit;
1286 	}
1287 	obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
1288 
1289 	rv = process_object_attributes(
1290 	    &priTemplate[pri_attr_count - pri_out_attr_count],
1291 	    pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
1292 	    &is_token_obj2);
1293 	if (rv != CKR_OK) {
1294 		goto failed_exit;
1295 	}
1296 	obj_nkp.nkp_out_private_count = pri_out_attr_count;
1297 
1298 	/*
1299 	 * The public key and the private key need to contain the same
1300 	 * attribute values for CKA_TOKEN.
1301 	 */
1302 	if (is_token_obj1 != is_token_obj2) {
1303 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
1304 		goto failed_exit;
1305 	}
1306 
1307 	/* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
1308 	obj_nkp.nkp_session = session_p-> k_session;
1309 	obj_nkp.nkp_mechanism.cm_type = k_mech_type;
1310 	obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
1311 	obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1312 
1313 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
1314 	    &obj_nkp)) < 0) {
1315 		if (errno != EINTR)
1316 			break;
1317 	}
1318 	if (r < 0) {
1319 		rv = CKR_FUNCTION_FAILED;
1320 	} else {
1321 		rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
1322 	}
1323 	free_attributes(obj_nkp.nkp_in_public_attributes,
1324 	    &obj_nkp.nkp_in_public_count);
1325 	free_attributes(obj_nkp.nkp_in_private_attributes,
1326 	    &obj_nkp.nkp_in_private_count);
1327 
1328 	if (rv != CKR_OK) {
1329 		goto failed_exit;
1330 	}
1331 
1332 	rv = get_object_attributes(
1333 	    &pubTemplate[pub_attr_count - pub_out_attr_count],
1334 	    pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
1335 	if (rv == CRYPTO_SUCCESS) {
1336 		rv = get_object_attributes(
1337 		    &priTemplate[pri_attr_count - pri_out_attr_count],
1338 		    pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
1339 	}
1340 	free_attributes(obj_nkp.nkp_out_public_attributes,
1341 	    &obj_nkp.nkp_out_public_count);
1342 	free_attributes(obj_nkp.nkp_out_private_attributes,
1343 	    &obj_nkp.nkp_out_private_count);
1344 	if (rv != CRYPTO_SUCCESS) {
1345 		goto failed_exit;
1346 	}
1347 
1348 	rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
1349 	    session_p, KERNEL_GEN_KEY);
1350 	if (rv != CRYPTO_SUCCESS) {
1351 		goto failed_exit;
1352 	}
1353 
1354 	/*
1355 	 * Copy CKA_EC_PARAMS from the public template to the
1356 	 * private template.
1357 	 */
1358 	rv = copy_attribute(CKA_EC_PARAMS, pubTemplate, pub_attr_count,
1359 	    &priTemplate[pri_attr_count]);
1360 	if (rv != CRYPTO_SUCCESS) {
1361 		goto failed_exit;
1362 	}
1363 
1364 	/* +1 to account for CKA_EC_PARAMS */
1365 	rv = kernel_build_object(priTemplate, pri_attr_count + 1,
1366 	    new_pri_objp, session_p, KERNEL_GEN_KEY);
1367 	(void) free(priTemplate[pri_attr_count].pValue);
1368 	if (rv != CRYPTO_SUCCESS) {
1369 		goto failed_exit;
1370 	}
1371 	(void) free(pubTemplate);
1372 	(void) free(priTemplate);
1373 
1374 	new_pub_objp->is_lib_obj = B_TRUE;
1375 	new_pri_objp->is_lib_obj = B_TRUE;
1376 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1377 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1378 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1379 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1380 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1381 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1382 	return (CKR_OK);
1383 
1384 failed_exit:
1385 	free_attributes(obj_nkp.nkp_in_public_attributes,
1386 	    &obj_nkp.nkp_in_public_count);
1387 	free_attributes(obj_nkp.nkp_out_public_attributes,
1388 	    &obj_nkp.nkp_out_public_count);
1389 	free_attributes(obj_nkp.nkp_in_private_attributes,
1390 	    &obj_nkp.nkp_in_private_count);
1391 	free_attributes(obj_nkp.nkp_out_private_attributes,
1392 	    &obj_nkp.nkp_out_private_count);
1393 	if (pubTemplate != NULL) {
1394 		(void) free(pubTemplate);
1395 	}
1396 	if (priTemplate != NULL) {
1397 		(void) free(priTemplate);
1398 	}
1399 	return (rv);
1400 }
1401 
1402 CK_RV
1403 C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
1404     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
1405     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
1406     CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
1407 {
1408 	CK_RV			rv = CKR_OK;
1409 	kernel_session_t	*session_p;
1410 	kernel_object_t		*new_pub_objp = NULL;
1411 	kernel_object_t		*new_pri_objp = NULL;
1412 	kernel_slot_t		*pslot;
1413 	boolean_t		ses_lock_held = B_FALSE;
1414 	CK_BBOOL		is_pri_obj1;
1415 	CK_BBOOL		is_pri_obj2;
1416 	CK_BBOOL		is_token_obj1 = FALSE;
1417 	CK_BBOOL		is_token_obj2 = FALSE;
1418 	crypto_mech_type_t	k_mech_type;
1419 	int r;
1420 	CK_RV (*func)(CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG,
1421 	    CK_ATTRIBUTE_PTR, CK_ULONG, kernel_session_t *, crypto_mech_type_t,
1422 	    kernel_object_t *, kernel_object_t *);
1423 
1424 	if (!kernel_initialized)
1425 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
1426 
1427 	/* Obtain the session pointer. */
1428 	rv = handle2session(hSession, &session_p);
1429 	if (rv != CKR_OK)
1430 		return (rv);
1431 
1432 	if ((pMechanism == NULL) || (phPublicKey == NULL) ||
1433 	    (phPrivateKey == NULL)) {
1434 		rv = CKR_ARGUMENTS_BAD;
1435 		goto failed_exit;
1436 	}
1437 
1438 	if ((pPublicKeyTemplate == NULL) && (ulPublicKeyAttributeCount != 0)) {
1439 		rv = CKR_ARGUMENTS_BAD;
1440 		goto failed_exit;
1441 	}
1442 
1443 	if ((pPrivateKeyTemplate == NULL) &&
1444 	    (ulPrivateKeyAttributeCount != 0)) {
1445 		rv = CKR_ARGUMENTS_BAD;
1446 		goto failed_exit;
1447 	}
1448 
1449 	/* Get the kernel's internal mechanism number. */
1450 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
1451 	if (rv != CKR_OK) {
1452 		goto failed_exit;
1453 	}
1454 
1455 	/* Create an object wrapper for the public key */
1456 	new_pub_objp = calloc(1, sizeof (kernel_object_t));
1457 	if (new_pub_objp == NULL) {
1458 		rv = CKR_HOST_MEMORY;
1459 		goto failed_exit;
1460 	}
1461 
1462 	/* Create an object wrapper for the private key. */
1463 	new_pri_objp = calloc(1, sizeof (kernel_object_t));
1464 	if (new_pri_objp == NULL) {
1465 		rv = CKR_HOST_MEMORY;
1466 		goto failed_exit;
1467 	}
1468 
1469 	/*
1470 	 * Special Case: if token does not support object creation,
1471 	 * but does support key generation by value, then create a session
1472 	 * object and initialize with values returned by token.
1473 	 */
1474 	pslot = slot_table[session_p->ses_slotid];
1475 	if (!pslot->sl_func_list.fl_object_create) {
1476 		switch (pMechanism->mechanism) {
1477 		case CKM_RSA_PKCS_KEY_PAIR_GEN:
1478 			func = key_gen_rsa_by_value;
1479 			break;
1480 
1481 		case CKM_DH_PKCS_KEY_PAIR_GEN:
1482 			func = key_gen_dh_by_value;
1483 			break;
1484 
1485 		case CKM_EC_KEY_PAIR_GEN:
1486 			func = key_gen_ec_by_value;
1487 			break;
1488 
1489 		default:
1490 			rv = CKR_MECHANISM_INVALID;
1491 			goto failed_exit;
1492 		}
1493 		rv = (*func)(pMechanism, pPublicKeyTemplate,
1494 		    ulPublicKeyAttributeCount, pPrivateKeyTemplate,
1495 		    ulPrivateKeyAttributeCount, session_p, k_mech_type,
1496 		    new_pub_objp, new_pri_objp);
1497 		if (rv != CKR_OK)
1498 			goto failed_exit;
1499 	} else {
1500 		crypto_object_generate_key_pair_t obj_kp;
1501 
1502 		/* Process the public key attributes. */
1503 		rv = process_object_attributes(pPublicKeyTemplate,
1504 		    ulPublicKeyAttributeCount, &obj_kp.kp_public_attributes,
1505 		    &is_token_obj1);
1506 		if (rv != CKR_OK) {
1507 			goto failed_exit;
1508 		}
1509 
1510 		/* Cannot create a token object with a READ-ONLY session. */
1511 		if (is_token_obj1 && session_p->ses_RO) {
1512 			free_object_attributes(obj_kp.kp_public_attributes,
1513 			    ulPublicKeyAttributeCount);
1514 			rv = CKR_SESSION_READ_ONLY;
1515 			goto failed_exit;
1516 		}
1517 
1518 		/* Process the private key attributes. */
1519 		rv = process_object_attributes(pPrivateKeyTemplate,
1520 		    ulPrivateKeyAttributeCount, &obj_kp.kp_private_attributes,
1521 		    &is_token_obj2);
1522 		if (rv != CKR_OK) {
1523 			free_object_attributes(obj_kp.kp_public_attributes,
1524 			    ulPublicKeyAttributeCount);
1525 			goto failed_exit;
1526 		}
1527 
1528 		/*
1529 		 * The public key and the private key need to contain the same
1530 		 * attribute values for CKA_TOKEN.
1531 		 */
1532 		if (is_token_obj1 != is_token_obj2) {
1533 			free_object_attributes(obj_kp.kp_public_attributes,
1534 			    ulPublicKeyAttributeCount);
1535 			free_object_attributes(obj_kp.kp_private_attributes,
1536 			    ulPrivateKeyAttributeCount);
1537 			rv = CKR_ATTRIBUTE_VALUE_INVALID;
1538 			goto failed_exit;
1539 		}
1540 
1541 		/* Call the CRYPTO_GENERATE_KEY_PAIR ioctl. */
1542 		obj_kp.kp_session = session_p-> k_session;
1543 		obj_kp.kp_mechanism.cm_type = k_mech_type;
1544 		obj_kp.kp_mechanism.cm_param = pMechanism->pParameter;
1545 		obj_kp.kp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1546 		obj_kp.kp_public_count = ulPublicKeyAttributeCount;
1547 		obj_kp.kp_private_count = ulPrivateKeyAttributeCount;
1548 
1549 		while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY_PAIR,
1550 		    &obj_kp)) < 0) {
1551 			if (errno != EINTR)
1552 				break;
1553 		}
1554 		if (r < 0) {
1555 			rv = CKR_FUNCTION_FAILED;
1556 		} else {
1557 			rv = crypto2pkcs11_error_number(obj_kp.kp_return_value);
1558 		}
1559 		free_object_attributes(obj_kp.kp_public_attributes,
1560 		    ulPublicKeyAttributeCount);
1561 		free_object_attributes(obj_kp.kp_private_attributes,
1562 		    ulPrivateKeyAttributeCount);
1563 
1564 		if (rv != CKR_OK)
1565 			goto failed_exit;
1566 
1567 		/* Get the CKA_PRIVATE value for the key pair. */
1568 		rv = get_cka_private_value(session_p, obj_kp.kp_public_handle,
1569 		    &is_pri_obj1);
1570 		if (rv != CKR_OK) {
1571 			goto failed_exit;
1572 		}
1573 
1574 		rv = get_cka_private_value(session_p, obj_kp.kp_private_handle,
1575 		    &is_pri_obj2);
1576 		if (rv != CKR_OK) {
1577 			goto failed_exit;
1578 		}
1579 
1580 		/*
1581 		 * Store the kernel public key handle into the public key
1582 		 * object and finish the public key object initialization.
1583 		 */
1584 		new_pub_objp->is_lib_obj = B_FALSE;
1585 		new_pub_objp->k_handle = obj_kp.kp_public_handle;
1586 		new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1587 		new_pub_objp->extra_attrlistp = NULL;
1588 
1589 		if (is_pri_obj1)
1590 			new_pub_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
1591 		else
1592 			new_pub_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
1593 
1594 		if (is_token_obj1)
1595 			new_pub_objp->bool_attr_mask |= TOKEN_BOOL_ON;
1596 		else
1597 			new_pub_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
1598 
1599 		(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1600 		new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1601 
1602 		/*
1603 		 * Store the kernel private key handle into the private key
1604 		 * object and finish the private key object initialization.
1605 		 */
1606 		new_pri_objp->is_lib_obj = B_FALSE;
1607 		new_pri_objp->k_handle = obj_kp.kp_private_handle;
1608 		new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1609 		new_pri_objp->extra_attrlistp = NULL;
1610 
1611 		if (is_pri_obj2)
1612 			new_pri_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
1613 		else
1614 			new_pri_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
1615 
1616 		if (is_token_obj2)
1617 			new_pri_objp->bool_attr_mask |= TOKEN_BOOL_ON;
1618 		else
1619 			new_pri_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
1620 
1621 	}
1622 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1623 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1624 
1625 	/*
1626 	 * Add the new pub/pri objects to the slot's token list if they are
1627 	 * token objects. Otherwise, add them to the session's object list.
1628 	 */
1629 	if (is_token_obj1) { /* is_token_obj1 == is_token_obj2 */
1630 		pslot = slot_table[session_p->ses_slotid];
1631 		kernel_add_token_object_to_slot(new_pub_objp, pslot);
1632 		kernel_add_token_object_to_slot(new_pri_objp, pslot);
1633 	} else {
1634 		kernel_add_object_to_session(new_pub_objp, session_p);
1635 		kernel_add_object_to_session(new_pri_objp, session_p);
1636 	}
1637 
1638 	*phPublicKey = (CK_OBJECT_HANDLE)new_pub_objp;
1639 	*phPrivateKey = (CK_OBJECT_HANDLE)new_pri_objp;
1640 	REFRELE(session_p, ses_lock_held);
1641 	return (rv);
1642 
1643 failed_exit:
1644 	if (new_pub_objp != NULL) {
1645 		(void) free(new_pub_objp);
1646 	}
1647 	if (new_pri_objp != NULL) {
1648 		(void) free(new_pri_objp);
1649 	}
1650 	REFRELE(session_p, ses_lock_held);
1651 	return (rv);
1652 }
1653 
1654 
1655 CK_RV
1656 C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
1657     CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
1658     CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen)
1659 {
1660 	CK_RV			rv = CKR_OK;
1661 	kernel_session_t	*session_p;
1662 	boolean_t		ses_lock_held = B_FALSE;
1663 	kernel_object_t		*wrappingkey_p;
1664 	kernel_object_t		*key_p;
1665 	crypto_mech_type_t	k_mech_type;
1666 	crypto_object_wrap_key_t obj_wrapkey;
1667 	int r;
1668 
1669 	if (!kernel_initialized)
1670 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
1671 
1672 	if (pulWrappedKeyLen == NULL || pMechanism == NULL) {
1673 		return (CKR_ARGUMENTS_BAD);
1674 	}
1675 
1676 	/*
1677 	 * Obtain the session pointer.  Also, increment the session
1678 	 * reference count.
1679 	 */
1680 	rv = handle2session(hSession, &session_p);
1681 	if (rv != CKR_OK)
1682 		return (rv);
1683 
1684 	/* Get the kernel's internal mechanism number. */
1685 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
1686 	if (rv != CKR_OK) {
1687 		REFRELE(session_p, ses_lock_held);
1688 		return (rv);
1689 	}
1690 
1691 	/* Obtain the wrapping key object pointer. */
1692 	HANDLE2OBJECT(hWrappingKey, wrappingkey_p, rv);
1693 	if (rv != CKR_OK) {
1694 		REFRELE(session_p, ses_lock_held);
1695 		return (rv);
1696 	}
1697 
1698 	/* Obtain the to_be_wrapped key object pointer. */
1699 	HANDLE2OBJECT(hKey, key_p, rv);
1700 	if (rv != CKR_OK) {
1701 		OBJ_REFRELE(wrappingkey_p);
1702 		REFRELE(session_p, ses_lock_held);
1703 		return (rv);
1704 	}
1705 
1706 	/* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */
1707 	obj_wrapkey.wk_session = session_p->k_session;
1708 	obj_wrapkey.wk_mechanism.cm_type = k_mech_type;
1709 	obj_wrapkey.wk_mechanism.cm_param = pMechanism->pParameter;
1710 	obj_wrapkey.wk_mechanism.cm_param_len = pMechanism->ulParameterLen;
1711 	obj_wrapkey.wk_wrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
1712 	obj_wrapkey.wk_wrapping_key.ck_obj_id = wrappingkey_p->k_handle;
1713 	obj_wrapkey.wk_object_handle = key_p->k_handle;
1714 	obj_wrapkey.wk_wrapped_key_len = *pulWrappedKeyLen;
1715 	obj_wrapkey.wk_wrapped_key = (char *)pWrappedKey;
1716 
1717 	while ((r = ioctl(kernel_fd, CRYPTO_WRAP_KEY, &obj_wrapkey)) < 0) {
1718 		if (errno != EINTR)
1719 			break;
1720 	}
1721 	if (r < 0) {
1722 		rv = CKR_FUNCTION_FAILED;
1723 	} else {
1724 		rv = crypto2pkcs11_error_number(obj_wrapkey.wk_return_value);
1725 	}
1726 
1727 	/*
1728 	 * Besides rv == CKR_OK, we will set the value of pulWrappedKeyLen
1729 	 * when the applciation-supplied wrapped key buffer is too small.
1730 	 * The situation that the application only asks for the length of
1731 	 * the wrapped key is covered in rv == CKR_OK.
1732 	 */
1733 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
1734 		*pulWrappedKeyLen = obj_wrapkey.wk_wrapped_key_len;
1735 	}
1736 
1737 	OBJ_REFRELE(key_p);
1738 	OBJ_REFRELE(wrappingkey_p);
1739 	REFRELE(session_p, ses_lock_held);
1740 	return (rv);
1741 }
1742 
1743 
1744 CK_RV
1745 C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
1746     CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey,
1747     CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
1748     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
1749 {
1750 	CK_RV			rv = CKR_OK;
1751 	kernel_session_t	*session_p;
1752 	kernel_object_t		*unwrappingkey_p;
1753 	kernel_object_t		*new_objp = NULL;
1754 	kernel_slot_t		*pslot;
1755 	boolean_t		ses_lock_held = B_FALSE;
1756 	CK_BBOOL		is_pri_obj;
1757 	CK_BBOOL		is_token_obj = FALSE;
1758 	CK_MECHANISM_INFO	info;
1759 	uint32_t		k_mi_flags;
1760 	CK_BYTE			*clear_key_val = NULL;
1761 	CK_ULONG 		ulDataLen;
1762 	CK_ATTRIBUTE_PTR	newTemplate = NULL;
1763 	crypto_mech_type_t	k_mech_type;
1764 	crypto_object_unwrap_key_t obj_unwrapkey;
1765 	int r;
1766 
1767 	if (!kernel_initialized)
1768 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
1769 
1770 	if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) {
1771 		return (CKR_ARGUMENTS_BAD);
1772 	}
1773 
1774 	if ((pTemplate == NULL) && (ulAttributeCount != 0)) {
1775 		return (CKR_ARGUMENTS_BAD);
1776 	}
1777 
1778 	/* Obtain the session pointer. */
1779 	rv = handle2session(hSession, &session_p);
1780 	if (rv != CKR_OK)
1781 		return (rv);
1782 
1783 	/* Obtain the wrapping key object pointer. */
1784 	HANDLE2OBJECT(hUnwrappingKey, unwrappingkey_p, rv);
1785 	if (rv != CKR_OK) {
1786 		REFRELE(session_p, ses_lock_held);
1787 		return (rv);
1788 	}
1789 
1790 	/*
1791 	 * If the HW provider doesn't support C_UnwrapKey, we will try
1792 	 * to emulate it in the library.
1793 	 */
1794 	pslot = slot_table[session_p->ses_slotid];
1795 	if ((!pslot->sl_func_list.fl_object_create) &&
1796 	    (!pslot->sl_func_list.fl_key_unwrap)) {
1797 		rv = get_mechanism_info(pslot, pMechanism->mechanism, &info,
1798 		    &k_mi_flags);
1799 		if (rv != CKR_OK) {
1800 			goto failed_exit;
1801 		}
1802 
1803 		/*
1804 		 * If the mechanism flag doesn't have CKF_UNWRAP, and it's
1805 		 * an unwrapping of a secret key object, then help this
1806 		 * out with a decryption followed by an object creation.
1807 		 */
1808 		if (!(k_mi_flags & CRYPTO_FG_UNWRAP) &&
1809 		    (k_mi_flags & CRYPTO_FG_DECRYPT) &&
1810 		    (is_secret_key_template(pTemplate, ulAttributeCount))) {
1811 
1812 			/* First allocate space for the recovered key value */
1813 			clear_key_val = malloc(ulWrappedKeyLen);
1814 			if (clear_key_val == NULL) {
1815 				rv = CKR_HOST_MEMORY;
1816 				goto failed_exit;
1817 			}
1818 
1819 			rv = kernel_decrypt_init(session_p, unwrappingkey_p,
1820 			    pMechanism);
1821 			if (rv != CKR_OK) {
1822 				goto failed_exit;
1823 			}
1824 
1825 			ulDataLen = ulWrappedKeyLen;
1826 			rv = kernel_decrypt(session_p, pWrappedKey,
1827 			    ulWrappedKeyLen, clear_key_val, &ulDataLen);
1828 			if (rv != CKR_OK) {
1829 				goto failed_exit;
1830 			}
1831 
1832 			newTemplate = grow_template(pTemplate, ulAttributeCount,
1833 			    ulAttributeCount + 1);
1834 			if (newTemplate == NULL) {
1835 				rv = CKR_HOST_MEMORY;
1836 				goto failed_exit;
1837 			}
1838 			/* Now add the CKA_VALUE attribute to template */
1839 			newTemplate[ulAttributeCount].type = CKA_VALUE;
1840 			newTemplate[ulAttributeCount].pValue = clear_key_val;
1841 			newTemplate[ulAttributeCount].ulValueLen = ulDataLen;
1842 
1843 			/* Finally create the key, based on the new template */
1844 			rv = kernel_add_object(newTemplate,
1845 			    ulAttributeCount + 1, phKey, session_p);
1846 			(void) free(clear_key_val);
1847 			(void) free(newTemplate);
1848 			OBJ_REFRELE(unwrappingkey_p);
1849 			REFRELE(session_p, ses_lock_held);
1850 			return (rv);
1851 		} else {
1852 			rv = CKR_FUNCTION_FAILED;
1853 			goto failed_exit;
1854 		}
1855 	}
1856 
1857 	/*
1858 	 * If we come here, the HW provider must have registered the unwrapkey
1859 	 * entry.  Therefore, the unwrap key will be performed in the HW
1860 	 * provider.
1861 	 */
1862 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
1863 	if (rv != CKR_OK) {
1864 		goto failed_exit;
1865 	}
1866 
1867 	/* Create an object wrapper for the new key in the library first */
1868 	new_objp = calloc(1, sizeof (kernel_object_t));
1869 	if (new_objp == NULL) {
1870 		rv = CKR_HOST_MEMORY;
1871 		goto failed_exit;
1872 	}
1873 
1874 	/* Process the attributes */
1875 	rv = process_object_attributes(pTemplate, ulAttributeCount,
1876 	    &obj_unwrapkey.uk_attributes, &is_token_obj);
1877 	if (rv != CKR_OK) {
1878 		goto failed_exit;
1879 	}
1880 
1881 	/* Cannot create a token object with a READ-ONLY session. */
1882 	if (is_token_obj && session_p->ses_RO) {
1883 		free_object_attributes(obj_unwrapkey.uk_attributes,
1884 		    ulAttributeCount);
1885 		rv = CKR_SESSION_READ_ONLY;
1886 		goto failed_exit;
1887 	}
1888 
1889 	/* Make the CRYPTO_UNWRAP_KEY ioctl call. */
1890 	obj_unwrapkey.uk_session = session_p->k_session;
1891 	obj_unwrapkey.uk_mechanism.cm_type = k_mech_type;
1892 	obj_unwrapkey.uk_mechanism.cm_param = pMechanism->pParameter;
1893 	obj_unwrapkey.uk_mechanism.cm_param_len = pMechanism->ulParameterLen;
1894 	obj_unwrapkey.uk_unwrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
1895 	obj_unwrapkey.uk_unwrapping_key.ck_obj_id = unwrappingkey_p->k_handle;
1896 	obj_unwrapkey.uk_wrapped_key = (char *)pWrappedKey;
1897 	obj_unwrapkey.uk_wrapped_key_len = ulWrappedKeyLen;
1898 	obj_unwrapkey.uk_count = ulAttributeCount;
1899 
1900 	while ((r = ioctl(kernel_fd, CRYPTO_UNWRAP_KEY, &obj_unwrapkey)) < 0) {
1901 		if (errno != EINTR)
1902 			break;
1903 	}
1904 	if (r < 0) {
1905 		rv = CKR_FUNCTION_FAILED;
1906 	} else {
1907 		rv = crypto2pkcs11_error_number(obj_unwrapkey.uk_return_value);
1908 	}
1909 
1910 	free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount);
1911 	if (rv != CKR_OK) {
1912 		goto failed_exit;
1913 	}
1914 
1915 	/* Get the CKA_PRIVATE value for the unwrapped key. */
1916 	rv = get_cka_private_value(session_p, obj_unwrapkey.uk_object_handle,
1917 	    &is_pri_obj);
1918 	if (rv != CKR_OK) {
1919 		goto failed_exit;
1920 	}
1921 
1922 	/*
1923 	 * Store the kernel object handle in the new key object wrapper and
1924 	 * initialize it.
1925 	 */
1926 	new_objp->k_handle = obj_unwrapkey.uk_object_handle;
1927 	new_objp->is_lib_obj = B_FALSE;
1928 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1929 	new_objp->extra_attrlistp = NULL;
1930 
1931 	if (is_pri_obj)
1932 		new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
1933 	else
1934 		new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
1935 
1936 	if (is_token_obj)
1937 		new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
1938 	else
1939 		new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
1940 
1941 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
1942 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1943 
1944 	/*
1945 	 * Add the new object to the slot's token object list if it is a
1946 	 * a token object. Otherwise, add it to the session's object list.
1947 	 */
1948 	if (is_token_obj) {
1949 		pslot = slot_table[session_p->ses_slotid];
1950 		kernel_add_token_object_to_slot(new_objp, pslot);
1951 	} else {
1952 		kernel_add_object_to_session(new_objp, session_p);
1953 	}
1954 
1955 	*phKey = (CK_OBJECT_HANDLE)new_objp;
1956 	OBJ_REFRELE(unwrappingkey_p);
1957 	REFRELE(session_p, ses_lock_held);
1958 	return (rv);
1959 
1960 failed_exit:
1961 	OBJ_REFRELE(unwrappingkey_p);
1962 	if (new_objp != NULL)
1963 		(void) free(new_objp);
1964 
1965 	if (clear_key_val != NULL)
1966 		(void) free(clear_key_val);
1967 
1968 	if (newTemplate != NULL)
1969 		(void) free(newTemplate);
1970 
1971 	REFRELE(session_p, ses_lock_held);
1972 	return (rv);
1973 }
1974 
1975 /*
1976  * Get sufficient attributes from a base key to pass by value in a
1977  * crypto_key structure. Storage for attributes is allocated.
1978  * For EC public keys, it is CKA_EC_PARAMS and CKA_EC_POINT.
1979  * For EC private keys, it is CKA_EC_PARAMS and CKA_VALUE.
1980  */
1981 static int
1982 get_base_key_attributes(kernel_object_t *base_key, crypto_key_t *key_by_value)
1983 {
1984 	CK_ATTRIBUTE tmp;
1985 	crypto_object_attribute_t *attrs;
1986 	biginteger_t *big;
1987 	int rv;
1988 
1989 	switch (base_key->key_type) {
1990 	case CKK_EC:
1991 		attrs = malloc(2 * sizeof (crypto_object_attribute_t));
1992 		if (attrs == NULL) {
1993 			rv = CKR_HOST_MEMORY;
1994 			goto out;
1995 		}
1996 		bzero(attrs, 2 * sizeof (crypto_object_attribute_t));
1997 
1998 		(void) pthread_mutex_lock(&base_key->object_mutex);
1999 
2000 		if (!base_key->is_lib_obj) {
2001 			rv = CRYPTO_ARGUMENTS_BAD;
2002 			goto out;
2003 		}
2004 
2005 		if (base_key->class != CKO_PUBLIC_KEY &&
2006 		    base_key->class != CKO_PRIVATE_KEY) {
2007 			rv = CRYPTO_ARGUMENTS_BAD;
2008 			goto out;
2009 		}
2010 
2011 		/*
2012 		 * Both public and private EC keys should have
2013 		 * a CKA_EC_PARAMS attribute.
2014 		 */
2015 		tmp.type = CKA_EC_PARAMS;
2016 		tmp.pValue = NULL;
2017 
2018 		/* get size of attribute */
2019 		rv = kernel_get_attribute(base_key, &tmp);
2020 		if (rv != CKR_OK) {
2021 			goto out;
2022 		}
2023 
2024 		tmp.pValue = malloc(tmp.ulValueLen);
2025 		if (tmp.pValue == NULL) {
2026 			rv = CKR_HOST_MEMORY;
2027 			goto out;
2028 		}
2029 		rv = kernel_get_attribute(base_key, &tmp);
2030 		if (rv != CKR_OK) {
2031 			goto out;
2032 		}
2033 		attrs[0].oa_type = tmp.type;
2034 		attrs[0].oa_value = tmp.pValue;
2035 		attrs[0].oa_value_len = tmp.ulValueLen;
2036 
2037 		switch (base_key->class) {
2038 		case CKO_PUBLIC_KEY:
2039 			big = OBJ_PUB_EC_POINT(base_key);
2040 			tmp.type = CKA_EC_POINT;
2041 			break;
2042 
2043 		case CKO_PRIVATE_KEY:
2044 			big = OBJ_PRI_EC_VALUE(base_key);
2045 			tmp.type = CKA_VALUE;
2046 			break;
2047 
2048 		default:
2049 			rv = CKR_ATTRIBUTE_TYPE_INVALID;
2050 			goto out;
2051 		}
2052 		tmp.ulValueLen = big->big_value_len;
2053 		tmp.pValue = malloc(tmp.ulValueLen);
2054 		if (tmp.pValue == NULL) {
2055 			rv = CKR_HOST_MEMORY;
2056 			goto out;
2057 		}
2058 		rv = kernel_get_attribute(base_key, &tmp);
2059 		if (rv != CKR_OK) {
2060 			goto out;
2061 		}
2062 		attrs[1].oa_type = tmp.type;
2063 		attrs[1].oa_value = tmp.pValue;
2064 		attrs[1].oa_value_len = tmp.ulValueLen;
2065 		key_by_value->ck_attrs = attrs;
2066 		key_by_value->ck_count = 2;
2067 		break;
2068 
2069 	case CKK_DH:
2070 		attrs = malloc(3 * sizeof (crypto_object_attribute_t));
2071 		if (attrs == NULL) {
2072 			rv = CKR_HOST_MEMORY;
2073 			goto out;
2074 		}
2075 		bzero(attrs, 3 * sizeof (crypto_object_attribute_t));
2076 
2077 		(void) pthread_mutex_lock(&base_key->object_mutex);
2078 
2079 		if (!base_key->is_lib_obj) {
2080 			rv = CRYPTO_ARGUMENTS_BAD;
2081 			goto out;
2082 		}
2083 
2084 		if (base_key->class != CKO_PRIVATE_KEY) {
2085 			rv = CRYPTO_ARGUMENTS_BAD;
2086 			goto out;
2087 		}
2088 		tmp.type = CKA_BASE;
2089 		tmp.pValue = NULL;
2090 
2091 		/* get size of attribute */
2092 		rv = kernel_get_attribute(base_key, &tmp);
2093 		if (rv != CKR_OK) {
2094 			goto out;
2095 		}
2096 
2097 		tmp.pValue = malloc(tmp.ulValueLen);
2098 		if (tmp.pValue == NULL) {
2099 			rv = CKR_HOST_MEMORY;
2100 			goto out;
2101 		}
2102 		rv = kernel_get_attribute(base_key, &tmp);
2103 		if (rv != CKR_OK) {
2104 			goto out;
2105 		}
2106 		attrs[0].oa_type = tmp.type;
2107 		attrs[0].oa_value = tmp.pValue;
2108 		attrs[0].oa_value_len = tmp.ulValueLen;
2109 
2110 		tmp.type = CKA_PRIME;
2111 		tmp.pValue = NULL;
2112 
2113 		/* get size of attribute */
2114 		rv = kernel_get_attribute(base_key, &tmp);
2115 		if (rv != CKR_OK) {
2116 			goto out;
2117 		}
2118 
2119 		tmp.pValue = malloc(tmp.ulValueLen);
2120 		if (tmp.pValue == NULL) {
2121 			rv = CKR_HOST_MEMORY;
2122 			goto out;
2123 		}
2124 		rv = kernel_get_attribute(base_key, &tmp);
2125 		if (rv != CKR_OK) {
2126 			goto out;
2127 		}
2128 		attrs[1].oa_type = tmp.type;
2129 		attrs[1].oa_value = tmp.pValue;
2130 		attrs[1].oa_value_len = tmp.ulValueLen;
2131 
2132 		big = OBJ_PRI_EC_VALUE(base_key);
2133 		tmp.type = CKA_VALUE;
2134 
2135 		tmp.ulValueLen = big->big_value_len;
2136 		tmp.pValue = malloc(tmp.ulValueLen);
2137 		if (tmp.pValue == NULL) {
2138 			rv = CKR_HOST_MEMORY;
2139 			goto out;
2140 		}
2141 		rv = kernel_get_attribute(base_key, &tmp);
2142 		if (rv != CKR_OK) {
2143 			goto out;
2144 		}
2145 		attrs[2].oa_type = tmp.type;
2146 		attrs[2].oa_value = tmp.pValue;
2147 		attrs[2].oa_value_len = tmp.ulValueLen;
2148 		key_by_value->ck_attrs = attrs;
2149 		key_by_value->ck_count = 3;
2150 		break;
2151 
2152 	default:
2153 		rv = CKR_ATTRIBUTE_TYPE_INVALID;
2154 		goto out;
2155 	}
2156 	(void) pthread_mutex_unlock(&base_key->object_mutex);
2157 	return (CKR_OK);
2158 
2159 out:
2160 	(void) pthread_mutex_unlock(&base_key->object_mutex);
2161 	return (rv);
2162 }
2163 
2164 CK_RV
2165 derive_key_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
2166     CK_ULONG ulAttributeCount, kernel_session_t *session_p,
2167     crypto_mech_type_t k_mech_type, kernel_object_t *basekey_p,
2168     kernel_object_t *new_objp)
2169 {
2170 	crypto_nostore_derive_key_t obj_ndk;
2171 	char *key_buf = NULL;
2172 	CK_ATTRIBUTE_PTR newTemplate = NULL;
2173 	CK_BBOOL is_token_obj = FALSE;
2174 	CK_RV rv = CKR_OK;
2175 	CK_ULONG secret_class = CKO_SECRET_KEY;
2176 	ulong_t key_len = 0;
2177 	uint_t attr_count = 0;
2178 	boolean_t removed;
2179 	boolean_t has_class;
2180 	int r, n;
2181 
2182 	obj_ndk.ndk_in_count = 0;
2183 	obj_ndk.ndk_out_count = 0;
2184 	obj_ndk.ndk_base_key.ck_count = 0;
2185 
2186 	rv = get_key_len_from_template(pMechanism, pTemplate, ulAttributeCount,
2187 	    basekey_p, &key_len);
2188 	if (rv != CKR_OK) {
2189 		goto failed_exit;
2190 	}
2191 
2192 	if ((key_buf = malloc(key_len)) == NULL) {
2193 		rv = CKR_HOST_MEMORY;
2194 		goto failed_exit;
2195 	}
2196 
2197 	has_class = attribute_in_template(CKA_CLASS, pTemplate,
2198 	    ulAttributeCount);
2199 
2200 	attr_count = ulAttributeCount + 1;
2201 	if (!has_class)
2202 		attr_count++;
2203 
2204 	newTemplate = grow_template(pTemplate, ulAttributeCount, attr_count);
2205 	if (newTemplate == NULL) {
2206 		rv = CKR_HOST_MEMORY;
2207 		goto failed_exit;
2208 	}
2209 
2210 	n = ulAttributeCount;
2211 	if (!has_class) {
2212 		newTemplate[n].type = CKA_CLASS;
2213 		newTemplate[n].pValue = (caddr_t)&secret_class;
2214 		newTemplate[n].ulValueLen = sizeof (secret_class);
2215 		n++;
2216 	}
2217 
2218 	/* Add CKA_VALUE to the template */
2219 	newTemplate[n].type = CKA_VALUE;
2220 	newTemplate[n].pValue = (caddr_t)key_buf;
2221 	newTemplate[n].ulValueLen = key_len;
2222 
2223 	rv = process_object_attributes(newTemplate, attr_count - 1,
2224 	    &obj_ndk.ndk_in_attributes, &is_token_obj);
2225 	if (rv != CKR_OK) {
2226 		goto failed_exit;
2227 	}
2228 
2229 	rv = process_object_attributes(&newTemplate[attr_count - 1],
2230 	    1, &obj_ndk.ndk_out_attributes, &is_token_obj);
2231 	if (rv != CKR_OK) {
2232 		goto failed_exit;
2233 	}
2234 
2235 	/* Cannot create a token object with a READ-ONLY session. */
2236 	if (is_token_obj && session_p->ses_RO) {
2237 		rv = CKR_SESSION_READ_ONLY;
2238 		goto failed_exit;
2239 	}
2240 
2241 	obj_ndk.ndk_session = session_p->k_session;
2242 	obj_ndk.ndk_mechanism.cm_type = k_mech_type;
2243 	obj_ndk.ndk_mechanism.cm_param = pMechanism->pParameter;
2244 	obj_ndk.ndk_mechanism.cm_param_len = pMechanism->ulParameterLen;
2245 
2246 	/*
2247 	 * Obtain the attributes of base key and pass them by value.
2248 	 */
2249 	rv = get_base_key_attributes(basekey_p, &obj_ndk.ndk_base_key);
2250 	if (rv != CKR_OK) {
2251 		goto failed_exit;
2252 	}
2253 
2254 	obj_ndk.ndk_base_key.ck_format = CRYPTO_KEY_ATTR_LIST;
2255 	obj_ndk.ndk_in_count = attr_count - 1;
2256 	obj_ndk.ndk_out_count = 1;
2257 
2258 	while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_DERIVE_KEY,
2259 	    &obj_ndk)) < 0) {
2260 		if (errno != EINTR)
2261 			break;
2262 	}
2263 	if (r < 0) {
2264 		rv = CKR_FUNCTION_FAILED;
2265 	} else {
2266 		rv = crypto2pkcs11_error_number(obj_ndk.ndk_return_value);
2267 	}
2268 	free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
2269 	free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
2270 	    &obj_ndk.ndk_base_key.ck_count);
2271 	if (rv != CKR_OK) {
2272 		goto failed_exit;
2273 	}
2274 
2275 	rv = get_object_attributes(&newTemplate[attr_count - 1],
2276 	    1, obj_ndk.ndk_out_attributes);
2277 	free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
2278 	if (rv != CRYPTO_SUCCESS) {
2279 		goto failed_exit;
2280 	}
2281 
2282 	removed = remove_one_attribute(newTemplate, CKA_VALUE_LEN,
2283 	    attr_count, B_FALSE);
2284 
2285 	rv = kernel_build_object(newTemplate, removed ? attr_count - 1 :
2286 	    attr_count, new_objp, session_p, KERNEL_GEN_KEY);
2287 	if (rv != CRYPTO_SUCCESS) {
2288 		goto failed_exit;
2289 	}
2290 
2291 	free(key_buf);
2292 	free(newTemplate);
2293 	new_objp->is_lib_obj = B_TRUE;
2294 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
2295 	return (CKR_OK);
2296 
2297 failed_exit:
2298 	if (key_buf != NULL)
2299 		free(key_buf);
2300 	if (newTemplate != NULL)
2301 		free(newTemplate);
2302 	free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
2303 	free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
2304 	free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
2305 	    &obj_ndk.ndk_base_key.ck_count);
2306 	return (rv);
2307 }
2308 
2309 CK_RV
2310 C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
2311     CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
2312     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
2313 {
2314 	CK_RV			rv = CKR_OK;
2315 	kernel_session_t	*session_p;
2316 	kernel_object_t		*basekey_p;
2317 	kernel_object_t		*new_objp;
2318 	kernel_slot_t		*pslot;
2319 	boolean_t		ses_lock_held = B_FALSE;
2320 	CK_BBOOL		is_pri_obj;
2321 	CK_BBOOL		is_token_obj = FALSE;
2322 	crypto_mech_type_t	k_mech_type;
2323 	int r;
2324 
2325 	if (!kernel_initialized)
2326 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
2327 
2328 	/* Obtain the session pointer. */
2329 	rv = handle2session(hSession, &session_p);
2330 	if (rv != CKR_OK)
2331 		return (rv);
2332 
2333 	if (pMechanism == NULL) {
2334 		REFRELE(session_p, ses_lock_held);
2335 		return (CKR_ARGUMENTS_BAD);
2336 	}
2337 
2338 	if ((pTemplate == NULL && ulAttributeCount != 0) ||
2339 	    (pTemplate != NULL && ulAttributeCount == 0)) {
2340 		REFRELE(session_p, ses_lock_held);
2341 		return (CKR_ARGUMENTS_BAD);
2342 	}
2343 
2344 	/* Obtain the base key object pointer. */
2345 	HANDLE2OBJECT(hBaseKey, basekey_p, rv);
2346 	if (rv != CKR_OK) {
2347 		REFRELE(session_p, ses_lock_held);
2348 		return (rv);
2349 	}
2350 
2351 	/* Get the kernel's internal mechanism number. */
2352 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
2353 	if (rv != CKR_OK) {
2354 		goto failed_exit;
2355 	}
2356 
2357 	/* Create an object wrapper in the library for the generated key. */
2358 	new_objp = calloc(1, sizeof (kernel_object_t));
2359 	if (new_objp == NULL) {
2360 		rv = CKR_HOST_MEMORY;
2361 		goto failed_exit;
2362 	}
2363 
2364 	/*
2365 	 * Special Case: if token does not support object creation,
2366 	 * but does support key derivation by value, then create a session
2367 	 * object and initialize with values returned by token.
2368 	 */
2369 	pslot = slot_table[session_p->ses_slotid];
2370 	if (!pslot->sl_func_list.fl_object_create) {
2371 		rv = derive_key_by_value(pMechanism, pTemplate,
2372 		    ulAttributeCount, session_p, k_mech_type, basekey_p,
2373 		    new_objp);
2374 		if (rv != CKR_OK)
2375 			goto failed_exit;
2376 	} else {
2377 		crypto_derive_key_t obj_dk;
2378 
2379 		rv = process_object_attributes(pTemplate, ulAttributeCount,
2380 		    &obj_dk.dk_attributes, &is_token_obj);
2381 		if (rv != CKR_OK) {
2382 			goto failed_exit;
2383 		}
2384 
2385 		/* Cannot create a token object with a READ-ONLY session. */
2386 		if (is_token_obj && session_p->ses_RO) {
2387 			free_object_attributes(obj_dk.dk_attributes,
2388 			    ulAttributeCount);
2389 			rv = CKR_SESSION_READ_ONLY;
2390 			goto failed_exit;
2391 		}
2392 
2393 		obj_dk.dk_session = session_p->k_session;
2394 		obj_dk.dk_mechanism.cm_type = k_mech_type;
2395 		obj_dk.dk_mechanism.cm_param = pMechanism->pParameter;
2396 		obj_dk.dk_mechanism.cm_param_len = pMechanism->ulParameterLen;
2397 		obj_dk.dk_base_key.ck_format = CRYPTO_KEY_REFERENCE;
2398 		obj_dk.dk_base_key.ck_obj_id = basekey_p->k_handle;
2399 		obj_dk.dk_count = ulAttributeCount;
2400 
2401 		while ((r = ioctl(kernel_fd, CRYPTO_DERIVE_KEY, &obj_dk)) < 0) {
2402 			if (errno != EINTR)
2403 				break;
2404 		}
2405 		if (r < 0) {
2406 			rv = CKR_FUNCTION_FAILED;
2407 		} else {
2408 			rv = crypto2pkcs11_error_number(obj_dk.dk_return_value);
2409 		}
2410 
2411 		free_object_attributes(obj_dk.dk_attributes, ulAttributeCount);
2412 		if (rv != CKR_OK) {
2413 			goto failed_exit;
2414 		}
2415 
2416 		/* Get the CKA_PRIVATE value for the derived key. */
2417 		rv = get_cka_private_value(session_p, obj_dk.dk_object_handle,
2418 		    &is_pri_obj);
2419 		if (rv != CKR_OK) {
2420 			goto failed_exit;
2421 		}
2422 
2423 		/*
2424 		 * Store the kernel object handle into the new derived key
2425 		 * object and finish the object initialization.
2426 		 */
2427 		new_objp->is_lib_obj = B_FALSE;
2428 		new_objp->k_handle = obj_dk.dk_object_handle;
2429 		new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
2430 		new_objp->extra_attrlistp = NULL;
2431 
2432 		if (is_pri_obj)
2433 			new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
2434 		else
2435 			new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
2436 
2437 		if (is_token_obj)
2438 			new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
2439 		else
2440 			new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
2441 	}
2442 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
2443 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
2444 
2445 	/*
2446 	 * Add the new derived object to the slot's token list if it is a
2447 	 * token object. Otherwise, add it to the session's object list.
2448 	 */
2449 	if (is_token_obj) {
2450 		pslot = slot_table[session_p->ses_slotid];
2451 		kernel_add_token_object_to_slot(new_objp, pslot);
2452 	} else {
2453 		kernel_add_object_to_session(new_objp, session_p);
2454 	}
2455 
2456 	*phKey = (CK_OBJECT_HANDLE)new_objp;
2457 	OBJ_REFRELE(basekey_p);
2458 	REFRELE(session_p, ses_lock_held);
2459 	return (rv);
2460 
2461 failed_exit:
2462 	OBJ_REFRELE(basekey_p);
2463 	if (new_objp != NULL) {
2464 		(void) free(new_objp);
2465 	}
2466 
2467 	REFRELE(session_p, ses_lock_held);
2468 	return (rv);
2469 }
2470