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