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