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