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