xref: /titanic_41/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelKeys.c (revision 4c0312813f96388b6ce9453c99f2db7d6a393bd4)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <strings.h>
30 #include <errno.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 is_secret_key_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
39 {
40 	int i;
41 	for (i = 0; i < ulAttributeCount; i++) {
42 		if (pTemplate[i].type == CKA_CLASS &&
43 		    *(CK_OBJECT_CLASS *)(pTemplate[i].pValue) ==
44 		    CKO_SECRET_KEY)
45 			return (B_TRUE);
46 	}
47 	return (B_FALSE);
48 }
49 
50 
51 CK_RV
52 C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
53     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
54 {
55 	CK_RV			rv = CKR_OK;
56 	kernel_session_t	*session_p;
57 	kernel_object_t		*new_objp = NULL;
58 	kernel_slot_t		*pslot;
59 	boolean_t		ses_lock_held = B_FALSE;
60 	CK_BBOOL		is_pri_obj;
61 	CK_BBOOL		is_token_obj = FALSE;
62 	crypto_mech_type_t	k_mech_type;
63 	crypto_object_generate_key_t 	obj_gk;
64 	int r;
65 
66 	if (!kernel_initialized)
67 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
68 
69 	/* Obtain the session pointer */
70 	rv = handle2session(hSession, &session_p);
71 	if (rv != CKR_OK)
72 		return (rv);
73 
74 	if ((pMechanism == NULL) || (phKey == NULL)) {
75 		rv = CKR_ARGUMENTS_BAD;
76 		goto failed_exit;
77 	}
78 
79 	if ((pTemplate == NULL) && (ulCount != 0)) {
80 		rv = CKR_ARGUMENTS_BAD;
81 		goto failed_exit;
82 	}
83 
84 	/* Get the kernel's internal mechanism number. */
85 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
86 	if (rv != CKR_OK) {
87 		goto failed_exit;
88 	}
89 
90 	/* Create an object wrapper in the library first */
91 	new_objp = calloc(1, sizeof (kernel_object_t));
92 	if (new_objp == NULL) {
93 		rv = CKR_HOST_MEMORY;
94 		goto failed_exit;
95 	}
96 
97 	/* Process the attributes */
98 	rv = process_object_attributes(pTemplate, ulCount,
99 	    &obj_gk.gk_attributes, &is_token_obj);
100 	if (rv != CKR_OK) {
101 		goto failed_exit;
102 	}
103 
104 	/* Cannot create a token object with a READ-ONLY session. */
105 	if (is_token_obj && session_p->ses_RO) {
106 		free_object_attributes(obj_gk.gk_attributes, ulCount);
107 		rv = CKR_SESSION_READ_ONLY;
108 		goto failed_exit;
109 	}
110 
111 	/* Call the CRYPTO_GENERATE_KEY ioctl */
112 	obj_gk.gk_session = session_p->k_session;
113 	obj_gk.gk_count = ulCount;
114 	obj_gk.gk_mechanism.cm_type = k_mech_type;
115 	obj_gk.gk_mechanism.cm_param = pMechanism->pParameter;
116 	obj_gk.gk_mechanism.cm_param_len = pMechanism->ulParameterLen;
117 
118 	while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY, &obj_gk)) < 0) {
119 		if (errno != EINTR)
120 			break;
121 	}
122 	if (r < 0) {
123 		rv = CKR_FUNCTION_FAILED;
124 	} else {
125 		rv = crypto2pkcs11_error_number(obj_gk.gk_return_value);
126 	}
127 
128 	free_object_attributes(obj_gk.gk_attributes, ulCount);
129 	if (rv != CKR_OK) {
130 		goto failed_exit;
131 	}
132 
133 	/* Get the value of the CKA_PRIVATE attribute. */
134 	rv = get_cka_private_value(session_p, obj_gk.gk_handle, &is_pri_obj);
135 	if (rv != CKR_OK) {
136 		goto failed_exit;
137 	}
138 
139 	/*
140 	 * Store the kernel object handle in the object wrapper and
141 	 * initialize the library object.
142 	 */
143 	new_objp->k_handle = obj_gk.gk_handle;
144 	new_objp->is_lib_obj = B_FALSE;
145 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
146 	new_objp->extra_attrlistp = NULL;
147 
148 	if (is_pri_obj)
149 		new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
150 	else
151 		new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
152 
153 	if (is_token_obj)
154 		new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
155 	else
156 		new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
157 
158 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
159 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
160 
161 	/*
162 	 * Add the new object to the slot's token object list if it is a
163 	 * a token object. Otherwise, add it to the session's object list.
164 	 */
165 	if (is_token_obj) {
166 		pslot = slot_table[session_p->ses_slotid];
167 		kernel_add_token_object_to_slot(new_objp, pslot);
168 	} else {
169 		kernel_add_object_to_session(new_objp, session_p);
170 	}
171 
172 	*phKey = (CK_OBJECT_HANDLE)new_objp;
173 	REFRELE(session_p, ses_lock_held);
174 	return (rv);
175 
176 failed_exit:
177 	if (new_objp != NULL) {
178 		(void) free(new_objp);
179 	}
180 
181 	REFRELE(session_p, ses_lock_held);
182 	return (rv);
183 }
184 
185 
186 CK_RV
187 C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
188     CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
189     CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
190     CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
191 {
192 	CK_RV			rv = CKR_OK;
193 	kernel_session_t	*session_p;
194 	kernel_object_t		*new_pub_objp = NULL;
195 	kernel_object_t		*new_pri_objp = NULL;
196 	kernel_slot_t		*pslot;
197 	boolean_t		ses_lock_held = B_FALSE;
198 	CK_BBOOL		is_pri_obj1;
199 	CK_BBOOL		is_pri_obj2;
200 	CK_BBOOL		is_token_obj1 = FALSE;
201 	CK_BBOOL		is_token_obj2 = FALSE;
202 	crypto_mech_type_t	k_mech_type;
203 	crypto_object_generate_key_pair_t 	obj_kp;
204 	int r;
205 
206 	if (!kernel_initialized)
207 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
208 
209 	/* Obtain the session pointer. */
210 	rv = handle2session(hSession, &session_p);
211 	if (rv != CKR_OK)
212 		return (rv);
213 
214 	if ((pMechanism == NULL) || (phPublicKey == NULL) ||
215 	    (phPrivateKey == NULL)) {
216 		rv = CKR_ARGUMENTS_BAD;
217 		goto failed_exit;
218 	}
219 
220 	if ((pPublicKeyTemplate == NULL) && (ulPublicKeyAttributeCount != 0)) {
221 		rv = CKR_ARGUMENTS_BAD;
222 		goto failed_exit;
223 	}
224 
225 	if ((pPrivateKeyTemplate == NULL) &&
226 	    (ulPrivateKeyAttributeCount != 0)) {
227 		rv = CKR_ARGUMENTS_BAD;
228 		goto failed_exit;
229 	}
230 
231 	/* Get the kernel's internal mechanism number. */
232 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
233 	if (rv != CKR_OK) {
234 		goto failed_exit;
235 	}
236 
237 	/* Create an object wrapper for the public key */
238 	new_pub_objp = calloc(1, sizeof (kernel_object_t));
239 	if (new_pub_objp == NULL) {
240 		rv = CKR_HOST_MEMORY;
241 		goto failed_exit;
242 	}
243 
244 	/* Create an object wrapper for the private key. */
245 	new_pri_objp = calloc(1, sizeof (kernel_object_t));
246 	if (new_pri_objp == NULL) {
247 		rv = CKR_HOST_MEMORY;
248 		goto failed_exit;
249 	}
250 
251 	/* Process the public key attributes. */
252 	rv = process_object_attributes(pPublicKeyTemplate,
253 	    ulPublicKeyAttributeCount, &obj_kp.kp_public_attributes,
254 	    &is_token_obj1);
255 	if (rv != CKR_OK) {
256 		goto failed_exit;
257 	}
258 
259 	/* Cannot create a token object with a READ-ONLY session. */
260 	if (is_token_obj1 && session_p->ses_RO) {
261 		free_object_attributes(obj_kp.kp_public_attributes,
262 		    ulPublicKeyAttributeCount);
263 		rv = CKR_SESSION_READ_ONLY;
264 		goto failed_exit;
265 	}
266 
267 	/* Process the private key attributes. */
268 	rv = process_object_attributes(pPrivateKeyTemplate,
269 	    ulPrivateKeyAttributeCount, &obj_kp.kp_private_attributes,
270 	    &is_token_obj2);
271 	if (rv != CKR_OK) {
272 		free_object_attributes(obj_kp.kp_public_attributes,
273 		    ulPublicKeyAttributeCount);
274 		goto failed_exit;
275 	}
276 
277 	/*
278 	 * The public key and the private key need to contain the same
279 	 * attribute values for CKA_TOKEN.
280 	 */
281 	if (is_token_obj1 != is_token_obj2) {
282 		free_object_attributes(obj_kp.kp_public_attributes,
283 		    ulPublicKeyAttributeCount);
284 		free_object_attributes(obj_kp.kp_private_attributes,
285 		    ulPrivateKeyAttributeCount);
286 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
287 		goto failed_exit;
288 	}
289 
290 	/* Call the CRYPTO_GENERATE_KEY_PAIR ioctl. */
291 	obj_kp.kp_session = session_p-> k_session;
292 	obj_kp.kp_mechanism.cm_type = k_mech_type;
293 	obj_kp.kp_mechanism.cm_param = pMechanism->pParameter;
294 	obj_kp.kp_mechanism.cm_param_len = pMechanism->ulParameterLen;
295 	obj_kp.kp_public_count = ulPublicKeyAttributeCount;
296 	obj_kp.kp_private_count = ulPrivateKeyAttributeCount;
297 
298 	while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY_PAIR, &obj_kp)) < 0) {
299 		if (errno != EINTR)
300 			break;
301 	}
302 	if (r < 0) {
303 		rv = CKR_FUNCTION_FAILED;
304 	} else {
305 		rv = crypto2pkcs11_error_number(obj_kp.kp_return_value);
306 	}
307 
308 	free_object_attributes(obj_kp.kp_public_attributes,
309 	    ulPublicKeyAttributeCount);
310 	free_object_attributes(obj_kp.kp_private_attributes,
311 	    ulPrivateKeyAttributeCount);
312 
313 	if (rv != CKR_OK) {
314 		goto failed_exit;
315 	}
316 
317 	/* Get the CKA_PRIVATE value for the key pair. */
318 	rv = get_cka_private_value(session_p, obj_kp.kp_public_handle,
319 	    &is_pri_obj1);
320 	if (rv != CKR_OK) {
321 		goto failed_exit;
322 	}
323 
324 	rv = get_cka_private_value(session_p, obj_kp.kp_private_handle,
325 	    &is_pri_obj2);
326 	if (rv != CKR_OK) {
327 		goto failed_exit;
328 	}
329 
330 	/*
331 	 * Store the kernel public key handle into the public key object and
332 	 * finish the public key object initialization.
333 	 */
334 	new_pub_objp->is_lib_obj = B_FALSE;
335 	new_pub_objp->k_handle = obj_kp.kp_public_handle;
336 	new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
337 	new_pub_objp->extra_attrlistp = NULL;
338 
339 	if (is_pri_obj1)
340 		new_pub_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
341 	else
342 		new_pub_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
343 
344 	if (is_token_obj1)
345 		new_pub_objp->bool_attr_mask |= TOKEN_BOOL_ON;
346 	else
347 		new_pub_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
348 
349 	(void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
350 	new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
351 
352 	/*
353 	 * Store the kernel private key handle into the private key object
354 	 * and finish the private key object initialization.
355 	 */
356 	new_pri_objp->is_lib_obj = B_FALSE;
357 	new_pri_objp->k_handle = obj_kp.kp_private_handle;
358 	new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
359 	new_pri_objp->extra_attrlistp = NULL;
360 
361 	if (is_pri_obj2)
362 		new_pri_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
363 	else
364 		new_pri_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
365 
366 	if (is_token_obj2)
367 		new_pri_objp->bool_attr_mask |= TOKEN_BOOL_ON;
368 	else
369 		new_pri_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
370 
371 	(void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
372 	new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
373 
374 	/*
375 	 * Add the new pub/pri objects to the slot's token list if they are
376 	 * token objects. Otherwise, add them to the session's object list.
377 	 */
378 	if (is_token_obj1) { /* is_token_obj1 == is_token_obj2 */
379 		pslot = slot_table[session_p->ses_slotid];
380 		kernel_add_token_object_to_slot(new_pub_objp, pslot);
381 		kernel_add_token_object_to_slot(new_pri_objp, pslot);
382 	} else {
383 		kernel_add_object_to_session(new_pub_objp, session_p);
384 		kernel_add_object_to_session(new_pri_objp, session_p);
385 	}
386 
387 	*phPublicKey = (CK_OBJECT_HANDLE)new_pub_objp;
388 	*phPrivateKey = (CK_OBJECT_HANDLE)new_pri_objp;
389 	REFRELE(session_p, ses_lock_held);
390 	return (rv);
391 
392 failed_exit:
393 	if (new_pub_objp != NULL) {
394 		(void) free(new_pub_objp);
395 	}
396 
397 	if (new_pri_objp != NULL) {
398 		(void) free(new_pri_objp);
399 	}
400 
401 	REFRELE(session_p, ses_lock_held);
402 	return (rv);
403 }
404 
405 
406 CK_RV
407 C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
408     CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
409     CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen)
410 {
411 	CK_RV			rv = CKR_OK;
412 	kernel_session_t	*session_p;
413 	boolean_t		ses_lock_held = B_FALSE;
414 	kernel_object_t		*wrappingkey_p;
415 	kernel_object_t		*key_p;
416 	crypto_mech_type_t	k_mech_type;
417 	crypto_object_wrap_key_t obj_wrapkey;
418 	int r;
419 
420 	if (!kernel_initialized)
421 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
422 
423 	if (pulWrappedKeyLen == NULL || pMechanism == NULL) {
424 		return (CKR_ARGUMENTS_BAD);
425 	}
426 
427 	/*
428 	 * Obtain the session pointer.  Also, increment the session
429 	 * reference count.
430 	 */
431 	rv = handle2session(hSession, &session_p);
432 	if (rv != CKR_OK)
433 		return (rv);
434 
435 	/* Get the kernel's internal mechanism number. */
436 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
437 	if (rv != CKR_OK) {
438 		REFRELE(session_p, ses_lock_held);
439 		return (rv);
440 	}
441 
442 	/* Obtain the wrapping key object pointer. */
443 	HANDLE2OBJECT(hWrappingKey, wrappingkey_p, rv);
444 	if (rv != CKR_OK) {
445 		REFRELE(session_p, ses_lock_held);
446 		return (rv);
447 	}
448 
449 	/* Obtain the to_be_wrapped key object pointer. */
450 	HANDLE2OBJECT(hKey, key_p, rv);
451 	if (rv != CKR_OK) {
452 		OBJ_REFRELE(wrappingkey_p);
453 		REFRELE(session_p, ses_lock_held);
454 		return (rv);
455 	}
456 
457 	/* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */
458 	obj_wrapkey.wk_session = session_p->k_session;
459 	obj_wrapkey.wk_mechanism.cm_type = k_mech_type;
460 	obj_wrapkey.wk_mechanism.cm_param = pMechanism->pParameter;
461 	obj_wrapkey.wk_mechanism.cm_param_len = pMechanism->ulParameterLen;
462 	obj_wrapkey.wk_wrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
463 	obj_wrapkey.wk_wrapping_key.ck_obj_id = wrappingkey_p->k_handle;
464 	obj_wrapkey.wk_object_handle = key_p->k_handle;
465 	obj_wrapkey.wk_wrapped_key_len = *pulWrappedKeyLen;
466 	obj_wrapkey.wk_wrapped_key = (char *)pWrappedKey;
467 
468 	while ((r = ioctl(kernel_fd, CRYPTO_WRAP_KEY, &obj_wrapkey)) < 0) {
469 		if (errno != EINTR)
470 			break;
471 	}
472 	if (r < 0) {
473 		rv = CKR_FUNCTION_FAILED;
474 	} else {
475 		rv = crypto2pkcs11_error_number(obj_wrapkey.wk_return_value);
476 	}
477 
478 	/*
479 	 * Besides rv == CKR_OK, we will set the value of pulWrappedKeyLen
480 	 * when the applciation-supplied wrapped key buffer is too small.
481 	 * The situation that the application only asks for the length of
482 	 * the wrapped key is covered in rv == CKR_OK.
483 	 */
484 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
485 		*pulWrappedKeyLen = obj_wrapkey.wk_wrapped_key_len;
486 	}
487 
488 	OBJ_REFRELE(key_p);
489 	OBJ_REFRELE(wrappingkey_p);
490 	REFRELE(session_p, ses_lock_held);
491 	return (rv);
492 }
493 
494 
495 CK_RV
496 C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
497     CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey,
498     CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
499     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
500 {
501 	CK_RV			rv = CKR_OK;
502 	kernel_session_t	*session_p;
503 	kernel_object_t		*unwrappingkey_p;
504 	kernel_object_t		*new_objp = NULL;
505 	kernel_slot_t		*pslot;
506 	boolean_t		ses_lock_held = B_FALSE;
507 	CK_BBOOL		is_pri_obj;
508 	CK_BBOOL		is_token_obj = FALSE;
509 	CK_MECHANISM_INFO	info;
510 	uint32_t		k_mi_flags;
511 	CK_BYTE			*clear_key_val = NULL;
512 	CK_ULONG 		ulDataLen;
513 	CK_ATTRIBUTE_PTR	newTemplate = NULL;
514 	CK_ULONG		templ_size;
515 	crypto_mech_type_t	k_mech_type;
516 	crypto_object_unwrap_key_t obj_unwrapkey;
517 	int r;
518 
519 	if (!kernel_initialized)
520 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
521 
522 	if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) {
523 		return (CKR_ARGUMENTS_BAD);
524 	}
525 
526 	if ((pTemplate == NULL) && (ulAttributeCount != 0)) {
527 		return (CKR_ARGUMENTS_BAD);
528 	}
529 
530 	/* Obtain the session pointer. */
531 	rv = handle2session(hSession, &session_p);
532 	if (rv != CKR_OK)
533 		return (rv);
534 
535 	/* Obtain the wrapping key object pointer. */
536 	HANDLE2OBJECT(hUnwrappingKey, unwrappingkey_p, rv);
537 	if (rv != CKR_OK) {
538 		REFRELE(session_p, ses_lock_held);
539 		return (rv);
540 	}
541 
542 	/*
543 	 * If the HW provider doesn't support C_UnwrapKey, we will try
544 	 * to emulate it in the library.
545 	 */
546 	pslot = slot_table[session_p->ses_slotid];
547 	if ((pslot->sl_func_list.fl_object_create == B_FALSE) &&
548 	    (pslot->sl_func_list.fl_key_unwrap == B_FALSE)) {
549 		rv = get_mechanism_info(pslot, pMechanism->mechanism, &info,
550 		    &k_mi_flags);
551 		if (rv != CKR_OK) {
552 			goto failed_exit;
553 		}
554 
555 		/*
556 		 * If the mechanism flag doesn't have CKF_UNWRAP, and it's
557 		 * an unwrapping of a secret key object, then help this
558 		 * out with a decryption followed by an object creation.
559 		 */
560 		if (!(k_mi_flags & CRYPTO_FG_UNWRAP) &&
561 		    (k_mi_flags & CRYPTO_FG_DECRYPT) &&
562 		    (is_secret_key_template(pTemplate, ulAttributeCount))) {
563 
564 			/* First allocate space for the recovered key value */
565 			clear_key_val = malloc(ulWrappedKeyLen);
566 			if (clear_key_val == NULL) {
567 				rv = CKR_HOST_MEMORY;
568 				goto failed_exit;
569 			}
570 
571 			rv = kernel_decrypt_init(session_p, unwrappingkey_p,
572 			    pMechanism);
573 			if (rv != CKR_OK) {
574 				goto failed_exit;
575 			}
576 
577 			ulDataLen = ulWrappedKeyLen;
578 			rv = kernel_decrypt(session_p, pWrappedKey,
579 			    ulWrappedKeyLen, clear_key_val, &ulDataLen);
580 			if (rv != CKR_OK) {
581 				goto failed_exit;
582 			}
583 
584 			/* Now add the CKA_VALUE attribute to template */
585 			templ_size = ulAttributeCount * sizeof (CK_ATTRIBUTE);
586 			newTemplate = malloc(templ_size +
587 			    sizeof (CK_ATTRIBUTE));
588 			if (newTemplate == NULL) {
589 				rv = CKR_HOST_MEMORY;
590 				goto failed_exit;
591 			}
592 
593 			bcopy(pTemplate, newTemplate, templ_size);
594 			newTemplate[ulAttributeCount].type = CKA_VALUE;
595 			newTemplate[ulAttributeCount].pValue = clear_key_val;
596 			newTemplate[ulAttributeCount].ulValueLen = ulDataLen;
597 
598 			/* Finally create the key, based on the new template */
599 			rv = kernel_add_object(newTemplate,
600 			    ulAttributeCount + 1, phKey, session_p);
601 			(void) free(clear_key_val);
602 			(void) free(newTemplate);
603 			OBJ_REFRELE(unwrappingkey_p);
604 			REFRELE(session_p, ses_lock_held);
605 			return (rv);
606 		} else {
607 			rv = CKR_FUNCTION_FAILED;
608 			goto failed_exit;
609 		}
610 	}
611 
612 	/*
613 	 * If we come here, the HW provider must have registered the unwrapkey
614 	 * entry.  Therefore, the unwrap key will be performed in the HW
615 	 * provider.
616 	 */
617 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
618 	if (rv != CKR_OK) {
619 		goto failed_exit;
620 	}
621 
622 	/* Create an object wrapper for the new key in the library first */
623 	new_objp = calloc(1, sizeof (kernel_object_t));
624 	if (new_objp == NULL) {
625 		rv = CKR_HOST_MEMORY;
626 		goto failed_exit;
627 	}
628 
629 	/* Process the attributes */
630 	rv = process_object_attributes(pTemplate, ulAttributeCount,
631 	    &obj_unwrapkey.uk_attributes, &is_token_obj);
632 	if (rv != CKR_OK) {
633 		goto failed_exit;
634 	}
635 
636 	/* Cannot create a token object with a READ-ONLY session. */
637 	if (is_token_obj && session_p->ses_RO) {
638 		free_object_attributes(obj_unwrapkey.uk_attributes,
639 		    ulAttributeCount);
640 		rv = CKR_SESSION_READ_ONLY;
641 		goto failed_exit;
642 	}
643 
644 	/* Make the CRYPTO_UNWRAP_KEY ioctl call. */
645 	obj_unwrapkey.uk_session = session_p->k_session;
646 	obj_unwrapkey.uk_mechanism.cm_type = k_mech_type;
647 	obj_unwrapkey.uk_mechanism.cm_param = pMechanism->pParameter;
648 	obj_unwrapkey.uk_mechanism.cm_param_len = pMechanism->ulParameterLen;
649 	obj_unwrapkey.uk_unwrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
650 	obj_unwrapkey.uk_unwrapping_key.ck_obj_id = unwrappingkey_p->k_handle;
651 	obj_unwrapkey.uk_wrapped_key = (char *)pWrappedKey;
652 	obj_unwrapkey.uk_wrapped_key_len = ulWrappedKeyLen;
653 	obj_unwrapkey.uk_count = ulAttributeCount;
654 
655 	while ((r = ioctl(kernel_fd, CRYPTO_UNWRAP_KEY, &obj_unwrapkey)) < 0) {
656 		if (errno != EINTR)
657 			break;
658 	}
659 	if (r < 0) {
660 		rv = CKR_FUNCTION_FAILED;
661 	} else {
662 		rv = crypto2pkcs11_error_number(obj_unwrapkey.uk_return_value);
663 	}
664 
665 	free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount);
666 	if (rv != CKR_OK) {
667 		goto failed_exit;
668 	}
669 
670 	/* Get the CKA_PRIVATE value for the unwrapped key. */
671 	rv = get_cka_private_value(session_p, obj_unwrapkey.uk_object_handle,
672 	    &is_pri_obj);
673 	if (rv != CKR_OK) {
674 		goto failed_exit;
675 	}
676 
677 	/*
678 	 * Store the kernel object handle in the new key object wrapper and
679 	 * initialize it.
680 	 */
681 	new_objp->k_handle = obj_unwrapkey.uk_object_handle;
682 	new_objp->is_lib_obj = B_FALSE;
683 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
684 	new_objp->extra_attrlistp = NULL;
685 
686 	if (is_pri_obj)
687 		new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
688 	else
689 		new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
690 
691 	if (is_token_obj)
692 		new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
693 	else
694 		new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
695 
696 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
697 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
698 
699 	/*
700 	 * Add the new object to the slot's token object list if it is a
701 	 * a token object. Otherwise, add it to the session's object list.
702 	 */
703 	if (is_token_obj) {
704 		pslot = slot_table[session_p->ses_slotid];
705 		kernel_add_token_object_to_slot(new_objp, pslot);
706 	} else {
707 		kernel_add_object_to_session(new_objp, session_p);
708 	}
709 
710 	*phKey = (CK_OBJECT_HANDLE)new_objp;
711 	OBJ_REFRELE(unwrappingkey_p);
712 	REFRELE(session_p, ses_lock_held);
713 	return (rv);
714 
715 failed_exit:
716 	OBJ_REFRELE(unwrappingkey_p);
717 	if (new_objp != NULL)
718 		(void) free(new_objp);
719 
720 	if (clear_key_val != NULL)
721 		(void) free(clear_key_val);
722 
723 	if (newTemplate != NULL)
724 		(void) free(newTemplate);
725 
726 	REFRELE(session_p, ses_lock_held);
727 	return (rv);
728 }
729 
730 
731 CK_RV
732 C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
733     CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
734     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
735 {
736 	CK_RV			rv = CKR_OK;
737 	kernel_session_t	*session_p;
738 	kernel_object_t		*basekey_p;
739 	kernel_object_t		*new_objp;
740 	kernel_slot_t		*pslot;
741 	boolean_t		ses_lock_held = B_FALSE;
742 	CK_BBOOL		is_pri_obj;
743 	CK_BBOOL		is_token_obj = FALSE;
744 	crypto_mech_type_t	k_mech_type;
745 	crypto_derive_key_t	obj_dk;
746 	int r;
747 
748 	if (!kernel_initialized)
749 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
750 
751 	/* Obtain the session pointer. */
752 	rv = handle2session(hSession, &session_p);
753 	if (rv != CKR_OK)
754 		return (rv);
755 
756 	if (pMechanism == NULL) {
757 		REFRELE(session_p, ses_lock_held);
758 		return (CKR_ARGUMENTS_BAD);
759 	}
760 
761 	if ((pTemplate == NULL && ulAttributeCount != 0) ||
762 	    (pTemplate != NULL && ulAttributeCount == 0)) {
763 		REFRELE(session_p, ses_lock_held);
764 		return (CKR_ARGUMENTS_BAD);
765 	}
766 
767 	/* Obtain the base key object pointer. */
768 	HANDLE2OBJECT(hBaseKey, basekey_p, rv);
769 	if (rv != CKR_OK) {
770 		REFRELE(session_p, ses_lock_held);
771 		return (rv);
772 	}
773 
774 	/* Get the kernel's internal mechanism number. */
775 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
776 	if (rv != CKR_OK) {
777 		goto failed_exit;
778 	}
779 
780 	/* Create an object wrapper in the library for the generated key. */
781 	new_objp = calloc(1, sizeof (kernel_object_t));
782 	if (new_objp == NULL) {
783 		rv = CKR_HOST_MEMORY;
784 		goto failed_exit;
785 	}
786 
787 	/* Process the attributes */
788 	rv = process_object_attributes(pTemplate, ulAttributeCount,
789 	    &obj_dk.dk_attributes, &is_token_obj);
790 	if (rv != CKR_OK) {
791 		goto failed_exit;
792 	}
793 
794 	/* Cannot create a token object with a READ-ONLY session. */
795 	if (is_token_obj && session_p->ses_RO) {
796 		free_object_attributes(obj_dk.dk_attributes, ulAttributeCount);
797 		rv = CKR_SESSION_READ_ONLY;
798 		goto failed_exit;
799 	}
800 
801 	/* Call the CRYPTO_DERIVE_KEY ioctl */
802 	obj_dk.dk_session = session_p->k_session;
803 	obj_dk.dk_mechanism.cm_type = k_mech_type;
804 	obj_dk.dk_mechanism.cm_param = pMechanism->pParameter;
805 	obj_dk.dk_mechanism.cm_param_len = pMechanism->ulParameterLen;
806 	obj_dk.dk_base_key.ck_format = CRYPTO_KEY_REFERENCE;
807 	obj_dk.dk_base_key.ck_obj_id = basekey_p->k_handle;
808 	obj_dk.dk_count = ulAttributeCount;
809 
810 	while ((r = ioctl(kernel_fd, CRYPTO_DERIVE_KEY, &obj_dk)) < 0) {
811 		if (errno != EINTR)
812 			break;
813 	}
814 	if (r < 0) {
815 		rv = CKR_FUNCTION_FAILED;
816 	} else {
817 		rv = crypto2pkcs11_error_number(obj_dk.dk_return_value);
818 	}
819 
820 	free_object_attributes(obj_dk.dk_attributes, ulAttributeCount);
821 	if (rv != CKR_OK) {
822 		goto failed_exit;
823 	}
824 
825 	/* Get the CKA_PRIVATE value for the derived key. */
826 	rv = get_cka_private_value(session_p, obj_dk.dk_object_handle,
827 	    &is_pri_obj);
828 	if (rv != CKR_OK) {
829 		goto failed_exit;
830 	}
831 
832 	/*
833 	 * Store the kernel object handle into the new derived key object
834 	 * and finish the object initialization.
835 	 */
836 	new_objp->is_lib_obj = B_FALSE;
837 	new_objp->k_handle = obj_dk.dk_object_handle;
838 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
839 	new_objp->extra_attrlistp = NULL;
840 
841 	if (is_pri_obj)
842 		new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
843 	else
844 		new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
845 
846 	if (is_token_obj)
847 		new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
848 	else
849 		new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
850 
851 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
852 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
853 
854 	/*
855 	 * Add the new derived object to the slot's token list if it is a
856 	 * token object. Otherwise, add it to the session's object list.
857 	 */
858 	if (is_token_obj) {
859 		pslot = slot_table[session_p->ses_slotid];
860 		kernel_add_token_object_to_slot(new_objp, pslot);
861 	} else {
862 		kernel_add_object_to_session(new_objp, session_p);
863 	}
864 
865 	*phKey = (CK_OBJECT_HANDLE)new_objp;
866 	OBJ_REFRELE(basekey_p);
867 	REFRELE(session_p, ses_lock_held);
868 	return (rv);
869 
870 failed_exit:
871 	OBJ_REFRELE(basekey_p);
872 	if (new_objp != NULL) {
873 		(void) free(new_objp);
874 	}
875 
876 	REFRELE(session_p, ses_lock_held);
877 	return (rv);
878 }
879